|
|
@ -22,6 +22,7 @@ command_step(struct mi_process proc) |
|
|
|
struct mi_sourcepoint *next_sp; |
|
|
|
struct mi_sourcepoint *next_sp; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
do { |
|
|
|
|
|
|
|
// TODO: step until source line changes (for active file)
|
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
|
|
|
waitpid(proc.pid, 0, 0); |
|
|
|
waitpid(proc.pid, 0, 0); |
|
|
|
regs = get_process_registers(proc); |
|
|
|
regs = get_process_registers(proc); |
|
|
@ -51,25 +52,39 @@ command_next(struct mi_process proc) |
|
|
|
struct mi_sourcepoint *next_sp; |
|
|
|
struct mi_sourcepoint *next_sp; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
do { |
|
|
|
|
|
|
|
// TODO: step until source line changes (for active file)
|
|
|
|
|
|
|
|
|
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
|
|
|
waitpid(proc.pid, 0, 0); |
|
|
|
waitpid(proc.pid, 0, 0); |
|
|
|
regs = get_process_registers(proc); |
|
|
|
regs = get_process_registers(proc); |
|
|
|
|
|
|
|
|
|
|
|
long instruction = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip, NULL); |
|
|
|
long instruction = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip, NULL); |
|
|
|
|
|
|
|
|
|
|
|
if (is_call_instruction(instruction)) { |
|
|
|
if (is_call_instruction(instruction)) { |
|
|
|
u64 call_at = regs.rip; |
|
|
|
long base_address = regs.rbp; |
|
|
|
|
|
|
|
|
|
|
|
// Do single step, get return address from stack, place breakpoint there, continue
|
|
|
|
// NOTE do single step, get return address from stack, place breakpoint there, continue
|
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
|
|
|
waitpid(proc.pid, 0, 0); |
|
|
|
waitpid(proc.pid, 0, 0); |
|
|
|
regs = get_process_registers(proc); |
|
|
|
regs = get_process_registers(proc); |
|
|
|
|
|
|
|
|
|
|
|
long return_address = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rsp, NULL); |
|
|
|
long return_address = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rsp, NULL); |
|
|
|
long saved_instruction = place_breakpoint_at(proc, return_address); |
|
|
|
|
|
|
|
run_until_breakpoint_and_restore(proc, return_address, saved_instruction); |
|
|
|
|
|
|
|
// TODO: disambiguate recursive calls
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
regs = get_process_registers(proc); |
|
|
|
// NOTE: disambiguate recursive calls
|
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
|
|
|
long saved_instruction = place_breakpoint_at(proc, return_address); |
|
|
|
|
|
|
|
run_until_breakpoint_and_restore(proc, return_address, saved_instruction); |
|
|
|
|
|
|
|
regs = get_process_registers(proc); |
|
|
|
|
|
|
|
long actual_base_address = regs.rbp; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (base_address == actual_base_address) { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// NOTE: step to the next instruction after the return address, so that we can add a breakpoint there
|
|
|
|
|
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
|
|
|
|
|
|
|
waitpid(proc.pid, 0, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// TODO: repXXX
|
|
|
|
// TODO: repXXX
|
|
|
|
|
|
|
|
|
|
|
|