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); } }