debugger: can dump, set, and read registers
This commit is contained in:
279
src/debugger.c
279
src/debugger.c
@@ -5,6 +5,11 @@ debugger* new_debugger(pid_t pid) {
|
||||
d->breakpoints = NULL;
|
||||
d->n_breakpoints = 0;
|
||||
d->pid = pid;
|
||||
#ifdef __APPLE__
|
||||
task_for_pid(mach_task_self(), pid, &d->port);
|
||||
#else
|
||||
d->port = 0;
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -23,6 +28,276 @@ void set_breakpoint(debugger* d, void* addr) {
|
||||
d->breakpoints[d->n_breakpoints-1] = b;
|
||||
}
|
||||
|
||||
//y u do dis to me
|
||||
#ifdef __APPLE__
|
||||
uint64_t get_register_value(debugger* d, reg r) {
|
||||
thread_act_port_array_t thread_list;
|
||||
mach_msg_type_number_t thread_count;
|
||||
|
||||
task_threads(d->port, &thread_list, &thread_count);
|
||||
|
||||
x86_thread_state64_t thread_state;
|
||||
mach_msg_type_number_t sc = x86_THREAD_STATE64_COUNT;
|
||||
|
||||
thread_get_state(thread_list[0], x86_THREAD_STATE64,
|
||||
(thread_state_t)&thread_state, &sc);
|
||||
|
||||
switch (r) {
|
||||
case rax: return thread_state.__rax;
|
||||
case rbx: return thread_state.__rbx;
|
||||
case rcx: return thread_state.__rcx;
|
||||
case rdx: return thread_state.__rdx;
|
||||
case rdi: return thread_state.__rdi;
|
||||
case rsi: return thread_state.__rsi;
|
||||
case rbp: return thread_state.__rbp;
|
||||
case rsp: return thread_state.__rsp;
|
||||
case r8: return thread_state.__r8;
|
||||
case r9: return thread_state.__r9;
|
||||
case r10: return thread_state.__r10;
|
||||
case r11: return thread_state.__r11;
|
||||
case r12: return thread_state.__r12;
|
||||
case r13: return thread_state.__r13;
|
||||
case r14: return thread_state.__r14;
|
||||
case r15: return thread_state.__r15;
|
||||
case rip: return thread_state.__rip;
|
||||
case rflags: return thread_state.__rflags;
|
||||
case cs: return thread_state.__cs;
|
||||
case fs: return thread_state.__fs;
|
||||
case gs: return thread_state.__gs;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_register_value(debugger* d, reg r, uint64_t val) {
|
||||
thread_act_port_array_t thread_list;
|
||||
mach_msg_type_number_t thread_count;
|
||||
|
||||
task_threads(d->port, &thread_list, &thread_count);
|
||||
|
||||
x86_thread_state64_t thread_state;
|
||||
mach_msg_type_number_t sc = x86_THREAD_STATE64_COUNT;
|
||||
|
||||
thread_get_state(thread_list[0], x86_THREAD_STATE64,
|
||||
(thread_state_t)&thread_state, &sc);
|
||||
|
||||
switch (r) {
|
||||
case rax:
|
||||
thread_state.__rax = val;
|
||||
break;
|
||||
case rbx:
|
||||
thread_state.__rbx = val;
|
||||
break;
|
||||
case rcx:
|
||||
thread_state.__rcx = val;
|
||||
break;
|
||||
case rdx:
|
||||
thread_state.__rdx = val;
|
||||
break;
|
||||
case rdi:
|
||||
thread_state.__rdi = val;
|
||||
break;
|
||||
case rsi:
|
||||
thread_state.__rsi = val;
|
||||
break;
|
||||
case rbp:
|
||||
thread_state.__rbp = val;
|
||||
break;
|
||||
case rsp:
|
||||
thread_state.__rsp = val;
|
||||
break;
|
||||
case r8:
|
||||
thread_state.__r8 = val;
|
||||
break;
|
||||
case r9:
|
||||
thread_state.__r9 = val;
|
||||
break;
|
||||
case r10:
|
||||
thread_state.__r10 = val;
|
||||
break;
|
||||
case r11:
|
||||
thread_state.__r11 = val;
|
||||
break;
|
||||
case r12:
|
||||
thread_state.__r12 = val;
|
||||
break;
|
||||
case r13:
|
||||
thread_state.__r13 = val;
|
||||
break;
|
||||
case r14:
|
||||
thread_state.__r14 = val;
|
||||
break;
|
||||
case r15:
|
||||
thread_state.__r15 = val;
|
||||
break;
|
||||
case rip:
|
||||
thread_state.__rip = val;
|
||||
break;
|
||||
case rflags:
|
||||
thread_state.__rflags = val;
|
||||
break;
|
||||
case cs:
|
||||
thread_state.__cs = val;
|
||||
break;
|
||||
case fs:
|
||||
thread_state.__fs = val;
|
||||
break;
|
||||
case gs:
|
||||
thread_state.__gs = val;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
thread_set_state(thread_list[0], x86_THREAD_STATE,
|
||||
(thread_state_t)&thread_state, sc);
|
||||
}
|
||||
#else
|
||||
uint64_t get_register_value(debugger* d, reg r) {
|
||||
struct user_regs_struct regs;
|
||||
ptrace(PTRACE_GETREGS, d->pid, NULL, ®s);
|
||||
|
||||
switch (r) {
|
||||
case rax: return regs.rax;
|
||||
case rbx: return regs.rbx;
|
||||
case rcx: return regs.rcx;
|
||||
case rdx: return regs.rdx;
|
||||
case rdi: return regs.rdi;
|
||||
case rsi: return regs.rsi;
|
||||
case rbp: return regs.rbp;
|
||||
case rsp: return regs.rsp;
|
||||
case r8: return regs.r8;
|
||||
case r9: return regs.r9;
|
||||
case r10: return regs.r10;
|
||||
case r11: return regs.r11;
|
||||
case r12: return regs.r12;
|
||||
case r13: return regs.r13;
|
||||
case r14: return regs.r14;
|
||||
case r15: return regs.r15;
|
||||
case rip: return regs.rip;
|
||||
case eflags: return regs.eflags;
|
||||
case cs: return regs.cs;
|
||||
case orig_rax: return regs.orig_rax;
|
||||
case fs_base: return regs.fs_base;
|
||||
case gs_base: return regs.gs_base;
|
||||
case fs: return regs.fs;
|
||||
case gs: return regs.gs;
|
||||
case ss: return regs.ss;
|
||||
case ds: return regs.ds;
|
||||
case es: return regs.es;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_register_value(debugger* d, reg r, uint64_t val) {
|
||||
struct user_regs_struct regs;
|
||||
ptrace(PTRACE_GETREGS, d->pid, NULL, ®s);
|
||||
|
||||
switch (r) {
|
||||
case rax:
|
||||
regs.rax = val;
|
||||
break;
|
||||
case rbx:
|
||||
regs.rbx = val;
|
||||
break;
|
||||
case rcx:
|
||||
regs.rcx = val;
|
||||
break;
|
||||
case rdx:
|
||||
regs.rdx = val;
|
||||
break;
|
||||
case rdi:
|
||||
regs.rdi = val;
|
||||
break;
|
||||
case rsi:
|
||||
regs.rsi = val;
|
||||
break;
|
||||
case rbp:
|
||||
regs.rbp = val;
|
||||
break;
|
||||
case rsp:
|
||||
regs.rsp = val;
|
||||
break;
|
||||
case r8:
|
||||
regs.r8 = val;
|
||||
break;
|
||||
case r9:
|
||||
regs.r9 = val;
|
||||
break;
|
||||
case r10:
|
||||
regs.r10 = val;
|
||||
break;
|
||||
case r11:
|
||||
regs.r11 = val;
|
||||
break;
|
||||
case r12:
|
||||
regs.r12 = val;
|
||||
break;
|
||||
case r13:
|
||||
regs.r13 = val;
|
||||
break;
|
||||
case r14:
|
||||
regs.r14 = val;
|
||||
break;
|
||||
case r15:
|
||||
regs.r15 = val;
|
||||
break;
|
||||
case rip:
|
||||
regs.rip = val;
|
||||
break;
|
||||
case eflags:
|
||||
regs.eflags = val;
|
||||
break;
|
||||
case cs:
|
||||
regs.cs = val;
|
||||
break;
|
||||
case orig_rax:
|
||||
regs.orig_rax = val;
|
||||
break;
|
||||
case fs_base:
|
||||
regs.fs_base = val;
|
||||
break;
|
||||
case gs_base:
|
||||
regs.gs_base = val;
|
||||
break;
|
||||
case fs:
|
||||
regs.fs = val;
|
||||
break;
|
||||
case gs:
|
||||
regs.gs = val;
|
||||
break;
|
||||
case ss:
|
||||
regs.ss = val;
|
||||
break;
|
||||
case ds:
|
||||
regs.ds = val;
|
||||
break;
|
||||
case es:
|
||||
regs.es = val;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
ptrace(PTRACE_SETREGS, d->pid, NULL, ®s);
|
||||
}
|
||||
#endif
|
||||
|
||||
const reg_descriptor* get_register_from_name(const char* name) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_registers; i++) {
|
||||
if (!strcmp(name, reg_descriptors[i].name)) return ®_descriptors[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dump_register(debugger* d, reg_descriptor r) {
|
||||
printf("%s: 0x%" PRIx64 "\n", r.name, get_register_value(d, r.r));
|
||||
}
|
||||
|
||||
void dump_registers(debugger* d) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_registers; i++) dump_register(d, reg_descriptors[i]);
|
||||
}
|
||||
|
||||
void run_target(char* program) {
|
||||
if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) perror("Error while creating child: ptrace failed");
|
||||
else execl(program, program, NULL);
|
||||
@@ -49,6 +324,10 @@ short debug_loop(char* command, debugger* d) {
|
||||
} else if ((!strcmp(command, "e")) || (!strcmp(command, "q"))) {
|
||||
puts("Moriturus te saluto.");
|
||||
quit = 1;
|
||||
} else if (!strcmp(command, "r")) {
|
||||
if (!args[1]) dump_registers(d);
|
||||
else if (!args[2]) dump_register(d, *get_register_from_name(args[1]));
|
||||
else set_register_value(d, get_register_from_name(args[1])->r, atol(args[2]));
|
||||
} else {
|
||||
printf("%s: Unknown command\n", command);
|
||||
}
|
||||
|
@@ -1,13 +1,23 @@
|
||||
#include <inttypes.h>
|
||||
#include <editline/readline.h>
|
||||
|
||||
#include "breakpoint.h"
|
||||
#include "register.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach.h>
|
||||
#else
|
||||
#include <sys/user.h>
|
||||
|
||||
typedef short task_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
breakpoint** breakpoints;
|
||||
int n_breakpoints;
|
||||
pid_t pid;
|
||||
task_t port;
|
||||
} debugger;
|
||||
|
||||
void debug(char*);
|
||||
|
@@ -28,6 +28,7 @@ typedef enum {
|
||||
ss,
|
||||
ds,
|
||||
es,
|
||||
eflags,
|
||||
} reg;
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user