[PATCH v3 2/5] objdump: New feature display of global variable information based on DWARF info section

Guillaume VACHERIAS guillaume.vacherias@foss.st.com
Mon Sep 1 17:50:41 GMT 2025


Add in objdump option --map-global-vars to display global variable information

binutils/

	* objdump.c (dump_global_vars_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 --map-global-vars.

Signed-off-by: Guillaume VACHERIAS <guillaume.vacherias@foss.st.com>
---
 binutils/ChangeLog         |  22 ++-
 binutils/doc/binutils.texi |   7 +
 binutils/dwarf.c           | 382 +++++++++++++++++++++++++++++++++++--
 binutils/dwarf.h           |   1 +
 binutils/objdump.c         |  86 ++++++++-
 5 files changed, 478 insertions(+), 20 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 0c061efcb17..72f0ed9eb0a 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,8 +1,28 @@
 2025-09-01  Guillaume Vacherias <guillaume.vacherias@foss.st.com>
-	* dwarf.c (DO_LOC, DO_TYPES): Define.
+	* dwarf.c (DO_LOC, DO_TYPES, DO_GLOBAL_VARS): Define.
 	(process_debug_info): Change arguments do_loc and do_types
 	to a single unsigned int do_flags.
+	(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.
 	(find_cu_tu_set_v2): Change parameter do_types from int to bool.
+	(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.
+
+	* objdump.c (dump_global_vars_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.
+
+	* doc/binutils.texi: Add documentation for new option --map-global-vars.
 
 2025-07-13  Nick Clifton  <nickc@redhat.com>
 
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 4543341e00c..de8b03dbcb5 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{--map-global-vars}]
         [@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 --map-global-vars
+Display global variable information.  This option only works when the object
+file is compiled with the debug option.  More precisely, it relies on DWARF2
+debug information entries.  It is useful for tracking the location and type of
+all global variables in the given 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 b2bb3e595fe..29aec096d95 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -53,6 +53,7 @@
 
 #define DO_LOC     0x1
 #define DO_TYPES   0x2
+#define DO_GLOBAL_VARS 0x4
 
 static const char *regname (unsigned int regno, int row);
 static const char *regname_internal_by_table_only (unsigned int regno);
@@ -1165,6 +1166,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,
@@ -2435,6 +2571,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 type.  */
+    case DW_TAG_typedef:
+      break;
+    /* enumeration type.  */
+    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;
+    /* Member 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,
@@ -2451,7 +2634,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;
@@ -2577,7 +2763,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;
@@ -2592,6 +2779,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:
@@ -2603,6 +2793,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;
 
@@ -2611,8 +2804,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:
@@ -2620,6 +2819,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:
@@ -2629,27 +2831,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;
 
@@ -2661,11 +2876,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++;
@@ -2719,6 +2946,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:
@@ -2732,6 +2962,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:
@@ -2755,6 +2988,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;
 
@@ -2769,6 +3005,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:
@@ -2779,6 +3019,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:
@@ -2855,14 +3098,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:
@@ -3143,6 +3397,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;
 
@@ -3490,7 +3814,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));
@@ -3498,7 +3825,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;
@@ -3753,6 +4081,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
@@ -3834,7 +4164,7 @@ process_debug_info (struct dwarf_section * section,
       alloc_num_debug_info_entries = num_units;
     }
 
-  if (!(do_flags & DO_LOC))
+  if (!(do_flags & DO_LOC) || do_flags & DO_GLOBAL_VARS)
     {
       load_debug_section_with_follow (str, file);
       load_debug_section_with_follow (line_str, file);
@@ -4316,7 +4646,10 @@ process_debug_info (struct dwarf_section * section,
 					    || ! do_printing,
 					    section,
 					    this_set,
-					    level);
+					    level,
+					    do_flags & DO_GLOBAL_VARS,
+					    entry->tag,
+					    die_offset);
 	    }
 
 	  /* If a locview attribute appears before a location one,
@@ -4620,7 +4953,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);
 	    }
 	}
 
@@ -5280,7 +5614,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)
 		    {
@@ -5379,7 +5714,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)
 		    {
@@ -6595,7 +6931,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 (",");
 		    }
@@ -7683,6 +8020,13 @@ 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,
+			     DO_LOC | DO_GLOBAL_VARS);
+}
+
 static int
 display_debug_info (struct dwarf_section *section, void *file)
 {
@@ -10972,7 +11316,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;
 	    }
@@ -12926,6 +13271,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..d6014e5a5e1 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_global_vars;              /* --map-global-vars.  */
 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, _("\
+      --map-global-vars    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"));
@@ -496,7 +499,8 @@ enum option_values
 #endif
     OPTION_SFRAME,
     OPTION_VISUALIZE_JUMPS,
-    OPTION_DISASSEMBLER_COLOR
+    OPTION_DISASSEMBLER_COLOR,
+    OPTION_MAP_GLOBAL_VARS
   };
 
 static struct option long_options[]=
@@ -567,6 +571,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-global-vars", no_argument, NULL, OPTION_MAP_GLOBAL_VARS},
   {NULL, no_argument, NULL, 0}
 };
 
@@ -4528,6 +4533,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 +4601,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_global_vars_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 +5905,8 @@ dump_bfd (bfd *abfd, bool is_mainfile)
       if (dump_dynamic_symtab)
 	dump_symbols (abfd, true);
     }
+  if (dump_global_vars)
+    dump_global_vars_info (abfd, is_mainfile);
   if (dump_dwarf_section_info)
     dump_dwarf (abfd, is_mainfile);
   if (is_mainfile || process_links)
@@ -6284,6 +6362,11 @@ main (int argc, char **argv)
 	  process_links = true;
 	  do_follow_links = true;
 	  break;
+	case OPTION_MAP_GLOBAL_VARS:
+	  dump_global_vars = true;
+	  dwarf_select_sections_all ();
+	  seenflag = true;
+	  break;
 	case 'W':
 	  seenflag = true;
 	  if (optarg)
@@ -6423,6 +6506,7 @@ main (int argc, char **argv)
 
   dump_any_debugging = (dump_debugging
 			|| dump_dwarf_section_info
+			|| dump_global_vars
 			|| process_links
 			|| with_source_code);
 
-- 
2.25.1



More information about the Binutils mailing list