summaryrefslogtreecommitdiff
path: root/addr2line.c
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-10-11 23:55:44 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-10-11 23:55:44 +0000
commit37ea0f19a7c31a7c8492f72aabdab8d493a2393c (patch)
treead1e2a5b5a90e97f36e8d38533df8200ae4c74a4 /addr2line.c
parent139f0bb44f7f36889c3686e43181f8351adb1a63 (diff)
Show backtrace with .debug_info
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65007 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'addr2line.c')
-rw-r--r--addr2line.c957
1 files changed, 626 insertions, 331 deletions
diff --git a/addr2line.c b/addr2line.c
index cb367e3184..786da0abfc 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -113,7 +113,7 @@ void *alloca();
PRINTF_ARGS(static int kprintf(const char *fmt, ...), 1, 2);
-typedef struct {
+typedef struct line_info {
const char *dirname;
const char *filename;
const char *path; /* object path */
@@ -122,6 +122,8 @@ typedef struct {
uintptr_t base_addr;
uintptr_t saddr;
const char *sname; /* function name */
+
+ struct line_info *next;
} line_info_t;
typedef struct obj_info obj_info_t;
struct obj_info {
@@ -194,8 +196,7 @@ get_nth_dirname(unsigned long dir, char *p)
}
static void
-fill_filename(int file, char *include_directories, char *filenames,
- line_info_t *line)
+fill_filename(int file, char *include_directories, char *filenames, line_info_t *line)
{
int i;
char *p = filenames;
@@ -522,11 +523,18 @@ fail:
void hexdump0(const unsigned char *p, size_t n) {
size_t i;
+ fprintf(stderr, " 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
for (i=0; i < n; i++){
- if ((i & 15) != 15) {
- fprintf(stderr, "%02X ", p[i]);
- } else {
+ switch (i & 15) {
+ case 0:
+ fprintf(stderr, "%02zd: %02X ", i/16, p[i]);
+ break;
+ case 15:
fprintf(stderr, "%02X\n", p[i]);
+ break;
+ default:
+ fprintf(stderr, "%02X ", p[i]);
+ break;
}
}
if ((i & 15) != 15) {
@@ -535,200 +543,214 @@ void hexdump0(const unsigned char *p, size_t n) {
}
#define hexdump(p,n) hexdump0((const unsigned char *)p, n)
+enum
+{
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_subprogram = 0x2e,
+};
+
/* Attributes encodings */
enum
{
- DW_AT_sibling = 0x01,
- DW_AT_location = 0x02,
- DW_AT_name = 0x03,
- /* Reserved 0x04 */
- /* Reserved 0x05 */
- /* Reserved 0x06 */
- /* Reserved 0x07 */
- /* Reserved 0x08 */
- DW_AT_ordering = 0x09,
- /* Reserved 0x0a */
- DW_AT_byte_size = 0x0b,
- /* Reserved 0x0c */
- DW_AT_bit_size = 0x0d,
- /* Reserved 0x0e */
- /* Reserved 0x0f */
- DW_AT_stmt_list = 0x10,
- DW_AT_low_pc = 0x11,
- DW_AT_high_pc = 0x12,
- DW_AT_language = 0x13,
- /* Reserved 0x14 */
- DW_AT_discr = 0x15,
- DW_AT_discr_value = 0x16,
- DW_AT_visibility = 0x17,
- DW_AT_import = 0x18,
- DW_AT_string_length = 0x19,
- DW_AT_common_reference = 0x1a,
- DW_AT_comp_dir = 0x1b,
- DW_AT_const_value = 0x1c,
- DW_AT_containing_type = 0x1d,
- DW_AT_default_value = 0x1e,
- /* Reserved 0x1f */
- DW_AT_inline = 0x20,
- DW_AT_is_optional = 0x21,
- DW_AT_lower_bound = 0x22,
- /* Reserved 0x23 */
- /* Reserved 0x24 */
- DW_AT_producer = 0x25,
- /* Reserved 0x26 */
- DW_AT_prototyped = 0x27,
- /* Reserved 0x28 */
- /* Reserved 0x29 */
- DW_AT_return_addr = 0x2a,
- /* Reserved 0x2b */
- DW_AT_start_scope = 0x2c,
- /* Reserved 0x2d */
- DW_AT_bit_stride = 0x2e,
- DW_AT_upper_bound = 0x2f,
- /* Reserved 0x30 */
- DW_AT_abstract_origin = 0x31,
- DW_AT_accessibility = 0x32,
- DW_AT_address_class = 0x33,
- DW_AT_artificial = 0x34,
- DW_AT_base_types = 0x35,
- DW_AT_calling_convention = 0x36,
- DW_AT_count = 0x37,
- DW_AT_data_member_location = 0x38,
- DW_AT_decl_column = 0x39,
- DW_AT_decl_file = 0x3a,
- DW_AT_decl_line = 0x3b,
- DW_AT_declaration = 0x3c,
- DW_AT_discr_list = 0x3d,
- DW_AT_encoding = 0x3e,
- DW_AT_external = 0x3f,
- DW_AT_frame_base = 0x40,
- DW_AT_friend = 0x41,
- DW_AT_identifier_case = 0x42,
- /* Reserved 0x43 */
- DW_AT_namelist_item = 0x44,
- DW_AT_priority = 0x45,
- DW_AT_segment = 0x46,
- DW_AT_specification = 0x47,
- DW_AT_static_link = 0x48,
- DW_AT_type = 0x49,
- DW_AT_use_location = 0x4a,
- DW_AT_variable_parameter = 0x4b,
- DW_AT_virtuality = 0x4c,
- DW_AT_vtable_elem_location = 0x4d,
- DW_AT_allocated = 0x4e,
- DW_AT_associated = 0x4f,
- DW_AT_data_location = 0x50,
- DW_AT_byte_stride = 0x51,
- DW_AT_entry_pc = 0x52,
- DW_AT_use_UTF8 = 0x53,
- DW_AT_extension = 0x54,
- DW_AT_ranges = 0x55,
- DW_AT_trampoline = 0x56,
- DW_AT_call_column = 0x57,
- DW_AT_call_file = 0x58,
- DW_AT_call_line = 0x59,
- DW_AT_description = 0x5a,
- DW_AT_binary_scale = 0x5b,
- DW_AT_decimal_scale = 0x5c,
- DW_AT_small = 0x5d,
- DW_AT_decimal_sign = 0x5e,
- DW_AT_digit_count = 0x5f,
- DW_AT_picture_string = 0x60,
- DW_AT_mutable = 0x61,
- DW_AT_threads_scaled = 0x62,
- DW_AT_explicit = 0x63,
- DW_AT_object_pointer = 0x64,
- DW_AT_endianity = 0x65,
- DW_AT_elemental = 0x66,
- DW_AT_pure = 0x67,
- DW_AT_recursive = 0x68,
- DW_AT_signature = 0x69,
- DW_AT_main_subprogram = 0x6a,
- DW_AT_data_bit_offset = 0x6b,
- DW_AT_const_expr = 0x6c,
- DW_AT_enum_class = 0x6d,
- DW_AT_linkage_name = 0x6e,
- DW_AT_string_length_bit_size = 0x6f,
- DW_AT_string_length_byte_size = 0x70,
- DW_AT_rank = 0x71,
- DW_AT_str_offsets_base = 0x72,
- DW_AT_addr_base = 0x73,
- DW_AT_rnglists_base = 0x74,
- /* Reserved 0x75 */
- DW_AT_dwo_name = 0x76,
- DW_AT_reference = 0x77,
- DW_AT_rvalue_reference = 0x78,
- DW_AT_macros = 0x79,
- DW_AT_call_all_calls = 0x7a,
- DW_AT_call_all_source_calls = 0x7b,
- DW_AT_call_all_tail_calls = 0x7c,
- DW_AT_call_return_pc = 0x7d,
- DW_AT_call_value = 0x7e,
- DW_AT_call_origin = 0x7f,
- DW_AT_call_parameter = 0x80,
- DW_AT_call_pc = 0x81,
- DW_AT_call_tail_call = 0x82,
- DW_AT_call_target = 0x83,
- DW_AT_call_target_clobbered = 0x84,
- DW_AT_call_data_location = 0x85,
- DW_AT_call_data_value = 0x86,
- DW_AT_noreturn = 0x87,
- DW_AT_alignment = 0x88,
- DW_AT_export_symbols = 0x89,
- DW_AT_deleted = 0x8a,
- DW_AT_defaulted = 0x8b,
- DW_AT_loclists_base = 0x8c,
- DW_AT_lo_user = 0x2000,
- DW_AT_hi_user = 0x3fff
+ DW_AT_sibling = 0x01,
+ DW_AT_location = 0x02,
+ DW_AT_name = 0x03,
+ /* Reserved 0x04 */
+ /* Reserved 0x05 */
+ /* Reserved 0x06 */
+ /* Reserved 0x07 */
+ /* Reserved 0x08 */
+ DW_AT_ordering = 0x09,
+ /* Reserved 0x0a */
+ DW_AT_byte_size = 0x0b,
+ /* Reserved 0x0c */
+ DW_AT_bit_size = 0x0d,
+ /* Reserved 0x0e */
+ /* Reserved 0x0f */
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+ /* Reserved 0x14 */
+ DW_AT_discr = 0x15,
+ DW_AT_discr_value = 0x16,
+ DW_AT_visibility = 0x17,
+ DW_AT_import = 0x18,
+ DW_AT_string_length = 0x19,
+ DW_AT_common_reference = 0x1a,
+ DW_AT_comp_dir = 0x1b,
+ DW_AT_const_value = 0x1c,
+ DW_AT_containing_type = 0x1d,
+ DW_AT_default_value = 0x1e,
+ /* Reserved 0x1f */
+ DW_AT_inline = 0x20,
+ DW_AT_is_optional = 0x21,
+ DW_AT_lower_bound = 0x22,
+ /* Reserved 0x23 */
+ /* Reserved 0x24 */
+ DW_AT_producer = 0x25,
+ /* Reserved 0x26 */
+ DW_AT_prototyped = 0x27,
+ /* Reserved 0x28 */
+ /* Reserved 0x29 */
+ DW_AT_return_addr = 0x2a,
+ /* Reserved 0x2b */
+ DW_AT_start_scope = 0x2c,
+ /* Reserved 0x2d */
+ DW_AT_bit_stride = 0x2e,
+ DW_AT_upper_bound = 0x2f,
+ /* Reserved 0x30 */
+ DW_AT_abstract_origin = 0x31,
+ DW_AT_accessibility = 0x32,
+ DW_AT_address_class = 0x33,
+ DW_AT_artificial = 0x34,
+ DW_AT_base_types = 0x35,
+ DW_AT_calling_convention = 0x36,
+ DW_AT_count = 0x37,
+ DW_AT_data_member_location = 0x38,
+ DW_AT_decl_column = 0x39,
+ DW_AT_decl_file = 0x3a,
+ DW_AT_decl_line = 0x3b,
+ DW_AT_declaration = 0x3c,
+ DW_AT_discr_list = 0x3d,
+ DW_AT_encoding = 0x3e,
+ DW_AT_external = 0x3f,
+ DW_AT_frame_base = 0x40,
+ DW_AT_friend = 0x41,
+ DW_AT_identifier_case = 0x42,
+ /* Reserved 0x43 */
+ DW_AT_namelist_item = 0x44,
+ DW_AT_priority = 0x45,
+ DW_AT_segment = 0x46,
+ DW_AT_specification = 0x47,
+ DW_AT_static_link = 0x48,
+ DW_AT_type = 0x49,
+ DW_AT_use_location = 0x4a,
+ DW_AT_variable_parameter = 0x4b,
+ DW_AT_virtuality = 0x4c,
+ DW_AT_vtable_elem_location = 0x4d,
+ DW_AT_allocated = 0x4e,
+ DW_AT_associated = 0x4f,
+ DW_AT_data_location = 0x50,
+ DW_AT_byte_stride = 0x51,
+ DW_AT_entry_pc = 0x52,
+ DW_AT_use_UTF8 = 0x53,
+ DW_AT_extension = 0x54,
+ DW_AT_ranges = 0x55,
+ DW_AT_trampoline = 0x56,
+ DW_AT_call_column = 0x57,
+ DW_AT_call_file = 0x58,
+ DW_AT_call_line = 0x59,
+ DW_AT_description = 0x5a,
+ DW_AT_binary_scale = 0x5b,
+ DW_AT_decimal_scale = 0x5c,
+ DW_AT_small = 0x5d,
+ DW_AT_decimal_sign = 0x5e,
+ DW_AT_digit_count = 0x5f,
+ DW_AT_picture_string = 0x60,
+ DW_AT_mutable = 0x61,
+ DW_AT_threads_scaled = 0x62,
+ DW_AT_explicit = 0x63,
+ DW_AT_object_pointer = 0x64,
+ DW_AT_endianity = 0x65,
+ DW_AT_elemental = 0x66,
+ DW_AT_pure = 0x67,
+ DW_AT_recursive = 0x68,
+ DW_AT_signature = 0x69,
+ DW_AT_main_subprogram = 0x6a,
+ DW_AT_data_bit_offset = 0x6b,
+ DW_AT_const_expr = 0x6c,
+ DW_AT_enum_class = 0x6d,
+ DW_AT_linkage_name = 0x6e,
+ DW_AT_string_length_bit_size = 0x6f,
+ DW_AT_string_length_byte_size = 0x70,
+ DW_AT_rank = 0x71,
+ DW_AT_str_offsets_base = 0x72,
+ DW_AT_addr_base = 0x73,
+ DW_AT_rnglists_base = 0x74,
+ /* Reserved 0x75 */
+ DW_AT_dwo_name = 0x76,
+ DW_AT_reference = 0x77,
+ DW_AT_rvalue_reference = 0x78,
+ DW_AT_macros = 0x79,
+ DW_AT_call_all_calls = 0x7a,
+ DW_AT_call_all_source_calls = 0x7b,
+ DW_AT_call_all_tail_calls = 0x7c,
+ DW_AT_call_return_pc = 0x7d,
+ DW_AT_call_value = 0x7e,
+ DW_AT_call_origin = 0x7f,
+ DW_AT_call_parameter = 0x80,
+ DW_AT_call_pc = 0x81,
+ DW_AT_call_tail_call = 0x82,
+ DW_AT_call_target = 0x83,
+ DW_AT_call_target_clobbered = 0x84,
+ DW_AT_call_data_location = 0x85,
+ DW_AT_call_data_value = 0x86,
+ DW_AT_noreturn = 0x87,
+ DW_AT_alignment = 0x88,
+ DW_AT_export_symbols = 0x89,
+ DW_AT_deleted = 0x8a,
+ DW_AT_defaulted = 0x8b,
+ DW_AT_loclists_base = 0x8c,
+ DW_AT_lo_user = 0x2000,
+ DW_AT_hi_user = 0x3fff
};
/* Attribute form encodings */
enum
{
- DW_FORM_addr = 0x01,
- /* Reserved 0x02 */
- DW_FORM_block2 = 0x03,
- DW_FORM_block4 = 0x04,
- DW_FORM_data2 = 0x05,
- DW_FORM_data4 = 0x06,
- DW_FORM_data8 = 0x07,
- DW_FORM_string = 0x08,
- DW_FORM_block = 0x09,
- DW_FORM_block1 = 0x0a,
- DW_FORM_data1 = 0x0b,
- DW_FORM_flag = 0x0c,
- DW_FORM_sdata = 0x0d,
- DW_FORM_strp = 0x0e,
- DW_FORM_udata = 0x0f,
- DW_FORM_ref_addr = 0x10,
- DW_FORM_ref1 = 0x11,
- DW_FORM_ref2 = 0x12,
- DW_FORM_ref4 = 0x13,
- DW_FORM_ref8 = 0x14,
- DW_FORM_ref_udata = 0x15,
- DW_FORM_indirect = 0x16,
- DW_FORM_sec_offset = 0x17,
- DW_FORM_exprloc = 0x18,
- DW_FORM_flag_present = 0x19,
- DW_FORM_strx = 0x1a,
- DW_FORM_addrx = 0x1b,
- DW_FORM_ref_sup4 = 0x1c,
- DW_FORM_strp_sup = 0x1d,
- DW_FORM_data16 = 0x1e,
- DW_FORM_line_strp = 0x1f,
- DW_FORM_ref_sig8 = 0x20,
- DW_FORM_implicit_const = 0x21,
- DW_FORM_loclistx = 0x22,
- DW_FORM_rnglistx = 0x23,
- DW_FORM_ref_sup8 = 0x24,
- DW_FORM_strx1 = 0x25,
- DW_FORM_strx2 = 0x26,
- DW_FORM_strx3 = 0x27,
- DW_FORM_strx4 = 0x28,
- DW_FORM_addrx1 = 0x29,
- DW_FORM_addrx2 = 0x2a,
- DW_FORM_addrx3 = 0x2b,
- DW_FORM_addrx4 = 0x2c
+ DW_FORM_addr = 0x01,
+ /* Reserved 0x02 */
+ DW_FORM_block2 = 0x03,
+ DW_FORM_block4 = 0x04,
+ DW_FORM_data2 = 0x05,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_data8 = 0x07,
+ DW_FORM_string = 0x08,
+ DW_FORM_block = 0x09,
+ DW_FORM_block1 = 0x0a,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_flag = 0x0c,
+ DW_FORM_sdata = 0x0d,
+ DW_FORM_strp = 0x0e,
+ DW_FORM_udata = 0x0f,
+ DW_FORM_ref_addr = 0x10,
+ DW_FORM_ref1 = 0x11,
+ DW_FORM_ref2 = 0x12,
+ DW_FORM_ref4 = 0x13,
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16,
+ DW_FORM_sec_offset = 0x17,
+ DW_FORM_exprloc = 0x18,
+ DW_FORM_flag_present = 0x19,
+ DW_FORM_strx = 0x1a,
+ DW_FORM_addrx = 0x1b,
+ DW_FORM_ref_sup4 = 0x1c,
+ DW_FORM_strp_sup = 0x1d,
+ DW_FORM_data16 = 0x1e,
+ DW_FORM_line_strp = 0x1f,
+ DW_FORM_ref_sig8 = 0x20,
+ DW_FORM_implicit_const = 0x21,
+ DW_FORM_loclistx = 0x22,
+ DW_FORM_rnglistx = 0x23,
+ DW_FORM_ref_sup8 = 0x24,
+ DW_FORM_strx1 = 0x25,
+ DW_FORM_strx2 = 0x26,
+ DW_FORM_strx3 = 0x27,
+ DW_FORM_strx4 = 0x28,
+ DW_FORM_addrx1 = 0x29,
+ DW_FORM_addrx2 = 0x2a,
+ DW_FORM_addrx3 = 0x2b,
+ DW_FORM_addrx4 = 0x2c
+};
+
+enum {
+ VAL_none = 0,
+ VAL_cstr = 1,
+ VAL_data = 2,
+ VAL_uint = 3,
+ VAL_int = 4
};
typedef struct {
@@ -747,25 +769,44 @@ typedef struct {
} __attribute__((packed)) DW_CompilationUnitHeader64;
typedef struct {
- char *file;
+ ElfW(Shdr) *abbrev;
ElfW(Shdr) *info;
+ ElfW(Shdr) *ranges;
+ ElfW(Shdr) *str;
+ ElfW(Shdr) *line;
+} dwarf_args;
+
+typedef struct {
+ dwarf_args *dwarf;
+ obj_info_t *obj;
+ char *file;
+ char *current_cu;
+ char *debug_line_cu_end;
+ char *debug_line_files;
+ char *debug_line_directories;
char *p0;
char *p;
char *pend;
- ElfW(Shdr) *abbrev;
char *q0;
char *q;
- ElfW(Shdr) *str;
int format; /* 32 or 64 */;
uint8_t address_size;
int level;
} DebugInfoReader;
typedef struct {
+ int tag;
+ int has_children;
+} DIE;
+
+typedef struct {
union {
char *ptr;
uint64_t uint64;
+ int64_t int64;
} as;
+ uint64_t at;
+ uint64_t form;
size_t size;
int type;
} DebugInfoValue;
@@ -842,64 +883,107 @@ read_sleb128(DebugInfoReader *reader)
return sleb128(&reader->p);
}
-static DebugInfoReader *
-debug_info_reader_new(char *file, ElfW(Shdr) *debug_info_shdr, ElfW(Shdr) *debug_abbrev_shdr, ElfW(Shdr) *debug_str_shdr)
+static void
+debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj, dwarf_args *dwarf)
{
- DebugInfoReader *p = malloc(sizeof(DebugInfoReader));
- p->file = file;
- p->info = debug_info_shdr;
- p->abbrev = debug_abbrev_shdr;
- p->str = debug_str_shdr;
- p->p0 = p->p = p->file + debug_info_shdr->sh_offset;
- p->pend = p->file + debug_info_shdr->sh_offset + debug_info_shdr->sh_size;
- return p;
+ reader->file = obj->mapped;
+ reader->obj = obj;
+ reader->dwarf = dwarf;
+ reader->p0 = reader->p = reader->file + dwarf->info->sh_offset;
+ reader->pend = reader->file + dwarf->info->sh_offset + dwarf->info->sh_size;
+ reader->debug_line_cu_end = reader->file + dwarf->line->sh_offset;
}
static void
-debug_info_reader_read_cu(DebugInfoReader *reader)
+di_read_debug_line_cu(DebugInfoReader *reader)
+{
+ char *p;
+ unsigned long unit_length;
+ unsigned int opcode_base;
+
+ p = reader->debug_line_cu_end;
+
+ unit_length = *(unsigned int *)p;
+ p += sizeof(unsigned int);
+ if (unit_length == 0xffffffff) {
+ unit_length = *(unsigned long *)p;
+ p += sizeof(unsigned long);
+ }
+
+ reader->debug_line_cu_end = p + unit_length;
+ p += 2;
+ p += sizeof(unsigned int);
+ p += 4;
+ opcode_base = *(unsigned char *)p++;
+
+ /* standard_opcode_lengths = (unsigned char *)p - 1; */
+ p += opcode_base - 1;
+
+ reader->debug_line_directories = p;
+
+ /* skip include directories */
+ while (*p) {
+ p = memchr(p, '\0', reader->debug_line_cu_end - p);
+ if (!p) {
+ fprintf(stderr, "Wrongly reached the end of Directory Table at %tx",
+ reader->debug_line_directories - (reader->file + reader->dwarf->line->sh_offset));
+ abort();
+ }
+ p++;
+ }
+ p++;
+ reader->debug_line_files = p;
+}
+
+
+static void
+di_read_cu(DebugInfoReader *reader)
{
DW_CompilationUnitHeader32 *hdr32 = (DW_CompilationUnitHeader32 *)reader->p;
+ reader->current_cu = reader->p;
if (hdr32->unit_length == 0xffffffff) {
DW_CompilationUnitHeader64 *hdr = (DW_CompilationUnitHeader64 *)hdr32;
reader->p += 23;
- reader->q0 = reader->file + reader->abbrev->sh_offset + hdr->debug_abbrev_offset;
+ reader->q0 = reader->file + reader->dwarf->abbrev->sh_offset + hdr->debug_abbrev_offset;
reader->address_size = hdr->address_size;
reader->format = 64;
} else {
DW_CompilationUnitHeader32 *hdr = hdr32;
reader->p += 11;
- reader->q0 = reader->file + reader->abbrev->sh_offset + hdr->debug_abbrev_offset;
+ reader->q0 = reader->file + reader->dwarf->abbrev->sh_offset + hdr->debug_abbrev_offset;
reader->address_size = hdr->address_size;
reader->format = 32;
}
+ reader->level = 0;
+ di_read_debug_line_cu(reader);
}
static void
set_uint_value(DebugInfoValue *v, uint64_t n)
{
v->as.uint64 = n;
- v->type = 1;
+ v->type = VAL_uint;
}
static void
-set_sint_value(DebugInfoValue *v, int64_t n)
+set_int_value(DebugInfoValue *v, int64_t n)
{
- v->as.uint64 = (uint64_t)n;
- v->type = 2;
+ v->as.int64 = n;
+ v->type = VAL_int;
}
static void
set_cstr_value(DebugInfoValue *v, char *s)
{
v->as.ptr = s;
- v->type = 3;
+ v->type = VAL_cstr;
}
static void
-set_bytes_value(DebugInfoValue *v, char *s)
+set_data_value(DebugInfoValue *v, char *s)
{
v->as.ptr = s;
- v->type = 4;
+ v->type = VAL_data;
}
static void
@@ -907,7 +991,6 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
{
switch (form) {
case DW_FORM_addr:
- fprintf(stderr, "%d: %d\n", __LINE__, reader->address_size);
if (reader->address_size == 4) {
set_uint_value(v, read_uint32(&reader->p));
} else if (reader->address_size == 8) {
@@ -919,12 +1002,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
break;
case DW_FORM_block2:
v->size = read_uint16(&reader->p);
- set_bytes_value(v, reader->p);
+ set_data_value(v, reader->p);
reader->p += v->size;
break;
case DW_FORM_block4:
v->size = read_uint32(&reader->p);
- set_bytes_value(v, reader->p);
+ set_data_value(v, reader->p);
reader->p += v->size;
break;
case DW_FORM_data2:
@@ -943,12 +1026,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
break;
case DW_FORM_block:
v->size = uleb128(&reader->p);
- set_bytes_value(v, reader->p);
+ set_data_value(v, reader->p);
reader->p += v->size;
break;
case DW_FORM_block1:
v->size = read_uint8(&reader->p);
- set_bytes_value(v, reader->p);
+ set_data_value(v, reader->p);
reader->p += v->size;
break;
case DW_FORM_data1:
@@ -958,10 +1041,10 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
set_uint_value(v, read_uint8(&reader->p));
break;
case DW_FORM_sdata:
- set_sint_value(v, read_sleb128(reader));
+ set_int_value(v, read_sleb128(reader));
break;
case DW_FORM_strp:
- set_cstr_value(v, reader->file + reader->str->sh_offset + read_uint(reader));
+ set_cstr_value(v, reader->file + reader->dwarf->str->sh_offset + read_uint(reader));
break;
case DW_FORM_udata:
set_uint_value(v, read_uleb128(reader));
@@ -1000,8 +1083,7 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
break;
case DW_FORM_exprloc:
v->size = read_uleb128(reader);
- set_bytes_value(v, reader->p);
- hexdump(reader->p, v->size);
+ set_data_value(v, reader->p);
reader->p += v->size;
break;
case DW_FORM_flag_present:
@@ -1077,70 +1159,284 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
exit(1);
}
+static char *
+find_abbrev(char *p, uint64_t abbrev_number) {
+ for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) {
+ if (n == 0) {
+ fprintf(stderr,"%d: Abbrev Number %ld not found\n",__LINE__, abbrev_number);
+ exit(1);
+ }
+ uleb128(&p); /* tag */
+ p++; /* has_children */
+ /* skip content */
+ for (;;) {
+ uint64_t at = uleb128(&p);
+ uint64_t form = uleb128(&p);
+ if (!at && !form) break;
+ }
+ }
+ return p;
+}
+
+#if 0
static void
-debug_info_read(DebugInfoReader *reader) {
- reader->level = 0;
+div_inspect(DebugInfoValue *v) {
+ switch (v->type) {
+ case VAL_uint:
+ fprintf(stderr,"%d: type:%d size:%zx v:%lx\n",__LINE__,v->type,v->size,v->as.uint64);
+ break;
+ case VAL_int:
+ fprintf(stderr,"%d: type:%d size:%zx v:%ld\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
+ break;
+ case VAL_cstr:
+ fprintf(stderr,"%d: type:%d size:%zx v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
+ break;
+ case VAL_data:
+ fprintf(stderr,"%d: type:%d size:%zx v:\n",__LINE__,v->type,v->size);
+ hexdump(v->as.ptr, 16);
+ break;
+ }
+}
+#endif
+
+static DIE *
+di_read_die(DebugInfoReader *reader, DIE *die) {
+ uint64_t abbrev_number = uleb128(&reader->p);
+ if (abbrev_number == 0) {
+ reader->level--;
+ return NULL;
+ }
+
+ reader->q = find_abbrev(reader->q0, abbrev_number);
+
+ die->tag = uleb128(&reader->q); /* tag */
+ die->has_children = *reader->q++; /* has_children */
+ if (die->has_children) {
+ reader->level++;
+ }
+ return die;
+}
+
+static DebugInfoValue *
+di_read_record(DebugInfoReader *reader, DebugInfoValue *vp) {
+ uint64_t at = uleb128(&reader->q);
+ uint64_t form = uleb128(&reader->q);
+ if (!at || !form) return NULL;
+ vp->at = at;
+ vp->form = form;
+ debug_info_reader_read_value(reader, form, vp);
+ return vp;
+}
+
+static void
+di_skip_records(DebugInfoReader *reader) {
for (;;) {
- uint64_t abbrev_number = uleb128(&reader->p);
- char has_children;
- fprintf(stderr,"\n\n%d: <%d> Abbrev Number: %lu\n",__LINE__,reader->level,abbrev_number);
- if (abbrev_number == 0) {
- if (reader->level == 1) {
- return;
+ DebugInfoValue v = {0};
+ uint64_t at = uleb128(&reader->q);
+ uint64_t form = uleb128(&reader->q);
+ if (!at || !form) return;
+ debug_info_reader_read_value(reader, form, &v);
+ }
+}
+
+typedef struct {
+ char *file;
+ uintptr_t debug_ranges_offset;
+ uint64_t low_pc;
+ uint64_t high_pc;
+ uint64_t ranges;
+ bool low_pc_set;
+ bool high_pc_set;
+ bool ranges_set;
+} ranges_t;
+
+static void
+ranges_set_low_pc(ranges_t *ptr, uint64_t low_pc) {
+ ptr->low_pc = low_pc;
+ ptr->low_pc_set = true;
+}
+
+static void
+ranges_set_high_pc(ranges_t *ptr, uint64_t high_pc) {
+ ptr->high_pc = high_pc;
+ ptr->high_pc_set = true;
+}
+
+static void
+ranges_set_ranges(ranges_t *ptr, uint64_t ranges) {
+ ptr->ranges = ranges;
+ ptr->ranges_set = true;
+}
+
+static int
+ranges_include(ranges_t *ptr, uint64_t addr) {
+ if (ptr->high_pc_set) {
+ if (ptr->ranges_set || !ptr->low_pc_set) {
+ exit(1);
+ }
+ if (ptr->low_pc <= addr && addr <= ptr->low_pc + ptr->high_pc) {
+ return true;
+ }
+ }
+ else if (ptr->ranges_set) {
+ char *p = ptr->file + ptr->debug_ranges_offset + ptr->ranges;
+ for (;;) {
+ uint64_t from = read_uint64(&p);
+ uint64_t to = read_uint64(&p);
+ if (!from && !to) break;
+ if (from <= addr && addr <= to) {
+ return true;
}
- reader->level--;
- continue;
}
+ }
+ else if (ptr->low_pc_set) {
+ if (ptr->low_pc == addr) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#if 0
+static void
+ranges_inspect(ranges_t *ptr) {
+ if (ptr->high_pc_set) {
+ if (ptr->ranges_set || !ptr->low_pc_set) {
+ fprintf(stderr,"low_pc_set:%d high_pc_set:%d ranges_set:%d\n",ptr->low_pc_set,ptr->high_pc_set,ptr->ranges_set);
+ exit(1);
+ }
+ fprintf(stderr,"low_pc:%lx high_pc:%lx\n",ptr->low_pc,ptr->high_pc);
+ }
+ else if (ptr->ranges_set) {
+ char *p;
+ fprintf(stderr,"low_pc:%lx ranges:%lx\n",ptr->low_pc,ptr->ranges);
+ p = ptr->file + ptr->debug_ranges_offset + ptr->ranges;
+ for (;;) {
+ uint64_t from = read_uint64(&p);
+ uint64_t to = read_uint64(&p);
+ if (!from && !to) break;
+ }
+ }
+ else if (ptr->low_pc_set) {
+ fprintf(stderr,"low_pc:%lx\n",ptr->low_pc);
+ }
+ else {
+ fprintf(stderr,"empty\n");
+ }
+}
+#endif
- reader->q = reader->q0;
+static void
+read_abstract_origin(DebugInfoReader *reader, uint64_t abstract_origin, line_info_t *line) {
+ char *p = reader->p;
+ char *q = reader->q;
+ int level = reader->level;
+ DIE die;
- /* find abbrev */
- for (uint64_t n = uleb128(&reader->q); abbrev_number != n; n = uleb128(&reader->q)) {
- if (n == 0) {
- fprintf(stderr,"%d: Abbrev Number not found\n",__LINE__);
- abort();
- }
- /* fprintf(stderr,"%d: %lu != %lu\n",__LINE__, abbrev_number, n); */
- uleb128(&reader->q); /* tag */
- reader->q++; /* children */
- /* skip content */
- for (;;) {
- uint64_t at = uleb128(&reader->q);
- uint64_t form = uleb128(&reader->q);
- if (!at && !form) break;
- }
+ reader->p = reader->current_cu + abstract_origin;
+ if (!di_read_die(reader, &die)) goto finish;
+
+ /* enumerate abbrev */
+ for (;;) {
+ DebugInfoValue v = {0};
+ if (!di_read_record(reader, &v)) break;
+ switch (v.at) {
+ case DW_AT_name:
+ line->sname = v.as.ptr;
+ break;
}
+ }
- uleb128(&reader->q); /* tag */
- has_children = *reader->q++; /* has_children */
- if (has_children) {
- reader->level++;
+ finish:
+ reader->p = p;
+ reader->q = q;
+ reader->level = level;
+}
+
+static void
+debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
+ line_info_t *lines, int offset) {
+ do {
+ DIE die;
+ ranges_t ranges = {reader->file, reader->dwarf->ranges->sh_offset};
+ //ptrdiff_t diepos = reader->p - reader->p0;
+ line_info_t line = {0};
+
+ if (!di_read_die(reader, &die)) continue;
+ //fprintf(stderr,"%d:%tx: <%d> Abbrev Number: %lu\n",__LINE__,diepos,reader->level,die.tag);
+
+ if (die.tag != DW_TAG_subprogram && die.tag != DW_TAG_inlined_subroutine) {
+ skip_die:
+ di_skip_records(reader);
+ continue;
}
/* enumerate abbrev */
for (;;) {
- uint64_t at = uleb128(&reader->q);
- uint64_t form = uleb128(&reader->q);
DebugInfoValue v = {0};
- fprintf(stderr,"\n%d:%lx: AT:%lx FORM:%lx\n",__LINE__,reader->p-reader->p0,at,form);
- if (!at && !form) break;
- debug_info_reader_read_value(reader, form, &v);
- switch (v.type) {
- case 1:
- fprintf(stderr,"%d: type:%d size:%zx v:%lx\n",__LINE__,v.type,v.size,v.as.uint64);
+ //ptrdiff_t pos = reader->p - reader->p0;
+ if (!di_read_record(reader, &v)) break;
+ //fprintf(stderr,"\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form);
+ //div_inspect(&v);
+ switch (v.at) {
+ case DW_AT_name:
+ line.sname = v.as.ptr;
+ break;
+ case DW_AT_call_file:
+ fill_filename(v.as.uint64, reader->debug_line_directories, reader->debug_line_files, &line);
break;
- case 2:
- fprintf(stderr,"%d: type:%d size:%zx v:%ld\n",__LINE__,v.type,v.size,(int64_t)v.as.uint64);
+ case DW_AT_call_line:
+ line.line = v.as.uint64;
break;
- case 3:
- fprintf(stderr,"%d: type:%d size:%zx v:'%s'\n",__LINE__,v.type,v.size,v.as.ptr);
+ case DW_AT_low_pc:
+ ranges_set_low_pc(&ranges, v.as.uint64);
break;
- case 4:
- fprintf(stderr,"%d: type:%d size:%zx v:\n",__LINE__,v.type,v.size);
- hexdump(v.as.ptr, 16);
+ case DW_AT_high_pc:
+ ranges_set_high_pc(&ranges, v.as.uint64);
break;
+ case DW_AT_declaration:
+ goto skip_die;
+ case DW_AT_inline:
+ /* 1 or 3 */
+ break; // goto skip_die;
+ case DW_AT_abstract_origin:
+ read_abstract_origin(reader, v.as.uint64, &line);
+ break; //goto skip_die;
+ case DW_AT_ranges:
+ ranges_set_ranges(&ranges, v.as.uint64);
+ break;
+ }
+ }
+ /* fprintf(stderr,"%d:%tx: %x ",__LINE__,diepos,die.tag); */
+ for (int i=offset; i < num_traces; i++) {
+ uintptr_t addr = (uintptr_t)traces[i];
+ uintptr_t offset = addr - reader->obj->base_addr;
+ if (ranges_include(&ranges, offset)) {
+ //fprintf(stderr, "%d:%tx: %lx %x %s: %s/%s %d\n",__LINE__,diepos,addr, die.tag,line.sname,line.dirname,line.filename,line.line);
+ if (lines[i].path) {
+ line_info_t *lp = malloc(sizeof(line_info_t));
+ memcpy(lp, &lines[i], sizeof(line_info_t));
+ lines[i].next = lp;
+ lp->dirname = line.dirname;
+ lp->filename = line.filename;
+ lp->line = line.line;
+ lp->saddr = 0;
+ }
+ lines[i].path = reader->obj->path;
+ lines[i].base_addr = line.base_addr;
+ lines[i].sname = line.sname;
+ lines[i].saddr = reader->obj->base_addr + ranges.low_pc;
}
}
+ } while (reader->level > 0);
+}
+
+static void print_line0(line_info_t *line, void *address);
+static void
+print_line(line_info_t *line, void *address) {
+ print_line0(line, address);
+ if (line->next) {
+ print_line(line->next, NULL);
}
}
@@ -1155,8 +1451,7 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
ElfW(Ehdr) *ehdr;
ElfW(Shdr) *shdr, *shstr_shdr;
ElfW(Shdr) *debug_line_shdr = NULL, *gnu_debuglink_shdr = NULL;
- ElfW(Shdr) *debug_info_shdr = NULL, *debug_abbrev_shdr = NULL;
- ElfW(Shdr) *debug_str_shdr = NULL;
+ dwarf_args dwarf = {0};
int fd;
off_t filesize;
char *file;
@@ -1236,51 +1531,27 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
compressed_p = true;
}
debug_line_shdr = shdr + i;
+ dwarf.line = shdr + i;
}
else if (!strcmp(section_name, ".gnu_debuglink")) {
gnu_debuglink_shdr = shdr + i;
}
- else if (!strcmp(section_name, ".debug_info")) {
- debug_info_shdr = shdr + i;
- }
else if (!strcmp(section_name, ".debug_abbrev")) {
- debug_abbrev_shdr = shdr + i;
+ dwarf.abbrev = shdr + i;
}
+ else if (!strcmp(section_name, ".debug_info")) {
+ dwarf.info = shdr + i;
+ }
+ else if (!strcmp(section_name, ".debug_ranges")) {
+ dwarf.ranges = shdr + i;
+ }
else if (!strcmp(section_name, ".debug_str")) {
- debug_str_shdr = shdr + i;
+ dwarf.str = shdr + i;
}
break;
}
}
- if (debug_info_shdr) {
- unsigned char *info = (unsigned char *)(file + debug_info_shdr->sh_offset);
- size_t info_count = debug_info_shdr->sh_size;
- fprintf(stderr, "size: %zd\n", info_count);
- hexdump(info, 11);
- info += 11;
- hexdump(info, 11);
- info += 11;
- hexdump(info, 32);
- }
- if (debug_abbrev_shdr) {
- unsigned char *abbrev = (unsigned char *)(file + debug_abbrev_shdr->sh_offset);
- size_t abbrev_count = debug_abbrev_shdr->sh_size;
- fprintf(stderr, "size: %zd\n", abbrev_count);
- hexdump(abbrev, 128);
- }
- {
- int i = 0;
- DebugInfoReader *reader = debug_info_reader_new(file, debug_info_shdr, debug_abbrev_shdr, debug_str_shdr);
-
- while (reader->p < reader->pend) {
- fprintf(stderr, "CU[%d]\n", i++);
- debug_info_reader_read_cu(reader);
- debug_info_read(reader);
- }
- }
- exit(0);
-
if (offset == -1) {
/* main executable */
offset = 0;
@@ -1312,6 +1583,16 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
}
}
+ if (dwarf.str && dwarf.info && dwarf.line && dwarf.abbrev && dwarf.ranges) {
+ DebugInfoReader reader;
+ debug_info_reader_init(&reader, obj, &dwarf);
+ while (reader.p < reader.pend) {
+ //fprintf(stderr, "%d:%tx: CU[%d]\n", __LINE__, di_pos(&reader), i++);
+ di_read_cu(&reader);
+ debug_info_read(&reader, num_traces, traces, lines, offset);
+ }
+ }
+
if (!symtab_shdr) {
symtab_shdr = dynsym_shdr;
strtab_shdr = dynstr_shdr;
@@ -1330,7 +1611,7 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
if (lines[i].line > 0 || d <= 0 || d > (uintptr_t)sym->st_size)
continue;
/* fill symbol name and addr from .symtab */
- lines[i].sname = strtab + sym->st_name;
+ if (!lines[i].sname) lines[i].sname = strtab + sym->st_name;
lines[i].saddr = saddr;
lines[i].path = obj->path;
lines[i].base_addr = obj->base_addr;
@@ -1408,6 +1689,43 @@ main_exe_path(void)
#undef HAVE_MAIN_EXE_PATH
#endif
+static void
+print_line0(line_info_t *line, void *address) {
+ uintptr_t addr = (uintptr_t)address;
+ uintptr_t d = addr - line->saddr;
+ if (!address) {
+ /* inlined */
+ if (line->dirname && line->dirname[0]) {
+ kprintf("%s(%s) %s/%s:%d\n", line->path, line->sname, line->dirname, line->filename, line->line);
+ }
+ else {
+ kprintf("%s(%s) %s:%d\n", line->path, line->sname, line->filename, line->line);
+ }
+ }
+ else if (!line->path) {
+ kprintf("[0x%lx]\n", addr);
+ }
+ else if (!line->saddr || !line->sname) {
+ kprintf("%s(0x%lx) [0x%lx]\n", line->path, addr-line->base_addr, addr);
+ }
+ else if (line->line <= 0) {
+ kprintf("%s(%s+0x%lx) [0x%lx]\n", line->path, line->sname,
+ d, addr);
+ }
+ else if (!line->filename) {
+ kprintf("%s(%s+0x%lx) [0x%lx] ???:%d\n", line->path, line->sname,
+ d, addr, line->line);
+ }
+ else if (line->dirname && line->dirname[0]) {
+ kprintf("%s(%s+0x%lx) [0x%lx] %s/%s:%d\n", line->path, line->sname,
+ d, addr, line->dirname, line->filename, line->line);
+ }
+ else {
+ kprintf("%s(%s+0x%lx) [0x%lx] %s:%d\n", line->path, line->sname,
+ d, addr, line->filename, line->line);
+ }
+}
+
void
rb_dump_backtrace_with_lines(int num_traces, void **traces)
{
@@ -1469,33 +1787,10 @@ next_line:
/* output */
for (i = 0; i < num_traces; i++) {
- line_info_t *line = &lines[i];
- uintptr_t addr = (uintptr_t)traces[i];
- uintptr_t d = addr - line->saddr;
- if (!line->path) {
- kprintf("[0x%lx]\n", addr);
- }
- else if (!line->saddr || !line->sname) {
- kprintf("%s(0x%lx) [0x%lx]\n", line->path, addr-line->base_addr, addr);
- }
- else if (line->line <= 0) {
- kprintf("%s(%s+0x%lx) [0x%lx]\n", line->path, line->sname,
- d, addr);
- }
- else if (!line->filename) {
- kprintf("%s(%s+0x%lx) [0x%lx] ???:%d\n", line->path, line->sname,
- d, addr, line->line);
- }
- else if (line->dirname && line->dirname[0]) {
- kprintf("%s(%s+0x%lx) [0x%lx] %s/%s:%d\n", line->path, line->sname,
- d, addr, line->dirname, line->filename, line->line);
- }
- else {
- kprintf("%s(%s+0x%lx) [0x%lx] %s:%d\n", line->path, line->sname,
- d, addr, line->filename, line->line);
- }
+ print_line(&lines[i], traces[i]);
+
/* FreeBSD's backtrace may show _start and so on */
- if (line->sname && strcmp("main", line->sname) == 0)
+ if (lines[i].sname && strcmp("main", lines[i].sname) == 0)
break;
}