aboutsummaryrefslogtreecommitdiff
path: root/binutils/dwarf.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils/dwarf.c')
-rw-r--r--binutils/dwarf.c217
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 },