int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end) { switch (mode) { case RM_RESUME: return context_continue(ctx); case RM_STEP_INTO: return context_single_step(ctx); case RM_TERMINATE: sigset_set(&ctx->pending_signals, SIGKILL, 1); return context_continue(ctx); } errno = ERR_UNSUPPORTED; return -1; }
static void command_resume(char * token, Channel * c) { char id[256]; long mode; long count; Context * ctx; int err = 0; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); mode = json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); count = json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (peek_stream(&c->inp) != MARKER_EOM) { json_read_struct(&c->inp, resume_params_callback, &err); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); } if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); if (err == 0) { ctx = id2ctx(id); assert(safe_event_list == NULL); if (ctx == NULL) { err = ERR_INV_CONTEXT; } else if (ctx->exited) { err = ERR_ALREADY_EXITED; } else if (!ctx->intercepted) { err = ERR_ALREADY_RUNNING; } else if (ctx->regs_error) { err = ctx->regs_error; } else if (count != 1) { err = EINVAL; } else if (mode == RM_RESUME || mode == RM_STEP_INTO) { send_event_context_resumed(&c->bcg->out, ctx); if (mode == RM_STEP_INTO) { if (context_single_step(ctx) < 0) { err = errno; } else { ctx->pending_intercept = 1; } } else if (context_continue(ctx) < 0) { err = errno; } } else { err = EINVAL; } } send_simple_result(c, token, err); }
int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end) { switch (mode) { case RM_RESUME: return context_continue(ctx); case RM_STEP_INTO: return context_single_step(ctx); case RM_TERMINATE: return context_terminate(ctx); } errno = ERR_UNSUPPORTED; return -1; }
static void event_context_stopped(Context * ctx, void * client_data) { TCFBroadcastGroup * bcg = client_data; assert(ctx->stopped); assert(!ctx->intercepted); assert(!ctx->exited); if (ctx->pending_safe_event) check_safe_events(ctx); if (ctx->pending_signals != 0) { send_event_context_exception(&bcg->out, ctx); } if (ctx->pending_intercept) { send_event_context_suspended(&bcg->out, ctx); flush_stream(&bcg->out); } if (!ctx->intercepted && safe_event_list == NULL) { context_continue(ctx); } }
static void continue_temporary_stopped(void * arg) { LINK * qp; if ((uintptr_t)arg != safe_event_generation) return; assert(safe_event_list == NULL); if (channels_get_message_count(suspend_group) > 0) { post_event(continue_temporary_stopped, (void *)safe_event_generation); return; } for (qp = context_root.next; qp != &context_root; qp = qp->next) { Context * ctx = ctxl2ctxp(qp); if (ctx->exited) continue; if (!ctx->stopped) continue; if (ctx->intercepted) continue; context_continue(ctx); } }
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; }