int context_continue(Context * ctx) { int signal = 0; assert(is_dispatch_thread()); assert(ctx->stopped); assert(!ctx->pending_intercept); assert(!EXT(ctx)->pending_step); assert(!ctx->exited); if (skip_breakpoint(ctx, 0)) return 0; if (!EXT(ctx)->ptrace_event) { while (ctx->pending_signals != 0) { while ((ctx->pending_signals & (1 << signal)) == 0) signal++; if (ctx->sig_dont_pass & (1 << signal)) { ctx->pending_signals &= ~(1 << signal); signal = 0; } else { break; } } assert(signal != SIGSTOP); assert(signal != SIGTRAP); } trace(LOG_CONTEXT, "context: resuming ctx %#lx, id %s, with signal %d", ctx, ctx->id, signal); if (EXT(ctx)->regs_dirty) { if (ptrace(PTRACE_SETREGS, EXT(ctx)->pid, 0, (int)EXT(ctx)->regs) < 0) { int err = errno; if (err == ESRCH) { EXT(ctx)->regs_dirty = 0; send_context_started_event(ctx); return 0; } trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } EXT(ctx)->regs_dirty = 0; } if (ptrace(PTRACE_CONT, EXT(ctx)->pid, 0, signal) < 0) { int err = errno; if (err == ESRCH) { send_context_started_event(ctx); return 0; } trace(LOG_ALWAYS, "error: ptrace(PTRACE_CONT, ...) failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } ctx->pending_signals &= ~(1 << signal); send_context_started_event(ctx); return 0; }
int context_single_step(Context * ctx) { assert(is_dispatch_thread()); assert(context_has_state(ctx)); assert(ctx->stopped); assert(!ctx->exited); assert(!EXT(ctx)->pending_step); if (skip_breakpoint(ctx, 1)) return 0; trace(LOG_CONTEXT, "context: single step ctx %#lx, id %s", ctx, ctx->id); if (EXT(ctx)->regs_dirty) { if (ptrace(PTRACE_SETREGS, EXT(ctx)->pid, 0, (int)EXT(ctx)->regs) < 0) { int err = errno; if (err == ESRCH) { EXT(ctx)->regs_dirty = 0; EXT(ctx)->pending_step = 1; send_context_started_event(ctx); return 0; } trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } EXT(ctx)->regs_dirty = 0; } if (ptrace(PTRACE_SINGLESTEP, EXT(ctx)->pid, 0, 0) < 0) { int err = errno; if (err == ESRCH) { EXT(ctx)->pending_step = 1; send_context_started_event(ctx); return 0; } trace(LOG_ALWAYS, "error: ptrace(PTRACE_SINGLESTEP, ...) failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } EXT(ctx)->pending_step = 1; send_context_started_event(ctx); return 0; }
int context_single_step(Context * ctx) { assert(is_dispatch_thread()); assert(context_has_state(ctx)); assert(ctx->stopped); assert(!ctx->exited); assert(!EXT(ctx)->pending_step); if (skip_breakpoint(ctx, 1)) return 0; if (syscall_never_returns(ctx)) return context_continue(ctx); trace(LOG_CONTEXT, "context: single step ctx %#lx, id %S", ctx, ctx->id); if (EXT(ctx)->regs_dirty) { unsigned int state_count; if (thread_set_state(EXT(ctx)->pid, x86_THREAD_STATE32, EXT(ctx)->regs, &state_count) != KERN_SUCCESS) { int err = errno; trace(LOG_ALWAYS, "error: thread_set_state failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } EXT(ctx)->regs_dirty = 0; } if (ptrace(PT_STEP, EXT(ctx)->pid, 0, 0) < 0) { int err = errno; if (err == ESRCH) { EXT(ctx)->pending_step = 1; send_context_started_event(ctx); return 0; } trace(LOG_ALWAYS, "error: ptrace(PT_STEP, ...) failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } EXT(ctx)->pending_step = 1; send_context_started_event(ctx); return 0; }
static int handle_breakpoint(struct task *task) { struct breakpoint *bp = task->event.e_un.breakpoint; unsigned int hw = bp->hw; debug(DEBUG_EVENT, "+++ process pid=%d breakpoint addr=%#lx", task->pid, bp->addr); assert(task->stopped); if (unlikely(options.verbose > 1)) set_timer(&task->halt_time, hw ? &hw_bp_time : &sw_bp_time); if (unlikely(options.verbose)) ++bp->count; if (unlikely(task->skip_bp)) { struct breakpoint *skip_bp = task->skip_bp; task->skip_bp = NULL; breakpoint_put(skip_bp); if (likely(skip_bp == bp)) { skip_breakpoint(task, bp); goto end; } if (unlikely(options.verbose)) fprintf(stderr, "!!!unhandled skip breakpoint for pid=%d\n", task->pid); } if (unlikely(bp->deleted)) { continue_task(task, 0); goto end; } #if HW_BREAKPOINTS > 1 if (bp->type >= BP_HW) { if (unlikely(++bp->hwcnt >= (BP_REORDER_THRESHOLD << hw))) { struct timespec start; if (unlikely(options.verbose > 1)) start_time(&start); reorder_hw_bp(task); if (unlikely(options.verbose > 1)) set_timer(&start, &reorder_time); } } #endif if (bp->on_hit && bp->on_hit(task, bp)) { continue_task(task, 0); goto end; } if (likely(bp->libsym && !task->breakpoint)) { struct library_symbol *libsym = bp->libsym; save_param_context(task); if (libsym->func->report_out || !options.nocpp) { task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, BP_HW_SCRATCH); if (likely(task->breakpoint)) { task->libsym = libsym; task->breakpoint->on_hit = handle_call_after; #if HW_BREAKPOINTS > 0 enable_scratch_hw_bp(task, task->breakpoint); #endif } } if (libsym->func->report_in) { struct timespec start; if (unlikely(options.verbose > 1)) start_time(&start); libsym->func->report_in(task, libsym); if (unlikely(options.verbose > 1)) set_timer(&start, &report_in_time); } } if (task->bp_skipped) task->bp_skipped = 0; else skip_breakpoint(task, bp); end: breakpoint_put(bp); return 0; }
int context_continue(Context * ctx) { int signal = 0; assert(is_dispatch_thread()); assert(ctx->stopped); assert(!ctx->exited); assert(!ctx->pending_intercept); assert(!EXT(ctx)->pending_step); if (skip_breakpoint(ctx, 0)) return 0; if (!EXT(ctx)->syscall_enter) { unsigned n = 0; while (sigset_get_next(&ctx->pending_signals, &n)) { if (sigset_get(&ctx->sig_dont_pass, n)) { sigset_set(&ctx->pending_signals, n, 0); } else { signal = n; break; } } assert(signal != SIGSTOP); assert(signal != SIGTRAP); } trace(LOG_CONTEXT, "context: resuming ctx %#lx, id %s, with signal %d", ctx, ctx->id, signal); #if defined(__i386__) if (EXT(ctx)->regs->__eflags & 0x100) { EXT(ctx)->regs->__eflags &= ~0x100; EXT(ctx)->regs_dirty = 1; } #elif defined(__x86_64__) if (EXT(ctx)->regs->__rflags & 0x100) { EXT(ctx)->regs->__rflags &= ~0x100; EXT(ctx)->regs_dirty = 1; } #endif if (EXT(ctx)->regs_dirty) { unsigned int state_count; if (thread_set_state(EXT(ctx)->pid, x86_THREAD_STATE32, EXT(ctx)->regs, &state_count) != KERN_SUCCESS) { int err = errno; trace(LOG_ALWAYS, "error: thread_set_state failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } EXT(ctx)->regs_dirty = 0; } if (ptrace(PT_CONTINUE, EXT(ctx)->pid, 0, signal) < 0) { int err = errno; if (err == ESRCH) { send_context_started_event(ctx); return 0; } trace(LOG_ALWAYS, "error: ptrace(PT_CONTINUE, ...) failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } sigset_set(&ctx->pending_signals, signal, 0); if (syscall_never_returns(ctx)) { EXT(ctx)->syscall_enter = 0; EXT(ctx)->syscall_exit = 0; EXT(ctx)->syscall_id = 0; } send_context_started_event(ctx); return 0; }