diff options
author | Malfurious <m@lfurio.us> | 2024-05-04 07:32:18 -0400 |
---|---|---|
committer | Malfurious <m@lfurio.us> | 2024-05-08 05:57:59 -0400 |
commit | 47cf13e8429e813aa2fd2b1f41f87722bc616d19 (patch) | |
tree | 9c994ceef54c8141fa40d6924be88160c7c8e19d /debugger.c | |
parent | d187dfc3c81d987ef851b3806fc0ba372c8a3348 (diff) | |
download | misplays-47cf13e8429e813aa2fd2b1f41f87722bc616d19.tar.gz misplays-47cf13e8429e813aa2fd2b1f41f87722bc616d19.zip |
Parameterize architecture-specific details
Abstract architecture details into architecture.h and add x86 constants.
This is slightly complicated by the fact that 64-bit hosts can run
32-bit code, so we do still need to resolve some values dynamically.
The architecture_info() function is intented to address this, and
performs parameter lookups based on the current state of the guest
process.
Resolving values on a per-process-state basis is important due to the
process model under Linux. If we fork to debug a 32-bit program, the
forked process will be native 64-bit until the execve system call. And
of course, the process is then free to exec anything it likes later on
as well.
Signed-off-by: Malfurious <m@lfurio.us>
Diffstat (limited to 'debugger.c')
-rw-r--r-- | debugger.c | 41 |
1 files changed, 31 insertions, 10 deletions
@@ -23,7 +23,6 @@ static const int PTRACE_OPTIONS = static const int PTRACE_CHILD_OPTIONS = PTRACE_OPTIONS | PTRACE_O_EXITKILL; //static const int STOP_ALL_ON_EVENT = 1; static const useconds_t SCHEDULER_DELAY = 10000; -static const unsigned int BREAKPOINT_INSN = 0xcc; static struct process *new_process(pid_t id, int child) { struct process *proc = xmalloc(sizeof(*proc)); @@ -69,6 +68,10 @@ static void free_breakpoints(struct process *proc) { } static void install_breakpoints(struct thread *th) { + struct archinfo archinfo; + struct iovec regs = { &th->state->regs, th->state->regsize }; + architecture_info(&archinfo, ®s); + struct list *breaks = &th->proc->breakpoints; for (struct breakpoint *b = breaks->head; b != breaks->end; b = b->next) { if (!b->installed) { @@ -76,7 +79,7 @@ static void install_breakpoints(struct thread *th) { word = ptrace(PTRACE_PEEKTEXT, th->id, b->address, NULL); b->text = word; - word = (word & ~0xff) | BREAKPOINT_INSN; + word = (word & ~archinfo.bp_mask) | archinfo.bp_insn; ptrace(PTRACE_POKETEXT, th->id, b->address, word); b->installed = 1; b->previously_installed = 1; @@ -108,18 +111,31 @@ static int detect_breakpoint(struct thread *th, int *restart) { int ret = 0; *restart = 0; - struct user_regs_struct regs; + /* Hack: Need to manually fetch registers here, since capture_state() has + * not yet run for this stop. It is not guaranteed that we even want to + * preserve the current state. */ + user_regs_t regs; struct iovec ivregs = { ®s, sizeof(regs) }; ptrace(PTRACE_GETREGSET, th->id, NT_PRSTATUS, &ivregs); - struct breakpoint *b = get_breakpoint(th->proc, regs.rip - 1); + struct archinfo archinfo; + architecture_info(&archinfo, &ivregs); + + unsigned long breakpt_address = archinfo.progmctr - archinfo.bp_adjust; + struct breakpoint *b = get_breakpoint(th->proc, breakpt_address); if (b && b->installed && th->doing != PTRACE_SINGLESTEP) { - regs.rip--; + /* restore actual program counter to breakpoint address */ + if (ivregs.iov_len == sizeof(struct user_regs_32)) { + regs.PROGMCTR_32 = breakpt_address; + } else { + regs.PROGMCTR_64 = breakpt_address; + } ptrace(PTRACE_SETREGSET, th->id, NT_PRSTATUS, &ivregs); + b->hits++; /* todo: consider whether this is firing too much */ ret = b->user; - if (b->stack != 0 && b->stack != regs.rsp) { + if (b->stack != 0 && b->stack != archinfo.stackptr) { *restart = 1; } else if (b->tid != 0 && b->tid != th->id) { *restart = 1; @@ -161,6 +177,7 @@ static void capture_state(struct process *proc) { struct state *s = xmalloc(sizeof(*s)); struct iovec regs = { &s->regs, sizeof(s->regs) }; ptrace(PTRACE_GETREGSET, th->id, NT_PRSTATUS, ®s); + s->regsize = regs.iov_len; list_init(&s->maps); list_insert(th->states.end, s); @@ -620,20 +637,24 @@ int dbg_stepover(struct thread *th) { return -1; } + struct archinfo archinfo; + struct iovec regs = { &th->state->regs, th->state->regsize }; + architecture_info(&archinfo, ®s); + csh handle; - cs_open(CS_ARCH_X86, CS_MODE_64, &handle); + cs_open(archinfo.cs_arch, archinfo.cs_mode, &handle); cs_insn *insn = cs_malloc(handle); - uint64_t address = th->state->regs.rip; + uint64_t address = archinfo.progmctr; size_t size = 128; const uint8_t *code = deref(th, address, size); cs_disasm_iter(handle, &code, &size, &address, insn); - if (insn->id == X86_INS_CALL) { + if (insn->id == archinfo.cs_call) { struct breakpoint *b = add_breakpoint(th->proc, address); b->user = 0; - b->stack = th->state->regs.rsp; + b->stack = archinfo.stackptr; b->tid = th->id; b->enabled = -1; |