void send_event_memory_changed(Context * ctx, ContextAddress addr, unsigned long size) { OutputStream * out = &broadcast_group->out; if (!context_has_state(ctx) || is_intercepted(ctx)) { write_stringz(out, "E"); write_stringz(out, MEMORY); write_stringz(out, "memoryChanged"); json_write_string(out, ctx->id); write_stream(out, 0); /* <array of addres ranges> */ write_stream(out, '['); write_stream(out, '{'); json_write_string(out, "addr"); write_stream(out, ':'); json_write_uint64(out, addr); write_stream(out, ','); json_write_string(out, "size"); write_stream(out, ':'); json_write_ulong(out, size); write_stream(out, '}'); write_stream(out, ']'); write_stream(out, 0); write_stream(out, MARKER_EOM); } }
static void send_event_context_removed(OutputStream * out, Context * ctx) { write_stringz(out, "E"); write_stringz(out, RUN_CONTROL); write_stringz(out, "contextRemoved"); /* <array of context IDs> */ write_stream(out, '['); if (context_has_state(ctx)) json_write_string(out, thread_id(ctx)); if (ctx->parent == NULL && list_is_empty(&ctx->children)) { if (context_has_state(ctx)) write_stream(out, ','); json_write_string(out, container_id(ctx)); } write_stream(out, ']'); write_stream(out, 0); write_stream(out, MARKER_EOM); }
int context_can_resume(Context * ctx, int mode) { switch (mode) { case RM_RESUME: return 1; case RM_STEP_INTO: case RM_TERMINATE: return context_has_state(ctx); } return 0; }
int is_all_stopped(pid_t mem) { LINK * qp; for (qp = context_root.next; qp != &context_root; qp = qp->next) { Context * ctx = ctxl2ctxp(qp); if (ctx->exited || ctx->exiting) continue; if (!context_has_state(ctx)) continue; if (mem > 0 && ctx->mem != mem) continue; if (!ctx->stopped) return 0; } return are_channels_suspended(suspend_group); }
const char * frame2id(Context * ctx, int frame) { static char id[256]; assert(frame >= 0); if (!context_has_state(ctx)) { errno = ERR_INV_CONTEXT; return NULL; } snprintf(id, sizeof(id), "FP%d.%s", frame, ctx->id); return id; }
static void command_get_children(char * token, Channel * c) { char id[256]; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, 0); write_stream(&c->out, '['); if (id[0] == 0) { LINK * qp; int cnt = 0; for (qp = context_root.next; qp != &context_root; qp = qp->next) { Context * ctx = ctxl2ctxp(qp); if (ctx->exited) continue; if (ctx->parent != NULL) continue; if (cnt > 0) write_stream(&c->out, ','); json_write_string(&c->out, container_id(ctx)); cnt++; } } else if (id[0] == 'P') { LINK * qp; int cnt = 0; pid_t ppd = 0; Context * parent = id2ctx(id); id2pid(id, &ppd); if (parent != NULL && parent->parent == NULL && ppd == 0) { if (!parent->exited && context_has_state(parent)) { if (cnt > 0) write_stream(&c->out, ','); json_write_string(&c->out, thread_id(parent)); cnt++; } for (qp = parent->children.next; qp != &parent->children; qp = qp->next) { Context * ctx = cldl2ctxp(qp); assert(!ctx->exited); assert(ctx->parent == parent); if (cnt > 0) write_stream(&c->out, ','); json_write_string(&c->out,thread_id(ctx)); cnt++; } } } write_stream(&c->out, ']'); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); }
static void command_get_cache_client(void * x) { GetArgs * args = (GetArgs *)x; Channel * c = cache_channel(); Trap trap; bbf_pos = 0; if (set_trap(&trap)) { int frame = 0; Context * ctx = NULL; RegisterDefinition * reg_def = NULL; if (id2register(args->id, &ctx, &frame, ®_def) < 0) exception(errno); if (ctx->exited) exception(ERR_ALREADY_EXITED); if ((ctx->reg_access & REG_ACCESS_RD_STOP) != 0) { check_all_stopped(ctx); } if ((ctx->reg_access & REG_ACCESS_RD_RUNNING) == 0) { if (!ctx->stopped && context_has_state(ctx)) str_exception(ERR_IS_RUNNING, "Cannot read register if not stopped"); } if (reg_def->size > bbf_len) { bbf_len += 0x100 + reg_def->size; bbf = (uint8_t *)loc_realloc(bbf, bbf_len); } bbf_pos = reg_def->size; memset(bbf, 0, reg_def->size); if (frame < 0 || is_top_frame(ctx, frame)) { if (context_read_reg(ctx, reg_def, 0, reg_def->size, bbf) < 0) exception(errno); } else { StackFrame * info = NULL; if (get_frame_info(ctx, frame, &info) < 0) exception(errno); if (read_reg_bytes(info, reg_def, 0, reg_def->size, bbf) < 0) exception(errno); } clear_trap(&trap); } cache_exit(); write_stringz(&c->out, "R"); write_stringz(&c->out, args->token); write_errno(&c->out, trap.error); json_write_binary(&c->out, bbf, bbf_pos); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); }
int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { ContextExtensionVxWorks * ext = EXT(ctx); assert(is_dispatch_thread()); assert(context_has_state(ctx)); assert(ctx->stopped); assert(!ctx->exited); assert(offs + size <= def->size); if (ext->regs_error) { set_error_report_errno(ext->regs_error); return -1; } memcpy(buf, (uint8_t *)ext->regs + def->offset + offs, size); return 0; }
static void send_event_context_changed(OutputStream * out, Context * ctx) { write_stringz(out, "E"); write_stringz(out, RUN_CONTROL); write_stringz(out, "contextChanged"); /* <array of context data> */ write_stream(out, '['); if (ctx->parent == NULL) { write_context(out, ctx, 0); } if (context_has_state(ctx)) { if (ctx->parent == NULL) write_stream(out, ','); write_context(out, ctx, 1); } write_stream(out, ']'); write_stream(out, 0); write_stream(out, MARKER_EOM); }
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; }
static void command_set_cache_client(void * x) { SetArgs * args = (SetArgs *)x; Channel * c = cache_channel(); int notify = 0; Trap trap; if (set_trap(&trap)) { int frame = 0; Context * ctx = NULL; RegisterDefinition * reg_def = NULL; if (id2register(args->id, &ctx, &frame, ®_def) < 0) exception(errno); if (frame >= 0 && !is_top_frame(ctx, frame)) exception(ERR_INV_CONTEXT); if (ctx->exited) exception(ERR_ALREADY_EXITED); if ((ctx->reg_access & REG_ACCESS_WR_STOP) != 0) { check_all_stopped(ctx); } if ((ctx->reg_access & REG_ACCESS_WR_RUNNING) == 0) { if (!ctx->stopped && context_has_state(ctx)) str_exception(ERR_IS_RUNNING, "Cannot write register if not stopped"); } if ((size_t)args->data_len > reg_def->size) exception(ERR_INV_DATA_SIZE); if (args->data_len > 0) { if (context_write_reg(ctx, reg_def, 0, args->data_len, args->data) < 0) exception(errno); notify = 1; } clear_trap(&trap); } cache_exit(); if (notify) send_event_register_changed(args->id); write_stringz(&c->out, "R"); write_stringz(&c->out, args->token); write_errno(&c->out, trap.error); write_stream(&c->out, MARKER_EOM); loc_free(args->data); }
static void check_location_list(Location * locs, unsigned cnt, int setm) { unsigned pos; for (pos = 0; pos < cnt; pos++) { Location * loc = locs + pos; if (id2register(loc->id, &loc->ctx, &loc->frame, &loc->reg_def) < 0) exception(errno); if (loc->ctx->exited) exception(ERR_ALREADY_EXITED); if ((loc->ctx->reg_access & setm ? REG_ACCESS_WR_STOP : REG_ACCESS_RD_STOP) != 0) { check_all_stopped(loc->ctx); } if ((loc->ctx->reg_access & setm ? REG_ACCESS_WR_RUNNING : REG_ACCESS_RD_RUNNING) == 0) { if (!loc->ctx->stopped && context_has_state(loc->ctx)) str_fmt_exception(ERR_IS_RUNNING, "Cannot %s register if not stopped", setm ? "write" : "read"); } if (loc->offs + loc->size > loc->reg_def->size) exception(ERR_INV_DATA_SIZE); if (loc->frame < 0 || is_top_frame(loc->ctx, loc->frame)) continue; if (setm) exception(ERR_INV_CONTEXT); if (get_frame_info(loc->ctx, loc->frame, &loc->frame_info) < 0) exception(errno); } }
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; }
int context_single_step(Context * ctx) { ContextExtensionVxWorks * ext = EXT(ctx); VXDBG_CTX vxdbg_ctx; assert(is_dispatch_thread()); assert(context_has_state(ctx)); assert(ctx->parent != NULL); assert(ctx->stopped); assert(!ctx->exited); assert(taskIsStopped(ext->pid)); trace(LOG_CONTEXT, "context: single step 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 (vxdbgStep(vxdbg_clnt_id, &vxdbg_ctx, NULL, NULL) != OK) { int error = errno; taskUnlock(); trace(LOG_ALWAYS, "context: can't step ctx %#lx, id %#x: %d", ctx, ext->pid, errno_to_str(error)); return -1; } taskUnlock(); send_context_started_event(ctx); return 0; }
int get_symbol_update_policy(const Symbol * sym, char ** id, int * policy) { assert(sym->magic == SYMBOL_MAGIC); *id = sym->ctx->id; *policy = context_has_state(sym->ctx) ? UPDATE_ON_EXE_STATE_CHANGES : UPDATE_ON_MEMORY_MAP_CHANGES; return 0; }
RegisterDefinition * get_PC_definition(Context * ctx) { if (!context_has_state(ctx)) return NULL; return pc_def; }
static void run_safe_events(void * arg) { LINK * qp; pid_t mem; if ((uintptr_t)arg != safe_event_generation) return; assert(safe_event_list != NULL); assert(are_channels_suspended(suspend_group)); safe_event_pid_count = 0; mem = safe_event_list->mem; for (qp = context_root.next; qp != &context_root; qp = qp->next) { Context * ctx = ctxl2ctxp(qp); if (ctx->exited || ctx->exiting || ctx->stopped || !context_has_state(ctx)) { ctx->pending_safe_event = 0; continue; } if (mem > 0 && ctx->mem != mem) { ctx->pending_safe_event = 0; continue; } if (!ctx->pending_step || ctx->pending_safe_event >= STOP_ALL_MAX_CNT / 2) { if (context_stop(ctx) < 0) { int error = errno; #ifdef _WRS_KERNEL if (error == S_vxdbgLib_INVALID_CTX) { /* Most often this means that context has exited, * but exit event is not delivered yet. * Not an error. */ error = 0; } #endif if (error) { trace(LOG_ALWAYS, "error: can't temporary stop pid %d; error %d: %s", ctx->pid, error, errno_to_str(error)); } } assert(!ctx->stopped); } if (ctx->pending_safe_event >= STOP_ALL_MAX_CNT) { trace(LOG_ALWAYS, "error: can't temporary stop pid %d; error: timeout", ctx->pid); ctx->exiting = 1; ctx->pending_safe_event = 0; } else { ctx->pending_safe_event++; safe_event_pid_count++; } } while (safe_event_list) { Trap trap; SafeEvent * i = safe_event_list; assert((uintptr_t)arg == safe_event_generation); if (safe_event_pid_count > 0) { post_event_with_delay(run_safe_events, (void *)++safe_event_generation, STOP_ALL_TIMEOUT); return; } if (mem > 0 && i->mem != mem) { post_event(run_safe_events, (void *)++safe_event_generation); return; } assert(is_all_stopped(i->mem)); safe_event_list = i->next; if (set_trap(&trap)) { i->done(i->arg); clear_trap(&trap); } else { trace(LOG_ALWAYS, "Unhandled exception in \"safe\" event dispatch: %d %s", trap.error, errno_to_str(trap.error)); } loc_free(i); if ((uintptr_t)arg != safe_event_generation) return; } channels_resume(suspend_group); cmdline_resume(); /* Lazily continue execution of temporary stopped contexts */ post_event(continue_temporary_stopped, (void *)safe_event_generation); }