X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=binutils%2Fdwarf.c;h=9f17af9ff823bc1517118c8d58b9cc42431bcbad;hb=37c18eedffe3926a330149ca93e7407917e2be38;hp=dec4c2ff8782e76287fb6dfe2df5a0edbccb5931;hpb=c54207d32681bb205c28facba73b6173ef15eabf;p=binutils-gdb.git diff --git a/binutils/dwarf.c b/binutils/dwarf.c index dec4c2ff878..9f17af9ff82 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -1,5 +1,5 @@ /* dwarf.c -- display DWARF contents of a BFD binary file - Copyright (C) 2005-2017 Free Software Foundation, Inc. + Copyright (C) 2005-2019 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -48,11 +48,26 @@ static debug_info *debug_information = NULL; that the .debug_info section could not be loaded/parsed. */ #define DEBUG_INFO_UNAVAILABLE (unsigned int) -1 -static const char * dwo_name; -static const char * dwo_dir; -static const unsigned char * dwo_id; -static bfd_size_type dwo_id_len; -static bfd_boolean need_dwo_info; +/* A .debug_info section can contain multiple links to separate + DWO object files. We use these structures to record these links. */ +typedef enum dwo_type +{ + DWO_NAME, + DWO_DIR, + DWO_ID +} dwo_type; + +typedef struct dwo_info +{ + dwo_type type; + const char * value; + struct dwo_info * next; +} dwo_info; + +static dwo_info * first_dwo_info = NULL; +static bfd_boolean need_dwo_info; + +separate_info * first_separate_info = NULL; unsigned int eh_addr_size; @@ -96,10 +111,6 @@ static unsigned int *shndx_pool = NULL; static unsigned int shndx_pool_size = 0; static unsigned int shndx_pool_used = 0; -/* Pointer to a separate file containing extra debug information. */ -static void * separate_debug_file = NULL; -static const char * separate_debug_filename = NULL; - /* For version 2 package files, each set contains an array of section offsets and an array of section sizes, giving the offset and size of the contribution from a CU or TU within one of the debug sections. @@ -387,6 +398,9 @@ read_uleb128 (unsigned char * data, } \ while (0) +/* Read AMOUNT bytes from PTR and store them in VAL as an unsigned value. + Checks to make sure that the read will not reach or pass END + and that VAL is big enough to hold AMOUNT bytes. */ #define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END) \ do \ { \ @@ -415,6 +429,7 @@ read_uleb128 (unsigned char * data, } \ while (0) +/* Like SAFE_BYTE_GET, but also increments PTR by AMOUNT. */ #define SAFE_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END) \ do \ { \ @@ -423,6 +438,7 @@ read_uleb128 (unsigned char * data, } \ while (0) +/* Like SAFE_BYTE_GET, but reads a signed value. */ #define SAFE_SIGNED_BYTE_GET(VAL, PTR, AMOUNT, END) \ do \ { \ @@ -441,6 +457,7 @@ read_uleb128 (unsigned char * data, } \ while (0) +/* Like SAFE_SIGNED_BYTE_GET, but also increments PTR by AMOUNT. */ #define SAFE_SIGNED_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END) \ do \ { \ @@ -1569,6 +1586,25 @@ decode_location_expression (unsigned char * data, data += bytes_read; printf ("DW_OP_GNU_const_index <0x%s>", dwarf_vmatoa ("x", uvalue)); break; + case DW_OP_GNU_variable_value: + /* FIXME: Strictly speaking for 64-bit DWARF3 files + this ought to be an 8-byte wide computation. */ + if (dwarf_version == -1) + { + printf (_("(DW_OP_GNU_variable_value in frame info)")); + /* No way to tell where the next op is, so just bail. */ + return need_frame_base; + } + if (dwarf_version == 2) + { + SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); + } + else + { + SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); + } + printf ("DW_OP_GNU_variable_value: <0x%s>", dwarf_vmatoa ("x", uvalue)); + break; /* HP extensions. */ case DW_OP_HP_is_value: @@ -1686,37 +1722,44 @@ add64 (dwarf_vma * high_bits, dwarf_vma * low_bits, dwarf_vma inc) static const char * fetch_alt_indirect_string (dwarf_vma offset) { - struct dwarf_section * section; - const char * ret; + separate_info * i; if (! do_follow_links) return ""; - if (separate_debug_file == NULL) - return _(""); + if (first_separate_info == NULL) + return _(""); - if (! load_debug_section (separate_debug_str, separate_debug_file)) - return _(""); + for (i = first_separate_info; i != NULL; i = i->next) + { + struct dwarf_section * section; + const char * ret; - section = &debug_displays [separate_debug_str].section; - if (section->start == NULL) - return _(""); + if (! load_debug_section (separate_debug_str, i->handle)) + continue; - if (offset >= section->size) - { - warn (_("DW_FORM_GNU_strp_alt offset too big: %s\n"), dwarf_vmatoa ("x", offset)); - return _(""); - } + section = &debug_displays [separate_debug_str].section; - ret = (const char *) (section->start + offset); - /* Unfortunately we cannot rely upon the .debug_str section ending with a - NUL byte. Since our caller is expecting to receive a well formed C - string we test for the lack of a terminating byte here. */ - if (strnlen ((const char *) ret, section->size - offset) - == section->size - offset) - return _(""); + if (section->start == NULL) + continue; - return ret; + if (offset >= section->size) + continue; + + ret = (const char *) (section->start + offset); + /* Unfortunately we cannot rely upon the .debug_str section ending with a + NUL byte. Since our caller is expecting to receive a well formed C + string we test for the lack of a terminating byte here. */ + if (strnlen ((const char *) ret, section->size - offset) + == section->size - offset) + return _(""); + + return ret; + } + + warn (_("DW_FORM_GNU_strp_alt offset (%s) too big or no string sections available\n"), + dwarf_vmatoa ("x", offset)); + return _(""); } static const char * @@ -1745,6 +1788,49 @@ get_AT_name (unsigned long attribute) return name; } +static void +add_dwo_info (const char * field, dwo_type type) +{ + dwo_info * dwinfo = xmalloc (sizeof * dwinfo); + + dwinfo->type = type; + dwinfo->value = field; + dwinfo->next = first_dwo_info; + first_dwo_info = dwinfo; +} + +static void +add_dwo_name (const char * name) +{ + add_dwo_info (name, DWO_NAME); +} + +static void +add_dwo_dir (const char * dir) +{ + add_dwo_info (dir, DWO_DIR); +} + +static void +add_dwo_id (const char * id) +{ + add_dwo_info (id, DWO_ID); +} + +static void +free_dwo_info (void) +{ + dwo_info * dwinfo; + dwo_info * next; + + for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = next) + { + next = dwinfo->next; + free (dwinfo); + } + first_dwo_info = NULL; +} + static unsigned char * read_and_display_attr_value (unsigned long attribute, unsigned long form, @@ -2168,19 +2254,28 @@ read_and_display_attr_value (unsigned long attribute, debug_info_p->have_frame_base [num] = have_frame_base; if (attribute != DW_AT_GNU_locviews) { - debug_info_p->loc_offsets [num] = uvalue; - debug_info_p->num_loc_offsets++; - assert (debug_info_p->num_loc_offsets - - debug_info_p->num_loc_views <= 1); + /* Corrupt DWARF info can produce more offsets than views. + See PR 23062 for an example. */ + if (debug_info_p->num_loc_offsets + > debug_info_p->num_loc_views) + warn (_("More location offset attributes than DW_AT_GNU_locview attributes\n")); + else + { + debug_info_p->loc_offsets [num] = uvalue; + debug_info_p->num_loc_offsets++; + } } else { assert (debug_info_p->num_loc_views <= num); num = debug_info_p->num_loc_views; - debug_info_p->loc_views [num] = uvalue; - debug_info_p->num_loc_views++; - assert (debug_info_p->num_loc_views - - debug_info_p->num_loc_offsets <= 1); + if (num > debug_info_p->num_loc_offsets) + warn (_("More DW_AT_GNU_locview attributes than location offset attributes\n")); + else + { + debug_info_p->loc_views [num] = uvalue; + debug_info_p->num_loc_views++; + } } } break; @@ -2226,18 +2321,17 @@ read_and_display_attr_value (unsigned long attribute, switch (form) { case DW_FORM_strp: - dwo_name = (const char *) fetch_indirect_string (uvalue); + add_dwo_name ((const char *) fetch_indirect_string (uvalue)); break; case DW_FORM_GNU_str_index: - dwo_name = fetch_indexed_string (uvalue, this_set, offset_size, FALSE); + add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, FALSE)); break; case DW_FORM_string: - dwo_name = (const char *) orig_data; + add_dwo_name ((const char *) orig_data); break; default: warn (_("Unsupported form (%s) for attribute %s\n"), get_FORM_name (form), get_AT_name (attribute)); - dwo_name = _(""); break; } break; @@ -2248,21 +2342,20 @@ read_and_display_attr_value (unsigned long attribute, switch (form) { case DW_FORM_strp: - dwo_dir = (const char *) fetch_indirect_string (uvalue); + add_dwo_dir ((const char *) fetch_indirect_string (uvalue)); break; case DW_FORM_line_strp: - dwo_dir = (const char *) fetch_indirect_line_string (uvalue); + add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue)); break; case DW_FORM_GNU_str_index: - dwo_dir = fetch_indexed_string (uvalue, this_set, offset_size, FALSE); + add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, FALSE)); break; case DW_FORM_string: - dwo_dir = (const char *) orig_data; + add_dwo_dir ((const char *) orig_data); break; default: warn (_("Unsupported form (%s) for attribute %s\n"), get_FORM_name (form), get_AT_name (attribute)); - dwo_dir = _(""); break; } break; @@ -2272,13 +2365,12 @@ read_and_display_attr_value (unsigned long attribute, switch (form) { case DW_FORM_data8: - dwo_id = data - 8; - dwo_id_len = 8; + /* FIXME: Record the length of the ID as well ? */ + add_dwo_id ((const char *) (data - 8)); break; default: warn (_("Unsupported form (%s) for attribute %s\n"), get_FORM_name (form), get_AT_name (attribute)); - dwo_id = NULL; break; } break; @@ -2346,12 +2438,22 @@ read_and_display_attr_value (unsigned long attribute, /* DWARF 4 values. */ case DW_LANG_Python: printf ("(Python)"); break; /* DWARF 5 values. */ + case DW_LANG_OpenCL: printf ("(OpenCL)"); break; case DW_LANG_Go: printf ("(Go)"); break; + case DW_LANG_Modula3: printf ("(Modula 3)"); break; + case DW_LANG_Haskell: printf ("(Haskell)"); break; + case DW_LANG_C_plus_plus_03: printf ("(C++03)"); break; case DW_LANG_C_plus_plus_11: printf ("(C++11)"); break; + case DW_LANG_OCaml: printf ("(OCaml)"); break; + case DW_LANG_Rust: printf ("(Rust)"); break; case DW_LANG_C11: printf ("(C11)"); break; + case DW_LANG_Swift: printf ("(Swift)"); break; + case DW_LANG_Julia: printf ("(Julia)"); break; + case DW_LANG_Dylan: printf ("(Dylan)"); break; case DW_LANG_C_plus_plus_14: printf ("(C++14)"); break; case DW_LANG_Fortran03: printf ("(Fortran 03)"); break; case DW_LANG_Fortran08: printf ("(Fortran 08)"); break; + case DW_LANG_RenderScript: printf ("(RenderScript)"); break; /* MIPS extension. */ case DW_LANG_Mips_Assembler: printf ("(MIPS assembler)"); break; /* UPC extension. */ @@ -2678,30 +2780,47 @@ read_and_display_attr (unsigned long attribute, } /* Like load_debug_section, but if the ordinary call fails, and we are - following debug links, and we have been able to load a separate debug - info file, then attempt to load the requested section from the separate - file. */ + following debug links, then attempt to load the requested section + from one of the separate debug info files. */ static bfd_boolean load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum, - void * data) + void * handle) { - if (load_debug_section (sec_enum, data)) + if (load_debug_section (sec_enum, handle)) { - if (data == separate_debug_file) - debug_displays[sec_enum].section.filename = separate_debug_filename; - - /* FIXME: We should check to see if there is a separate debug info file - that also contains this section, and if so, issue a warning. */ + if (debug_displays[sec_enum].section.filename == NULL) + { + /* See if we can associate a filename with this section. */ + separate_info * i; + + for (i = first_separate_info; i != NULL; i = i->next) + if (i->handle == handle) + { + debug_displays[sec_enum].section.filename = i->filename; + break; + } + } + return TRUE; } - if (do_follow_links && separate_debug_file != NULL) - if (load_debug_section (sec_enum, separate_debug_file)) - { - debug_displays[sec_enum].section.filename = separate_debug_filename; - return TRUE; - } + if (do_follow_links) + { + separate_info * i; + + for (i = first_separate_info; i != NULL; i = i->next) + { + if (load_debug_section (sec_enum, i->handle)) + { + debug_displays[sec_enum].section.filename = i->filename; + + /* FIXME: We should check to see if any of the remaining debug info + files also contain this section, and, umm, do something about it. */ + return TRUE; + } + } + } return FALSE; } @@ -3399,7 +3518,7 @@ display_formatted_table (unsigned char * data, unsigned char * end, const DWARF2_Internal_LineInfo * linfo, struct dwarf_section * section, - const char * what) + bfd_boolean is_dir) { unsigned char *format_start, format_count, *format, formati; dwarf_vma data_count, datai; @@ -3415,7 +3534,10 @@ display_formatted_table (unsigned char * data, data += bytes_read; if (data == end) { - warn (_("Corrupt %s format table entry\n"), what); + if (is_dir) + warn (_("Corrupt directory format table entry\n")); + else + warn (_("Corrupt file name format table entry\n")); return data; } } @@ -3424,18 +3546,28 @@ display_formatted_table (unsigned char * data, data += bytes_read; if (data == end) { - warn (_("Corrupt %s list\n"), what); + if (is_dir) + warn (_("Corrupt directory list\n")); + else + warn (_("Corrupt file name list\n")); return data; } if (data_count == 0) { - printf (_("\n The %s Table is empty.\n"), what); + if (is_dir) + printf (_("\n The Directory Table is empty.\n")); + else + printf (_("\n The File Name Table is empty.\n")); return data; } - printf (_("\n The %s Table (offset 0x%lx):\n"), what, - (long)(data - start)); + if (is_dir) + printf (_("\n The Directory Table (offset 0x%lx):\n"), + (long) (data - start)); + else + printf (_("\n The File Name Table (offset 0x%lx):\n"), + (long) (data - start)); printf (_(" Entry")); /* Delay displaying name as the last entry for better screen layout. */ @@ -3503,7 +3635,10 @@ display_formatted_table (unsigned char * data, } if (data == end) { - warn (_("Corrupt %s entries list\n"), what); + if (is_dir) + warn (_("Corrupt directory entries list\n")); + else + warn (_("Corrupt file name entries list\n")); return data; } putchar ('\n'); @@ -3611,9 +3746,9 @@ display_debug_lines_raw (struct dwarf_section * section, load_debug_section_with_follow (line_str, file); data = display_formatted_table (data, start, end, &linfo, section, - _("Directory")); + TRUE); data = display_formatted_table (data, start, end, &linfo, section, - _("File name")); + FALSE); } else { @@ -4297,7 +4432,7 @@ display_debug_lines_decoded (struct dwarf_section * section, printf ("%s:\n", file_table[0].name); } - printf (_("File name Line number Starting address View\n")); + printf (_("File name Line number Starting address View Stmt\n")); saved_linfo = linfo; } @@ -4635,9 +4770,14 @@ display_debug_lines_decoded (struct dwarf_section * section, } if (state_machine_regs.view) - printf (" %6u\n", state_machine_regs.view); + printf (" %6u", state_machine_regs.view); else - putchar ('\n'); + printf (" "); + + if (state_machine_regs.is_stmt) + printf (" x"); + + putchar ('\n'); state_machine_regs.view++; if (xop == -DW_LNE_end_sequence) @@ -5938,12 +6078,12 @@ display_debug_loc (struct dwarf_section *section, void *file) unsigned char *next = start, *vnext = vstart; unsigned int *array = NULL; const char *suffix = strrchr (section->name, '.'); - int is_dwo = 0; + bfd_boolean is_dwo = FALSE; int is_loclists = strstr (section->name, "debug_loclists") != NULL; dwarf_vma expected_start = 0; if (suffix && strcmp (suffix, ".dwo") == 0) - is_dwo = 1; + is_dwo = TRUE; bytes = section->size; @@ -6489,6 +6629,7 @@ display_debug_addr (struct dwarf_section *section, } /* Display the .debug_str_offsets and .debug_str_offsets.dwo sections. */ + static int display_debug_str_offsets (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED) @@ -6543,6 +6684,7 @@ display_debug_ranges_list (unsigned char *start, unsigned char *finish, break; SAFE_SIGNED_BYTE_GET_AND_INC (end, start, pointer_size, finish); + printf (" %8.8lx ", offset); if (begin == 0 && end == 0) @@ -6810,6 +6952,13 @@ display_debug_ranges (struct dwarf_section *section, continue; } + if (next < section_begin || next >= finish) + { + warn (_("Corrupt offset (%#8.8lx) in range entry %u\n"), + (unsigned long) offset, i); + continue; + } + if (dwarf_check != 0 && i > 0) { if (start < next) @@ -6825,6 +6974,7 @@ display_debug_ranges (struct dwarf_section *section, (unsigned long) (next - section_begin), section->name); } } + start = next; last_start = next; @@ -7065,6 +7215,27 @@ init_dwarf_regnames_s390 (void) dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_s390); } +static const char *const dwarf_regnames_riscv[] = +{ + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", /* 0 - 7 */ + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", /* 8 - 15 */ + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", /* 16 - 23 */ + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", /* 24 - 31 */ + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", /* 32 - 39 */ + "fs0", "fs1", /* 40 - 41 */ + "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7", /* 42 - 49 */ + "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", /* 50 - 57 */ + "fs10", "fs11", /* 58 - 59 */ + "ft8", "ft9", "ft10", "ft11" /* 60 - 63 */ +}; + +void +init_dwarf_regnames_riscv (void) +{ + dwarf_regnames = dwarf_regnames_riscv; + dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_riscv); +} + void init_dwarf_regnames (unsigned int e_machine) { @@ -7092,6 +7263,10 @@ init_dwarf_regnames (unsigned int e_machine) init_dwarf_regnames_s390 (); break; + case EM_RISCV: + init_dwarf_regnames_riscv (); + break; + default: break; } @@ -7224,7 +7399,7 @@ read_cie (unsigned char *start, unsigned char *end, if (start == end) { warn (_("No terminator for augmentation name\n")); - return start; + goto fail; } if (strcmp (fc->augmentation, "eh") == 0) @@ -7236,7 +7411,7 @@ read_cie (unsigned char *start, unsigned char *end, if (fc->ptr_size < 1 || fc->ptr_size > 8) { warn (_("Invalid pointer size (%d) in CIE data\n"), fc->ptr_size); - return end; + goto fail; } GET (fc->segment_size, 1); @@ -7244,7 +7419,7 @@ read_cie (unsigned char *start, unsigned char *end, if (fc->segment_size > 8 || fc->segment_size + fc->ptr_size > 8) { warn (_("Invalid segment size (%d) in CIE data\n"), fc->segment_size); - return end; + goto fail; } eh_addr_size = fc->ptr_size; @@ -7254,8 +7429,10 @@ read_cie (unsigned char *start, unsigned char *end, fc->ptr_size = eh_addr_size; fc->segment_size = 0; } + READ_ULEB (fc->code_factor); READ_SLEB (fc->data_factor); + if (version == 1) { GET (fc->ra, 1); @@ -7275,7 +7452,7 @@ read_cie (unsigned char *start, unsigned char *end, warn (_("Augmentation data too long: 0x%s, expected at most %#lx\n"), dwarf_vmatoa ("x", augmentation_data_len), (unsigned long) (end - start)); - return end; + goto fail; } start += augmentation_data_len; } @@ -7300,6 +7477,8 @@ read_cie (unsigned char *start, unsigned char *end, fc->fde_encoding = *q++; else if (*p == 'S') ; + else if (*p == 'B') + ; else break; p++; @@ -7317,6 +7496,12 @@ read_cie (unsigned char *start, unsigned char *end, *p_aug = augmentation_data; } return start; + + fail: + free (fc->col_offset); + free (fc->col_type); + free (fc); + return end; } /* Prints out the contents on the DATA array formatted as unsigned bytes. @@ -7362,10 +7547,10 @@ display_debug_frames (struct dwarf_section *section, unsigned char *start = section->start; unsigned char *end = start + section->size; unsigned char *section_start = start; - Frame_Chunk *chunks = 0, *forward_refs = 0; - Frame_Chunk *remembered_state = 0; + Frame_Chunk *chunks = NULL, *forward_refs = NULL; + Frame_Chunk *remembered_state = NULL; Frame_Chunk *rs; - int is_eh = strcmp (section->name, ".eh_frame") == 0; + bfd_boolean is_eh = strcmp (section->name, ".eh_frame") == 0; unsigned int length_return; unsigned int max_regs = 0; const char *bad_reg = _("bad register: "); @@ -8298,6 +8483,36 @@ display_debug_frames (struct dwarf_section *section, printf ("\n"); + while (remembered_state != NULL) + { + rs = remembered_state; + remembered_state = rs->next; + free (rs->col_type); + free (rs->col_offset); + rs->next = NULL; /* Paranoia. */ + free (rs); + } + + while (chunks != NULL) + { + rs = chunks; + chunks = rs->next; + free (rs->col_type); + free (rs->col_offset); + rs->next = NULL; /* Paranoia. */ + free (rs); + } + + while (forward_refs != NULL) + { + rs = forward_refs; + forward_refs = rs->next; + free (rs->col_type); + free (rs->col_offset); + rs->next = NULL; /* Paranoia. */ + free (rs); + } + return 1; } @@ -9237,7 +9452,18 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) } if (!do_display) - memcpy (&this_set[row - 1].signature, ph, sizeof (uint64_t)); + { + size_t num_copy = sizeof (uint64_t); + + /* PR 23064: Beware of buffer overflow. */ + if (ph + num_copy < limit) + memcpy (&this_set[row - 1].signature, ph, num_copy); + else + { + warn (_("Signature (%p) extends beyond end of space in section\n"), ph); + return 0; + } + } prow = poffsets + (row - 1) * ncols * 4; /* PR 17531: file: b8ce60a8. */ @@ -9600,6 +9826,7 @@ parse_gnu_debuglink (struct dwarf_section * section, void * data) The CRC value is stored after the filename, aligned up to 4 bytes. */ name = (const char *) section->start; + crc_offset = strnlen (name, section->size) + 1; crc_offset = (crc_offset + 3) & ~3; if (crc_offset + 4 > section->size) @@ -9661,6 +9888,17 @@ parse_gnu_debugaltlink (struct dwarf_section * section, void * data) return name; } +static void +add_separate_debug_file (const char * filename, void * handle) +{ + separate_info * i = xmalloc (sizeof * i); + + i->filename = filename; + i->handle = handle; + i->next = first_separate_info; + first_separate_info = i; +} + static void * load_separate_debug_info (const char * main_filename, struct dwarf_section * xlink, @@ -9669,7 +9907,7 @@ load_separate_debug_info (const char * main_filename, void * func_data) { const char * separate_filename; - char * debugfile; + char * debug_filename; char * canon_dir; size_t canon_dirlen; size_t dirlen; @@ -9701,191 +9939,234 @@ load_separate_debug_info (const char * main_filename, #define EXTRA_DEBUG_ROOT2 "/usr/lib/debug/usr" #endif - debugfile = (char *) malloc (strlen (DEBUGDIR) + 1 - + canon_dirlen - + strlen (".debug/") + debug_filename = (char *) malloc (strlen (DEBUGDIR) + 1 + + canon_dirlen + + strlen (".debug/") #ifdef EXTRA_DEBUG_ROOT1 - + strlen (EXTRA_DEBUG_ROOT1) + + strlen (EXTRA_DEBUG_ROOT1) #endif #ifdef EXTRA_DEBUG_ROOT2 - + strlen (EXTRA_DEBUG_ROOT2) + + strlen (EXTRA_DEBUG_ROOT2) #endif - + strlen (separate_filename) - + 1); - if (debugfile == NULL) + + strlen (separate_filename) + + 1); + if (debug_filename == NULL) { warn (_("Out of memory")); + free (canon_dir); return NULL; } /* First try in the current directory. */ - sprintf (debugfile, "%s", separate_filename); - if (check_func (debugfile, func_data)) + sprintf (debug_filename, "%s", separate_filename); + if (check_func (debug_filename, func_data)) goto found; /* Then try in a subdirectory called .debug. */ - sprintf (debugfile, ".debug/%s", separate_filename); - if (check_func (debugfile, func_data)) + sprintf (debug_filename, ".debug/%s", separate_filename); + if (check_func (debug_filename, func_data)) goto found; /* Then try in the same directory as the original file. */ - sprintf (debugfile, "%s%s", canon_dir, separate_filename); - if (check_func (debugfile, func_data)) + sprintf (debug_filename, "%s%s", canon_dir, separate_filename); + if (check_func (debug_filename, func_data)) goto found; /* And the .debug subdirectory of that directory. */ - sprintf (debugfile, "%s.debug/%s", canon_dir, separate_filename); - if (check_func (debugfile, func_data)) + sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename); + if (check_func (debug_filename, func_data)) goto found; #ifdef EXTRA_DEBUG_ROOT1 /* Try the first extra debug file root. */ - sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename); - if (check_func (debugfile, func_data)) + sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename); + if (check_func (debug_filename, func_data)) + goto found; + + /* Try the first extra debug file root. */ + sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename); + if (check_func (debug_filename, func_data)) goto found; #endif #ifdef EXTRA_DEBUG_ROOT2 /* Try the second extra debug file root. */ - sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename); - if (check_func (debugfile, func_data)) + sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename); + if (check_func (debug_filename, func_data)) goto found; #endif - /* Then try in the global debugfile directory. */ - strcpy (debugfile, DEBUGDIR); + /* Then try in the global debug_filename directory. */ + strcpy (debug_filename, DEBUGDIR); dirlen = strlen (DEBUGDIR) - 1; if (dirlen > 0 && DEBUGDIR[dirlen] != '/') - strcat (debugfile, "/"); - strcat (debugfile, (const char *) separate_filename); + strcat (debug_filename, "/"); + strcat (debug_filename, (const char *) separate_filename); - if (check_func (debugfile, func_data)) + if (check_func (debug_filename, func_data)) goto found; /* Failed to find the file. */ warn (_("could not find separate debug file '%s'\n"), separate_filename); - warn (_("tried: %s\n"), debugfile); + warn (_("tried: %s\n"), debug_filename); #ifdef EXTRA_DEBUG_ROOT2 - sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename); - warn (_("tried: %s\n"), debugfile); + sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename); + warn (_("tried: %s\n"), debug_filename); #endif #ifdef EXTRA_DEBUG_ROOT1 - sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename); - warn (_("tried: %s\n"), debugfile); + sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename); + warn (_("tried: %s\n"), debug_filename); + + sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename); + warn (_("tried: %s\n"), debug_filename); #endif - sprintf (debugfile, "%s.debug/%s", canon_dir, separate_filename); - warn (_("tried: %s\n"), debugfile); + sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename); + warn (_("tried: %s\n"), debug_filename); - sprintf (debugfile, "%s%s", canon_dir, separate_filename); - warn (_("tried: %s\n"), debugfile); + sprintf (debug_filename, "%s%s", canon_dir, separate_filename); + warn (_("tried: %s\n"), debug_filename); - sprintf (debugfile, ".debug/%s", separate_filename); - warn (_("tried: %s\n"), debugfile); + sprintf (debug_filename, ".debug/%s", separate_filename); + warn (_("tried: %s\n"), debug_filename); - sprintf (debugfile, "%s", separate_filename); - warn (_("tried: %s\n"), debugfile); + sprintf (debug_filename, "%s", separate_filename); + warn (_("tried: %s\n"), debug_filename); free (canon_dir); - free (debugfile); + free (debug_filename); return NULL; found: free (canon_dir); + void * debug_handle; + /* Now open the file.... */ - if ((separate_debug_file = open_debug_file (debugfile)) == NULL) + if ((debug_handle = open_debug_file (debug_filename)) == NULL) { - warn (_("failed to open separate debug file: %s\n"), debugfile); - free (debugfile); + warn (_("failed to open separate debug file: %s\n"), debug_filename); + free (debug_filename); return FALSE; } /* FIXME: We do not check to see if there are any other separate debug info files that would also match. */ - printf (_("%s: Found separate debug info file: %s\n\n"), main_filename, debugfile); - separate_debug_filename = debugfile; + printf (_("%s: Found separate debug info file: %s\n\n"), main_filename, debug_filename); + add_separate_debug_file (debug_filename, debug_handle); - /* Do not free debugfile - it might be referenced inside + /* Do not free debug_filename - it might be referenced inside the structure returned by open_debug_file(). */ - return separate_debug_file; + return debug_handle; } /* Attempt to load a separate dwarf object file. */ static void * -load_dwo_file (const char * main_filename) +load_dwo_file (const char * main_filename, const char * name, const char * dir, const char * id ATTRIBUTE_UNUSED) { - char * filename; + char * separate_filename; + void * separate_handle; /* FIXME: Skip adding / if dwo_dir ends in /. */ - filename = concat (dwo_dir, "/", dwo_name, NULL); - if (filename == NULL) + separate_filename = concat (dir, "/", name, NULL); + if (separate_filename == NULL) { warn (_("Out of memory allocating dwo filename\n")); return NULL; } - if ((separate_debug_file = open_debug_file (filename)) == NULL) + if ((separate_handle = open_debug_file (separate_filename)) == NULL) { - warn (_("Unable to load dwo file: %s\n"), filename); - free (filename); + warn (_("Unable to load dwo file: %s\n"), separate_filename); + free (separate_filename); return NULL; } /* FIXME: We should check the dwo_id. */ - printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, filename); - separate_debug_filename = filename; - return separate_debug_file; + printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, separate_filename); + add_separate_debug_file (separate_filename, separate_handle); + /* Note - separate_filename will be freed in free_debug_memory(). */ + return separate_handle; } -/* Load a separate debug info file, if it exists. - Returns the data pointer that is the result of calling open_debug_file - on the separate debug info file, or NULL if there were problems or there - is no such file. */ +/* Load the separate debug info file(s) attached to FILE, if any exist. + Returns TRUE if any were found, FALSE otherwise. + If TRUE is returned then the linked list starting at first_separate_info + will be populated with open file handles. */ -void * -load_separate_debug_file (void * file, const char * filename) +bfd_boolean +load_separate_debug_files (void * file, const char * filename) { - /* See if there is a dwo link. */ + /* Skip this operation if we are not interested in debug links. */ + if (! do_follow_links && ! do_debug_links) + return FALSE; + + /* See if there are any dwo links. */ if (load_debug_section (str, file) && load_debug_section (abbrev, file) && load_debug_section (info, file)) { - dwo_name = dwo_dir = NULL; - dwo_id = NULL; - dwo_id_len = 0; + free_dwo_info (); if (process_debug_info (& debug_displays[info].section, file, abbrev, TRUE, FALSE)) { - if (dwo_name != NULL) + bfd_boolean introduced = FALSE; + dwo_info * dwinfo; + const char * dir = NULL; + const char * id = NULL; + + for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = dwinfo->next) { - if (do_debug_links) + switch (dwinfo->type) { - printf (_("The %s section contains a link to a dwo file:\n"), - debug_displays [info].section.uncompressed_name); - printf (_(" Name: %s\n"), dwo_name); - printf (_(" Directory: %s\n"), dwo_dir ? dwo_dir : _("")); - if (dwo_id != NULL) - display_data (printf (_(" ID: ")), dwo_id, dwo_id_len); - else - printf (_(" ID: \n")); - printf ("\n\n"); - } + case DWO_NAME: + if (do_debug_links) + { + if (! introduced) + { + printf (_("The %s section contains link(s) to dwo file(s):\n\n"), + debug_displays [info].section.uncompressed_name); + introduced = TRUE; + } + + printf (_(" Name: %s\n"), dwinfo->value); + printf (_(" Directory: %s\n"), dir ? dir : _("")); + if (id != NULL) + display_data (printf (_(" ID: ")), (unsigned char *) id, 8); + else + printf (_(" ID: \n")); + printf ("\n\n"); + } + + if (do_follow_links) + load_dwo_file (filename, dwinfo->value, dir, id); + break; - /* FIXME: We do not check to see if there are any more dwo links in the file... */ - if (do_follow_links) - return load_dwo_file (filename); + case DWO_DIR: + dir = dwinfo->value; + break; + + case DWO_ID: + id = dwinfo->value; + break; + + default: + error (_("Unexpected DWO INFO type")); + break; + } } } } if (! do_follow_links) - return NULL; + /* The other debug links will be displayed by display_debug_links() + so we do not need to do any further processing here. */ + return FALSE; /* FIXME: We do not check for the presence of both link sections in the same file. */ /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks. */ @@ -9896,26 +10177,29 @@ load_separate_debug_file (void * file, const char * filename) { Build_id_data * build_id_data; - return load_separate_debug_info (filename, - & debug_displays[gnu_debugaltlink].section, - parse_gnu_debugaltlink, - check_gnu_debugaltlink, - & build_id_data); + load_separate_debug_info (filename, + & debug_displays[gnu_debugaltlink].section, + parse_gnu_debugaltlink, + check_gnu_debugaltlink, + & build_id_data); } if (load_debug_section (gnu_debuglink, file)) { unsigned long crc32; - return load_separate_debug_info (filename, - & debug_displays[gnu_debuglink].section, - parse_gnu_debuglink, - check_gnu_debuglink, - & crc32); + load_separate_debug_info (filename, + & debug_displays[gnu_debuglink].section, + parse_gnu_debuglink, + check_gnu_debuglink, + & crc32); } + if (first_separate_info != NULL) + return TRUE; + do_follow_links = 0; - return NULL; + return FALSE; } void @@ -9948,14 +10232,19 @@ free_debug_memory (void) alloc_num_debug_info_entries = num_debug_info_entries = 0; } - if (separate_debug_file != NULL) - { - close_debug_file (separate_debug_file); - separate_debug_file = NULL; + separate_info * d; + separate_info * next; - free ((void *) separate_debug_filename); - separate_debug_filename = NULL; + for (d = first_separate_info; d != NULL; d = next) + { + close_debug_file (d->handle); + free ((void *) d->filename); + next = d->next; + free ((void *) d); } + first_separate_info = NULL; + + free_dwo_info (); } void