|
|
|
@ -139,153 +139,91 @@ abbrev_entry_offset(u8 *file, u64 abbrev_offset, u32 requested_code)
@@ -139,153 +139,91 @@ abbrev_entry_offset(u8 *file, u64 abbrev_offset, u32 requested_code)
|
|
|
|
|
return(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static u64 |
|
|
|
|
find_subroutine_offset(u8 *file, u64 header_size, u8 address_size, |
|
|
|
|
u64 string_offset, u64 abbrev_offset, u64 data_offset, |
|
|
|
|
char *subroutine) |
|
|
|
|
static u32 |
|
|
|
|
read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_data_offset, u32 form, u64 data_offset, u64 *value) |
|
|
|
|
{ |
|
|
|
|
u32 code, tag; |
|
|
|
|
u64 schema_offset; |
|
|
|
|
u32 depth = 0; |
|
|
|
|
u64 original_data_offset = data_offset; |
|
|
|
|
|
|
|
|
|
int found_sr = 0; |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
data_offset += decode_leb128(file + data_offset, &code); |
|
|
|
|
|
|
|
|
|
if (code == 0) { |
|
|
|
|
if (depth > 1) { |
|
|
|
|
--depth; |
|
|
|
|
continue; |
|
|
|
|
} else { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
schema_offset = abbrev_entry_offset(file, abbrev_offset, code); |
|
|
|
|
schema_offset += decode_leb128(file + schema_offset, NULL); |
|
|
|
|
schema_offset += decode_leb128(file + schema_offset, &tag); |
|
|
|
|
|
|
|
|
|
//printf("%d %s\n", code, tag_to_str(tag));
|
|
|
|
|
|
|
|
|
|
u32 has_children = file[schema_offset++]; |
|
|
|
|
if (has_children) { |
|
|
|
|
++depth; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
u32 attribute, form; |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
schema_offset += decode_leb128(file + schema_offset, &attribute); |
|
|
|
|
schema_offset += decode_leb128(file + schema_offset, &form); |
|
|
|
|
|
|
|
|
|
if (attribute) { |
|
|
|
|
//printf("\t%s ", attribute_to_str(attribute));
|
|
|
|
|
} |
|
|
|
|
u32 increment = 0; |
|
|
|
|
|
|
|
|
|
switch (form) { |
|
|
|
|
case DW_FORM_sec_offset: |
|
|
|
|
case DW_FORM_strp: { |
|
|
|
|
u32 data; |
|
|
|
|
memcpy(&data, file + data_offset, 4); |
|
|
|
|
data_offset += 4; // 8 bytes for x64 DWARF!
|
|
|
|
|
|
|
|
|
|
if (form == DW_FORM_strp) { |
|
|
|
|
char *str = (char *) file + string_offset + data; |
|
|
|
|
//printf("(indirect string, offset: %#x): %s\n", data, str);
|
|
|
|
|
if (tag == DW_TAG_subprogram) { |
|
|
|
|
if (strcmp(str, subroutine) == 0) { |
|
|
|
|
found_sr = 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
//printf("%#x\n", data);
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
u32 offset; |
|
|
|
|
memcpy(&offset, file + data_offset, 4); |
|
|
|
|
char *str = (char *) (file + string_offset + offset); |
|
|
|
|
*value = (u64) str; |
|
|
|
|
increment = 4; // 8 bytes for x64 DWARF!
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_addr: { |
|
|
|
|
u64 data = 0; |
|
|
|
|
memcpy(&data, file + data_offset, address_size); |
|
|
|
|
data_offset += address_size; |
|
|
|
|
//printf("%#lx\n", data);
|
|
|
|
|
|
|
|
|
|
if (tag == DW_TAG_subprogram && found_sr == 1 && attribute == DW_AT_low_pc) { |
|
|
|
|
return(data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
memcpy(value, file + data_offset, address_size); |
|
|
|
|
increment = address_size; |
|
|
|
|
break; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_string: { |
|
|
|
|
char *data = (char *) file + data_offset; |
|
|
|
|
data_offset += strlen(data) + 1; |
|
|
|
|
//printf("%s\n", data);
|
|
|
|
|
char *ptr = (char *) (file + data_offset); |
|
|
|
|
*value = (u64) ptr; |
|
|
|
|
increment = strlen(ptr) + 1; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_flag_present: { |
|
|
|
|
int data = 1; |
|
|
|
|
//printf("Flag = 1\n");
|
|
|
|
|
*value = 1; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_ref4: { |
|
|
|
|
u32 data; |
|
|
|
|
memcpy(&data, file + data_offset, 4); |
|
|
|
|
data_offset += 4; |
|
|
|
|
//printf("%#x\n", data);
|
|
|
|
|
u32 referenced_data = file[original_data_offset - header_size + data]; |
|
|
|
|
u32 offset; |
|
|
|
|
memcpy(&offset, file + data_offset, 4); |
|
|
|
|
increment = 4; |
|
|
|
|
*value = file[base_data_offset + offset]; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_exprloc: { |
|
|
|
|
u32 length; |
|
|
|
|
data_offset += decode_leb128(file + data_offset, &length); |
|
|
|
|
//printf("%d byte block:", length);
|
|
|
|
|
// TODO: return value to caller
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < length; ++i) { |
|
|
|
|
//printf(" %x", file[data_offset + i]);
|
|
|
|
|
} |
|
|
|
|
//printf("\n");
|
|
|
|
|
|
|
|
|
|
data_offset += length; |
|
|
|
|
u32 length; |
|
|
|
|
increment = decode_leb128(file + data_offset, &length); |
|
|
|
|
increment += length; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_data1: { |
|
|
|
|
u8 data = file[data_offset]; |
|
|
|
|
data_offset += 1; |
|
|
|
|
//printf("%#x\n", data);
|
|
|
|
|
*value = file[data_offset]; |
|
|
|
|
increment = 1; |
|
|
|
|
break; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_data2: { |
|
|
|
|
u16 data; |
|
|
|
|
memcpy(&data, file + data_offset, 2); |
|
|
|
|
data_offset += 2; |
|
|
|
|
//printf("%#x\n", data);
|
|
|
|
|
memcpy(value, file + data_offset, 2); |
|
|
|
|
increment = 2; |
|
|
|
|
break; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_data4: { |
|
|
|
|
u32 data; |
|
|
|
|
memcpy(&data, file + data_offset, 4); |
|
|
|
|
data_offset += 4; |
|
|
|
|
//printf("%#x\n", data);
|
|
|
|
|
memcpy(value, file + data_offset, 4); |
|
|
|
|
increment = 4; |
|
|
|
|
break; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_data8: { |
|
|
|
|
u64 data; |
|
|
|
|
memcpy(&data, file + data_offset, 8); |
|
|
|
|
data_offset += 8; |
|
|
|
|
//printf("%#lx\n", data);
|
|
|
|
|
memcpy(value, file + data_offset, 8); |
|
|
|
|
increment = 8; |
|
|
|
|
break; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_sdata: { |
|
|
|
|
increment = decode_leb128s(file + data_offset, (s32 *) value); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_FORM_udata: { |
|
|
|
|
increment = decode_leb128(file + data_offset, (u32 *) value); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: { |
|
|
|
|
if (form) { |
|
|
|
@ -293,14 +231,93 @@ find_subroutine_offset(u8 *file, u64 header_size, u8 address_size,
@@ -293,14 +231,93 @@ find_subroutine_offset(u8 *file, u64 header_size, u8 address_size,
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return(increment); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
parse_debug_info(u8 *file, struct mi_debuginfo *dest) |
|
|
|
|
{ |
|
|
|
|
u64 debug_info_offset = get_section_offset(file, ".debug_info"); |
|
|
|
|
printf("Found .debug_info at offset %#lx\n", debug_info_offset); |
|
|
|
|
|
|
|
|
|
u64 debug_abbrev_offset = get_section_offset(file, ".debug_abbrev"); |
|
|
|
|
printf("Found .debug_abbrev at offset %#lx\n", debug_abbrev_offset); |
|
|
|
|
|
|
|
|
|
u64 debug_str_offset = get_section_offset(file, ".debug_str"); |
|
|
|
|
printf("Found .debug_str at offset %#lx\n", debug_str_offset); |
|
|
|
|
|
|
|
|
|
struct dwarf_debug_info_header_x32 di_header = { 0 }; |
|
|
|
|
u32 header_size = sizeof(di_header); |
|
|
|
|
memcpy(&di_header, file + debug_info_offset, header_size); |
|
|
|
|
|
|
|
|
|
u64 abbrev_offset = debug_abbrev_offset + di_header.debug_abbrev_offset; |
|
|
|
|
u64 data_offset = debug_info_offset + header_size; |
|
|
|
|
|
|
|
|
|
u32 code, tag; |
|
|
|
|
u64 schema_offset; |
|
|
|
|
u32 depth = 0; |
|
|
|
|
u64 base_data_offset = data_offset - header_size; |
|
|
|
|
|
|
|
|
|
int found_sr = 0; |
|
|
|
|
|
|
|
|
|
struct mi_function *func = dest->functions; |
|
|
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
data_offset += decode_leb128(file + data_offset, &code); |
|
|
|
|
|
|
|
|
|
if (code == 0) { |
|
|
|
|
if (depth > 1) { |
|
|
|
|
--depth; |
|
|
|
|
continue; |
|
|
|
|
} else { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
schema_offset = abbrev_entry_offset(file, abbrev_offset, code); |
|
|
|
|
schema_offset += decode_leb128(file + schema_offset, NULL); |
|
|
|
|
schema_offset += decode_leb128(file + schema_offset, &tag); |
|
|
|
|
|
|
|
|
|
//printf("%d %s\n", code, tag_to_str(tag));
|
|
|
|
|
|
|
|
|
|
u32 has_children = file[schema_offset++]; |
|
|
|
|
if (has_children) { |
|
|
|
|
++depth; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
u32 attribute, form; |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
schema_offset += decode_leb128(file + schema_offset, &attribute); |
|
|
|
|
schema_offset += decode_leb128(file + schema_offset, &form); |
|
|
|
|
|
|
|
|
|
u64 value; |
|
|
|
|
|
|
|
|
|
data_offset += read_actual_debug_data(file, debug_str_offset, di_header.address_size, base_data_offset, form, data_offset, &value); |
|
|
|
|
|
|
|
|
|
if (tag == DW_TAG_compile_unit) { |
|
|
|
|
if (attribute == DW_AT_comp_dir) { |
|
|
|
|
dest->comp_dir = (char *) value; |
|
|
|
|
} |
|
|
|
|
} else if (tag == DW_TAG_subprogram) { |
|
|
|
|
if (attribute == DW_AT_name) { |
|
|
|
|
func->name = (char *) value; |
|
|
|
|
} else if (attribute == DW_AT_low_pc) { |
|
|
|
|
func->offset = value; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} while (attribute != 0 || form != 0); |
|
|
|
|
} while (1); |
|
|
|
|
|
|
|
|
|
return(0); |
|
|
|
|
if (tag == DW_TAG_subprogram) { |
|
|
|
|
++func; |
|
|
|
|
++dest->func_count; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
construct_line_number_table(u8 *file, struct mi_sourcepoint *dest, char **dest_files, int *dest_size, int *dest_files_size) |
|
|
|
|
parse_debug_line(u8 *file, struct mi_sourcepoint *dest, char **dest_files, int *dest_size, int *dest_files_size) |
|
|
|
|
{ |
|
|
|
|
u64 dl_offset = get_section_offset(file, ".debug_line"); |
|
|
|
|
|
|
|
|
@ -326,15 +343,15 @@ is followed by a single null byte." */
@@ -326,15 +343,15 @@ is followed by a single null byte." */
|
|
|
|
|
while (*p != 0) { |
|
|
|
|
++p; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
++p; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
header.ndirs = ndirs; |
|
|
|
|
header.include_directories = 0; // malloc(ndirs * sizeof(char *));
|
|
|
|
|
|
|
|
|
|
dl_offset += (p - (file + dl_offset)) + 1; |
|
|
|
|
|
|
|
|
|
++p; |
|
|
|
|
|
|
|
|
|
p = file + dl_offset; |
|
|
|
|
while (*p != 0) { |
|
|
|
|
/* null-terminated string */ |
|
|
|
|
if (dest_files) { |
|
|
|
@ -658,7 +675,7 @@ get_executable_base_address(u8 *elf_file, int pid)
@@ -658,7 +675,7 @@ get_executable_base_address(u8 *elf_file, int pid)
|
|
|
|
|
end = strtoll(at + 1, &at, 16); |
|
|
|
|
(void) end; |
|
|
|
|
|
|
|
|
|
while (*at < '0' || *at > '9') ++at; |
|
|
|
|
while (*at < '0' || '9' < *at) ++at; |
|
|
|
|
|
|
|
|
|
offset = strtoll(at, &at, 16); |
|
|
|
|
|
|
|
|
@ -671,30 +688,3 @@ get_executable_base_address(u8 *elf_file, int pid)
@@ -671,30 +688,3 @@ get_executable_base_address(u8 *elf_file, int pid)
|
|
|
|
|
|
|
|
|
|
return(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static u64 |
|
|
|
|
get_address_of_subroutine(u8 *file, char *sr) |
|
|
|
|
{ |
|
|
|
|
u64 debug_info_offset = get_section_offset(file, ".debug_info"); |
|
|
|
|
printf("Found .debug_info at offset %#lx\n", debug_info_offset); |
|
|
|
|
|
|
|
|
|
u64 debug_line_offset = get_section_offset(file, ".debug_line"); |
|
|
|
|
printf("Found .debug_line at offset %#lx\n", debug_line_offset); |
|
|
|
|
|
|
|
|
|
u64 debug_abbrev_offset = get_section_offset(file, ".debug_abbrev"); |
|
|
|
|
printf("Found .debug_abbrev at offset %#lx\n", debug_abbrev_offset); |
|
|
|
|
|
|
|
|
|
u64 debug_str_offset = get_section_offset(file, ".debug_str"); |
|
|
|
|
printf("Found .debug_str at offset %#lx\n", debug_str_offset); |
|
|
|
|
|
|
|
|
|
struct dwarf_debug_info_header_x32 di_header = { 0 }; |
|
|
|
|
memcpy(&di_header, file + debug_info_offset, sizeof(di_header)); |
|
|
|
|
|
|
|
|
|
u64 abbrev_offset = debug_abbrev_offset + di_header.debug_abbrev_offset; |
|
|
|
|
u64 data_offset = debug_info_offset + sizeof(di_header); |
|
|
|
|
|
|
|
|
|
u64 result = find_subroutine_offset(file, sizeof(di_header), di_header.address_size, |
|
|
|
|
debug_str_offset, abbrev_offset, data_offset, sr); |
|
|
|
|
|
|
|
|
|
return(result); |
|
|
|
|
} |