[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