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 kill_context(Context * ctx) { ContextExtensionVxWorks * ext = EXT(ctx); assert(ctx->stopped); assert(ctx->parent != NULL); if (taskDelete(ext->pid) != OK) { int error = errno; trace(LOG_ALWAYS, "context: can't kill ctx %#lx, id %#x: %s", ctx, ext->pid, errno_to_str(error)); return -1; } send_context_started_event(ctx); trace(LOG_CONTEXT, "context: killed ctx %#lx, id %#x", ctx, ext->pid); release_error_report(ext->regs_error); loc_free(ext->regs); ext->regs_error = NULL; ext->regs = NULL; send_context_exited_event(ctx); return 0; }
int context_continue(Context * ctx) { ContextExtensionVxWorks * ext = EXT(ctx); VXDBG_CTX vxdbg_ctx; assert(is_dispatch_thread()); assert(ctx->parent != NULL); assert(ctx->stopped); assert(!ctx->pending_intercept); assert(!ctx->exited); assert(taskIsStopped(ext->pid)); trace(LOG_CONTEXT, "context: continue ctx %#lx, id %#x", ctx, ext->pid); if (ext->regs_dirty) { if (taskRegsSet(ext->pid, ext->regs) != OK) { int error = errno; trace(LOG_ALWAYS, "context: can't set regs ctx %#lx, id %#x: %s", ctx, ext->pid, errno_to_str(error)); return -1; } ext->regs_dirty = 0; } vxdbg_ctx.ctxId = ext->pid; vxdbg_ctx.ctxType = VXDBG_CTX_TASK; taskLock(); if (vxdbgCont(vxdbg_clnt_id, &vxdbg_ctx) != OK) { int error = errno; taskUnlock(); trace(LOG_ALWAYS, "context: can't continue ctx %#lx, id %#x: %s", ctx, ext->pid, errno_to_str(error)); return -1; } assert(!taskIsStopped(ext->pid)); taskUnlock(); send_context_started_event(ctx); return 0; }
static void event_pid_exited(pid_t pid, int status, int signal) { Context * ctx; ctx = context_find_from_pid(pid, 1); if (ctx == NULL) { ctx = find_pending(pid); if (ctx == NULL) { trace(LOG_EVENTS, "event: ctx not found, pid %d, exit status %d, term signal %d", pid, status, signal); } else { assert(ctx->ref_count == 0); ctx->ref_count = 1; if (EXT(ctx)->attach_callback != NULL) { if (status == 0) status = EINVAL; EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); } assert(list_is_empty(&ctx->children)); assert(ctx->parent == NULL); ctx->exited = 1; context_unlock(ctx); } } else { /* Note: ctx->exiting should be 1 here. However, PTRACE_EVENT_EXIT can be lost by PTRACE because of racing * between PTRACE_CONT (or PTRACE_SYSCALL) and SIGTRAP/PTRACE_EVENT_EXIT. So, ctx->exiting can be 0. */ if (EXT(ctx->parent)->pid == pid) ctx = ctx->parent; assert(EXT(ctx)->attach_callback == NULL); if (ctx->exited) { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, exited %d", ctx, pid, status, ctx->stopped, ctx->exited); } else { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d, term signal %d", ctx, pid, status, signal); ctx->exiting = 1; if (ctx->stopped) send_context_started_event(ctx); if (!list_is_empty(&ctx->children)) { LINK * l = ctx->children.next; while (l != &ctx->children) { Context * c = cldl2ctxp(l); l = l->next; assert(c->parent == ctx); if (!c->exited) { c->exiting = 1; if (c->stopped) send_context_started_event(c); release_error_report(EXT(c)->regs_error); loc_free(EXT(c)->regs); EXT(c)->regs_error = NULL; EXT(c)->regs = NULL; send_context_exited_event(c); } } } release_error_report(EXT(ctx)->regs_error); loc_free(EXT(ctx)->regs); EXT(ctx)->regs_error = NULL; EXT(ctx)->regs = NULL; send_context_exited_event(ctx); } } }
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; }