diff --git a/src/pin/pin_exec/analysis_functions.cc b/src/pin/pin_exec/analysis_functions.cc index 98116ed1..e886d3e3 100644 --- a/src/pin/pin_exec/analysis_functions.cc +++ b/src/pin/pin_exec/analysis_functions.cc @@ -25,42 +25,6 @@ #include "../pin_lib/decoder.h" -namespace { - -/* -void add_right_path_exec_br(CONTEXT* ctxt) { - // Create dummy jmp - ADDRINT eip; - PIN_GetContextRegval(ctxt, REG_INST_PTR, (UINT8*)&eip); - compressed_op cop = create_dummy_jump(saved_excp_next_eip, eip); - cop.inst_uid = pintool_state.get_curr_inst_uid(); - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, -dbg_print_end_uid, "Prev EIPs %lx, %lx\n", saved_excp_eip, saved_excp_next_eip); - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, -dbg_print_end_uid, "At EIP %" PRIx64 "\n", eip); - - // Mailbox will be empty as we clear it before a rightpath excpetion - ASSERTM(0, !op_mailbox_full, - "Expected empty mailbox for rightpath exception op @ %" PRIu64 ".\n", - pintool_state.get_curr_inst_uid()); - - // Insert in mailbox - op_mailbox = cop; - op_mailbox_full = true; - - // Save checkpoint - checkpoints.append_to_cir_buf(); - checkpoints.get_tail().init(pintool_state.get_curr_inst_uid(), false, -on_wrongpath, on_wrongpath_nop_mode, next_eip, 0); - //pintool_state.get_curr_inst_uid()++; - save_context(ctxt); -} -*/ - - -} // namespace - - #define ENABLE_HYPER_FF_HEARTBEAT void PIN_FAST_ANALYSIS_CALL docount(UINT32 c) { int64_t temp = hyper_fast_forward_count - c; @@ -179,6 +143,8 @@ void logging(ADDRINT next_rip, ADDRINT curr_rip, bool check_next_addr, } } + pintool_state.set_next_rip(next_rip); + if(!fast_forward_count) { if(heartbeat_enabled && !(pintool_state.get_curr_inst_uid() & 0x7FFFF)) { std::cout << "Heartbeat (uid=" << pintool_state.get_curr_inst_uid() << ")" @@ -216,6 +182,35 @@ void logging(ADDRINT next_rip, ADDRINT curr_rip, bool check_next_addr, } } +void exception_handler_followup(CONTEXT* ctxt) { + if(pintool_state.should_insert_dummy_exception_br()) { + ASSERTM(0, !op_mailbox_full, + "Expected empty mailbox for rightpath exception op @ %" PRIu64 + ".\n", + pintool_state.get_curr_inst_uid()); + + const auto inst_uid = pintool_state.get_next_inst_uid(); + + uint64_t curr_rip = PIN_GetContextReg(ctxt, REG_INST_PTR); + op_mailbox = create_dummy_jump( + pintool_state.get_rightpath_exception_next_rip(), curr_rip); + op_mailbox.inst_uid = inst_uid; + op_mailbox_full = true; + + DBG_PRINT(inst_uid, dbg_print_start_uid, dbg_print_end_uid, + "Inserting a dummy branch following an exception. Exception RIP: " + "%lx, Branch RIP: %lx, jumping to %lx\n", + pintool_state.get_rightpath_exception_rip(), + pintool_state.get_rightpath_exception_next_rip(), curr_rip); + + checkpoints.append_to_cir_buf(); + checkpoints.get_tail().update(ctxt, inst_uid, false, false, false, curr_rip, + Mem_Writes_Info{}, false); + + pintool_state.clear_rightpath_exception(); + } +} + void check_ret_control_ins(ADDRINT read_addr, UINT32 read_size, CONTEXT* ctxt) { if(!fast_forward_count) { read_addr = ADDR_MASK(read_addr); @@ -226,12 +221,15 @@ void check_ret_control_ins(ADDRINT read_addr, UINT32 read_size, CONTEXT* ctxt) { uint64_t target_addr; PIN_SafeCopy(&target_addr, (void*)read_addr, read_size); target_addr = ADDR_MASK(target_addr); + pintool_state.set_next_rip(target_addr); DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, dbg_print_end_uid, "Ret Control targetaddr=%" PRIx64 "\n", (uint64_t)target_addr); + if(pintool_state.is_on_wrongpath() && !instrumented_rip_tracker.contains(target_addr)) { + target_addr = target_addr ? target_addr : 1; DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, dbg_print_end_uid, "Entering from ret WPNM targetaddr=%" PRIx64 "\n", @@ -244,12 +242,14 @@ void check_ret_control_ins(ADDRINT read_addr, UINT32 read_size, CONTEXT* ctxt) { void check_nonret_control_ins(bool taken, ADDRINT target_addr) { if(!fast_forward_count) { + pintool_state.set_next_rip(target_addr); target_addr = ADDR_MASK(target_addr); DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, dbg_print_end_uid, "Non Ret Control targetaddr=%" PRIx64 "\n", (uint64_t)target_addr); if(pintool_state.is_on_wrongpath() && taken && !instrumented_rip_tracker.contains(target_addr)) { + target_addr = target_addr ? target_addr : 1; DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, dbg_print_end_uid, "Entering from nonret WPNM targetaddr=%" PRIx64 "\n", @@ -287,4 +287,4 @@ void handle_scarab_marker(ADDRINT op) { std::cerr << "Error: Found Scarab Marker that does not have known code." << endl; } -} +} \ No newline at end of file diff --git a/src/pin/pin_exec/analysis_functions.h b/src/pin/pin_exec/analysis_functions.h index f39ac2b4..1b1c145f 100644 --- a/src/pin/pin_exec/analysis_functions.h +++ b/src/pin/pin_exec/analysis_functions.h @@ -47,6 +47,8 @@ void redirect(CONTEXT* ctx); void logging(ADDRINT next_rip, ADDRINT curr_rip, bool check_next_addr, bool taken); +void exception_handler_followup(CONTEXT* ctxt); + void check_ret_control_ins(ADDRINT read_addr, UINT32 read_size, CONTEXT* ctxt); void check_nonret_control_ins(bool taken, ADDRINT target_addr); diff --git a/src/pin/pin_exec/exception_handling.cc b/src/pin/pin_exec/exception_handling.cc index 483847d5..b012d61d 100644 --- a/src/pin/pin_exec/exception_handling.cc +++ b/src/pin/pin_exec/exception_handling.cc @@ -28,74 +28,6 @@ namespace { -/* -void excp_do_fe_null() { - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, -dbg_print_end_uid, "fenull curr_uid=%" PRIu64 "\n", -pintool_state.get_curr_inst_uid()); compressed_op* cop; ASSERTM(0, -!generate_dummy_nops, "Dummy NOP generated exception @uid %" PRIu64 ".\n", -pintool_state.get_curr_inst_uid()); ASSERTM(0, op_mailbox_full, "Expected full -mailbox for exc @ %" PRIu64 ".\n", pintool_state.get_curr_inst_uid()); - - cop = &op_mailbox; - op_mailbox_full = false; - cop->cf_type = CF_SYS; - cop->is_ifetch_barrier = 1; - // cop->fake_inst = 1; - cop->instruction_next_addr = saved_excp_next_eip; - - op_mailbox.instruction_next_addr = cop->instruction_addr; - if(op_mailbox.cf_type && op_mailbox.actually_taken) { - op_mailbox.branch_target = cop->instruction_addr; - } - insert_scarab_op_in_buffer(op_mailbox); - op_mailbox_full = false; - - insert_scarab_op_in_buffer(*cop); - - // only syscalls create checkpoints BEFORE being sent, - // so we update pintool_state.get_curr_inst_uid() here to prep. for next -instruction pintool_state.get_curr_inst_uid()++; -} -*/ - -} // namespace - -void register_signal_handlers() { - // Intercept signals to see exceptions - PIN_InterceptSignal(SIGFPE, signal_handler, 0); - PIN_InterceptSignal(SIGILL, signal_handler, 0); - PIN_InterceptSignal(SIGSEGV, signal_handler, 0); - PIN_InterceptSignal(SIGBUS, signal_handler, 0); - - PIN_InterceptSignal(SIGHUP, dummy_handler, 0); - PIN_InterceptSignal(SIGINT, dummy_handler, 0); - PIN_InterceptSignal(SIGQUIT, dummy_handler, 0); - PIN_InterceptSignal(SIGTRAP, dummy_handler, 0); - PIN_InterceptSignal(SIGIOT, dummy_handler, 0); - PIN_InterceptSignal(SIGKILL, dummy_handler, 0); - PIN_InterceptSignal(SIGUSR1, dummy_handler, 0); - PIN_InterceptSignal(SIGUSR2, dummy_handler, 0); - PIN_InterceptSignal(SIGPIPE, dummy_handler, 0); - PIN_InterceptSignal(SIGALRM, dummy_handler, 0); - PIN_InterceptSignal(SIGTERM, dummy_handler, 0); - PIN_InterceptSignal(SIGSTKFLT, dummy_handler, 0); - PIN_InterceptSignal(SIGCHLD, dummy_handler, 0); - PIN_InterceptSignal(SIGCONT, dummy_handler, 0); - PIN_InterceptSignal(SIGSTOP, dummy_handler, 0); - PIN_InterceptSignal(SIGTSTP, dummy_handler, 0); - PIN_InterceptSignal(SIGTTIN, dummy_handler, 0); - PIN_InterceptSignal(SIGTTOU, dummy_handler, 0); - PIN_InterceptSignal(SIGURG, dummy_handler, 0); - PIN_InterceptSignal(SIGXCPU, dummy_handler, 0); - PIN_InterceptSignal(SIGXFSZ, dummy_handler, 0); - PIN_InterceptSignal(SIGVTALRM, dummy_handler, 0); - PIN_InterceptSignal(SIGPROF, dummy_handler, 0); - PIN_InterceptSignal(SIGWINCH, dummy_handler, 0); - PIN_InterceptSignal(SIGIO, dummy_handler, 0); - PIN_InterceptSignal(SIGPWR, dummy_handler, 0); -} - bool dummy_handler(THREADID tid, INT32 sig, CONTEXT* ctxt, bool hasHandler, const EXCEPTION_INFO* pExceptInfo, void* v) { #ifdef DEBUG_PRINT @@ -110,174 +42,142 @@ bool dummy_handler(THREADID tid, INT32 sig, CONTEXT* ctxt, bool hasHandler, return true; } -bool signal_handler(THREADID tid, INT32 sig, CONTEXT* ctxt, bool hasHandler, - const EXCEPTION_INFO* pExceptInfo, void* v) { +bool propagate_the_signal() { return true; - /* - ADDRINT curr_eip; - PIN_GetContextRegval(ctxt, REG_INST_PTR, (UINT8*)&curr_eip); - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, - dbg_print_end_uid, "signalhandler curr_uid=%" PRIu64 ", curr_eip=%" PRIx64 - ", sig=%d, wp=%d\n", - pintool_state.get_curr_inst_uid(), (uint64_t)curr_eip, sig, - on_wrongpath); if(!fast_forward_count || on_wrongpath) { if(on_wrongpath) { - if(sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) { - PIN_SetContextRegval(ctxt, REG_INST_PTR, (const UINT8*)(&next_eip)); - - // mark the checkpoint for the excepting instruction as unretireable - INT64 idx = checkpoints.get_head_index(); - INT64 n = checkpoints.get_size(); - - bool found_uid = false; - UINT64 uid = pintool_state.get_curr_inst_uid() - 1; - - if(!fast_forward_count) { - while(n > 0) { - if(checkpoints[idx].uid == uid) { - found_uid = true; - checkpoints[idx].unretireable_instruction = true; - break; - } - - idx++; - n--; - } - ASSERTM(0, found_uid, "Checkpoint %" PRIu64 " not found. \n", uid); - } - - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, - dbg_print_end_uid, "signalhandler return false\n"); return false; } else - if(sig == SIGILL) { DBG_PRINT(pintool_state.get_curr_inst_uid(), - dbg_print_start_uid, dbg_print_end_uid, "Fail to detect ILLOP at %" PRIx64 - "\n", curr_eip); pending_syscall = true; // Treat illegal ops as syscalls - (fetch barrier - // behavior) - pending_exception = true; - - seen_rightpath_exc_mode = false; - return excp_main_loop(sig); - - ASSERTM(0, false, - "Reached end of wrong excp after retiring all instructions\n"); - - return true; // Throw the exception to PIN process to terminate it - } else { - return true; // Throw the exception to PIN process to terminate it - } - } else { // On Right Path - if(sig == SIGFPE || sig == SIGSEGV || sig == SIGILL) { - // The mailbox op is currently the offending op, it needs to be treated - // as syscall - // The main loop should upgrade the mailbox op to be buffered for - // sending to scarab - pending_syscall = true; // Treat illegal ops as syscalls (fetch barrier - // behavior) - pending_exception = true; - - saved_excp_eip = curr_eip; - saved_excp_next_eip = next_eip; - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, - dbg_print_end_uid, "Found rightpath excp at %" PRIx64 "\n", curr_eip); +} - // Before starting the handler, wait for scarab to retire all ops. - // If it turns out scarab wait to redirect/recover, then this is - // actually on the wrong path! +bool skip_this_instruction(CONTEXT* ctxt) { + // TODO: Does this work properly while fast-forwarding? + // As is, next_rip is probably bogus while fast-forwarding. + PIN_SetContextReg(ctxt, REG_INST_PTR, pintool_state.get_next_rip()); + return false; +} - return excp_main_loop(sig); +void mark_checkpoint_as_unretirable() { + // mark the checkpoint for the excepting instruction as unretireable + bool found_uid = false; + UINT64 uid = pintool_state.get_curr_inst_uid() - 1; + INT64 idx = checkpoints.get_head_index(); + INT64 n = checkpoints.get_size(); + while(n > 0) { + if(checkpoints[idx].uid == uid) { + found_uid = true; + checkpoints[idx].unretireable_instruction = true; + break; + } - ASSERTM(0, false, - "Reached end of rightpath excp without retiring all " - "instructions\n"); + idx++; + n--; + } + ASSERTM(0, found_uid, "Checkpoint %" PRIu64 " not found. \n", uid); +} - return true; +void mark_mailbox_op_as_exception_and_insert_in_buffer() { + ASSERTM(0, op_mailbox_full, + "Op mailbox empty when an exception was triggered, uid: %ld.\n", + pintool_state.get_curr_inst_uid()); + op_mailbox.is_ifetch_barrier = 1; + op_mailbox.cf_type = CF_SYS; + insert_scarab_op_in_buffer(op_mailbox); + op_mailbox_full = false; +} - } else { - ASSERTM(0, false, "Unhandled rightpath exception\n"); - return true; // Throw the exception to PIN process to terminate it - } +bool process_exception_on_wrongpath(CONTEXT* ctxt, INT32 sig) { + if(sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) { + mark_checkpoint_as_unretirable(); + DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, + dbg_print_end_uid, "signalhandler return false\n"); + return skip_this_instruction(ctxt); + } else { + mark_mailbox_op_as_exception_and_insert_in_buffer(); + send_buffer_wait_until_scarab_retires_everything(ctxt); + + ASSERTM(0, pintool_state.should_change_control_flow(), + "An exception in the wrongpath should be flushed before getting " + "committed, uid=%ld.\n", + pintool_state.get_curr_inst_uid()); + + PIN_SaveContext(pintool_state.get_context_for_changing_control_flow(), + ctxt); + if(pintool_state.should_skip_next_instruction()) { + fast_forward_count = 2; } + pintool_state.clear_changing_control_flow(); + return false; } +} - // Handles the case when fast forward for recover cause an excption - if(excp_ff && on_wrongpath) { - PIN_SetContextRegval(ctxt, REG_INST_PTR, (const UINT8*)(&next_eip)); - return false; +bool process_exception_on_rightpath(CONTEXT* ctxt, INT32 sig, ADDRINT rip, + ADDRINT next_rip) { + if(sig == SIGFPE || sig == SIGSEGV || sig == SIGILL) { + send_buffer_wait_until_scarab_retires_everything(ctxt); + + if(pintool_state.should_change_control_flow()) { + // The exception is not to be committed due to a recover/redirect. + // Update the CONTEXT and suppress the signal. + PIN_SaveContext(pintool_state.get_context_for_changing_control_flow(), + ctxt); + if(pintool_state.should_skip_next_instruction()) { + fast_forward_count = 2; + } + pintool_state.clear_changing_control_flow(); + return false; + } else { + pintool_state.set_rightpath_exception(rip, next_rip); + return true; + } } else { - fprintf(stderr, "PIN: Found exception sig=%d on rightpath\n", sig); - return true; + ASSERTM(0, false, "Unhandled rightpath exception\n"); } - */ } -bool excp_main_loop(int sig) { - return true; - /* - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, - dbg_print_end_uid, "excp main loop next_eip=%" PRIx64 "\n", - (uint64_t)next_eip); - - bool buffer_ready = false; - bool syscall_has_been_sent_to_scarab = false; - bool have_consumed_op = false; - bool need_scarab_cmd = false; - - excp_do_fe_null(); - while(true) { - Scarab_To_Pin_Msg cmd; - cmd.type = FE_NULL; +ADDRINT get_next_rip() { + ASSERTM(0, op_mailbox_full, + "Op mailbox empty when an exception was triggered, uid: %ld.\n", + pintool_state.get_curr_inst_uid()); + return op_mailbox.instruction_next_addr; +} - if(need_scarab_cmd) { - cmd = get_scarab_cmd(); +bool signal_handler(THREADID tid, INT32 sig, CONTEXT* ctxt, bool hasHandler, + const EXCEPTION_INFO* pExceptInfo, void* v) { + ADDRINT curr_rip = PIN_GetContextReg(ctxt, REG_INST_PTR); + DBG_PRINT( + pintool_state.get_curr_inst_uid(), dbg_print_start_uid, dbg_print_end_uid, + "signalhandler curr_uid=%" PRIu64 ", curr_eip=%" PRIx64 ", sig=%d, wp=%d\n", + pintool_state.get_curr_inst_uid(), (uint64_t)curr_rip, sig, + pintool_state.is_on_wrongpath()); + + if(fast_forward_count) { + if(pintool_state.is_on_wrongpath()) { + return skip_this_instruction(ctxt); + } else { + return propagate_the_signal(); } - saved_cmd = cmd; - - if(cmd.type == FE_RECOVER_BEFORE || cmd.type == FE_RECOVER_AFTER) { - seen_rightpath_exc_mode = false; - excp_rewind_msg = true; - return false; - } else if(cmd.type == FE_REDIRECT) { - seen_rightpath_exc_mode = false; - excp_rewind_msg = true; - return false; - } else if(cmd.type == FE_RETIRE) { - if(do_fe_retire(cmd)) { - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, - dbg_print_end_uid, "term retire in exec\n"); excp_rewind_msg = false; - pending_exception = false; - pending_syscall = false; - fprintf(stderr, "PIN: Found exception sig=%d on rightpath\n", sig); - seen_rightpath_exc_mode = true; - return true; - } - // Once all instruction upto the excpeting instructions are retired, take - // the exception - if(cmd.inst_uid + 1 == pintool_state.get_curr_inst_uid() && !on_wrongpath) - { DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, - dbg_print_end_uid, "execute rightpath exception handler\n"); fprintf(stderr, - "PIN: Found exception sig=%d on rightpath\n", sig); excp_rewind_msg = - false; pending_exception = false; pending_syscall = false; - seen_rightpath_exc_mode = true; - return true; - } - } else if(cmd.type == FE_FETCH_OP) { - do_fe_fetch_op(syscall_has_been_sent_to_scarab); - } else if(cmd.type == FE_NULL) { - // If a syscall causes an exception, it has already been sent to scarab + } else { + if(pintool_state.is_on_wrongpath()) { + return process_exception_on_wrongpath(ctxt, sig); + } else { + ADDRINT next_rip = get_next_rip(); + mark_mailbox_op_as_exception_and_insert_in_buffer(); + return process_exception_on_rightpath(ctxt, sig, curr_rip, next_rip); } + } +} - // We always have a scarab command - buffer_ready = scarab_buffer_full() || pending_syscall; - bool send_buffer_to_scarab = buffer_ready && pending_fetch_op && - have_consumed_op; - if(send_buffer_to_scarab) { - scarab_send_buffer(); - pending_fetch_op = false; - pending_exception = false; - pending_syscall = false; - } +} // namespace + +void register_signal_handlers() { + int intercepted_signals[] = {SIGFPE, SIGILL, SIGSEGV, SIGBUS}; + for(int sig : intercepted_signals) { + PIN_InterceptSignal(sig, signal_handler, 0); + } - if(have_consumed_op) - need_scarab_cmd = true; + int pass_through_signals[] = { + SIGHUP, SIGINT, SIGQUIT, SIGTRAP, SIGIOT, SIGKILL, SIGUSR1, + SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, + SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR}; + for(int sig : pass_through_signals) { + PIN_InterceptSignal(sig, dummy_handler, 0); } - */ } diff --git a/src/pin/pin_exec/exception_handling.h b/src/pin/pin_exec/exception_handling.h index 69b2676f..5ea2c66b 100644 --- a/src/pin/pin_exec/exception_handling.h +++ b/src/pin/pin_exec/exception_handling.h @@ -26,14 +26,4 @@ void register_signal_handlers(); -bool dummy_handler(THREADID tid, INT32 sig, CONTEXT* ctxt, bool hasHandler, - const EXCEPTION_INFO* pExceptInfo, void* v); - -bool signal_handler(THREADID tid, INT32 sig, CONTEXT* ctxt, bool hasHandler, - const EXCEPTION_INFO* pExceptInfo, void* v); - -// Main loop for rightpath execptions: any context change is delayed until we -// reach the execption handler -bool excp_main_loop(int sig); - #endif // PIN_EXEC_EXCEPTION_HANDLING_H__ \ No newline at end of file diff --git a/src/pin/pin_exec/main_loop.cc b/src/pin/pin_exec/main_loop.cc index 18c47db5..fe9623aa 100644 --- a/src/pin/pin_exec/main_loop.cc +++ b/src/pin/pin_exec/main_loop.cc @@ -180,25 +180,26 @@ void do_fe_recover(Scarab_To_Pin_Msg& cmd, CONTEXT* ctxt) { checkpoint.uid); pintool_state.set_wrongpath(checkpoint.wrongpath); - ASSERTM(0, !checkpoint.wrongpath_nop_mode, - "Cannot recover to a dummy checkpoint created in Wrongpath NOP mode"); - pintool_state.set_wrongpath_nop_mode(WPNM_NOT_IN_WPNM, 0); - bool should_skip_an_instruction_after_recovery = cmd.type == FE_RECOVER_AFTER; - pintool_state.set_next_state_for_changing_control_flow( - &checkpoint.ctxt, /*redirect_rip=*/false, 0, - should_skip_an_instruction_after_recovery); + if(!checkpoint.wrongpath_nop_mode) { + pintool_state.set_wrongpath_nop_mode(WPNM_NOT_IN_WPNM, 0); + + bool should_skip_an_instruction_after_recovery = cmd.type == + FE_RECOVER_AFTER; + pintool_state.set_next_state_for_changing_control_flow( + &checkpoint.ctxt, /*redirect_rip=*/false, 0, + should_skip_an_instruction_after_recovery); - /* - if(!on_wrongpath_nop_mode) { } else { - const auto prev_eip = PIN_GetContextReg(&checkpoints[idx].ctxt, - REG_INST_PTR); - const auto this_eip = checkpoints[idx].wpnm_eip; - next_eip = ADDR_MASK(cmd.type == FE_RECOVER_AFTER ? this_eip : prev_eip); - wpnm_skip_ckp = true; + ASSERTM(0, pintool_state.is_on_wrongpath_nop_mode(), + "We must already be in wrongpath nop mode if recovering to " + "wrongpath nop mode\n"); + uint64_t recover_rip = checkpoint.wpnm_eip; + DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, + dbg_print_end_uid, + "Even after recovery, we remain in wrongpath nop mode.\n"); + pintool_state.set_next_rip(recover_rip); } - */ } void do_fe_redirect(Scarab_To_Pin_Msg& cmd, CONTEXT* ctxt) { @@ -222,13 +223,15 @@ void do_fe_redirect(Scarab_To_Pin_Msg& cmd, CONTEXT* ctxt) { ASSERTM(0, !checkpoint.is_syscall, "Unexpected Redirect to current syscall inst @uid=%" PRIu64 "\n", checkpoint.uid); - ASSERTM(0, !checkpoint.wrongpath_nop_mode, - "Cannot redirect a dummy instruction created in Wrongpath NOP mode"); - - // redirect by definition switches to wrongpath - pintool_state.set_wrongpath(true); - if(!instrumented_rip_tracker.contains(cmd.inst_addr)) { + if(checkpoint.wrongpath_nop_mode) { + // We are already in wrongpath nop mode + ASSERTM(0, pintool_state.is_on_wrongpath_nop_mode(), + "We must already be in wrongpath nop mode if redirecting from a " + "checkpoint in wrongpath nop mode\n"); + pintool_state.clear_changing_control_flow(); + pintool_state.set_next_rip(cmd.inst_addr); + } else if(!instrumented_rip_tracker.contains(cmd.inst_addr)) { DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, dbg_print_end_uid, "Entering from redirect WPNM targetaddr=%" PRIx64 "\n", @@ -236,9 +239,34 @@ void do_fe_redirect(Scarab_To_Pin_Msg& cmd, CONTEXT* ctxt) { pintool_state.set_wrongpath_nop_mode( WPNM_REASON_REDIRECT_TO_NOT_INSTRUMENTED, cmd.inst_addr); pintool_state.clear_changing_control_flow(); + } else { + // redirect by definition switches to wrongpath + pintool_state.set_wrongpath(true); + pintool_state.set_wrongpath_nop_mode(WPNM_NOT_IN_WPNM, 0); } } +void do_fe_retire(Scarab_To_Pin_Msg& cmd) { + DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, + dbg_print_end_uid, + "retire curr_uid=%" PRIu64 ", target_uid=%" PRIu64 ", addr=%llx\n", + pintool_state.get_curr_inst_uid(), cmd.inst_uid, cmd.inst_addr); + if(cmd.inst_addr) { + // A non-zero inst address in a retire command signifies to early exit the + // app. + PIN_ExitApplication(0); + ASSERTM(0, false, + "PIN could not safely terminate app upon scarab request.\n"); + } + retire_older_checkpoints(cmd.inst_uid); +} + +void do_fe_fetch_op() { + DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, + dbg_print_end_uid, "fetch curr_uid=%" PRIu64 "\n", + pintool_state.get_curr_inst_uid()); +} + void buffer_next_instruction(CONTEXT* ctxt, compressed_op* cop, Mem_Writes_Info mem_writes_info, bool is_syscall, bool is_exit_syscall, bool wrongpath_nop_mode) { @@ -249,7 +277,7 @@ void buffer_next_instruction(CONTEXT* ctxt, compressed_op* cop, checkpoints.get_tail().update( ctxt, inst_uid, false, pintool_state.is_on_wrongpath(), wrongpath_nop_mode, - cop->instruction_addr + cop->size, mem_writes_info, is_syscall); + pintool_state.get_next_rip(), mem_writes_info, is_syscall); DBG_PRINT(inst_uid, dbg_print_start_uid, dbg_print_end_uid, "fenull curr_uid=%" PRIu64 "\n", inst_uid); @@ -290,6 +318,7 @@ void buffer_next_instruction(CONTEXT* ctxt, compressed_op* cop, if(is_syscall) { // bypass mailbox + cop->is_ifetch_barrier = 1; if(is_exit_syscall) { cop->exit = 1; } @@ -305,7 +334,7 @@ void buffer_next_instruction(CONTEXT* ctxt, compressed_op* cop, } template -void process_scarab_cmds_until(CONTEXT* ctxt, F&& condition_func) { +void process_scarab_cmds_until(CONTEXT* ctxt, F&& exit_condition) { while(true) { Scarab_To_Pin_Msg cmd = get_scarab_cmd(); if(cmd.type == FE_RECOVER_BEFORE || cmd.type == FE_RECOVER_AFTER) { @@ -322,7 +351,7 @@ void process_scarab_cmds_until(CONTEXT* ctxt, F&& condition_func) { ASSERTM(0, false, "Uncorecorgnized Scarab Command Type: %d", cmd.type); } - if(condition_func(cmd)) + if(exit_condition(cmd)) return; } } @@ -332,7 +361,7 @@ void wait_until_scarab_sends_fetch_op(CONTEXT* ctxt) { ctxt, [](const Scarab_To_Pin_Msg& cmd) { return cmd.type == FE_FETCH_OP; }); } -void wait_until_scarab_retires_the_syscall(CONTEXT* ctxt) { +void wait_until_scarab_retires_everything(CONTEXT* ctxt) { process_scarab_cmds_until(ctxt, [](const Scarab_To_Pin_Msg& cmd) { if(cmd.type == FE_FETCH_OP) { ASSERTM(0, false, @@ -343,35 +372,18 @@ void wait_until_scarab_retires_the_syscall(CONTEXT* ctxt) { }); } - } // namespace -void do_fe_retire(Scarab_To_Pin_Msg& cmd) { - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, - dbg_print_end_uid, - "retire curr_uid=%" PRIu64 ", target_uid=%" PRIu64 ", addr=%llx\n", - pintool_state.get_curr_inst_uid(), cmd.inst_uid, cmd.inst_addr); - if(cmd.inst_addr) { - // A non-zero inst address in a retire command signifies to early exit the - // app. - PIN_ExitApplication(0); - ASSERTM(0, false, - "PIN could not safely terminate app upon scarab request.\n"); - } - retire_older_checkpoints(cmd.inst_uid); -} - -void do_fe_fetch_op() { - DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, - dbg_print_end_uid, "fetch curr_uid=%" PRIu64 "\n", - pintool_state.get_curr_inst_uid()); -} - // Communicates with scarab, and performs the requested actions void main_loop(CONTEXT* ctxt, Mem_Writes_Info mem_writes_info, bool is_syscall, bool is_exit_syscall) { buffer_next_instruction(ctxt, pin_decoder_get_latest_inst(), mem_writes_info, - is_syscall, is_exit_syscall, false); + is_syscall, is_exit_syscall, + pintool_state.is_on_wrongpath_nop_mode()); + + if(pintool_state.is_on_wrongpath_nop_mode()) { + return; + } if(scarab_buffer_full() || is_syscall) { wait_until_scarab_sends_fetch_op(ctxt); @@ -382,34 +394,51 @@ void main_loop(CONTEXT* ctxt, Mem_Writes_Info mem_writes_info, bool is_syscall, scarab_send_buffer(); if(is_syscall) { - wait_until_scarab_retires_the_syscall(ctxt); + wait_until_scarab_retires_everything(ctxt); } } } +void send_buffer_wait_until_scarab_retires_everything(CONTEXT* ctxt) { + wait_until_scarab_sends_fetch_op(ctxt); + if(!pintool_state.skip_further_processing()) { + scarab_send_buffer(); + wait_until_scarab_retires_everything(ctxt); + } + + if(pintool_state.is_on_wrongpath_nop_mode()) { + wrongpath_nop_mode_main_loop(); + } +} + void wrongpath_nop_mode_main_loop() { CONTEXT dummy_ctxt; Mem_Writes_Info empty_write_info; - uint64_t next_rip = pintool_state.get_next_rip(); while(true) { - compressed_op dummy_nop = create_dummy_nop( - next_rip, pintool_state.get_wrongpath_nop_mode_reason()); - buffer_next_instruction(&dummy_ctxt, &dummy_nop, empty_write_info, false, - false, true); if(scarab_buffer_full()) { wait_until_scarab_sends_fetch_op(&dummy_ctxt); DBG_PRINT(pintool_state.get_curr_inst_uid(), dbg_print_start_uid, dbg_print_end_uid, "============ %d =============\n", (int)pintool_state.skip_further_processing()); - if(pintool_state.skip_further_processing()) { + if(pintool_state.should_change_control_flow()) { return; } - scarab_send_buffer(); + ASSERTM(0, pintool_state.is_on_wrongpath_nop_mode(), + "Expect to remain in wrongpath nop mode until we received a " + "command that involves changing the control flow.\n"); + + if(!scarab_op_buffer.empty()) { + // A recovery within wrongpath nop mode could empty the buffer. + scarab_send_buffer(); + } } + const uint64_t rip = pintool_state.get_next_rip(); + pintool_state.set_next_rip(rip + 1); - ++next_rip; - if(!next_rip) - next_rip = 0; + compressed_op dummy_nop = create_dummy_nop( + rip, pintool_state.get_wrongpath_nop_mode_reason()); + buffer_next_instruction(&dummy_ctxt, &dummy_nop, empty_write_info, false, + false, true); } } \ No newline at end of file diff --git a/src/pin/pin_exec/main_loop.h b/src/pin/pin_exec/main_loop.h index 7a6082e7..ecd08afb 100644 --- a/src/pin/pin_exec/main_loop.h +++ b/src/pin/pin_exec/main_loop.h @@ -30,8 +30,6 @@ void main_loop(CONTEXT* ctxt, Mem_Writes_Info mem_writes_info, bool is_syscall, void wrongpath_nop_mode_main_loop(); -void do_fe_retire(Scarab_To_Pin_Msg& cmd); - -void do_fe_fetch_op(); +void send_buffer_wait_until_scarab_retires_everything(CONTEXT* ctxt); #endif // PIN_EXEC_MAIN_LOOP_H__ \ No newline at end of file diff --git a/src/pin/pin_exec/pin_exec.cpp b/src/pin/pin_exec/pin_exec.cpp index 7e21d0e3..ecc5e828 100644 --- a/src/pin/pin_exec/pin_exec.cpp +++ b/src/pin/pin_exec/pin_exec.cpp @@ -118,6 +118,11 @@ void insert_check_for_magic_instructions(const INS& ins) { } } +void insert_exception_handler_followup(const INS& ins) { + INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)exception_handler_followup, + IARG_CONTEXT, IARG_END); +} + void insert_processing_for_syscalls(const INS& ins) { INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(process_syscall), IARG_INST_PTR, IARG_SYSCALL_NUMBER, IARG_SYSARG_VALUE, 0, IARG_SYSARG_VALUE, @@ -253,6 +258,7 @@ void instrumentation_func_per_instruction(INS ins, void* v) { insert_logging(ins); insert_check_for_magic_instructions(ins); + insert_exception_handler_followup(ins); // Inserting functions to create a compressed op pin_decoder_insert_analysis_functions(ins); diff --git a/src/pin/pin_exec/utils.h b/src/pin/pin_exec/utils.h index 4c17f444..4bed73c8 100644 --- a/src/pin/pin_exec/utils.h +++ b/src/pin/pin_exec/utils.h @@ -365,12 +365,18 @@ class Pintool_State { Pintool_State() { clear_changing_control_flow(); } // *********************** Getters ********************** - bool skip_further_processing() { return should_change_control_flow(); } + bool skip_further_processing() { + return should_change_control_flow() || is_on_wrongpath_nop_mode(); + } bool should_change_control_flow() { return should_change_control_flow_; } bool should_skip_next_instruction() { return should_skip_next_instruction_; } + bool should_insert_dummy_exception_br() { + return should_insert_dummy_exception_br_; + } + uint64_t get_next_inst_uid() { return uid_ctr++; } uint64_t get_curr_inst_uid() { return uid_ctr; } @@ -384,14 +390,22 @@ class Pintool_State { Wrongpath_Nop_Mode_Reason get_wrongpath_nop_mode_reason() { return wrongpath_nop_mode_reason_; } + uint64_t get_next_rip() { return next_rip_; } + uint64_t get_rightpath_exception_rip() { return rightpath_exception_rip_; } + uint64_t get_rightpath_exception_next_rip() { + return rightpath_exception_next_rip_; + } + // *********************** Setters ********************** void clear_changing_control_flow() { should_change_control_flow_ = false; should_skip_next_instruction_ = false; } + void set_next_rip(uint64_t next_rip) { next_rip_ = next_rip; } + void set_next_state_for_changing_control_flow(const CONTEXT* next_ctxt, bool redirect_rip, uint64_t next_rip, @@ -408,18 +422,26 @@ class Pintool_State { void set_wrongpath_nop_mode( Wrongpath_Nop_Mode_Reason wrongpath_nop_mode_reason, uint64_t next_rip) { wrongpath_nop_mode_reason_ = wrongpath_nop_mode_reason; - if(!next_rip) { - next_rip_ = 1; - } else { - next_rip_ = ADDR_MASK(next_rip); - } + next_rip_ = ADDR_MASK(next_rip); + } + + void clear_rightpath_exception() { + should_insert_dummy_exception_br_ = false; + } + void set_rightpath_exception(uint64_t rip, uint64_t next_rip) { + should_insert_dummy_exception_br_ = true; + rightpath_exception_rip_ = rip; + rightpath_exception_next_rip_ = next_rip; } private: - bool should_change_control_flow_; - bool should_skip_next_instruction_; + bool should_change_control_flow_ = false; + bool should_skip_next_instruction_ = false; + bool should_insert_dummy_exception_br_ = false; CONTEXT next_ctxt_; + uint64_t rightpath_exception_rip_; + uint64_t rightpath_exception_next_rip_; uint64_t uid_ctr = 0; bool on_wrongpath_ = false;