|
|
|
static void
|
|
|
|
command_regs(struct mi_process proc)
|
|
|
|
{
|
|
|
|
struct mi_registers regs = get_process_registers(proc);
|
|
|
|
printf("rax = %#018lx rcx = %#018lx\n"
|
|
|
|
"rbp = %#018lx rbx = %#018lx\n"
|
|
|
|
"rdx = %#018lx rsi = %#018lx\n"
|
|
|
|
"rdi = %#018lx rip = %#018lx\n"
|
|
|
|
"rsp = %#018lx\n",
|
|
|
|
regs.rax, regs.rcx, regs.rbp, regs.rbx,
|
|
|
|
regs.rdx, regs.rsi, regs.rdi, regs.rip,
|
|
|
|
regs.rsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_step(struct mi_process proc)
|
|
|
|
{
|
|
|
|
int comp_unit;
|
|
|
|
|
|
|
|
struct mi_registers regs = get_process_registers(proc);
|
|
|
|
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
|
|
|
|
struct mi_sourcepoint *next_sp;
|
|
|
|
|
|
|
|
do {
|
|
|
|
// TODO: step until source line changes !for active file!
|
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0);
|
|
|
|
waitpid(proc.pid, 0, 0);
|
|
|
|
regs = get_process_registers(proc);
|
|
|
|
next_sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
|
|
|
|
if (!next_sp) break;
|
|
|
|
} while (next_sp->line == sp->line);
|
|
|
|
|
|
|
|
print_sourcepoint(proc, comp_unit, next_sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_start(struct mi_process proc)
|
|
|
|
{
|
|
|
|
u64 main_address = proc.base_address + proc.main_address;
|
|
|
|
long saved_instruction = place_breakpoint_at(proc, main_address);
|
|
|
|
run_until_breakpoint_and_restore(proc, main_address, saved_instruction);
|
|
|
|
|
|
|
|
// TODO: restart if already running/paused
|
|
|
|
// TODO: process state: not running / running / paused
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_next(struct mi_process proc)
|
|
|
|
{
|
|
|
|
int comp_unit;
|
|
|
|
|
|
|
|
struct mi_registers regs = get_process_registers(proc);
|
|
|
|
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
|
|
|
|
struct mi_sourcepoint *next_sp;
|
|
|
|
|
|
|
|
do {
|
|
|
|
// TODO: step until source line changes !for active file!
|
|
|
|
|
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0);
|
|
|
|
waitpid(proc.pid, 0, 0);
|
|
|
|
regs = get_process_registers(proc);
|
|
|
|
|
|
|
|
long instruction = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip, NULL);
|
|
|
|
|
|
|
|
if (is_call_instruction(instruction)) {
|
|
|
|
long base_address = regs.rbp;
|
|
|
|
|
|
|
|
// NOTE do single step, get return address from stack, place breakpoint there, continue
|
|
|
|
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0);
|
|
|
|
waitpid(proc.pid, 0, 0);
|
|
|
|
regs = get_process_registers(proc);
|
|
|
|
|
|
|
|
long return_address = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rsp, NULL);
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
//printf("%#lx\n", regs.rip - proc.base_address);
|
|
|
|
next_sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
|
|
|
|
|
|
|
|
if (!next_sp) break;
|
|
|
|
} while (next_sp->line == sp->line);
|
|
|
|
|
|
|
|
print_sourcepoint(proc, comp_unit, next_sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_list(struct mi_process proc)
|
|
|
|
{
|
|
|
|
int comp_unit;
|
|
|
|
struct mi_registers regs = get_process_registers(proc);
|
|
|
|
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit);
|
|
|
|
print_sourcepoint(proc, comp_unit, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_cont(struct mi_process proc)
|
|
|
|
{
|
|
|
|
ptrace(PTRACE_CONT, proc.pid, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_kill(struct mi_process proc)
|
|
|
|
{
|
|
|
|
kill(proc.pid, SIGKILL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_backtrace(struct mi_process proc)
|
|
|
|
{
|
|
|
|
struct mi_registers regs = get_process_registers(proc);
|
|
|
|
struct mi_function *func = get_function_around_pc(proc, regs.rip - proc.base_address);
|
|
|
|
|
|
|
|
u64 fb = regs.rbp;
|
|
|
|
u64 return_address = ptrace(PTRACE_PEEKDATA, proc.pid, fb + 8, NULL);
|
|
|
|
|
|
|
|
printf("%s: %#lx\n", func->name, regs.rip);
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
func = get_function_around_pc(proc, return_address - proc.base_address);
|
|
|
|
if (func) {
|
|
|
|
printf("%s: %#lx\n", func->name, regs.rip);
|
|
|
|
}
|
|
|
|
fb = ptrace(PTRACE_PEEKDATA, proc.pid, fb, NULL);
|
|
|
|
return_address = ptrace(PTRACE_PEEKDATA, proc.pid, fb + 8, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_print(struct mi_process proc, char *name, int name_length)
|
|
|
|
{
|
|
|
|
struct mi_registers regs = get_process_registers(proc);
|
|
|
|
u64 pc = regs.rip - proc.base_address;
|
|
|
|
u64 cfa = get_cfa_at_pc(proc, pc);
|
|
|
|
|
|
|
|
struct mi_variable *variable = get_variable(proc, name, name_length, pc);
|
|
|
|
struct mi_type type = proc.debug.types[variable->type];
|
|
|
|
|
|
|
|
if (cfa && variable) {
|
|
|
|
u64 address = cfa + variable->location;
|
|
|
|
u64 raw_value = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL);
|
|
|
|
|
|
|
|
u8 raw_value1;
|
|
|
|
u16 raw_value2;
|
|
|
|
u32 raw_value4;
|
|
|
|
|
|
|
|
if (type.size == 1) {
|
|
|
|
raw_value1 = (raw_value & 0x00000000000000ffUL);
|
|
|
|
} else if (type.size == 2) {
|
|
|
|
raw_value2 = (raw_value & 0x000000000000ffffUL);
|
|
|
|
} else if (type.size == 4) {
|
|
|
|
raw_value4 = (raw_value & 0x00000000ffffffffUL);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type.encoding) {
|
|
|
|
case MI_ADDRESS: {
|
|
|
|
printf("(address) %.*s = %#lx\n", name_length, name, raw_value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MI_BOOLEAN: {
|
|
|
|
if (raw_value) {
|
|
|
|
printf("(boolean) %.*s = true\n", name_length, name);
|
|
|
|
} else {
|
|
|
|
printf("(boolean) %.*s = false\n", name_length, name);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MI_FLOAT: {
|
|
|
|
if (type.size == 4) {
|
|
|
|
f32 float_val;
|
|
|
|
memcpy(&float_val, &raw_value4, 4);
|
|
|
|
printf("(float) %.*s = %f\n", name_length, name, float_val);
|
|
|
|
} else if (type.size == 8) {
|
|
|
|
f64 float_val;
|
|
|
|
memcpy(&float_val, &raw_value, 8);
|
|
|
|
printf("(double) %.*s = %f\n", name_length, name, float_val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MI_SIGNED: {
|
|
|
|
if (type.size == 1) {
|
|
|
|
s8 signed_value1;
|
|
|
|
memcpy(&signed_value1, &raw_value1, 1);
|
|
|
|
printf("(s8) %.*s = %d\n", name_length, name, signed_value1);
|
|
|
|
} else if (type.size == 2) {
|
|
|
|
s16 signed_value2;
|
|
|
|
memcpy(&signed_value2, &raw_value2, 2);
|
|
|
|
printf("(s16) %.*s = %d\n", name_length, name, signed_value2);
|
|
|
|
} else if (type.size == 4) {
|
|
|
|
s32 signed_value4;
|
|
|
|
memcpy(&signed_value4, &raw_value4, 4);
|
|
|
|
printf("(s32) %.*s = %d\n", name_length, name, signed_value4);
|
|
|
|
} else if (type.size == 8) {
|
|
|
|
s64 signed_value8;
|
|
|
|
memcpy(&signed_value8, &raw_value, 8);
|
|
|
|
printf("(s64) %.*s = %ld\n", name_length, name, signed_value8);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MI_UNSIGNED: {
|
|
|
|
if (type.size == 1) {
|
|
|
|
printf("(u8) %.*s = %u\n", name_length, name, raw_value1);
|
|
|
|
} else if (type.size == 2) {
|
|
|
|
printf("(u16) %.*s = %u\n", name_length, name, raw_value2);
|
|
|
|
} else if (type.size == 4) {
|
|
|
|
printf("(u32) %.*s = %u\n", name_length, name, raw_value4);
|
|
|
|
} else if (type.size == 8) {
|
|
|
|
printf("(u64) %.*s = %lu\n", name_length, name, raw_value);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printf("Variable %.*s not found\n", name_length, name);
|
|
|
|
}
|
|
|
|
}
|