diff options
Diffstat (limited to 'binutils/dwarf.c')
| -rw-r--r-- | binutils/dwarf.c | 492 |
1 files changed, 324 insertions, 168 deletions
diff --git a/binutils/dwarf.c b/binutils/dwarf.c index fb09b86..c5ceaa9 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 @@ -50,6 +51,9 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define DO_LOC 0x1 +#define DO_TYPES 0x2 + static const char *regname (unsigned int regno, int row); static const char *regname_internal_by_table_only (unsigned int regno); @@ -102,6 +106,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 +588,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; } @@ -1725,7 +1728,7 @@ decode_location_expression (unsigned char * data, This is used for DWARF package files. */ static struct cu_tu_set * -find_cu_tu_set_v2 (uint64_t cu_offset, int do_types) +find_cu_tu_set_v2 (uint64_t cu_offset, bool do_types) { struct cu_tu_set *p; unsigned int nsets; @@ -1822,6 +1825,74 @@ get_AT_name (unsigned long attribute) return name; } +static const char * +get_AT_language_name (unsigned long value) +{ + /* Libiberty does not (yet) provide a get_DW_AT_language_name() + function so we define our own. */ + + switch (value) + { + case DW_LNAME_Ada: return "Ada"; + case DW_LNAME_BLISS: return "BLISS"; + case DW_LNAME_C: return "C"; + case DW_LNAME_C_plus_plus: return "C_plus_plus"; + case DW_LNAME_Cobol: return "Cobol"; + case DW_LNAME_Crystal: return "Crystal"; + case DW_LNAME_D: return "D"; + case DW_LNAME_Dylan: return "Dylan"; + case DW_LNAME_Fortran: return "Fortran"; + case DW_LNAME_Go: return "Go"; + case DW_LNAME_Haskell: return "Haskell"; + case DW_LNAME_Java: return "Java"; + case DW_LNAME_Julia: return "Julia"; + case DW_LNAME_Kotlin: return "Kotlin"; + case DW_LNAME_Modula2: return "Modula2"; + case DW_LNAME_Modula3: return "Modula3"; + case DW_LNAME_ObjC: return "ObjC"; + case DW_LNAME_ObjC_plus_plus: return "ObjC_plus_plus"; + case DW_LNAME_OCaml: return "OCaml"; + case DW_LNAME_OpenCL_C: return "OpenCL_C"; + case DW_LNAME_Pascal: return "Pascal"; + case DW_LNAME_PLI: return "PLI"; + case DW_LNAME_Python: return "Python"; + case DW_LNAME_RenderScript: return "RenderScript"; + case DW_LNAME_Rust: return "Rust"; + case DW_LNAME_Swift: return "Swift"; + case DW_LNAME_UPC: return "UPC"; + case DW_LNAME_Zig: return "Zig"; + case DW_LNAME_Assembly: return "Assembly"; + case DW_LNAME_C_sharp: return "C_sharp"; + case DW_LNAME_Mojo: return "Mojo"; + case DW_LNAME_GLSL: return "GLSL"; + case DW_LNAME_GLSL_ES: return "GLSL_ES"; + case DW_LNAME_HLSL: return "HLSL"; + case DW_LNAME_OpenCL_CPP: return "OpenCL_CPP"; + case DW_LNAME_CPP_for_OpenCL: return "CPP_for_OpenCL"; + case DW_LNAME_SYCL: return "SYCL"; + case DW_LNAME_Ruby: return "Ruby"; + case DW_LNAME_Move: return "Move"; + case DW_LNAME_Hylo: return "Hylo"; + case DW_LNAME_HIP: return "HIP"; + case DW_LNAME_Odin: return "Odin"; + case DW_LNAME_P4: return "P4"; + case DW_LNAME_Metal: return "Metal"; + case DW_LNAME_Algol68: return "Algol68"; + default: break; + } + + static char buffer[100]; + + if (value >= DW_LNAME_lo_user && value <= DW_LNAME_hi_user) + snprintf (buffer, sizeof (buffer), _("Implementation specific AT_language_name value: %lx"), + value); + else + snprintf (buffer, sizeof (buffer), _("Unknown AT_language_name value: %lx"), + value); + + return buffer; +} + static void add_dwo_info (const char * value, uint64_t cu_offset, dwo_type type) { @@ -3057,7 +3128,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 +3161,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: @@ -3144,6 +3215,14 @@ read_and_display_attr_value (unsigned long attribute, /* For some attributes we can display further information. */ switch (attribute) { + case DW_AT_language_name: + printf ("\t(%s)", get_AT_language_name (uvalue)); + break; + + case DW_AT_language_version: + printf ("\t(%lu)", (unsigned long) uvalue); + break; + case DW_AT_type: if (level >= 0 && level < MAX_CU_NESTING && uvalue < (size_t) (end - start)) @@ -3744,21 +3823,20 @@ read_bases (abbrev_entry * entry, } /* Process the contents of a .debug_info section. - If do_loc is TRUE then we are scanning for location lists and dwo tags - and we do not want to display anything to the user. - If do_types is TRUE, we are processing a .debug_types section instead of - a .debug_info section. - The information displayed is restricted by the values in DWARF_START_DIE - and DWARF_CUTOFF_LEVEL. - Returns TRUE upon success. Otherwise an error or warning message is - printed and FALSE is returned. */ + If do_flags & DO_LOC then we are scanning for location lists and + dwo tags and we do not want to display anything to the user. + If do_flags & DO_TYPES, we are processing a .debug_types section + instead of a .debug_info section. + The information displayed is restricted by the values in + DWARF_START_DIE and DWARF_CUTOFF_LEVEL. + Returns TRUE upon success. Otherwise an error or warning message + is printed and FALSE is returned. */ static bool process_debug_info (struct dwarf_section * section, void *file, enum dwarf_section_display_enum abbrev_sec, - bool do_loc, - bool do_types) + unsigned int do_flags) { unsigned char *start = section->start; unsigned char *end = start + section->size; @@ -3806,9 +3884,9 @@ process_debug_info (struct dwarf_section * section, return false; } - if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info) + if (((do_flags & DO_LOC) || do_debug_loc || do_debug_ranges || do_debug_info) && alloc_num_debug_info_entries == 0 - && !do_types) + && !(do_flags & DO_TYPES)) { /* Then allocate an array to hold the information. */ debug_information = cmalloc (num_units, sizeof (*debug_information)); @@ -3830,7 +3908,7 @@ process_debug_info (struct dwarf_section * section, alloc_num_debug_info_entries = num_units; } - if (!do_loc) + if (!(do_flags & DO_LOC)) { load_debug_section_with_follow (str, file); load_debug_section_with_follow (line_str, file); @@ -3853,7 +3931,7 @@ process_debug_info (struct dwarf_section * section, return false; } - if (!do_loc && dwarf_start_die == 0) + if (!(do_flags & DO_LOC) && dwarf_start_die == 0) introduce (section, false); free_all_abbrevs (); @@ -3889,8 +3967,6 @@ process_debug_info (struct dwarf_section * section, SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end_cu); - this_set = find_cu_tu_set_v2 (cu_offset, do_types); - if (compunit.cu_version < 5) { compunit.cu_unit_type = DW_UT_compile; @@ -3900,8 +3976,6 @@ process_debug_info (struct dwarf_section * section, else { SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end_cu); - do_types = (compunit.cu_unit_type == DW_UT_type); - SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end_cu); } @@ -3915,6 +3989,7 @@ process_debug_info (struct dwarf_section * section, SAFE_BYTE_GET_AND_INC (dwo_id, hdrptr, 8, end_cu); } + this_set = find_cu_tu_set_v2 (cu_offset, (do_flags & DO_TYPES)); if (this_set == NULL) { abbrev_base = 0; @@ -3971,8 +4046,6 @@ process_debug_info (struct dwarf_section * section, SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end_cu); - this_set = find_cu_tu_set_v2 (cu_offset, do_types); - if (compunit.cu_version < 5) { compunit.cu_unit_type = DW_UT_compile; @@ -3982,13 +4055,12 @@ process_debug_info (struct dwarf_section * section, else { SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end_cu); - do_types = (compunit.cu_unit_type == DW_UT_type); - SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end_cu); } SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end_cu); + this_set = find_cu_tu_set_v2 (cu_offset, (do_flags & DO_TYPES)); if (this_set == NULL) { abbrev_base = 0; @@ -4020,7 +4092,7 @@ process_debug_info (struct dwarf_section * section, compunit.cu_pointer_size = offset_size; } - if (do_types) + if ((do_flags & DO_TYPES) || compunit.cu_unit_type == DW_UT_type) { SAFE_BYTE_GET_AND_INC (signature, hdrptr, 8, end_cu); SAFE_BYTE_GET_AND_INC (type_offset, hdrptr, offset_size, end_cu); @@ -4032,10 +4104,11 @@ process_debug_info (struct dwarf_section * section, continue; } - if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info) + if (((do_flags & DO_LOC) || do_debug_loc + || do_debug_ranges || do_debug_info) && num_debug_info_entries == 0 && alloc_num_debug_info_entries > unit - && ! do_types) + && !(do_flags & DO_TYPES)) { free_debug_information (&debug_information[unit]); memset (&debug_information[unit], 0, sizeof (*debug_information)); @@ -4047,7 +4120,7 @@ process_debug_info (struct dwarf_section * section, debug_information[unit].ranges_base = DEBUG_INFO_UNAVAILABLE; } - if (!do_loc && dwarf_start_die == 0) + if (!(do_flags & DO_LOC) && dwarf_start_die == 0) { printf (_(" Compilation Unit @ offset %#" PRIx64 ":\n"), cu_offset); @@ -4066,7 +4139,7 @@ process_debug_info (struct dwarf_section * section, printf (_(" Abbrev Offset: %#" PRIx64 "\n"), compunit.cu_abbrev_offset); printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size); - if (do_types) + if ((do_flags & DO_TYPES) || compunit.cu_unit_type == DW_UT_type) { printf (_(" Signature: %#" PRIx64 "\n"), signature); printf (_(" Type Offset: %#" PRIx64 "\n"), type_offset); @@ -4127,7 +4200,7 @@ process_debug_info (struct dwarf_section * section, unsigned long die_offset; abbrev_entry *entry; abbrev_attr *attr; - int do_printing = 1; + bool do_printing; die_offset = tags - section_begin; @@ -4149,7 +4222,7 @@ process_debug_info (struct dwarf_section * section, break; } - if (!do_loc && die_offset >= dwarf_start_die + if (!(do_flags & DO_LOC) && die_offset >= dwarf_start_die && (dwarf_cutoff_level == -1 || level < dwarf_cutoff_level)) printf (_(" <%d><%lx>: Abbrev Number: 0\n"), @@ -4178,24 +4251,22 @@ process_debug_info (struct dwarf_section * section, continue; } - if (!do_loc) + if ((do_flags & DO_LOC) + || (dwarf_start_die != 0 && die_offset < dwarf_start_die)) + do_printing = false; + else { - if (dwarf_start_die != 0 && die_offset < dwarf_start_die) - do_printing = 0; - else - { - if (dwarf_start_die != 0 && die_offset == dwarf_start_die) - saved_level = level; - do_printing = (dwarf_cutoff_level == -1 - || level < dwarf_cutoff_level); - if (do_printing) - printf (_(" <%d><%lx>: Abbrev Number: %lu"), - level, die_offset, abbrev_number); - else if (dwarf_cutoff_level == -1 - || last_level < dwarf_cutoff_level) - printf (_(" <%d><%lx>: ...\n"), level, die_offset); - last_level = level; - } + if (dwarf_start_die != 0 && die_offset == dwarf_start_die) + saved_level = level; + do_printing = (dwarf_cutoff_level == -1 + || level < dwarf_cutoff_level); + if (do_printing) + printf (_(" <%d><%lx>: Abbrev Number: %lu"), + level, die_offset, abbrev_number); + else if (dwarf_cutoff_level == -1 + || last_level < dwarf_cutoff_level) + printf (_(" <%d><%lx>: ...\n"), level, die_offset); + last_level = level; } /* Scan through the abbreviation list until we reach the @@ -4208,7 +4279,7 @@ process_debug_info (struct dwarf_section * section, if (entry == NULL) { - if (!do_loc && do_printing) + if (do_printing) { printf ("\n"); fflush (stdout); @@ -4220,7 +4291,7 @@ process_debug_info (struct dwarf_section * section, return false; } - if (!do_loc && do_printing) + if (do_printing) printf (" (%s)\n", get_TAG_name (entry->tag)); switch (entry->tag) @@ -4231,7 +4302,7 @@ process_debug_info (struct dwarf_section * section, case DW_TAG_compile_unit: case DW_TAG_skeleton_unit: need_base_address = 1; - need_dwo_info = do_loc; + need_dwo_info = do_flags & DO_LOC; break; case DW_TAG_entry_point: need_base_address = 0; @@ -4246,9 +4317,11 @@ process_debug_info (struct dwarf_section * section, break; } - debug_info *debug_info_p = ((debug_information - && unit < alloc_num_debug_info_entries) - ? debug_information + unit : NULL); + debug_info *debug_info_p = NULL; + if (debug_information + && num_debug_info_entries != DEBUG_INFO_UNAVAILABLE + && unit < alloc_num_debug_info_entries) + debug_info_p = debug_information + unit; assert (!debug_info_p || (debug_info_p->num_loc_offsets @@ -4287,7 +4360,7 @@ process_debug_info (struct dwarf_section * section, attr && attr->attribute; attr = attr->next) { - if (! do_loc && do_printing) + if (do_printing) /* Show the offset from where the tag was extracted. */ printf (" <%tx>", tags - section_begin); tags = read_and_display_attr (attr->attribute, @@ -4301,7 +4374,7 @@ process_debug_info (struct dwarf_section * section, offset_size, compunit.cu_version, debug_info_p, - do_loc || ! do_printing, + !do_printing, section, this_set, level); @@ -4341,9 +4414,9 @@ process_debug_info (struct dwarf_section * section, /* Set num_debug_info_entries here so that it can be used to check if we need to process .debug_loc and .debug_ranges sections. */ - if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info) + if (((do_flags & DO_LOC) || do_debug_loc || do_debug_ranges || do_debug_info) && num_debug_info_entries == 0 - && ! do_types) + && !(do_flags & DO_TYPES)) { if (num_units > alloc_num_debug_info_entries) num_debug_info_entries = alloc_num_debug_info_entries; @@ -4351,7 +4424,7 @@ process_debug_info (struct dwarf_section * section, num_debug_info_entries = num_units; } - if (!do_loc) + if (!(do_flags & DO_LOC)) printf ("\n"); return true; @@ -4379,12 +4452,13 @@ load_debug_info (void * file) (void) load_cu_tu_indexes (file); if (load_debug_section_with_follow (info, file) - && process_debug_info (&debug_displays [info].section, file, abbrev, true, false)) + && process_debug_info (&debug_displays [info].section, file, + abbrev, DO_LOC)) return num_debug_info_entries; if (load_debug_section_with_follow (info_dwo, file) && process_debug_info (&debug_displays [info_dwo].section, file, - abbrev_dwo, true, false)) + abbrev_dwo, DO_LOC)) return num_debug_info_entries; num_debug_info_entries = DEBUG_INFO_UNAVAILABLE; @@ -5112,7 +5186,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 +5214,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 +5298,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 +5330,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 +5411,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 +5470,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 +6407,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 +6490,7 @@ display_debug_macro (struct dwarf_section *section, while (1) { unsigned int op; + const char *string; if (curr >= end) { @@ -6434,20 +6506,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 +6609,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 @@ -7255,8 +7329,6 @@ display_loclists_unit_header (struct dwarf_section * section, bool is_64bit; uint32_t i; - printf (_("Table at Offset %#" PRIx64 "\n"), header_offset); - SAFE_BYTE_GET_AND_INC (length, start, 4, end); if (length == 0xffffffff) { @@ -7265,6 +7337,11 @@ display_loclists_unit_header (struct dwarf_section * section, } else is_64bit = false; + if (length < 8) + return (uint64_t) -1; + + printf (_("Table at Offset %#" PRIx64 "\n"), header_offset); + header_offset = start - section->start; SAFE_BYTE_GET_AND_INC (version, start, 2, end); SAFE_BYTE_GET_AND_INC (address_size, start, 1, end); @@ -7277,15 +7354,21 @@ display_loclists_unit_header (struct dwarf_section * section, printf (_(" Segment size: %u\n"), segment_selector_size); printf (_(" Offset entries: %u\n"), *offset_count); + if (length > section->size - header_offset) + length = section->size - header_offset; + if (segment_selector_size != 0) { warn (_("The %s section contains an " "unsupported segment selector size: %d.\n"), section->name, segment_selector_size); - return (uint64_t)-1; + return (uint64_t) -1; } - if ( *offset_count) + uint64_t max_off_count = length >> (is_64bit ? 3 : 2); + if (*offset_count > max_off_count) + *offset_count = max_off_count; + if (*offset_count) { printf (_("\n Offset Entries starting at %#tx:\n"), start - section->start); @@ -7302,8 +7385,7 @@ display_loclists_unit_header (struct dwarf_section * section, putchar ('\n'); *loclists_start = start; - /* The length field doesn't include the length field itself. */ - return header_offset + length + (is_64bit ? 12 : 4); + return header_offset + length; } static int @@ -7673,19 +7755,50 @@ display_debug_str (struct dwarf_section *section, static int display_debug_info (struct dwarf_section *section, void *file) { - return process_debug_info (section, file, section->abbrev_sec, false, false); + return process_debug_info (section, file, section->abbrev_sec, 0); } static int display_debug_types (struct dwarf_section *section, void *file) { - return process_debug_info (section, file, section->abbrev_sec, false, true); + return process_debug_info (section, file, section->abbrev_sec, DO_TYPES); } static int display_trace_info (struct dwarf_section *section, void *file) { - return process_debug_info (section, file, section->abbrev_sec, false, true); + return process_debug_info (section, file, section->abbrev_sec, DO_TYPES); +} + +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 @@ -8043,7 +8156,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. */ @@ -8051,8 +8164,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); @@ -8090,7 +8203,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, @@ -8137,6 +8250,8 @@ display_debug_ranges_list (unsigned char * start, putchar ('\n'); } + + return start; } static unsigned char * @@ -8247,7 +8362,7 @@ display_debug_rnglists_list (unsigned char * start, return start; } -static int +static bool display_debug_rnglists_unit_header (struct dwarf_section * section, uint64_t * unit_offset, unsigned char * poffset_size) @@ -8255,7 +8370,8 @@ display_debug_rnglists_unit_header (struct dwarf_section * section, uint64_t start_offset = *unit_offset; unsigned char * p = section->start + start_offset; unsigned char * finish = section->start + section->size; - uint64_t initial_length; + unsigned char * hdr; + uint64_t length; unsigned char segment_selector_size; unsigned int offset_entry_count; unsigned int i; @@ -8264,66 +8380,59 @@ display_debug_rnglists_unit_header (struct dwarf_section * section, unsigned char offset_size; /* Get and check the length of the block. */ - SAFE_BYTE_GET_AND_INC (initial_length, p, 4, finish); + SAFE_BYTE_GET_AND_INC (length, p, 4, finish); - if (initial_length == 0xffffffff) + if (length == 0xffffffff) { /* This section is 64-bit DWARF 3. */ - SAFE_BYTE_GET_AND_INC (initial_length, p, 8, finish); + SAFE_BYTE_GET_AND_INC (length, p, 8, finish); *poffset_size = offset_size = 8; } else *poffset_size = offset_size = 4; - if (initial_length > (size_t) (finish - p)) - { - /* If the length field has a relocation against it, then we should - not complain if it is inaccurate (and probably negative). - It is copied from .debug_line handling code. */ - if (reloc_at (section, (p - section->start) - offset_size)) - initial_length = finish - p; - else - { - warn (_("The length field (%#" PRIx64 - ") in the debug_rnglists header is wrong" - " - the section is too small\n"), - initial_length); - return 0; - } - } - - /* Report the next unit offset to the caller. */ - *unit_offset = (p - section->start) + initial_length; + if (length < 8) + return false; /* Get the other fields in the header. */ + hdr = p; SAFE_BYTE_GET_AND_INC (version, p, 2, finish); SAFE_BYTE_GET_AND_INC (address_size, p, 1, finish); SAFE_BYTE_GET_AND_INC (segment_selector_size, p, 1, finish); SAFE_BYTE_GET_AND_INC (offset_entry_count, p, 4, finish); printf (_(" Table at Offset: %#" PRIx64 ":\n"), start_offset); - printf (_(" Length: %#" PRIx64 "\n"), initial_length); + printf (_(" Length: %#" PRIx64 "\n"), length); printf (_(" DWARF version: %u\n"), version); printf (_(" Address size: %u\n"), address_size); printf (_(" Segment size: %u\n"), segment_selector_size); printf (_(" Offset entries: %u\n"), offset_entry_count); + if (length > (size_t) (finish - hdr)) + length = finish - hdr; + + /* Report the next unit offset to the caller. */ + *unit_offset = (hdr - section->start) + length; + /* Check the fields. */ if (segment_selector_size != 0) { warn (_("The %s section contains " "unsupported segment selector size: %d.\n"), section->name, segment_selector_size); - return 0; + return false; } if (version < 5) { warn (_("Only DWARF version 5+ debug_rnglists info " "is currently supported.\n")); - return 0; + return false; } + uint64_t max_off_count = (length - 8) / offset_size; + if (offset_entry_count > max_off_count) + offset_entry_count = max_off_count; if (offset_entry_count != 0) { printf (_("\n Offsets starting at %#tx:\n"), p - section->start); @@ -8337,7 +8446,7 @@ display_debug_rnglists_unit_header (struct dwarf_section * section, } } - return 1; + return true; } static bool @@ -8358,6 +8467,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; @@ -8368,6 +8478,7 @@ display_debug_ranges (struct dwarf_section *section, uint64_t last_offset = 0; uint64_t next_rnglists_cu_offset = 0; unsigned char offset_size; + bool ok_header = true; if (bytes == 0) { @@ -8421,14 +8532,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]; @@ -8460,13 +8568,23 @@ display_debug_ranges (struct dwarf_section *section, /* If we've moved on to the next compile unit in the rnglists section - dump the unit header(s). */ if (is_rnglists && next_rnglists_cu_offset < offset) { - while (next_rnglists_cu_offset < offset) - display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size); + while (ok_header && next_rnglists_cu_offset < offset) + ok_header = display_debug_rnglists_unit_header (section, + &next_rnglists_cu_offset, + &offset_size); + if (!ok_header) + break; printf (_(" Offset Begin End\n")); } 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 @@ -8476,11 +8594,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) @@ -8494,18 +8616,23 @@ 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. */ - if (is_rnglists) + if (is_rnglists && ok_header) while (next_rnglists_cu_offset < section->size) - display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size); - + if (!display_debug_rnglists_unit_header (section, + &next_rnglists_cu_offset, + &offset_size)) + break; putchar ('\n'); free (range_entries); @@ -8528,6 +8655,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; @@ -8536,6 +8664,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; @@ -8848,9 +8978,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; @@ -8872,6 +9015,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: @@ -8895,9 +9039,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; @@ -8925,6 +9070,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: @@ -9007,7 +9153,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++) @@ -9170,7 +9317,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; @@ -9730,6 +9877,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) { @@ -10199,6 +10347,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; @@ -10221,6 +10370,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; @@ -10247,10 +10397,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: @@ -10263,8 +10414,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: @@ -10384,6 +10536,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", @@ -10395,6 +10548,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; @@ -10917,7 +11071,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. */ @@ -12317,7 +12471,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; @@ -12328,7 +12482,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; @@ -12486,7 +12640,7 @@ load_separate_debug_files (void * file, const char * filename) free_dwo_info (); if (process_debug_info (& debug_displays[info].section, file, abbrev, - true, false)) + DO_LOC)) { bool introduced = false; dwo_info *dwinfo; @@ -12658,6 +12812,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 }, @@ -12816,6 +12971,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 }, |
