diff --git a/command.c b/command.c index 600021e..85df614 100644 --- a/command.c +++ b/command.c @@ -143,7 +143,19 @@ command_backtrace(struct mi_process proc) } static void -command_print(struct mi_process proc, char *command, int command_length) +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); + if (variable) { + u64 address = cfa + variable->location; + long value = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL); + int val4 = value & 0x00000000FFFFFFFF; + printf("%.*s = %d\n", name_length, name, val4); + } else { + printf("variable %.*s not found\n", name_length, name); + } } \ No newline at end of file diff --git a/dwarf.c b/dwarf.c index 574517b..69487dd 100644 --- a/dwarf.c +++ b/dwarf.c @@ -59,7 +59,7 @@ decode_leb128(u8 *at, u32 *dest) u64 result = 0; u64 shift = 0; - while (1) { + for (;;) { u8 byte = at[offset++]; result |= ((byte & 127) << shift); @@ -88,7 +88,7 @@ decode_leb128s(u8 *at, s32 *dest) u32 size = 32; u8 byte; - while (1) { + for (;;) { byte = at[offset++]; result |= ((byte & 127) << shift); shift += 7; diff --git a/eh_frame.c b/eh_frame.c index 0a768cd..c031209 100644 --- a/eh_frame.c +++ b/eh_frame.c @@ -1,5 +1,6 @@ static u64 -iterate_call_frame_instructions(u8 *data, u64 to_read) +iterate_call_frame_instructions(struct dwarf_cie *cie, u8 *data, u64 to_read, + struct mi_registers *regs, struct dwarf_regset *regset, u64 location) { u64 read = 0; @@ -12,13 +13,15 @@ iterate_call_frame_instructions(u8 *data, u64 to_read) if (high_two == DW_CFA_advance_loc) { u8 delta = low_six; + if (regset) { + regset->loc += delta * cie->code_alignment; + } } else if (high_two == DW_CFA_offset) { u8 reg = low_six; u32 factored_offset; increment += decode_leb128(data, &factored_offset); } else if (high_two == DW_CFA_restore) { u8 reg = low_six; - } else if (high_two == 0) { switch (low_six) { case DW_CFA_nop: { @@ -29,6 +32,9 @@ iterate_call_frame_instructions(u8 *data, u64 to_read) u64 address; memcpy(&address, data, 8); increment = 8; + if (regset) { + regset->loc = address; // TODO: encoding?? + } break; } @@ -36,6 +42,9 @@ iterate_call_frame_instructions(u8 *data, u64 to_read) u8 advance; memcpy(&advance, data, 1); increment = 1; + if (regset) { + regset->loc += advance * cie->code_alignment; + } break; } @@ -43,6 +52,9 @@ iterate_call_frame_instructions(u8 *data, u64 to_read) u16 advance; memcpy(&advance, data, 2); increment = 2; + if (regset) { + regset->loc += advance * cie->code_alignment; + } break; } @@ -50,6 +62,9 @@ iterate_call_frame_instructions(u8 *data, u64 to_read) u32 advance; memcpy(&advance, data, 4); increment = 4; + if (regset) { + regset->loc += advance * cie->code_alignment; + } break; } @@ -98,20 +113,35 @@ iterate_call_frame_instructions(u8 *data, u64 to_read) case DW_CFA_def_cfa: { u32 reg; u32 nonfactored_offset; + increment += decode_leb128(data, ®); - increment += decode_leb128(data, &nonfactored_offset); + increment += decode_leb128(data + increment, &nonfactored_offset); + + if (regset) { + regset->cfa_offset = nonfactored_offset; + regset->cfa_register = reg; + } + break; } case DW_CFA_def_cfa_register: { u32 reg; increment += decode_leb128(data, ®); + + if (regset) { + regset->cfa_register = reg; + } + break; } case DW_CFA_def_cfa_offset: { u32 offset; increment += decode_leb128(data, &offset); + if (regset) { + regset->cfa_offset = offset; + } break; } @@ -188,6 +218,11 @@ iterate_call_frame_instructions(u8 *data, u64 to_read) } } + if (location && regset->loc > location) { + regset->cfa = regset->system[regset->cfa_register] + regset->cfa_offset; + break; + } + data += increment; read += increment + 1; @@ -236,8 +271,10 @@ read_one_cie(struct dwarf_cie *header, u64 length, u8 *data, u8 *original_data) } header->has_z = has_z; + header->instructions = data; + header->instructions_length = header->length - (data - original_data - 4); - data += iterate_call_frame_instructions(data, header->length - (data - original_data - 4)); + data += iterate_call_frame_instructions(header, data, header->instructions_length, 0, 0, 0); if (has_R) { // NOTE(aolo2): this shit is undocumented. Best sources I could find: @@ -372,14 +409,13 @@ read_encoded_pointer(struct mi_process proc, struct dwarf_cie *cie, u8 *data, u6 } static u64 -read_one_fde(struct mi_process proc, struct dwarf_cie *cie, u64 length, u32 cie_offset, u8 *data, u8 *original_data) +read_one_fde(struct mi_process proc, struct dwarf_cie *cie, u64 length, u8 *data, u8 *original_data, + struct dwarf_fde *header) { - struct dwarf_fde header = { 0 }; - - header.length = length; - header.cie = (struct dwarf_cie *) (data - 4 - cie_offset); + header->length = length; + header->cie = *cie; - u32 pointer_size = read_encoded_pointer(proc, cie, data, &header.low_pc); + u32 pointer_size = read_encoded_pointer(proc, cie, data, &header->low_pc); data += pointer_size; u64 fde_length = 0; @@ -394,21 +430,24 @@ read_one_fde(struct mi_process proc, struct dwarf_cie *cie, u64 length, u32 cie_ data += 8; } - header.high_pc = header.low_pc + fde_length; + header->high_pc = header->low_pc + fde_length; if (cie->has_z) { - data += decode_leb128(data, &header.augmentation_data_length); - header.augmentation_data = data; - data += header.augmentation_data_length; + data += decode_leb128(data, &header->augmentation_data_length); + header->augmentation_data = data; + data += header->augmentation_data_length; } - data += iterate_call_frame_instructions(data, header.length - (data - original_data - 4)); + header->instructions = data; + header->instructions_length = header->length - (data - original_data - 4); + + data += iterate_call_frame_instructions(cie, data, header->instructions_length, 0, 0, 0); return(data - original_data); } static u64 -read_one_call_frame_record(struct mi_process proc, struct dwarf_cie *last_cie, u8 *data) +read_one_call_frame_record(struct mi_process proc, struct dwarf_cie *last_cie, struct dwarf_fde *last_fde, int *is_cie, u8 *data) { u8 *original_data = data; u64 length; @@ -436,49 +475,76 @@ read_one_call_frame_record(struct mi_process proc, struct dwarf_cie *last_cie, u if (cie_id == 0) { result = read_one_cie(last_cie, length, data, original_data); + *is_cie = 1; } else { - result = read_one_fde(proc, last_cie, length, cie_id, data, original_data); + result = read_one_fde(proc, last_cie, length, data, original_data, last_fde); + *is_cie = 0; } return(result); } -static void -parse_eh_frame(struct mi_process proc) +static struct dwarf_fde +eh_frame_find_fde(struct mi_process proc, u64 pc) { struct elf_section_table_entry_x64 eh_frame = get_section_entry(proc.elf, ".eh_frame"); struct dwarf_cie last_cie = { 0 }; + struct dwarf_fde last_fde = { 0 }; + int is_cie = 0; u64 read = 0; for (;;) { - u64 size = read_one_call_frame_record(proc, &last_cie, proc.elf + eh_frame.offset_in_file + read); + u64 size = read_one_call_frame_record(proc, &last_cie, &last_fde, &is_cie, proc.elf + eh_frame.offset_in_file + read); + + if (!is_cie) { + if (last_fde.low_pc <= pc && pc < last_fde.high_pc) { + return(last_fde); + } + } + read += size; if (read >= eh_frame.size) { break; } } -} - -static struct dwarf_fde * -eh_frame_find_fde(struct mi_process proc, u64 pc) -{ -} - -static struct dwarf_regset -eh_frame_init_registers(struct mi_process proc, struct dwarf_cie *cie) -{ + last_fde.length = 0; + return(last_fde); } static struct dwarf_regset -eh_frame_find_pc(struct mi_process proc, struct dwarf_fde *fde, struct dwarf_regset regs, u64 pc) +eh_frame_init_registers(struct mi_process proc, struct mi_registers regs, struct dwarf_cie cie) { - + struct dwarf_regset regset = { 0 }; + + regset.system[0] = regs._sys.rax; + regset.system[1] = regs._sys.rdx; + regset.system[2] = regs._sys.rcx; + regset.system[3] = regs._sys.rbx; + regset.system[4] = regs._sys.rsi; + regset.system[5] = regs._sys.rdi; + regset.system[6] = regs._sys.rbp; + regset.system[7] = regs._sys.rsp; + regset.system[8] = regs._sys.r8; + regset.system[9] = regs._sys.r9; + regset.system[10] = regs._sys.r10; + regset.system[11] = regs._sys.r11; + regset.system[12] = regs._sys.r12; + regset.system[13] = regs._sys.r13; + regset.system[14] = regs._sys.r14; + regset.system[15] = regs._sys.r15; + + iterate_call_frame_instructions(&cie, cie.instructions, cie.instructions_length, ®s, ®set, 0); + + return(regset); } -static u64 -eh_frame_compute_cfa(struct mi_process proc, struct dwarf_regset regs) +static struct dwarf_regset +eh_frame_find_pc(struct mi_process proc, struct dwarf_fde fde, struct mi_registers regs, struct dwarf_regset regset, u64 pc) { + regset.loc = fde.low_pc; + iterate_call_frame_instructions(&fde.cie, fde.instructions, fde.instructions_length, ®s, ®set, pc); + return(regset); } \ No newline at end of file diff --git a/elf_dwarf.h b/elf_dwarf.h index d0d560a..0e295af 100644 --- a/elf_dwarf.h +++ b/elf_dwarf.h @@ -649,7 +649,9 @@ struct dwarf_cie { u32 return_address_register; u32 augmentation_data_length; u8 *augmentation_data; + u8 *instructions; + u32 instructions_length; int has_z; enum dwarf_cie_pointer_format pointer_format; @@ -660,14 +662,41 @@ struct dwarf_cie { struct dwarf_fde { u32 length; u64 optional_length; - struct dwarf_cie *cie; + struct dwarf_cie cie; u64 low_pc; u64 high_pc; u32 augmentation_data_length; u8 *augmentation_data; + u8 *instructions; + u32 instructions_length; +}; + +enum dwarf_regset_register { + RAX = 0, + RDX = 1, + RCX = 2, + RBX = 3, + RSI = 4, + RDI = 5, + RBP = 6, + RSP = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, + RA = 16 }; struct dwarf_regset { - s64 cfa; + u64 loc; + u64 cfa; + u64 system[17]; + + enum dwarf_regset_register cfa_register; + u32 cfa_offset; }; \ No newline at end of file diff --git a/main.c b/main.c index e3ac23c..4d476dd 100644 --- a/main.c +++ b/main.c @@ -22,7 +22,6 @@ main(int argc, char *argv[]) char *last_command = malloc(max_command_length + 1); parse_debug_info(process.elf, &process.debug); - parse_eh_frame(process); process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid); process.main_address = get_address_of_subroutine(process, "main"); @@ -35,6 +34,15 @@ main(int argc, char *argv[]) parse_debug_line(process.elf, &process.debug); +#if 0 + command_start(process); + command_step(process); + command_step(process); + command_print(process, "test", 4); + return(0); +#endif + + while ((command_length = getline(&command, &max_command_length, stdin))) { if (command_length == 1) { memset(command, 0, max_command_length); diff --git a/res/004-scoped-variables.c b/res/004-scoped-variables.c index 97974c7..b50cb52 100644 --- a/res/004-scoped-variables.c +++ b/res/004-scoped-variables.c @@ -31,7 +31,7 @@ f1() int main(int argc, char **argv) { - int a_main = 0; + int a_main = 123123; f1(); f3(); return(0); diff --git a/util.c b/util.c index 6affb8c..b7f148a 100644 --- a/util.c +++ b/util.c @@ -298,17 +298,53 @@ get_function_around_pc(struct mi_process proc, u64 pc) return(0); } +static struct mi_variable * +get_variable(struct mi_process proc, char *name, int length, u64 pc) +{ + struct mi_debuginfo debug = proc.debug; + + for (int c = 0; c < debug.cu_count; ++c) { + struct mi_compunit *unit = debug.compilation_units + c; + + if (unit->low_pc <= pc && pc < unit->high_pc) { + + for (int f = 0; f < unit->functions_count; ++f) { + struct mi_function *func = debug.functions + unit->functions_from + f; + + if (func->low_pc <= pc && pc < func->high_pc) { + + for (int v = 0; v < func->variables_count; ++v) { + struct mi_variable *variable = debug.variables + func->variables_from + v; + if (0 == strncmp(name, variable->name, length)) { + return(variable); + } + } + + return(0); + } + + } + + break; + } + + } + + return(0); +} + static u64 get_cfa_at_pc(struct mi_process proc, u64 pc) { - struct dwarf_fde *fde = eh_frame_find_fde(proc, pc); - if (!fde) { + struct dwarf_fde fde = eh_frame_find_fde(proc, pc); + if (!fde.length) { DIE("could not find FDE for pc!\n"); } - struct dwarf_regset regs = eh_frame_init_registers(proc, fde->cie); - regs = eh_frame_find_pc(proc, fde, regs, pc); - u64 cfa = eh_frame_compute_cfa(proc, regs); + struct mi_registers regs = get_process_registers(proc); + struct dwarf_regset regset = eh_frame_init_registers(proc, regs, fde.cie); + + regset = eh_frame_find_pc(proc, fde, regs, regset, pc); - return(cfa); + return(regset.cfa); } \ No newline at end of file