debugger: can read and write memory
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
|
|
||||||
debugger* new_debugger(pid_t pid) {
|
debugger* new_debugger(char* pname, pid_t pid) {
|
||||||
debugger* d = malloc(sizeof(debugger));
|
debugger* d = malloc(sizeof(debugger));
|
||||||
|
d->pname = pname;
|
||||||
d->breakpoints = NULL;
|
d->breakpoints = NULL;
|
||||||
d->n_breakpoints = 0;
|
d->n_breakpoints = 0;
|
||||||
d->pid = pid;
|
d->pid = pid;
|
||||||
@@ -289,7 +290,7 @@ const reg_descriptor* get_register_from_name(const char* name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dump_register(debugger* d, reg_descriptor r) {
|
void dump_register(debugger* d, reg_descriptor r) {
|
||||||
printf("%s: 0x%" PRIx64 "\n", r.name, get_register_value(d, r.r));
|
printf("%s: 0x%"PRIx64"\n", r.name, get_register_value(d, r.r));
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_registers(debugger* d) {
|
void dump_registers(debugger* d) {
|
||||||
@@ -298,16 +299,56 @@ void dump_registers(debugger* d) {
|
|||||||
for (i = 0; i < n_registers; i++) dump_register(d, reg_descriptors[i]);
|
for (i = 0; i < n_registers; i++) dump_register(d, reg_descriptors[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint64_t read_mem(debugger* d, uint64_t addr) {
|
||||||
|
return ptrace(PTRACE_PEEKDATA, d->pid, (void*)addr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void write_mem(debugger* d, uint64_t addr, uint64_t val) {
|
||||||
|
ptrace(PTRACE_POKEDATA, d->pid, (void*)addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t get_pc(debugger* d) {
|
||||||
|
return get_register_value(d, rip);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_pc(debugger* d, uint64_t pc) {
|
||||||
|
set_register_value(d, rip, pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_for_signal(debugger* d) {
|
||||||
|
int status;
|
||||||
|
waitpid(d->pid, &status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void step_over_breakpoint(debugger* d) {
|
||||||
|
int i;
|
||||||
|
uint64_t loc = get_pc(d) - 1;
|
||||||
|
|
||||||
|
for (i = 0; i < d->n_breakpoints; i++) {
|
||||||
|
if (d->breakpoints[i]->addr == (void*)loc) {
|
||||||
|
breakpoint* b = d->breakpoints[i];
|
||||||
|
|
||||||
|
if (b->enabled) {
|
||||||
|
set_pc(d, loc);
|
||||||
|
|
||||||
|
disable(b);
|
||||||
|
ptrace(PTRACE_SINGLESTEP, d->pid, NULL, 0);
|
||||||
|
wait_for_signal(d);
|
||||||
|
enable(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_continue(pid_t pid) {
|
void debug_continue(debugger* d) {
|
||||||
int status;
|
step_over_breakpoint(d);
|
||||||
ptrace(PTRACE_CONT, pid, NULL, 0);
|
ptrace(PTRACE_CONT, d->pid, NULL, 0);
|
||||||
|
wait_for_signal(d);
|
||||||
waitpid(pid, &status, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
short debug_loop(char* command, debugger* d) {
|
short debug_loop(char* command, debugger* d) {
|
||||||
@@ -317,7 +358,7 @@ short debug_loop(char* command, debugger* d) {
|
|||||||
command = args[0];
|
command = args[0];
|
||||||
|
|
||||||
if (!strcmp(command, "c")) {
|
if (!strcmp(command, "c")) {
|
||||||
debug_continue(d->pid);
|
debug_continue(d);
|
||||||
} else if (!strcmp(command, "b")) {
|
} else if (!strcmp(command, "b")) {
|
||||||
if (!args[1]) puts("'b' needs an argument");
|
if (!args[1]) puts("'b' needs an argument");
|
||||||
else set_breakpoint(d, (void*)strtol(args[1], NULL, 16));
|
else set_breakpoint(d, (void*)strtol(args[1], NULL, 16));
|
||||||
@@ -328,6 +369,14 @@ short debug_loop(char* command, debugger* d) {
|
|||||||
if (!args[1]) dump_registers(d);
|
if (!args[1]) dump_registers(d);
|
||||||
else if (!args[2]) dump_register(d, *get_register_from_name(args[1]));
|
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 set_register_value(d, get_register_from_name(args[1])->r, atol(args[2]));
|
||||||
|
} else if(!strcmp(command, "m")) {
|
||||||
|
uint64_t addr = strtol(args[2], NULL, 16);
|
||||||
|
if (!args[3]) {
|
||||||
|
printf("%"PRIx64"\n", read_mem(d, addr));
|
||||||
|
} else {
|
||||||
|
uint64_t val = strtol(args[3], NULL, 16);
|
||||||
|
write_mem(d, addr, val);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("%s: Unknown command\n", command);
|
printf("%s: Unknown command\n", command);
|
||||||
}
|
}
|
||||||
@@ -336,10 +385,10 @@ short debug_loop(char* command, debugger* d) {
|
|||||||
return quit;
|
return quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_debugger(pid_t pid) {
|
void run_debugger(char* pname, pid_t pid) {
|
||||||
int status;
|
int status;
|
||||||
char* line = NULL;
|
char* line = NULL;
|
||||||
debugger* d = new_debugger(pid);
|
debugger* d = new_debugger(pname, pid);
|
||||||
short quit = 0;
|
short quit = 0;
|
||||||
|
|
||||||
waitpid(pid, &status, 0);
|
waitpid(pid, &status, 0);
|
||||||
@@ -356,6 +405,6 @@ void debug(char* program) {
|
|||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
if (!pid) run_target(program);
|
if (!pid) run_target(program);
|
||||||
else if (pid > 0) run_debugger(pid);
|
else if (pid > 0) run_debugger(program, pid);
|
||||||
else perror("Error while creating debugger: unable to fork.");
|
else perror("Error while creating debugger: unable to fork.");
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
#define PTRACE_SINGLESTEP PT_STEP
|
||||||
#else
|
#else
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
|
|
||||||
@@ -14,6 +16,7 @@ typedef short task_t;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
char* pname;
|
||||||
breakpoint** breakpoints;
|
breakpoint** breakpoints;
|
||||||
int n_breakpoints;
|
int n_breakpoints;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
Reference in New Issue
Block a user