[PATCH 1/4] objdump: New feature display of global variable information based on DWARF info section
Guillaume VACHERIAS
guillaume.vacherias@foss.st.com
Tue Aug 19 02:12:24 GMT 2025
Add in objdump option -Y/--map-file to display global variable information
binutils/
* objdump.c (dump_map_file_info): New function. Entry point of display
of variable information option.
(dump_global_variable_info): New function. Load and go through dwarf
info section to process information.
* dwarf.c (insert_element_in_list): New function. Retrieve valuable
information from dwarf attributes of all DWARF debug information
entries.
(get_location_expression): New function. Useful to retrieve
DW_AT_location value which gives the data object location.
(read_and_display_attr_value): Add arguments useful to identify DWARF
information entry, and instrument with function
insert_element_in_list.
(read_and_display_attr): Add arguments useful to identify DWARF
information entry.
(process_debug_info): Add argument to process DWARF information entry
for the display of global variable information.
(display_variable_mapping_info): New function.
binutils/doc/
* binutils.texi: Add documentation for new option -Y/--map-file.
---
binutils/doc/binutils.texi | 7 +
binutils/dwarf.c | 400 ++++++++++++++++++++++++++++++++++---
binutils/dwarf.h | 1 +
binutils/objdump.c | 85 +++++++-
4 files changed, 467 insertions(+), 26 deletions(-)
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 4543341e00c..cccff298330 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2294,6 +2294,7 @@ objdump [@option{-a}|@option{--archive-headers}]
[@option{-WN}|@option{--dwarf=no-follow-links}]
[@option{-wD}|@option{--dwarf=use-debuginfod}]
[@option{-wE}|@option{--dwarf=do-not-use-debuginfod}]
+ [@option{-Y}|@option{--map-file}]
[@option{-L}|@option{--process-links}]
[@option{--ctf=}@var{section}]
[@option{--sframe=}@var{section}]
@@ -2540,6 +2541,12 @@ for specification with @option{-b} or @option{-m}.
Display information for section @var{name}. This option may be
specified multiple times.
+@item -Y
+@itemx --map-file
+Display global variable information. This option only works when the object
+file is compiled with debug option. Useful to track the location and the
+type of all global variables in the passed object file.
+
@item -L
@itemx --process-links
Display the contents of non-debug sections found in separate debuginfo
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index f4bcb677761..6b24828736b 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -1162,6 +1162,141 @@ display_block (unsigned char *data,
return data;
}
+static int
+get_location_expression (int die_tag,
+ unsigned long attribute,
+ unsigned char * data,
+ unsigned int pointer_size,
+ unsigned int offset_size,
+ int dwarf_version,
+ uint64_t length,
+ uint64_t die_offset,
+ uint64_t cu_offset,
+ struct dwarf_section * section)
+{
+ unsigned op;
+ uint64_t uvalue = 0;
+ int64_t svalue;
+ unsigned char *end = data + length;
+ int need_frame_base = 0;
+
+ while (data < end)
+ {
+ op = *data++;
+
+ switch (op)
+ {
+ case DW_OP_addr:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+ break;
+ case DW_OP_const1u:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
+ break;
+ case DW_OP_const1s:
+ SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 1, end);
+ break;
+ case DW_OP_const2u:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
+ break;
+ case DW_OP_const2s:
+ SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
+ break;
+ case DW_OP_const4u:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
+ break;
+ case DW_OP_const4s:
+ SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
+ break;
+ case DW_OP_const8u:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 8, end);
+ break;
+ case DW_OP_const8s:
+ SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 8, end);
+ break;
+ case DW_OP_bra:
+ SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
+ break;
+ case DW_OP_skip:
+ SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
+ break;
+
+ case DW_OP_deref_size:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
+ break;
+ case DW_OP_xderef_size:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
+ break;
+
+ case DW_OP_call2:
+ SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
+ break;
+ case DW_OP_call4:
+ SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
+ break;
+ case DW_OP_call_ref:
+ if (dwarf_version == -1)
+ /* No way to tell where the next op is, so just bail. */
+ return need_frame_base;
+ else 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);
+ break;
+ case DW_OP_implicit_value:
+ READ_ULEB (uvalue, data, end);
+ break;
+ case DW_OP_implicit_pointer:
+ case DW_OP_GNU_implicit_pointer:
+ if (dwarf_version == -1)
+ return need_frame_base;
+ else 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);
+ break;
+ case DW_OP_entry_value:
+ case DW_OP_GNU_entry_value:
+ READ_ULEB (uvalue, data, end);
+ /* PR 17531: file: 0cc9cd00. */
+ if (uvalue > (size_t) (end - data))
+ uvalue = end - data;
+ if (get_location_expression
+ (die_tag, attribute, data, pointer_size, offset_size,
+ dwarf_version, uvalue, die_offset, cu_offset, section))
+ need_frame_base = 1;
+ data += uvalue;
+ break;
+ case DW_OP_const_type:
+ case DW_OP_GNU_const_type:
+ READ_ULEB (uvalue, data, end);
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
+ break;
+ case DW_OP_deref_type:
+ case DW_OP_GNU_deref_type:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
+ break;
+ case DW_OP_GNU_parameter_ref:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
+ break;
+ case DW_OP_addrx:
+ READ_ULEB (uvalue, data, end);
+ break;
+ case DW_OP_GNU_variable_value:
+ if (dwarf_version == -1)
+ return need_frame_base;
+ else 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);
+ break;
+
+ default:
+ return need_frame_base;
+ }
+ }
+ return need_frame_base;
+}
+
static int
decode_location_expression (unsigned char * data,
unsigned int pointer_size,
@@ -2432,6 +2567,53 @@ display_lang (uint64_t uvalue)
}
}
+static void
+insert_element_in_list (enum dwarf_tag dw_tag,
+ enum dwarf_attribute dw_attr ATTRIBUTE_UNUSED,
+ uint64_t die_offset ATTRIBUTE_UNUSED,
+ uint64_t *uvalue ATTRIBUTE_UNUSED,
+ int64_t *svalue ATTRIBUTE_UNUSED,
+ const unsigned char *data ATTRIBUTE_UNUSED)
+{
+ /* TODO: Retrieve attributes information from
+ below dwarf entries tag. */
+ switch (dw_tag)
+ {
+ /* Base type. */
+ case DW_TAG_base_type:
+ break;
+ /* typedef. */
+ case DW_TAG_typedef:
+ break;
+ /* enumeration. */
+ case DW_TAG_enumerator:
+ break;
+ case DW_TAG_enumeration_type:
+ break;
+ /* Array type. */
+ case DW_TAG_subrange_type:
+ break;
+ case DW_TAG_array_type:
+ break;
+ /* Memnber type. */
+ case DW_TAG_member:
+ break;
+ /* Structure type. */
+ case DW_TAG_structure_type:
+ /* Union type. */
+ case DW_TAG_union_type:
+ break;
+ case DW_TAG_const_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_pointer_type:
+ break;
+ case DW_TAG_variable:
+ break;
+ default:
+ break;
+ }
+}
+
static unsigned char *
read_and_display_attr_value (unsigned long attribute,
unsigned long form,
@@ -2448,7 +2630,10 @@ read_and_display_attr_value (unsigned long attribute,
struct dwarf_section *section,
struct cu_tu_set *this_set,
char delimiter,
- int level)
+ int level,
+ int do_var_map,
+ int die_tag,
+ unsigned long die_offset)
{
int64_t svalue;
uint64_t uvalue = 0;
@@ -2574,7 +2759,8 @@ read_and_display_attr_value (unsigned long attribute,
cu_offset, pointer_size,
offset_size, dwarf_version,
debug_info_p, do_loc,
- section, this_set, delimiter, level);
+ section, this_set, delimiter, level,
+ do_var_map, die_tag, die_offset);
case DW_FORM_implicit_const:
uvalue = implicit_const;
@@ -2589,6 +2775,9 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_ref_addr:
if (!do_loc)
printf ("%c<%#" PRIx64 ">", delimiter, uvalue);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue, NULL, NULL);
break;
case DW_FORM_GNU_ref_alt:
@@ -2600,6 +2789,9 @@ read_and_display_attr_value (unsigned long attribute,
else
printf ("%c<alt %#" PRIx64 ">", delimiter, uvalue);
}
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue, NULL, NULL);
/* FIXME: Follow the reference... */
break;
@@ -2608,8 +2800,14 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_ref4:
case DW_FORM_ref_sup4:
case DW_FORM_ref_udata:
- if (!do_loc)
- printf ("%c<%#" PRIx64 ">", delimiter, uvalue + cu_offset);
+ {
+ uint64_t utmp = uvalue + cu_offset;
+ if (!do_loc)
+ printf ("%c<%#" PRIx64 ">", delimiter, utmp);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &utmp, NULL, NULL);
+ }
break;
case DW_FORM_data4:
@@ -2617,6 +2815,9 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_sec_offset:
if (!do_loc)
printf ("%c%#" PRIx64, delimiter, uvalue);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue, NULL, NULL);
break;
case DW_FORM_flag_present:
@@ -2626,27 +2827,40 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_sdata:
if (!do_loc)
printf ("%c%" PRId64, delimiter, uvalue);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue, NULL, NULL);
break;
case DW_FORM_udata:
if (!do_loc)
printf ("%c%" PRIu64, delimiter, uvalue);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue, NULL, NULL);
break;
case DW_FORM_implicit_const:
if (!do_loc)
printf ("%c%" PRId64, delimiter, implicit_const);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ NULL, &implicit_const, NULL);
break;
case DW_FORM_ref_sup8:
case DW_FORM_ref8:
case DW_FORM_data8:
- if (!do_loc)
+ if (!do_loc || do_var_map)
{
uint64_t utmp = uvalue;
if (form == DW_FORM_ref8)
utmp += cu_offset;
- printf ("%c%#" PRIx64, delimiter, utmp);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &utmp, NULL, NULL);
+ else
+ printf ("%c%#" PRIx64, delimiter, utmp);
}
break;
@@ -2658,11 +2872,23 @@ read_and_display_attr_value (unsigned long attribute,
else
printf (" %#" PRIx64 "%016" PRIx64, uvalue_hi, uvalue);
}
+ if (do_var_map)
+ {
+ if (uvalue_hi == 0)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue, NULL, NULL);
+ else
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue_hi, NULL, NULL);
+ }
break;
case DW_FORM_string:
if (!do_loc)
printf ("%c%.*s", delimiter, (int) (end - data), data);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ NULL, NULL, data);
data += strnlen ((char *) data, end - data);
if (data < end)
data++;
@@ -2716,6 +2942,9 @@ read_and_display_attr_value (unsigned long attribute,
printf (_("%c(indirect string, offset: %#" PRIx64 "): %s"),
delimiter, uvalue, fetch_indirect_string (uvalue));
}
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ NULL, NULL, fetch_indirect_string (uvalue));
break;
case DW_FORM_line_strp:
@@ -2729,6 +2958,9 @@ read_and_display_attr_value (unsigned long attribute,
printf (_("%c(indirect line string, offset: %#" PRIx64 "): %s"),
delimiter, uvalue, fetch_indirect_line_string (uvalue));
}
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ NULL, NULL, fetch_indirect_line_string (uvalue));
break;
case DW_FORM_GNU_str_index:
@@ -2752,6 +2984,9 @@ read_and_display_attr_value (unsigned long attribute,
else
printf (_("%c(indexed string: %#" PRIx64 "): %s"),
delimiter, uvalue, strng);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ NULL, NULL, (const unsigned char *) strng);
}
break;
@@ -2766,6 +3001,10 @@ read_and_display_attr_value (unsigned long attribute,
printf (_("%c(alt indirect string, offset: %#" PRIx64 ") %s"),
delimiter, uvalue, fetch_alt_indirect_string (uvalue));
}
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ NULL, NULL, (const unsigned char *)
+ fetch_alt_indirect_string (uvalue));
break;
case DW_FORM_indirect:
@@ -2776,6 +3015,9 @@ read_and_display_attr_value (unsigned long attribute,
if (!do_loc)
printf ("%c%s: %#" PRIx64, delimiter, do_wide ? "" : "signature",
uvalue);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue, NULL, NULL);
break;
case DW_FORM_GNU_addr_index:
@@ -2852,14 +3094,25 @@ read_and_display_attr_value (unsigned long attribute,
/* We have already displayed the form name. */
if (idx != (uint64_t) -1)
- printf (_("%c(index: %#" PRIx64 "): %#" PRIx64),
+ {
+ printf (_("%c(index: %#" PRIx64 "): %#" PRIx64),
delimiter, uvalue, idx);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &uvalue, NULL, NULL);
+ }
}
break;
case DW_FORM_strp_sup:
- if (!do_loc)
- printf ("%c<%#" PRIx64 ">", delimiter, uvalue + cu_offset);
+ {
+ uint64_t utmp = uvalue + cu_offset;
+ if (!do_loc)
+ printf ("%c<%#" PRIx64 ">", delimiter, utmp);
+ if (do_var_map)
+ insert_element_in_list (die_tag, attribute, die_offset,
+ &utmp, NULL, NULL);
+ }
break;
default:
@@ -3140,6 +3393,76 @@ read_and_display_attr_value (unsigned long attribute,
}
}
+ if (do_var_map && attribute != 0)
+ {
+ switch (attribute)
+ {
+ case DW_AT_frame_base:
+ case DW_AT_location:
+ case DW_AT_loclists_base:
+ case DW_AT_rnglists_base:
+ case DW_AT_str_offsets_base:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_data_member_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_use_location:
+ case DW_AT_call_value:
+ case DW_AT_GNU_call_site_value:
+ case DW_AT_call_data_value:
+ case DW_AT_GNU_call_site_data_value:
+ case DW_AT_call_target:
+ case DW_AT_GNU_call_site_target:
+ case DW_AT_call_target_clobbered:
+ case DW_AT_GNU_call_site_target_clobbered:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_stride:
+ case DW_AT_upper_bound:
+ case DW_AT_lower_bound:
+ case DW_AT_rank:
+ if (block_start)
+ {
+ get_location_expression (die_tag,
+ attribute,
+ block_start,
+ pointer_size,
+ offset_size,
+ dwarf_version,
+ die_offset,
+ uvalue,
+ cu_offset,
+ section);
+ }
+ break;
+ case DW_AT_data_bit_offset:
+ case DW_AT_byte_size:
+ case DW_AT_bit_size:
+ case DW_AT_string_length_byte_size:
+ case DW_AT_string_length_bit_size:
+ case DW_AT_bit_stride:
+ if (form == DW_FORM_exprloc)
+ {
+ get_location_expression (die_tag,
+ attribute,
+ block_start,
+ pointer_size,
+ offset_size,
+ dwarf_version,
+ die_offset,
+ uvalue,
+ cu_offset,
+ section);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
if (do_loc || attribute == 0)
return data;
@@ -3487,7 +3810,10 @@ read_and_display_attr (unsigned long attribute,
int do_loc,
struct dwarf_section *section,
struct cu_tu_set *this_set,
- int level)
+ int level,
+ int do_var_map,
+ int die_tag,
+ unsigned long die_offset)
{
if (!do_loc)
printf (" %-18s:", get_AT_name (attribute));
@@ -3495,7 +3821,8 @@ read_and_display_attr (unsigned long attribute,
start, data, end,
cu_offset, pointer_size, offset_size,
dwarf_version, debug_info_p,
- do_loc, section, this_set, ' ', level);
+ do_loc, section, this_set, ' ', level,
+ do_var_map, die_tag, die_offset);
if (!do_loc)
printf ("\n");
return data;
@@ -3750,6 +4077,8 @@ read_bases (abbrev_entry * entry,
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.
+ If do_var_map is TRUE, we are processing a .debug_types section without
+ displaying anything to the user yet.
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
@@ -3760,7 +4089,8 @@ process_debug_info (struct dwarf_section * section,
void *file,
enum dwarf_section_display_enum abbrev_sec,
bool do_loc,
- bool do_types)
+ bool do_types,
+ bool do_var_map)
{
unsigned char *start = section->start;
unsigned char *end = start + section->size;
@@ -3832,7 +4162,7 @@ process_debug_info (struct dwarf_section * section,
alloc_num_debug_info_entries = num_units;
}
- if (!do_loc)
+ if (!do_loc || do_var_map)
{
load_debug_section_with_follow (str, file);
load_debug_section_with_follow (line_str, file);
@@ -4306,7 +4636,10 @@ process_debug_info (struct dwarf_section * section,
do_loc || ! do_printing,
section,
this_set,
- level);
+ level,
+ do_var_map,
+ entry->tag,
+ die_offset);
}
/* If a locview attribute appears before a location one,
@@ -4381,12 +4714,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, true, false, false))
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, true, false, false))
return num_debug_info_entries;
num_debug_info_entries = DEBUG_INFO_UNAVAILABLE;
@@ -4609,7 +4943,8 @@ display_formatted_table (unsigned char *data,
0, 0, linfo->li_offset_size,
linfo->li_version, NULL,
((content_type == DW_LNCT_path) != (namepass == 1)),
- section, NULL, '\t', -1);
+ section, NULL, '\t', -1,
+ false, 0, 0);
}
}
@@ -5269,7 +5604,8 @@ display_debug_lines_decoded (struct dwarf_section * section,
linfo.li_offset_size,
linfo.li_version,
NULL, 1, section,
- NULL, '\t', -1);
+ NULL, '\t', -1,
+ false, 0, 0);
}
if (data >= end)
{
@@ -5368,7 +5704,8 @@ display_debug_lines_decoded (struct dwarf_section * section,
linfo.li_offset_size,
linfo.li_version,
NULL, 1, section,
- NULL, '\t', -1);
+ NULL, '\t', -1,
+ false, 0, 0);
}
if (data >= end)
{
@@ -6584,7 +6921,8 @@ display_debug_macro (struct dwarf_section *section,
start, curr, end, 0, 0,
offset_size, version,
NULL, 0, section,
- NULL, ' ', -1);
+ NULL, ' ', -1,
+ false, 0, 0);
if (n != nargs - 1)
printf (",");
}
@@ -7672,22 +8010,32 @@ display_debug_str (struct dwarf_section *section,
return 1;
}
+static int
+display_variable_mapping_info (struct dwarf_section *section, void *file)
+{
+ return process_debug_info (section, file, section->abbrev_sec,
+ true, false, true);
+}
+
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,
+ false, false, false);
}
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,
+ false, true, false);
}
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,
+ false, true, false);
}
static int
@@ -10952,7 +11300,8 @@ display_debug_names (struct dwarf_section *section, void *file)
0, 0, offset_size,
dwarf_version, NULL,
(tagno < 0), section,
- NULL, '=', -1);
+ NULL, '=', -1,
+ false, 0, 0);
}
++tagno;
}
@@ -12550,7 +12899,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))
+ true, false, false))
{
bool introduced = false;
dwo_info *dwinfo;
@@ -12906,6 +13255,7 @@ struct dwarf_section_display debug_displays[] =
in the main file. Hence we need to have two entries for .debug_str. */
{ { ".debug_str", ".zdebug_str", "", NO_ABBREVS }, display_debug_str, &do_debug_str, false },
{ { ".note.gnu.build-id", "", "", NO_ABBREVS }, display_debug_not_supported, NULL, false },
+ { { ".debug_info", ".zdebug_info", ".dwinfo", ABBREV (abbrev)}, display_variable_mapping_info, &do_debug_info, true }
};
/* A static assertion. */
diff --git a/binutils/dwarf.h b/binutils/dwarf.h
index 13afb4a0da3..8efd0c37b5b 100644
--- a/binutils/dwarf.h
+++ b/binutils/dwarf.h
@@ -124,6 +124,7 @@ enum dwarf_section_display_enum
debug_sup,
separate_debug_str,
note_gnu_build_id,
+ debug_variable_info,
max
};
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 0bea4d0761c..e955cf8ec89 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -138,6 +138,7 @@ static bool color_output = false; /* --visualize-jumps=color. */
static bool extended_color_output = false; /* --visualize-jumps=extended-color. */
static int process_links = false; /* --process-links. */
static int show_all_symbols; /* --show-all-symbols. */
+static bool dump_map_file; /* -Y, --map-file. */
static bool decompressed_dumps = false; /* -Z, --decompress. */
static struct symbol_entry
@@ -327,6 +328,8 @@ usage (FILE *stream, int status)
-WE --dwarf=do-not-use-debuginfod\n\
When following links, do not query debuginfod servers\n"));
#endif
+ fprintf (stream, _("\
+ -Y, --map-file Display memory mapping of global variables\n"));
fprintf (stream, _("\
-L, --process-links Display the contents of non-debug sections in\n\
separate debuginfo files. (Implies -WK)\n"));
@@ -567,6 +570,7 @@ static struct option long_options[]=
{"visualize-jumps", optional_argument, 0, OPTION_VISUALIZE_JUMPS},
{"wide", no_argument, NULL, 'w'},
{"disassembler-color", required_argument, NULL, OPTION_DISASSEMBLER_COLOR},
+ {"map-file", no_argument, NULL, 'Y'},
{NULL, no_argument, NULL, 0}
};
@@ -4528,6 +4532,42 @@ dump_dwarf_section (bfd *abfd, asection *section,
}
}
+static void
+dump_global_variable_info (bfd *abfd, asection *section,
+ void *arg)
+{
+ const char *name = bfd_section_name (section);
+ const char *match;
+ bool is_mainfile = *(bool *) arg;
+
+ if (*name == 0)
+ return;
+
+ if (!is_mainfile && !process_links
+ && (section->flags & SEC_DEBUGGING) == 0)
+ return;
+
+ if (startswith (name, ".gnu.linkonce.wi."))
+ match = ".debug_info";
+ else
+ match = name;
+
+ if (((strcmp (debug_displays[info].section.uncompressed_name,match) == 0
+ || strcmp (debug_displays[info].section.compressed_name, match) == 0
+ || strcmp (debug_displays[info].section.xcoff_name, match) == 0))
+ && debug_displays[info].enabled != NULL
+ && *debug_displays[info].enabled)
+ {
+ struct dwarf_section *sec = &debug_displays[info].section;
+
+ if (load_specific_debug_section (info, section, abfd))
+ {
+ debug_displays [debug_variable_info].display (sec, abfd);
+ free_debug_section (info);
+ }
+ }
+}
+
/* Dump the dwarf debugging information. */
static void
@@ -4560,6 +4600,41 @@ dump_dwarf (bfd *abfd, bool is_mainfile)
bfd_map_over_sections (abfd, dump_dwarf_section, (void *) &is_mainfile);
}
+
+/* Dump all global variable information in memory. */
+
+static void
+dump_map_file_info (bfd *abfd, bool is_mainfile)
+{
+ /* The byte_get pointer should have been set at the start of dump_bfd (). */
+ if (byte_get == NULL)
+ {
+ warn (_ ("File %s does not contain any dwarf debug information\n"),
+ bfd_get_filename (abfd));
+ return;
+ }
+
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_s12z:
+ /* S12Z has a 24 bit address space. But the only known
+ producer of dwarf_info encodes addresses into 32 bits. */
+ eh_addr_size = 4;
+ break;
+
+ default:
+ eh_addr_size = bfd_arch_bits_per_address (abfd) / 8;
+ break;
+ }
+
+ init_dwarf_by_bfd_arch_and_mach (bfd_get_arch (abfd),
+ bfd_get_mach (abfd));
+
+ bfd_map_over_sections (abfd,
+ dump_global_variable_info,
+ (void *) &is_mainfile);
+}
+
/* Read ABFD's section SECT_NAME into *CONTENTS, and return a pointer to
the section. Return NULL on failure. */
@@ -5829,6 +5904,8 @@ dump_bfd (bfd *abfd, bool is_mainfile)
if (dump_dynamic_symtab)
dump_symbols (abfd, true);
}
+ if (dump_map_file)
+ dump_map_file_info (abfd, is_mainfile);
if (dump_dwarf_section_info)
dump_dwarf (abfd, is_mainfile);
if (is_mainfile || process_links)
@@ -6039,7 +6116,7 @@ main (int argc, char **argv)
set_default_bfd_target ();
while ((c = getopt_long (argc, argv,
- "CDE:FGHI:LM:P:RSTU:VW::Zab:defghij:lm:prstvwxz",
+ "CDE:FGHI:LM:P:RSTU:VW::Zab:defghij:lm:prstvwxz::Y",
long_options, (int *) 0))
!= EOF)
{
@@ -6284,6 +6361,11 @@ main (int argc, char **argv)
process_links = true;
do_follow_links = true;
break;
+ case 'Y':
+ dump_map_file = true;
+ dwarf_select_sections_all ();
+ seenflag = true;
+ break;
case 'W':
seenflag = true;
if (optarg)
@@ -6423,6 +6505,7 @@ main (int argc, char **argv)
dump_any_debugging = (dump_debugging
|| dump_dwarf_section_info
+ || dump_map_file
|| process_links
|| with_source_code);
--
2.25.1
More information about the Binutils
mailing list