A.Olokhtonov
3 years ago
4 changed files with 375 additions and 43 deletions
@ -0,0 +1,372 @@
@@ -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; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue