diff options
Diffstat (limited to 'binutils/dwarf.c')
-rw-r--r-- | binutils/dwarf.c | 217 |
1 files changed, 150 insertions, 67 deletions
diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 08bb623..0fc0329 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -30,6 +30,7 @@ #include "gdb/gdb-index.h" #include "filenames.h" #include "safe-ctype.h" +#include "sframe-api.h" #include <assert.h> #ifdef HAVE_LIBDEBUGINFOD @@ -102,6 +103,7 @@ int do_debug_str; int do_debug_str_offsets; int do_debug_loc; int do_gdb_index; +int do_sframe; int do_trace_info; int do_trace_abbrevs; int do_trace_aranges; @@ -583,56 +585,54 @@ process_extended_line_op (unsigned char * data, return len + header_len; } -static const unsigned char * +static const char * fetch_indirect_string (uint64_t offset) { struct dwarf_section *section = &debug_displays [str].section; - const unsigned char * ret; + const char *ret; if (section->start == NULL) - return (const unsigned char *) _("<no .debug_str section>"); + return _("<no .debug_str section>"); if (offset >= section->size) { warn (_("DW_FORM_strp offset too big: %#" PRIx64 "\n"), offset); - return (const unsigned char *) _("<offset is too big>"); + return _("<offset is too big>"); } - ret = section->start + offset; + 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) + if (strnlen (ret, section->size - offset) == section->size - offset) - ret = (const unsigned char *) - _("<no NUL byte at end of .debug_str section>"); + ret = _("<no NUL byte at end of .debug_str section>"); return ret; } -static const unsigned char * +static const char * fetch_indirect_line_string (uint64_t offset) { struct dwarf_section *section = &debug_displays [line_str].section; - const unsigned char * ret; + const char *ret; if (section->start == NULL) - return (const unsigned char *) _("<no .debug_line_str section>"); + return _("<no .debug_line_str section>"); if (offset >= section->size) { warn (_("DW_FORM_line_strp offset too big: %#" PRIx64 "\n"), offset); - return (const unsigned char *) _("<offset is too big>"); + return _("<offset is too big>"); } - ret = section->start + offset; + ret = (const char *) (section->start + offset); /* Unfortunately we cannot rely upon the .debug_line_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) + if (strnlen (ret, section->size - offset) == section->size - offset) - ret = (const unsigned char *) - _("<no NUL byte at end of .debug_line_str section>"); + ret = _("<no NUL byte at end of .debug_line_str section>"); return ret; } @@ -3057,7 +3057,7 @@ read_and_display_attr_value (unsigned long attribute, switch (form) { case DW_FORM_strp: - add_dwo_name ((const char *) fetch_indirect_string (uvalue), + add_dwo_name (fetch_indirect_string (uvalue), cu_offset); break; case DW_FORM_GNU_strp_alt: @@ -3090,13 +3090,13 @@ read_and_display_attr_value (unsigned long attribute, switch (form) { case DW_FORM_strp: - add_dwo_dir ((const char *) fetch_indirect_string (uvalue), cu_offset); + add_dwo_dir (fetch_indirect_string (uvalue), cu_offset); break; case DW_FORM_GNU_strp_alt: add_dwo_dir (fetch_alt_indirect_string (uvalue), cu_offset); break; case DW_FORM_line_strp: - add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue), cu_offset); + add_dwo_dir (fetch_indirect_line_string (uvalue), cu_offset); break; case DW_FORM_GNU_str_index: case DW_FORM_strx: @@ -5112,7 +5112,7 @@ display_debug_lines_raw (struct dwarf_section * section, typedef struct { - char *name; + const char *name; unsigned int directory_index; unsigned int modification_date; unsigned int length; @@ -5140,7 +5140,7 @@ display_debug_lines_decoded (struct dwarf_section * section, int i; File_Entry *file_table = NULL; unsigned int n_files = 0; - char **directory_table = NULL; + const char **directory_table = NULL; unsigned int n_directories = 0; if (startswith (section->name, ".debug_line.") @@ -5224,12 +5224,12 @@ display_debug_lines_decoded (struct dwarf_section * section, return 0; } else - directory_table = (char **) - xcalloc (n_directories, sizeof (unsigned char *)); + directory_table = (const char **) + xcalloc (n_directories, sizeof (const char *)); for (entryi = 0; entryi < n_directories; entryi++) { - char **pathp = &directory_table[entryi]; + const char **pathp = &directory_table[entryi]; format = format_start; for (formati = 0; formati < format_count; formati++) @@ -5256,8 +5256,7 @@ display_debug_lines_decoded (struct dwarf_section * section, SAFE_BYTE_GET (uvalue, data, linfo.li_offset_size, end); /* Remove const by the cast. */ - *pathp = (char *) - fetch_indirect_line_string (uvalue); + *pathp = fetch_indirect_line_string (uvalue); break; } break; @@ -5338,8 +5337,7 @@ display_debug_lines_decoded (struct dwarf_section * section, SAFE_BYTE_GET (uvalue, data, linfo.li_offset_size, end); /* Remove const by the cast. */ - file->name = (char *) - fetch_indirect_line_string (uvalue); + file->name = fetch_indirect_line_string (uvalue); break; } break; @@ -5398,8 +5396,8 @@ display_debug_lines_decoded (struct dwarf_section * section, } /* Go through the directory table again to save the directories. */ - directory_table = (char **) - xmalloc (n_directories * sizeof (unsigned char *)); + directory_table = (const char **) + xmalloc (n_directories * sizeof (const char *)); i = 0; while (*ptr_directory_table != 0) @@ -6335,7 +6333,6 @@ display_debug_macro (struct dwarf_section *section, { unsigned int lineno, version, flags; unsigned int offset_size; - const unsigned char *string; uint64_t line_offset = 0, sec_offset = curr - start, offset; unsigned char **extended_ops = NULL; @@ -6419,6 +6416,7 @@ display_debug_macro (struct dwarf_section *section, while (1) { unsigned int op; + const char *string; if (curr >= end) { @@ -6434,20 +6432,22 @@ display_debug_macro (struct dwarf_section *section, { case DW_MACRO_define: READ_ULEB (lineno, curr, end); - string = curr; - curr += strnlen ((char *) string, end - string); + string = (const char *) curr; + op = strnlen (string, end - curr); + curr += op; printf (_(" DW_MACRO_define - lineno : %d macro : %*s\n"), - lineno, (int) (curr - string), string); + lineno, (int) op, string); if (curr < end) curr++; break; case DW_MACRO_undef: READ_ULEB (lineno, curr, end); - string = curr; - curr += strnlen ((char *) string, end - string); + string = (const char *) curr; + op = strnlen (string, end - curr); + curr += op; printf (_(" DW_MACRO_undef - lineno : %d macro : %*s\n"), - lineno, (int) (curr - string), string); + lineno, (int) op, string); if (curr < end) curr++; break; @@ -6535,8 +6535,8 @@ display_debug_macro (struct dwarf_section *section, case DW_MACRO_undef_strx: READ_ULEB (lineno, curr, end); READ_ULEB (offset, curr, end); - string = (const unsigned char *) - fetch_indexed_string (offset, NULL, offset_size, is_dwo, 0); + string = fetch_indexed_string (offset, NULL, offset_size, + is_dwo, 0); if (op == DW_MACRO_define_strx) printf (" DW_MACRO_define_strx "); else @@ -7324,7 +7324,7 @@ display_debug_loc (struct dwarf_section *section, void *file) unsigned int *array = NULL; const char *suffix = strrchr (section->name, '.'); bool is_dwo = false; - int is_loclists = strstr (section->name, "debug_loclists") != NULL; + bool is_loclists = strstr (section->name, "debug_loclists") != NULL; uint64_t next_header_offset = 0; if (suffix && strcmp (suffix, ".dwo") == 0) @@ -7450,6 +7450,16 @@ display_debug_loc (struct dwarf_section *section, void *file) debug_info *debug_info_p = debug_information + i; uint32_t offset_count; + /* .debug_loclists section is loaded into debug_information as + DWARF-5 debug info and .debug_loc section is loaded into + debug_information as pre-DWARF-5 debug info. When dumping + .debug_loc section, we should only process pre-DWARF-5 debug + info in debug_information. When dumping .debug_loclists + section, we should only process DWARF-5 info in + debug_information. */ + if ((debug_info_p->dwarf_version >= 5) != is_loclists) + continue; + if (!locs_sorted) { for (k = 0; k < debug_info_p->num_loc_offsets; k++) @@ -7462,7 +7472,7 @@ display_debug_loc (struct dwarf_section *section, void *file) /* .debug_loclists has a per-unit header. Update start if we are detecting it. */ - if (debug_info_p->dwarf_version == 5) + if (debug_info_p->dwarf_version >= 5) { j = locs_sorted ? 0 : array [0]; @@ -7679,6 +7689,37 @@ display_trace_info (struct dwarf_section *section, void *file) } static int +display_sframe (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED) +{ + sframe_decoder_ctx *sfd_ctx = NULL; + unsigned char *data = section->start; + size_t sf_size = section->size; + int err = 0; + + if (strcmp (section->name, "") == 0) + { + error (_("Section name must be provided \n")); + return false; + } + + /* Decode the contents of the section. */ + sfd_ctx = sframe_decode ((const char*)data, sf_size, &err); + if (!sfd_ctx || err) + { + error (_("SFrame decode failure: %s\n"), sframe_errmsg (err)); + return false; + } + + printf (_("Contents of the SFrame section %s:"), section->name); + /* Dump the contents as text. */ + dump_sframe (sfd_ctx, section->address); + + sframe_decoder_free (&sfd_ctx); + + return true; +} + +static int display_debug_aranges (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED) { @@ -8033,7 +8074,7 @@ display_debug_str_offsets (struct dwarf_section *section, for (idx = 0; curr < entries_end; idx++) { uint64_t offset; - const unsigned char * string; + const char *string; if ((size_t) (entries_end - curr) < entry_length) /* Not enough space to read one entry_length, give up. */ @@ -8041,8 +8082,8 @@ display_debug_str_offsets (struct dwarf_section *section, SAFE_BYTE_GET_AND_INC (offset, curr, entry_length, entries_end); if (dwo) - string = (const unsigned char *) - fetch_indexed_string (idx, NULL, entry_length, dwo, debug_str_offsets_hdr_len); + string = fetch_indexed_string (idx, NULL, entry_length, dwo, + debug_str_offsets_hdr_len); else string = fetch_indirect_string (offset); @@ -8080,7 +8121,7 @@ range_entry_compar (const void *ap, const void *bp) return (a > b) - (b > a); } -static void +static unsigned char * display_debug_ranges_list (unsigned char * start, unsigned char * finish, unsigned int pointer_size, @@ -8127,6 +8168,8 @@ display_debug_ranges_list (unsigned char * start, putchar ('\n'); } + + return start; } static unsigned char * @@ -8348,6 +8391,7 @@ display_debug_ranges (struct dwarf_section *section, { unsigned char *start = section->start; unsigned char *last_start = start; + unsigned char *last_end; uint64_t bytes = section->size; unsigned char *section_begin = start; unsigned char *finish = start + bytes; @@ -8411,14 +8455,11 @@ display_debug_ranges (struct dwarf_section *section, qsort (range_entries, num_range_list, sizeof (*range_entries), range_entry_compar); - if (dwarf_check != 0 && range_entries[0].ranges_offset != 0) - warn (_("Range lists in %s section start at %#" PRIx64 "\n"), - section->name, range_entries[0].ranges_offset); - putchar ('\n'); if (!is_rnglists) printf (_(" Offset Begin End\n")); + last_end = NULL; for (i = 0; i < num_range_list; i++) { struct range_entry *range_entry = &range_entries[i]; @@ -8457,6 +8498,12 @@ display_debug_ranges (struct dwarf_section *section, next = section_begin + offset; /* Offset is from the section start, the base has already been added. */ + if (i == 0) + { + last_end = section_begin; + if (is_rnglists) + last_end += 2 * offset_size - 4 + 2 + 1 + 1 + 4; + } /* If multiple DWARF entities reference the same range then we will have multiple entries in the `range_entries' list for the same offset. Thanks to the sort above these will all be consecutive in @@ -8466,11 +8513,15 @@ display_debug_ranges (struct dwarf_section *section, continue; last_offset = offset; - if (dwarf_check != 0 && i > 0) + if (dwarf_check != 0) { if (start < next) - warn (_("There is a hole [%#tx - %#tx] in %s section.\n"), - start - section_begin, next - section_begin, section->name); + { + if (last_end != next) + warn (_("There is a hole [%#tx - %#tx] in %s section.\n"), + last_end - section_begin, next - section_begin, + section->name); + } else if (start > next) { if (next == last_start) @@ -8484,11 +8535,14 @@ display_debug_ranges (struct dwarf_section *section, last_start = next; if (is_rnglists) - display_debug_rnglists_list - (start, finish, pointer_size, offset, base_address, debug_info_p->addr_base); + last_end + = display_debug_rnglists_list + (start, finish, pointer_size, offset, base_address, + debug_info_p->addr_base); else - display_debug_ranges_list - (start, finish, pointer_size, offset, base_address); + last_end + = display_debug_ranges_list + (start, finish, pointer_size, offset, base_address); } /* Display trailing empty (or unreferenced) compile units, if any. */ @@ -8518,6 +8572,7 @@ typedef struct Frame_Chunk uint64_t pc_range; unsigned int cfa_reg; uint64_t cfa_offset; + bool cfa_ofs_signed_p; unsigned int ra; unsigned char fde_encoding; unsigned char cfa_exp; @@ -8526,6 +8581,8 @@ typedef struct Frame_Chunk } Frame_Chunk; +typedef bool (*is_mach_augmentation_ftype) (char c); +static is_mach_augmentation_ftype is_mach_augmentation; typedef const char *(*dwarf_regname_lookup_ftype) (unsigned int); static dwarf_regname_lookup_ftype dwarf_regnames_lookup_func; static const char *const *dwarf_regnames; @@ -8838,9 +8895,22 @@ init_dwarf_regnames_loongarch (void) dwarf_regnames_lookup_func = regname_internal_by_table_only; } +static bool +is_nomach_augmentation (char c ATTRIBUTE_UNUSED) +{ + return false; +} + +static bool +is_aarch64_augmentation (char c) +{ + return (c == 'B' || c == 'G'); +} + void -init_dwarf_regnames_by_elf_machine_code (unsigned int e_machine) +init_dwarf_by_elf_machine_code (unsigned int e_machine) { + is_mach_augmentation = is_nomach_augmentation; dwarf_regnames_lookup_func = NULL; is_aarch64 = false; @@ -8862,6 +8932,7 @@ init_dwarf_regnames_by_elf_machine_code (unsigned int e_machine) case EM_AARCH64: init_dwarf_regnames_aarch64 (); + is_mach_augmentation = is_aarch64_augmentation; break; case EM_S390: @@ -8885,9 +8956,10 @@ init_dwarf_regnames_by_elf_machine_code (unsigned int e_machine) architecture and specific machine type of a BFD. */ void -init_dwarf_regnames_by_bfd_arch_and_mach (enum bfd_architecture arch, - unsigned long mach) +init_dwarf_by_bfd_arch_and_mach (enum bfd_architecture arch, + unsigned long mach) { + is_mach_augmentation = is_nomach_augmentation; dwarf_regnames_lookup_func = NULL; is_aarch64 = false; @@ -8915,6 +8987,7 @@ init_dwarf_regnames_by_bfd_arch_and_mach (enum bfd_architecture arch, case bfd_arch_aarch64: init_dwarf_regnames_aarch64(); + is_mach_augmentation = is_aarch64_augmentation; break; case bfd_arch_s390: @@ -8997,7 +9070,8 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg if (fc->cfa_exp) strcpy (tmp, "exp"); else - sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), (int) fc->cfa_offset); + sprintf (tmp, (fc->cfa_ofs_signed_p ? "%s%+" PRId64 : "%s+%" PRIu64), + regname (fc->cfa_reg, 1), fc->cfa_offset); printf ("%-8s ", tmp); for (r = 0; r < fc->ncols; r++) @@ -9160,7 +9234,7 @@ read_cie (unsigned char *start, unsigned char *end, fc->fde_encoding = *q++; else if (*p == 'S') ; - else if (*p == 'B') + else if (is_mach_augmentation (*p)) ; else break; @@ -9720,6 +9794,7 @@ display_debug_frames (struct dwarf_section *section, fc->data_factor = cie->data_factor; fc->cfa_reg = cie->cfa_reg; fc->cfa_offset = cie->cfa_offset; + fc->cfa_ofs_signed_p = cie->cfa_ofs_signed_p; fc->ra = cie->ra; if (frame_need_space (fc, max_regs > 0 ? max_regs - 1: 0) < 0) { @@ -10189,6 +10264,7 @@ display_debug_frames (struct dwarf_section *section, printf (" DW_CFA_remember_state\n"); rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); rs->cfa_offset = fc->cfa_offset; + rs->cfa_ofs_signed_p = fc->cfa_ofs_signed_p; rs->cfa_reg = fc->cfa_reg; rs->ra = fc->ra; rs->cfa_exp = fc->cfa_exp; @@ -10211,6 +10287,7 @@ display_debug_frames (struct dwarf_section *section, { remembered_state = rs->next; fc->cfa_offset = rs->cfa_offset; + fc->cfa_ofs_signed_p = rs->cfa_ofs_signed_p; fc->cfa_reg = rs->cfa_reg; fc->ra = rs->ra; fc->cfa_exp = rs->cfa_exp; @@ -10237,10 +10314,11 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa: READ_ULEB (fc->cfa_reg, start, block_end); READ_ULEB (fc->cfa_offset, start, block_end); + fc->cfa_ofs_signed_p = false; fc->cfa_exp = 0; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa: %s ofs %d\n", - regname (fc->cfa_reg, 0), (int) fc->cfa_offset); + printf (" DW_CFA_def_cfa: %s ofs %" PRIu64 "\n", + regname (fc->cfa_reg, 0), fc->cfa_offset); break; case DW_CFA_def_cfa_register: @@ -10253,8 +10331,9 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa_offset: READ_ULEB (fc->cfa_offset, start, block_end); + fc->cfa_ofs_signed_p = false; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset); + printf (" DW_CFA_def_cfa_offset: %" PRIu64 "\n", fc->cfa_offset); break; case DW_CFA_nop: @@ -10374,6 +10453,7 @@ display_debug_frames (struct dwarf_section *section, ofs = sofs; ofs *= fc->data_factor; fc->cfa_offset = ofs; + fc->cfa_ofs_signed_p = true; fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_sf: %s ofs %" PRId64 "\n", @@ -10385,6 +10465,7 @@ display_debug_frames (struct dwarf_section *section, ofs = sofs; ofs *= fc->data_factor; fc->cfa_offset = ofs; + fc->cfa_ofs_signed_p = true; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_offset_sf: %" PRId64 "\n", ofs); break; @@ -10907,7 +10988,7 @@ display_debug_links (struct dwarf_section * section, (padding) If needed to reach a 4 byte boundary. (uint32_t) CRC32 value. - The .gun_debugaltlink section is formatted as: + The .gnu_debugaltlink section is formatted as: (c-string) Filename. (binary) Build-ID. */ @@ -12307,7 +12388,7 @@ load_build_id_debug_file (const char * main_filename ATTRIBUTE_UNUSED, void * ma + strlen (".debug") /* The next string should be the same as the longest name found in the prefixes[] array below. */ - + strlen ("/usrlib64/debug/usr") + + strlen ("/usr/lib64/debug/usr/") + 1); void * handle; @@ -12318,7 +12399,7 @@ load_build_id_debug_file (const char * main_filename ATTRIBUTE_UNUSED, void * ma "/usr/lib/debug/", "/usr/lib/debug/usr/", "/usr/lib64/debug/", - "/usr/lib64/debug/usr" + "/usr/lib64/debug/usr/" }; long unsigned int i; @@ -12648,6 +12729,7 @@ static const debug_dump_long_opts debug_option_table[] = /* For compatibility with earlier versions of readelf. */ { 'r', "ranges", &do_debug_aranges, 1 }, { 's', "str", &do_debug_str, 1 }, + { '\0', "sframe-internal-only", &do_sframe, 1 }, { 'T', "trace_aranges", &do_trace_aranges, 1 }, { 't', "pubtypes", &do_debug_pubtypes, 1 }, { 'U', "trace_info", &do_trace_info, 1 }, @@ -12806,6 +12888,7 @@ struct dwarf_section_display debug_displays[] = { { ".debug_weaknames", ".zdebug_weaknames", "", NO_ABBREVS }, display_debug_not_supported, NULL, false }, { { ".gdb_index", "", "", NO_ABBREVS }, display_gdb_index, &do_gdb_index, false }, { { ".debug_names", "", "", NO_ABBREVS }, display_debug_names, &do_gdb_index, false }, + { { ".sframe", "", "", NO_ABBREVS }, display_sframe, &do_sframe, true }, { { ".trace_info", "", "", ABBREV (trace_abbrev) }, display_trace_info, &do_trace_info, true }, { { ".trace_abbrev", "", "", NO_ABBREVS }, display_debug_abbrev, &do_trace_abbrevs, false }, { { ".trace_aranges", "", "", NO_ABBREVS }, display_debug_aranges, &do_trace_aranges, false }, |