diff options
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; |