Browse Source

eh_frame parser closed to working (but still very far)

master
A.Olokhtonov 3 years ago
parent
commit
c45c3cd01f
  1. 7
      command.c
  2. 372
      eh_frame.c
  3. 4
      main.c
  4. 35
      util.c

7
command.c

@ -100,13 +100,6 @@ command_next(struct mi_process proc)
print_sourcepoint(proc, comp_unit, next_sp); 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 static void
command_list(struct mi_process proc) command_list(struct mi_process proc)
{ {

372
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, &reg);
increment += decode_leb128(data, &offset);
break;
}
case DW_CFA_restore_extended: {
u32 reg;
increment += decode_leb128(data, &reg);
break;
}
case DW_CFA_undefined: {
u32 reg;
increment += decode_leb128(data, &reg);
break;
}
case DW_CFA_same_value: {
u32 reg;
increment += decode_leb128(data, &reg);
break;
}
case DW_CFA_register: {
u32 reg;
s32 factored_offset;
increment += decode_leb128(data, &reg);
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, &reg);
increment += decode_leb128(data, &nonfactored_offset);
break;
}
case DW_CFA_def_cfa_register: {
u32 reg;
increment += decode_leb128(data, &reg);
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, &reg);
increment += decode_leb128(data, &length);
increment += length;
break;
}
case DW_CFA_offset_extended_sf: {
u32 reg;
s32 factored_offset;
increment += decode_leb128(data, &reg);
increment += decode_leb128s(data, &factored_offset);
break;
}
case DW_CFA_def_cfa_sf: {
u32 reg;
s32 factored_offset;
increment += decode_leb128(data, &reg);
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, &reg);
increment += decode_leb128(data, &factored_offset);
break;
}
case DW_CFA_val_offset_sf: {
u32 reg;
s32 factored_offset;
increment += decode_leb128(data, &reg);
increment += decode_leb128s(data, &factored_offset);
break;
}
case DW_CFA_val_expression: {
u32 reg;
u32 length;
increment += decode_leb128(data, &reg);
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;
}
}
}

4
main.c

@ -1,6 +1,7 @@
#include "common.h" #include "common.h"
#include "dwarf.c" #include "dwarf.c"
#include "eh_frame.c"
#include "util.c" #include "util.c"
#include "command.c" #include "command.c"
@ -21,6 +22,7 @@ main(int argc, char *argv[])
char *last_command = malloc(max_command_length + 1); char *last_command = malloc(max_command_length + 1);
parse_debug_info(process.elf, &process.debug); parse_debug_info(process.elf, &process.debug);
parse_eh_frame(process.elf);
process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid); process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid);
process.main_address = get_address_of_subroutine(process, "main"); 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)) { } else if (0 == strncmp(command, "start\n", command_length)) {
command_start(process); command_start(process);
} else if (0 == strncmp(command, "print ", 6)) { } 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)) { } else if (0 == strncmp(command, "next\n", command_length)) {
command_next(process); command_next(process);
} else if (0 == strncmp(command, "line\n", command_length)) { } else if (0 == strncmp(command, "line\n", command_length)) {

35
util.c

@ -273,41 +273,6 @@ print_current_instruction(struct mi_process proc)
nb[8], nb[9], nb[10], nb[11]); 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 * static struct mi_function *
get_function_around_pc(struct mi_process proc, u64 pc) get_function_around_pc(struct mi_process proc, u64 pc)
{ {

Loading…
Cancel
Save