This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[PATCH]: Add support for displaying location lists to readelf
- From: Daniel Berlin <dan at dberlin dot org>
- To: binutils at sources dot redhat dot com
- Date: 20 Mar 2002 12:07:27 -0500
- Subject: [PATCH]: Add support for displaying location lists to readelf
- Organization:
We don't display them inline, because they can get very long.
This patch was tested against a gcc that can generate location lists for variables.
The output looks like this:
Contents of the .debug_loc section:
Offset Begin End Expression
00000000 00000024 00000028 (DW_OP_fbreg: 8; )
00000000 00000028 0000003c (DW_OP_reg0; )
00000000 0000003c 00000040 (DW_OP_fbreg: 8; )
00000000 00000040 00000080 (DW_OP_reg0; )
00000000 00000080 00000084 (DW_OP_fbreg: 8; )
00000000 00000084 0000008c (DW_OP_reg9; )
00000000 0000008c 00000090 (DW_OP_fbreg: 8; )
00000000 00000090 000000a0 (DW_OP_reg0; )
00000000 000000a0 000000a4 (DW_OP_fbreg: 8; )
00000000 000000a4 000000d0 (DW_OP_reg4; )
0000007b 0000004c 00000050 (DW_OP_fbreg: 12; )
0000007b 00000050 00000090 (DW_OP_reg0; )
0000007b 00000090 00000094 (DW_OP_fbreg: 12; )
0000007b 00000094 000000a4 (DW_OP_reg0; )
0000007b 000000a4 000000a8 (DW_OP_fbreg: 12; )
0000007b 000000a8 000000d0 (DW_OP_reg5; )
000000c8 00000048 00000070 (DW_OP_fbreg: 16; )
000000c8 00000070 000000a8 (DW_OP_reg9; )
000000c8 000000a8 000000ac (DW_OP_fbreg: 16; )
000000c8 000000ac 000000d0 (DW_OP_reg6; )
2002-03-20 Daniel Berlin <dan@dberlin.org>
* readelf.c: Add support for displaying dwarf2 location lists.
(do_debug_loc, debug_loc_section, debug_loc_size): New.
(parse_args): Use 'O' as shorthand for displaying location list
section.
(process_section_headers): Handle debug_loc as well.
(load_debug_loc): New.
(free_debug_loc): New.
(fetch_location_list): New.
(display_debug_loc): New.
(display_debug_info): Call load_debug_loc and free_debug_loc.
(debug_displays): We can display .debug_loc now, too.
(usage): Update usage string.
(read_and_display_attr_value): Note location lists, but don't
display them inline.
Index: readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.153
diff -c -3 -p -w -B -b -r1.153 readelf.c
*** readelf.c 2002/02/21 22:39:19 1.153
--- readelf.c 2002/03/20 17:03:45
*************** int do_debug_frames;
*** 127,132 ****
--- 127,133 ----
int do_debug_frames_interp;
int do_debug_macinfo;
int do_debug_str;
+ int do_debug_loc;
int do_arch;
int do_notes;
int is_32bit_elf;
*************** static int display_debug_
*** 227,236 ****
--- 228,241 ----
static int display_debug_frames PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *));
static int display_debug_macinfo PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *));
static int display_debug_str PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *));
+ static int display_debug_loc PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *));
static unsigned char * process_abbrev_section PARAMS ((unsigned char *, unsigned char *));
static void load_debug_str PARAMS ((FILE *));
static void free_debug_str PARAMS ((void));
static const char * fetch_indirect_string PARAMS ((unsigned long));
+ static void load_debug_loc PARAMS ((FILE *));
+ static void free_debug_loc PARAMS ((void));
+ static const char * fetch_location_list PARAMS ((unsigned long));
static unsigned long read_leb128 PARAMS ((unsigned char *, int *, int));
static int process_extended_line_op PARAMS ((unsigned char *, int, int));
static void reset_state_machine PARAMS ((int));
*************** usage ()
*** 2248,2254 ****
-A --arch-specific Display architecture specific information (if any).\n\
-D --use-dynamic Use the dynamic section info when displaying symbols\n\
-x --hex-dump=<number> Dump the contents of section <number>\n\
! -w --debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=str]\n\
Display the contents of DWARF2 debug sections\n"));
#ifdef SUPPORT_DISASSEMBLY
fprintf (stdout, _("\
--- 2253,2259 ----
-A --arch-specific Display architecture specific information (if any).\n\
-D --use-dynamic Use the dynamic section info when displaying symbols\n\
-x --hex-dump=<number> Dump the contents of section <number>\n\
! -w --debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=str,=loc]\n\
Display the contents of DWARF2 debug sections\n"));
#ifdef SUPPORT_DISASSEMBLY
fprintf (stdout, _("\
*************** parse_args (argc, argv)
*** 2435,2440 ****
--- 2440,2450 ----
do_debug_str = 1;
break;
+ case 'o':
+ case 'O':
+ do_debug_loc = 1;
+ break;
+
default:
warn (_("Unrecognized debug option '%s'\n"), optarg);
break;
*************** process_section_headers (file)
*** 3301,3307 ****
}
else if ((do_debugging || do_debug_info || do_debug_abbrevs
|| do_debug_lines || do_debug_pubnames || do_debug_aranges
! || do_debug_frames || do_debug_macinfo || do_debug_str)
&& strncmp (name, ".debug_", 7) == 0)
{
name += 7;
--- 3311,3318 ----
}
else if ((do_debugging || do_debug_info || do_debug_abbrevs
|| do_debug_lines || do_debug_pubnames || do_debug_aranges
! || do_debug_frames || do_debug_macinfo || do_debug_str
! || do_debug_loc)
&& strncmp (name, ".debug_", 7) == 0)
{
name += 7;
*************** process_section_headers (file)
*** 3315,3320 ****
--- 3326,3332 ----
|| (do_debug_frames && (strcmp (name, "frame") == 0))
|| (do_debug_macinfo && (strcmp (name, "macinfo") == 0))
|| (do_debug_str && (strcmp (name, "str") == 0))
+ || (do_debug_loc && (strcmp (name, "loc") == 0))
)
request_dump (i, DEBUG_DUMP);
}
*************** decode_location_expression (data, pointe
*** 7187,7193 ****
--- 7199,7322 ----
}
}
+ static const char * debug_loc_contents;
+ static bfd_vma debug_loc_size;
+
+ static void
+ load_debug_loc (file)
+ FILE * file;
+ {
+ Elf32_Internal_Shdr * sec;
+ unsigned int i;
+
+ /* If it is already loaded, do nothing. */
+ if (debug_loc_contents != NULL)
+ return;
+
+ /* Locate the .debug_loc section. */
+ for (i = 0, sec = section_headers;
+ i < elf_header.e_shnum;
+ i ++, sec ++)
+ if (strcmp (SECTION_NAME (sec), ".debug_loc") == 0)
+ break;
+
+ if (i == elf_header.e_shnum || sec->sh_size == 0)
+ return;
+
+ debug_loc_size = sec->sh_size;
+
+ debug_loc_contents = ((char *)
+ get_data (NULL, file, sec->sh_offset, sec->sh_size,
+ _("debug_loc section data")));
+ }
+
+ static void
+ free_debug_loc ()
+ {
+ if (debug_loc_contents == NULL)
+ return;
+
+ free ((char *) debug_loc_contents);
+ debug_loc_contents = NULL;
+ debug_loc_size = 0;
+ }
+
+ static const char *
+ fetch_location_list (offset)
+ unsigned long offset;
+ {
+ if (debug_loc_contents == NULL)
+ return _("<no .debug_loc section>");
+ if (offset > debug_loc_size)
+ return _("<offset is too big>");
+
+ return debug_loc_contents + offset;
+ }
+ static int
+ display_debug_loc (section, start, file)
+ Elf32_Internal_Shdr * section;
+ unsigned char * start;
+ FILE * file ATTRIBUTE_UNUSED;
+ {
+ unsigned char *section_end;
+ unsigned long bytes;
+ unsigned char *section_begin = start;
+ bfd_vma addr;
+
+ addr = section->sh_addr;
+ bytes = section->sh_size;
+ section_end = start + bytes;
+ if (bytes == 0)
+ {
+ printf (_("\nThe .debug_loc section is empty.\n"));
+ return 0;
+ }
+ printf (_("Contents of the .debug_loc section:\n\n"));
+ printf (_("\n Offset Begin End Expression\n"));
+ while (start < section_end)
+ {
+ unsigned long begin;
+ unsigned long end;
+ unsigned short length;
+ unsigned long offset;
+
+ offset = start - section_begin;
+
+ while (1)
+ {
+ /* Normally, the lists in the debug_loc section are related to a
+ given compilation unit, and thus, we would use the
+ pointer size of that compilation unit. However, since we are
+ displaying it seperately here, we either have to store
+ pointer sizes of all compilation units, or assume they don't
+ change. We assume, like the debug_line display, that
+ it doesn't change. */
+ begin = byte_get (start, debug_line_pointer_size);
+ start += debug_line_pointer_size;
+ end = byte_get (start, debug_line_pointer_size);
+ start += debug_line_pointer_size;
+
+ if (begin == 0 && end == 0)
+ break;
+
+ begin += addr;
+ end += addr;
+
+ length = byte_get (start, 2);
+ start += 2;
+
+ printf (" %8.8lx %8.8lx %8.8lx (", offset, begin, end);
+ decode_location_expression (start, debug_line_pointer_size, length);
+ printf (")\n");
+
+ start += length;
+ }
+ printf ("\n");
+ }
+ return 1;
+ }
+
static const char * debug_str_contents;
static bfd_vma debug_str_size;
*************** read_and_display_attr_value (attribute,
*** 7591,7596 ****
--- 7720,7731 ----
decode_location_expression (block_start, pointer_size, uvalue);
printf (")");
}
+ else if (form == DW_FORM_data4)
+ {
+ printf ("(");
+ printf ("location list");
+ printf (")");
+ }
break;
default:
*************** display_debug_info (section, start, file
*** 7627,7632 ****
--- 7762,7768 ----
printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
load_debug_str (file);
+ load_debug_loc (file);
while (start < end)
{
*************** display_debug_info (section, start, file
*** 7811,7816 ****
--- 7947,7953 ----
}
free_debug_str ();
+ free_debug_loc ();
printf ("\n");
*************** debug_displays[] =
*** 8622,8628 ****
{ ".eh_frame", display_debug_frames, NULL },
{ ".debug_macinfo", display_debug_macinfo, NULL },
{ ".debug_str", display_debug_str, NULL },
!
{ ".debug_pubtypes", display_debug_not_supported, NULL },
{ ".debug_ranges", display_debug_not_supported, NULL },
{ ".debug_static_func", display_debug_not_supported, NULL },
--- 8759,8765 ----
{ ".eh_frame", display_debug_frames, NULL },
{ ".debug_macinfo", display_debug_macinfo, NULL },
{ ".debug_str", display_debug_str, NULL },
! { ".debug_loc", display_debug_loc, NULL },
{ ".debug_pubtypes", display_debug_not_supported, NULL },
{ ".debug_ranges", display_debug_not_supported, NULL },
{ ".debug_static_func", display_debug_not_supported, NULL },