static void command_set_signal_mask(char * token, Channel * c) { int err = 0; char id[256]; pid_t pid; Context * ctx = NULL; int dont_stop; int dont_pass; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); dont_stop = json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); dont_pass = json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); pid = id2pid(id, NULL); ctx = context_find_from_pid(pid); if (ctx == NULL) { err = ERR_INV_CONTEXT; } else { ctx->sig_dont_stop = dont_stop; ctx->sig_dont_pass = dont_pass; } write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); }
static void command_get_context(char * token, Channel * c) { int err = 0; char id[256]; Context * ctx = NULL; 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); ctx = id2ctx(id); if (ctx == NULL) err = ERR_INV_CONTEXT; else if (ctx->exited) err = ERR_ALREADY_EXITED; if (err) { write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stringz(&c->out, "null"); write_stream(&c->out, MARKER_EOM); } else { /* Need to stop everything to access context properties. * In particular, proc FS access can fail when process is running. */ GetContextArgs * s = loc_alloc_zero(sizeof(GetContextArgs)); s->c = c; stream_lock(c); strcpy(s->token, token); s->ctx = ctx; context_lock(ctx); id2pid(id, &s->parent); post_safe_event(ctx->mem, event_get_context, s); } }
static void command_signal(char * token, Channel * c) { int err = 0; char id[256]; int signal = 0; pid_t pid, parent; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); signal = (int)json_read_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); pid = id2pid(id, &parent); write_stringz(&c->out, "R"); write_stringz(&c->out, token); #if defined(WIN32) err = ENOSYS; #elif defined(_WRS_KERNEL) if (kill(pid, signal) < 0) err = errno; #elif defined(__APPLE__) if (kill(pid, signal) < 0) err = errno; #else if (parent == 0) { if (kill(pid, signal) < 0) err = errno; } else { if (tkill(pid, signal) < 0) err = errno; } #endif write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); }
static void command_terminate(char * token, Channel * c) { int err = 0; char id[256]; pid_t pid, parent; 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); pid = id2pid(id, &parent); write_stringz(&c->out, "R"); write_stringz(&c->out, token); if (parent != 0) { err = ERR_INV_CONTEXT; } else { #if defined(WIN32) HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (h == NULL) { err = ERR_INV_CONTEXT; } else { TerminateProcess(h, 1); CloseHandle(h); } #else if (kill(pid, SIGTERM) < 0) err = errno; #endif } write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); }
static void command_attach(char * token, Channel * c) { int err = 0; char id[256]; pid_t pid, parent; 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); pid = id2pid(id, &parent); if (parent != 0) { err = ERR_INV_CONTEXT; } else if (context_find_from_pid(pid) != NULL) { err = ERR_ALREADY_ATTACHED; } else { AttachDoneArgs * data = loc_alloc_zero(sizeof *data); data->c = c; strcpy(data->token, token); if (context_attach(pid, attach_done, data, 0) == 0) { stream_lock(c); return; } err = errno; loc_free(data); } write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); }
static void command_get_signal_list(char * token, Channel * c) { int err = 0; char id[256]; pid_t pid; 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); pid = id2pid(id, NULL); write_stringz(&c->out, "R"); write_stringz(&c->out, token); /* pid is ignored, same signal list for all */ write_errno(&c->out, err); if (err) { write_stringz(&c->out, "null"); } else { int i = 0; int n = 0; write_stream(&c->out, '['); for (i = 0; i < 32; i++) { char * name = signal_name(i); char * desc = signal_description(i); if (name != NULL || desc != NULL) { if (n > 0) write_stream(&c->out, ','); write_stream(&c->out, '{'); json_write_string(&c->out, "Index"); write_stream(&c->out, ':'); json_write_long(&c->out, i); if (name != NULL) { write_stream(&c->out, ','); json_write_string(&c->out, "Name"); write_stream(&c->out, ':'); json_write_string(&c->out, name); } if (desc != NULL) { write_stream(&c->out, ','); json_write_string(&c->out, "Description"); write_stream(&c->out, ':'); json_write_string(&c->out, desc); } write_stream(&c->out, ','); json_write_string(&c->out, "Code"); write_stream(&c->out, ':'); json_write_ulong(&c->out, signal_code(i)); write_stream(&c->out, '}'); n++; } } write_stream(&c->out, ']'); write_stream(&c->out, 0); } write_stream(&c->out, MARKER_EOM); }
static void command_get_context(char * token, Channel * c) { int err = 0; char id[256]; pid_t pid, parent; 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); pid = id2pid(id, &parent); write_stringz(&c->out, "R"); write_stringz(&c->out, token); pid = id2pid(id, &parent); if (pid != 0 && parent == 0) { #if defined(WIN32) #elif defined(_WRS_KERNEL) if (TASK_ID_VERIFY(pid) == ERROR) err = ERR_INV_CONTEXT; #elif defined(__APPLE__) #else struct stat st; char dir[FILE_PATH_SIZE]; snprintf(dir, sizeof(dir), "/proc/%d", pid); if (lstat(dir, &st) < 0) err = errno; else if (!S_ISDIR(st.st_mode)) err = ERR_INV_CONTEXT; #endif } write_errno(&c->out, err); if (err == 0 && pid != 0 && parent == 0) { write_context(&c->out, pid); write_stream(&c->out, 0); } else { write_stringz(&c->out, "null"); } write_stream(&c->out, MARKER_EOM); }
int cpu_bp_on_suspend(Context * ctx, int * triggered) { unsigned cb_cnt = 0; ContextExtensionARM * ext = EXT(ctx); ContextExtensionARM * bps = EXT(context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT)); if (ctx->exiting) return 0; if (bps->bp_cnt > 0 || bps->wp_cnt > 0) { int i; ContextAddress pc = 0; if (read_reg(ctx, pc_def, pc_def->size, &pc) < 0) return -1; if (ext->skip_wp_addr != pc) ext->skip_wp_set = 0; if (bps->bp_cnt > 0) { for (i = 0; i < bps->bp_cnt; i++) { ContextBreakpoint * cb = bps->hw_bps[i]; if (cb != NULL && ((uint32_t)cb->address & ~0x1) == pc && (ext->armed & (1u << i))) { ext->triggered_hw_bps[cb_cnt++] = cb; } } } if (bps->wp_cnt > 0) { siginfo_t siginfo; pid_t pid = id2pid(ctx->id, NULL); if (ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo) < 0) return -1; if (siginfo.si_signo == SIGTRAP && (siginfo.si_code & 0xffff) == 0x0004 && siginfo.si_errno < 0) { /* Watchpoint */ for (i = bps->bp_cnt; i < bps->bp_cnt + bps->wp_cnt; i++) { ContextBreakpoint * cb = bps->hw_bps[i]; if (cb != NULL && (ext->armed & (1u << i))) { if (bps->wp_cnt > 1) { ContextAddress addr = (ContextAddress)siginfo.si_addr; if (addr < cb->address || addr >= cb->address + cb->length) continue; } ext->triggered_hw_bps[cb_cnt++] = cb; ext->skip_wp_set |= 1u << i; ext->skip_wp_addr = pc; } } } } if (cb_cnt > 0) { ctx->stopped_by_cb = ext->triggered_hw_bps; ctx->stopped_by_cb[cb_cnt] = NULL; } } *triggered = cb_cnt > 0; return 0; }
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 int get_bp_info(Context * ctx) { uint32_t buf = 0; ContextExtensionARM * bps = EXT(ctx); if (bps->info_ok) return 0; if (ptrace(PTRACE_GETHBPREGS, id2pid(ctx->id, NULL), 0, &buf) < 0) { /* Kernel does not support hardware breakpoints */ bps->arch = 0; bps->wp_size = 0; bps->wp_cnt = 0; bps->bp_cnt = 0; bps->info_ok = 1; return 0; } bps->arch = (uint8_t)(buf >> 24); bps->wp_size = (uint8_t)(buf >> 16); bps->wp_cnt = (uint8_t)(buf >> 8); bps->bp_cnt = (uint8_t)buf; if (bps->wp_cnt > MAX_HWP) bps->wp_cnt = MAX_HWP; if (bps->bp_cnt > MAX_HBP) bps->bp_cnt = MAX_HBP; bps->info_ok = 1; return 0; }
static int set_debug_regs(Context * ctx, int * step_over_hw_bp) { int i, j; ContextAddress pc = 0; Context * grp = context_get_group(ctx, CONTEXT_GROUP_BREAKPOINT); ContextExtensionARM * ext = EXT(ctx); ContextExtensionARM * bps = EXT(grp); pid_t pid = id2pid(ctx->id, NULL); assert(bps->info_ok); ext->armed = 0; *step_over_hw_bp = 0; if (read_reg(ctx, pc_def, pc_def->size, &pc) < 0) return -1; for (i = 0; i < bps->bp_cnt + bps->wp_cnt; i++) { uint32_t cr = 0; ContextBreakpoint * cb = bps->hw_bps[i]; if (i == 0 && ext->hw_stepping) { uint32_t vr = 0; if (ext->hw_stepping == 1) { vr = (uint32_t)ext->step_addr & ~0x1; cr |= 0x3 << 5; } else { vr = (uint32_t)pc; cr |= 0x1 << 22; cr |= 0xf << 5; } cr |= 0x7u; if (ptrace(PTRACE_SETHBPREGS, pid, 1, &vr) < 0) return -1; } else if (cb != NULL) { if (i < bps->bp_cnt && ((uint32_t)cb->address & ~0x1) == pc) { /* Skipping the breakpoint */ *step_over_hw_bp = 1; } else if (bps->arch >= ARM_DEBUG_ARCH_V7_ECP14 && (ext->skip_wp_set & (1u << i))) { /* Skipping the watchpoint */ assert(i >= bps->bp_cnt); *step_over_hw_bp = 1; } else { uint32_t vr = (uint32_t)cb->address & ~0x1; if (i < bps->bp_cnt) { cr |= 0x3 << 5; } else { vr = (uint32_t)cb->address & ~0x3; for (j = 0; j < 4; j++) { if (vr + j < cb->address) continue; if (vr + j >= cb->address + cb->length) continue; cr |= 1 << (5 + j); } if (cb->access_types & CTX_BP_ACCESS_DATA_READ) cr |= 1 << 3; if (cb->access_types & CTX_BP_ACCESS_DATA_WRITE) cr |= 1 << 4; } cr |= 0x7; if (i < bps->bp_cnt) { if (ptrace(PTRACE_SETHBPREGS, pid, i * 2 + 1, &vr) < 0) return -1; } else { if (ptrace(PTRACE_SETHBPREGS, pid, -(i * 2 + 1), &vr) < 0) return -1; } ext->armed |= 1 << i; } } if (cr == 0) { /* Linux kernel does not allow 0 as Control Register value */ cr |= 0x3u << 1; cr |= 0xfu << 5; if (i >= bps->bp_cnt) { cr |= 1u << 4; } } if (i < bps->bp_cnt) { if (ptrace(PTRACE_SETHBPREGS, pid, i * 2 + 2, &cr) < 0) return -1; } else { if (ptrace(PTRACE_SETHBPREGS, pid, -(i * 2 + 2), &cr) < 0) return -1; } } ext->hw_bps_regs_generation = bps->hw_bps_generation; return 0; }