/** * Run execution forwards for |ctx| until |ctx->trace.rbc| is reached, * and the $ip reaches the recorded $ip. After that, deliver |sig| if * nonzero. Return 0 if successful or 1 if an unhandled interrupt * occurred. */ static int emulate_async_signal(struct context* ctx, uint64_t rcb, const struct user_regs_struct* regs, int sig, int stepi) { if (advance_to(ctx, rcb, regs, 0, stepi)) { return 1; } if (sig) { emulate_signal_delivery(); } stop_hpc(ctx); return 0; }
void rep_process_signal(struct context *ctx) { struct trace* trace = &(ctx->trace); int tid = ctx->child_tid; int sig = -trace->stop_reason; /* if the there is still a signal pending here, two signals in a row must be delivered?\n */ assert(ctx->child_sig == 0); switch (sig) { /* set the eax and edx register to the recorded values */ case -SIG_SEGV_RDTSC: { struct user_regs_struct regs; int size; /* goto the event */ goto_next_event(ctx); /* make sure we are there */ assert(WSTOPSIG(ctx->status) == SIGSEGV); char* inst = get_inst(tid, 0, &size); assert(strncmp(inst,"rdtsc",5) == 0); read_child_registers(tid, ®s); regs.eax = trace->recorded_regs.eax; regs.edx = trace->recorded_regs.edx; regs.eip += size; write_child_registers(tid, ®s); sys_free((void**) &inst); compare_register_files("rdtsv_now", ®s, "rdsc_rec", &ctx->trace.recorded_regs, 1, 1); /* this signal should not be recognized by the application */ ctx->child_sig = 0; break; } case -USR_SCHED: { assert(trace->rbc_up > 0); /* if the current architecture over-counts the event in question, * substract the overcount here */ reset_hpc(ctx, trace->rbc_up - SKID_SIZE); goto_next_event(ctx); /* make sure that the signal came from hpc */ if (fcntl(ctx->hpc->rbc_down.fd, F_GETOWN) == ctx->child_tid) { /* this signal should not be recognized by the application */ ctx->child_sig = 0; stop_hpc_down(ctx); compensate_branch_count(ctx, sig); stop_hpc(ctx); } else { fprintf(stderr, "internal error: next event should be: %d but it is: %d -- bailing out\n", -USR_SCHED, ctx->event); sys_exit(); } break; } case SIGIO: case SIGCHLD: { /* synchronous signal (signal received in a system call) */ if (trace->rbc_up == 0) { ctx->replay_sig = sig; return; } // setup and start replay counters reset_hpc(ctx, trace->rbc_up - SKID_SIZE); /* single-step if the number of instructions to the next event is "small" */ if (trace->rbc_up <= 10000) { stop_hpc_down(ctx); compensate_branch_count(ctx, sig); stop_hpc(ctx); } else { printf("large count\n"); sys_ptrace_syscall(tid); sys_waitpid(tid, &ctx->status); // make sure we ere interrupted by ptrace assert(WSTOPSIG(ctx->status) == SIGIO); /* reset the penig sig, since it did not occur in the original execution */ ctx->child_sig = 0; ctx->status = 0; //DO NOT FORGET TO STOP HPC!!! compensate_branch_count(ctx, sig); stop_hpc(ctx); stop_hpc_down(ctx); } break; } case SIGSEGV: { /* synchronous signal (signal received in a system call) */ if (trace->rbc_up == 0 && trace->page_faults == 0) { ctx->replay_sig = sig; return; } sys_ptrace_syscall(ctx->child_tid); sys_waitpid(ctx->child_tid, &ctx->status); assert(WSTOPSIG(ctx->status) == SIGSEGV); struct user_regs_struct regs; read_child_registers(ctx->child_tid, ®s); assert(compare_register_files("now", ®s, "rec", &ctx->trace.recorded_regs, 1, 1) == 0); /* deliver the signal */ singlestep(ctx, SIGSEGV, 0x57f); break; } default: printf("unknown signal %d -- bailing out\n", sig); sys_exit(); break; } }