From c45c3cd01f22f4fb5d689bffa9b14b13aef013ee Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Sat, 24 Jul 2021 01:40:20 +0300 Subject: [PATCH] eh_frame parser closed to working (but still very far) --- command.c | 7 - eh_frame.c | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 4 +- util.c | 35 ----- 4 files changed, 375 insertions(+), 43 deletions(-) create mode 100644 eh_frame.c diff --git a/command.c b/command.c index 8b5af75..8984e9b 100644 --- a/command.c +++ b/command.c @@ -100,13 +100,6 @@ command_next(struct mi_process proc) print_sourcepoint(proc, comp_unit, next_sp); } -static void -command_print(struct mi_process proc, char *identifier, int len) -{ - u64 location = lookup_identifier_address(proc, identifier, len); - printf("%#lx\n", location); -} - static void command_list(struct mi_process proc) { diff --git a/eh_frame.c b/eh_frame.c new file mode 100644 index 0000000..fd2d797 --- /dev/null +++ b/eh_frame.c @@ -0,0 +1,372 @@ +enum dwarf_cfa_op_base { + DW_CFA_advance_loc = 0x1, + DW_CFA_offset = 0x2, + DW_CFA_restore = 0x3 +}; + +enum dwarf_cfa_op { + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + DW_CFA_lo_user = 0x1c, + DW_CFA_hi_user = 0x3f, +}; + +struct dwarf_cie_header { + u32 length; + u8 version; + u32 code_alignment; + s32 data_alignment; + u32 return_address_register; + u32 augmentation_data_length; + u8 *augmentation_data; +}; + +struct dwarf_fde_header { + u32 length; + u64 optional_length; + struct dwarf_cie_header *cie; + u64 low_pc; + u64 high_pc; + u32 augmentation_data_length; + u8 *augmentation_data; +}; + +static u64 +iterate_call_frame_instructions(struct dwarf_cie_header header, u8 *data, u8 *original_data) +{ + u64 already_read = data - original_data - 4; + u64 leftover = header.length - already_read; + u64 read = 0; + + for (;;) { + u8 op_byte = *data++; + enum dwarf_cfa_op_base high_two = op_byte >> 6; + enum dwarf_cfa_op low_six = op_byte & 0x3f; + + u32 increment = 0; + + if (high_two == DW_CFA_advance_loc) { + u8 delta = low_six; + } 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: { + break; + } + + case DW_CFA_set_loc: { + u64 address; + memcpy(&address, data, 8); + increment = 8; + break; + } + + case DW_CFA_advance_loc1: { + u8 advance; + memcpy(&advance, data, 1); + increment = 1; + break; + } + + case DW_CFA_advance_loc2: { + u16 advance; + memcpy(&advance, data, 2); + increment = 2; + break; + } + + case DW_CFA_advance_loc4: { + u32 advance; + memcpy(&advance, data, 4); + increment = 4; + break; + } + + case DW_CFA_offset_extended: { + u32 reg; + u32 offset; + increment += decode_leb128(data, ®); + increment += decode_leb128(data, &offset); + break; + } + + case DW_CFA_restore_extended: { + u32 reg; + increment += decode_leb128(data, ®); + break; + } + + case DW_CFA_undefined: { + u32 reg; + increment += decode_leb128(data, ®); + break; + } + + case DW_CFA_same_value: { + u32 reg; + increment += decode_leb128(data, ®); + break; + } + + case DW_CFA_register: { + u32 reg; + s32 factored_offset; + increment += decode_leb128(data, ®); + increment += decode_leb128s(data, &factored_offset); + break; + } + + case DW_CFA_remember_state: { + break; + } + + case DW_CFA_restore_state: { + break; + } + + case DW_CFA_def_cfa: { + u32 reg; + u32 nonfactored_offset; + increment += decode_leb128(data, ®); + increment += decode_leb128(data, &nonfactored_offset); + break; + } + + case DW_CFA_def_cfa_register: { + u32 reg; + increment += decode_leb128(data, ®); + break; + } + + case DW_CFA_def_cfa_offset: { + u32 offset; + increment += decode_leb128(data, &offset); + break; + } + + case DW_CFA_def_cfa_expression: { + u32 length; + increment += decode_leb128(data, &length); + increment += length; + break; + } + + case DW_CFA_expression: { + u32 reg; + u32 length; + increment += decode_leb128(data, ®); + increment += decode_leb128(data, &length); + increment += length; + break; + } + + case DW_CFA_offset_extended_sf: { + u32 reg; + s32 factored_offset; + increment += decode_leb128(data, ®); + increment += decode_leb128s(data, &factored_offset); + break; + } + + case DW_CFA_def_cfa_sf: { + u32 reg; + s32 factored_offset; + increment += decode_leb128(data, ®); + increment += decode_leb128s(data, &factored_offset); + break; + } + + case DW_CFA_def_cfa_offset_sf: { + s32 factored_offset; + increment += decode_leb128s(data, &factored_offset); + break; + } + + case DW_CFA_val_offset: { + u32 reg; + u32 factored_offset; + increment += decode_leb128(data, ®); + increment += decode_leb128(data, &factored_offset); + break; + } + + case DW_CFA_val_offset_sf: { + u32 reg; + s32 factored_offset; + increment += decode_leb128(data, ®); + increment += decode_leb128s(data, &factored_offset); + break; + } + + case DW_CFA_val_expression: { + u32 reg; + u32 length; + increment += decode_leb128(data, ®); + increment += decode_leb128(data, &length); + increment += length; + break; + } + + case DW_CFA_lo_user: { + break; + } + + case DW_CFA_hi_user: { + break; + } + } + } + + data += increment; + read += increment + 1; + + if (read >= leftover) { + break; + } + } + + return(read); +} + +static u64 +read_one_cie(u64 length, u8 *data, u8 *original_data) +{ + struct dwarf_cie_header header = { 0 }; + + header.length = length; + header.version = *data++; + + char *augmenation_string = (char *) data; + + // NOTE: null-terminated string + int has_z = 0; + int has_L = 0; + int has_P = 0; + int has_R = 0; + + while (*data) { + if (*data == 'z') has_z = 1; + if (*data == 'L') has_L = 1; + if (*data == 'P') has_P = 1; + if (*data == 'R') has_R = 1; + ++data; + } + ++data; + + (void) has_L; + (void) has_P; + (void) has_R; + + data += decode_leb128(data, &header.code_alignment); + data += decode_leb128s(data, &header.data_alignment); + data += decode_leb128(data, &header.return_address_register); + + if (has_z) { + data += decode_leb128(data, &header.augmentation_data_length); + header.augmentation_data = data; + data += header.augmentation_data_length; + } + + data += iterate_call_frame_instructions(header, data, original_data); + + return(data - original_data); +} + +static u64 +read_one_fde(u64 length, u32 cie_offset, u8 *data, u8 *original_data) +{ + struct dwarf_fde_header header = { 0 }; + + header.length = length; + header.cie = (struct dwarf_cie_header *) (data - 4 - cie_offset); + memcpy(&header.low_pc, data, 8); + data += 8; + memcpy(&header.high_pc, data, 8); + data += 8; + header.high_pc = header.low_pc + header.high_pc; + + // if (cie has 'z') + data += decode_leb128(data, &header.augmentation_data_length); + header.augmentation_data = data; + data += header.augmentation_data_length; + + + struct dwarf_cie_header hh = { 0 }; + data += iterate_call_frame_instructions(hh, data, original_data); + + return(0); +} + +static u64 +read_one_call_frame_record(u8 *data) +{ + u8 *original_data = data; + u64 length; + u32 length32; + u32 cie_id; + + memcpy(&length32, data, 4); + length = length32; + data += 4; + + if (length == 0) { + memcpy(&length, data, 8); + data += 8; + } + + memcpy(&cie_id, data, 4); + data += 4; + + u64 result; + + if (cie_id == 0) { + result = read_one_cie(length, data, original_data); + } else { + result = read_one_fde(length, cie_id, data, original_data); + } + + return(result); +} + +static void +parse_eh_frame(u8 *file) +{ + struct elf_section_table_entry_x64 eh_frame = get_section_entry(file, ".eh_frame"); + + u64 read = 0; + + for (;;) { + u64 size = read_one_call_frame_record(file + eh_frame.offset_in_file + read); + read += size; + if (read >= eh_frame.size) { + break; + } + } +} \ No newline at end of file diff --git a/main.c b/main.c index a88ecaa..90f5436 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ #include "common.h" #include "dwarf.c" +#include "eh_frame.c" #include "util.c" #include "command.c" @@ -21,6 +22,7 @@ main(int argc, char *argv[]) char *last_command = malloc(max_command_length + 1); parse_debug_info(process.elf, &process.debug); + parse_eh_frame(process.elf); process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid); process.main_address = get_address_of_subroutine(process, "main"); @@ -50,7 +52,7 @@ main(int argc, char *argv[]) } else if (0 == strncmp(command, "start\n", command_length)) { command_start(process); } else if (0 == strncmp(command, "print ", 6)) { - command_print(process, command + 6, command_length - 7); + //command_print(process, command + 6, command_length - 7); } else if (0 == strncmp(command, "next\n", command_length)) { command_next(process); } else if (0 == strncmp(command, "line\n", command_length)) { diff --git a/util.c b/util.c index 0aeb232..528b8b2 100644 --- a/util.c +++ b/util.c @@ -273,41 +273,6 @@ print_current_instruction(struct mi_process proc) nb[8], nb[9], nb[10], nb[11]); } -static u64 -lookup_identifier_address(struct mi_process proc, char *ident, int len) -{ - struct mi_registers regs = get_process_registers(proc); - u64 pc_local = regs.rip - proc.base_address; - -#if 0 - for (int c = 0; c < proc.debug.cu_count; ++c) { - struct mi_compunit unit = proc.debug.compilation_units[c]; - - if (unit.low_pc <= pc_local && pc_local < unit.high_pc) { - for (int b = 0; b < unit.block_count; ++b) { - struct mi_block block = unit.blocks[b]; - - if (block.low_pc <= pc_local && pc_local < block.high_pc) { - for (int v = 0; v < block.var_count; ++v) { - struct mi_variable variable = block.variables[v]; - - if (0 == strncmp(variable.name, ident, len)) { - return(variable.location); - } - } - break; - - } - } - break; - - } - } -#endif - - return(0); -} - static struct mi_function * get_function_around_pc(struct mi_process proc, u64 pc) {