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->breakpoints = NULL;
|
||||||
d->n_breakpoints = 0;
|
d->n_breakpoints = 0;
|
||||||
d->pid = pid;
|
d->pid = pid;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
task_for_pid(mach_task_self(), pid, &d->port);
|
||||||
|
#else
|
||||||
|
d->port = 0;
|
||||||
|
#endif
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +28,276 @@ void set_breakpoint(debugger* d, void* addr) {
|
|||||||
d->breakpoints[d->n_breakpoints-1] = b;
|
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) {
|
void run_target(char* program) {
|
||||||
if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) perror("Error while creating child: ptrace failed");
|
if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) perror("Error while creating child: ptrace failed");
|
||||||
else execl(program, program, NULL);
|
else execl(program, program, NULL);
|
||||||
@@ -49,6 +324,10 @@ short debug_loop(char* command, debugger* d) {
|
|||||||
} else if ((!strcmp(command, "e")) || (!strcmp(command, "q"))) {
|
} else if ((!strcmp(command, "e")) || (!strcmp(command, "q"))) {
|
||||||
puts("Moriturus te saluto.");
|
puts("Moriturus te saluto.");
|
||||||
quit = 1;
|
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 {
|
} else {
|
||||||
printf("%s: Unknown command\n", command);
|
printf("%s: Unknown command\n", command);
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,23 @@
|
|||||||
|
#include <inttypes.h>
|
||||||
#include <editline/readline.h>
|
#include <editline/readline.h>
|
||||||
|
|
||||||
#include "breakpoint.h"
|
#include "breakpoint.h"
|
||||||
#include "register.h"
|
#include "register.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#else
|
||||||
|
#include <sys/user.h>
|
||||||
|
|
||||||
|
typedef short task_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
breakpoint** breakpoints;
|
breakpoint** breakpoints;
|
||||||
int n_breakpoints;
|
int n_breakpoints;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
task_t port;
|
||||||
} debugger;
|
} debugger;
|
||||||
|
|
||||||
void debug(char*);
|
void debug(char*);
|
||||||
|
@@ -28,6 +28,7 @@ typedef enum {
|
|||||||
ss,
|
ss,
|
||||||
ds,
|
ds,
|
||||||
es,
|
es,
|
||||||
|
eflags,
|
||||||
} reg;
|
} reg;
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user