diff --git a/src/debugger.c b/src/debugger.c index 1109854..0170382 100644 --- a/src/debugger.c +++ b/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); } diff --git a/src/debugger.h b/src/debugger.h index 322f25c..6c24b73 100644 --- a/src/debugger.h +++ b/src/debugger.h @@ -1,13 +1,23 @@ +#include #include #include "breakpoint.h" #include "register.h" #include "util.h" +#ifdef __APPLE__ +#include +#else +#include + +typedef short task_t; +#endif + typedef struct { breakpoint** breakpoints; int n_breakpoints; pid_t pid; + task_t port; } debugger; void debug(char*); diff --git a/src/register.h b/src/register.h index 9ece69a..faa2fa7 100644 --- a/src/register.h +++ b/src/register.h @@ -28,6 +28,7 @@ typedef enum { ss, ds, es, + eflags, } reg;