This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] decoded output of .debug_line from readelf -wL
- From: "Torleif Sandnes" <torleif dot sandnes at gmail dot com>
- To: binutils at sourceware dot org
- Date: Sun, 25 Feb 2007 16:31:56 +0100
- Subject: [PATCH] decoded output of .debug_line from readelf -wL
- Dkim-signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:mime-version:content-type; b=qJS6VLHyLg7eW2TgbZ5Nd8O/CmOcOfBONJ+N8CwXnddwr8Smjc5hjticQY3qDyAFP56GxAa5C+yAGz0hqDCx3Y5UAsxVPFgBWGCKbHuvbZ4j+Tq5G/r4rhpJZrITyc2aEKjtjFfLL7hvh998hgHGuQD/eUC6qhG8lgjDk7SPUTU=
Hi.
I added the option -WL to readelf for outputting decoded address/line
information from the .debug_line section.
Let me know if you have any suggestions for improving the output or the source.
Torleif
? config.cache
? config.log
? dwarf_line_address.patch
? serdep.tmp
? bfd/.libs
? bfd/Makefile
? bfd/aout32.lo
? bfd/archive.lo
? bfd/archures.lo
? bfd/bfd-in3.h
? bfd/bfd.h
? bfd/bfd.lo
? bfd/bfdio.lo
? bfd/bfdver.h
? bfd/bfdwin.lo
? bfd/binary.lo
? bfd/cache.lo
? bfd/coffgen.lo
? bfd/cofflink.lo
? bfd/config.cache
? bfd/config.h
? bfd/config.log
? bfd/config.status
? bfd/corefile.lo
? bfd/cpu-i386.lo
? bfd/dwarf1.lo
? bfd/dwarf2.lo
? bfd/efi-app-ia32.lo
? bfd/elf-eh-frame.lo
? bfd/elf-strtab.lo
? bfd/elf-vxworks.lo
? bfd/elf.lo
? bfd/elf32-gen.lo
? bfd/elf32-i386.lo
? bfd/elf32-target.h
? bfd/elf32.lo
? bfd/elflink.lo
? bfd/format.lo
? bfd/hash.lo
? bfd/i386linux.lo
? bfd/ihex.lo
? bfd/init.lo
? bfd/libbfd.la
? bfd/libbfd.lo
? bfd/libtool
? bfd/linker.lo
? bfd/merge.lo
? bfd/ofiles
? bfd/opncls.lo
? bfd/peigen.c
? bfd/peigen.lo
? bfd/reloc.lo
? bfd/section.lo
? bfd/simple.lo
? bfd/srec.lo
? bfd/stab-syms.lo
? bfd/stabs.lo
? bfd/stamp-h1
? bfd/stamp-lib
? bfd/stamp-ofiles
? bfd/stmp-bfd-h
? bfd/syms.lo
? bfd/targets.lo
? bfd/targmatch.h
? bfd/tekhex.lo
? bfd/trad-core.lo
? bfd/doc/Makefile
? bfd/doc/aoutx.texi
? bfd/doc/archive.texi
? bfd/doc/archures.texi
? bfd/doc/bfd.info
? bfd/doc/bfdio.texi
? bfd/doc/bfdt.texi
? bfd/doc/bfdwin.texi
? bfd/doc/cache.texi
? bfd/doc/coffcode.texi
? bfd/doc/core.texi
? bfd/doc/elf.texi
? bfd/doc/elfcode.texi
? bfd/doc/format.texi
? bfd/doc/hash.texi
? bfd/doc/init.texi
? bfd/doc/libbfd.texi
? bfd/doc/linker.texi
? bfd/doc/mmo.texi
? bfd/doc/opncls.texi
? bfd/doc/reloc.texi
? bfd/doc/section.texi
? bfd/doc/syms.texi
? bfd/doc/targets.texi
? bfd/po/BLD-POTFILES
? bfd/po/Makefile
? bfd/po/Makefile.in
? bfd/po/SRC-POTFILES
? binutils/.libs
? binutils/Makefile
? binutils/arlex.c
? binutils/arparse.c
? binutils/arparse.h
? binutils/config.cache
? binutils/config.h
? binutils/config.log
? binutils/config.status
? binutils/libtool
? binutils/readelf
? binutils/stamp-h1
? binutils/doc/Makefile
? binutils/doc/addr2line.1
? binutils/doc/ar.1
? binutils/doc/binutils.info
? binutils/doc/config.texi
? binutils/doc/cxxfilt.man
? binutils/doc/dlltool.1
? binutils/doc/nlmconv.1
? binutils/doc/nm.1
? binutils/doc/objcopy.1
? binutils/doc/objdump.1
? binutils/doc/ranlib.1
? binutils/doc/readelf.1
? binutils/doc/size.1
? binutils/doc/strings.1
? binutils/doc/strip.1
? binutils/doc/windres.1
? binutils/po/Makefile
? binutils/po/Makefile.in
? binutils/po/POTFILES
? intl/Makefile
? intl/config.cache
? intl/config.h
? intl/config.intl
? intl/config.log
? intl/config.status
? libiberty/Makefile
? libiberty/config.cache
? libiberty/config.h
? libiberty/config.log
? libiberty/config.status
? libiberty/needed-list
? libiberty/required-list
? libiberty/stamp-h
? libiberty/stamp-picdir
? libiberty/xhost-mkfrag
? libiberty/testsuite/Makefile
? opcodes/.libs
? opcodes/Makefile
? opcodes/config.cache
? opcodes/config.h
? opcodes/config.log
? opcodes/config.status
? opcodes/dis-buf.lo
? opcodes/dis-init.lo
? opcodes/disassemble.lo
? opcodes/i386-dis.lo
? opcodes/libopcodes.la
? opcodes/libtool
? opcodes/stamp-h1
? opcodes/stamp-lib
? opcodes/po/Makefile
? opcodes/po/Makefile.in
? opcodes/po/POTFILES
Index: binutils/dwarf.c
===================================================================
RCS file: /cvs/src/src/binutils/dwarf.c,v
retrieving revision 1.11
diff -u -r1.11 dwarf.c
--- binutils/dwarf.c 6 Feb 2007 16:47:47 -0000 1.11
+++ binutils/dwarf.c 25 Feb 2007 15:08:32 -0000
@@ -41,6 +41,7 @@
int do_debug_info;
int do_debug_abbrevs;
int do_debug_lines;
+int do_debug_lines_addresses;
int do_debug_pubnames;
int do_debug_aranges;
int do_debug_ranges;
@@ -1802,17 +1803,9 @@
}
static int
-display_debug_lines (struct dwarf_section *section, void *file)
+display_debug_lines_raw(struct dwarf_section *section, unsigned char *data,
+ unsigned char *end)
{
- unsigned char *start = section->start;
- unsigned char *data = start;
- unsigned char *end = start + section->size;
-
- printf (_("\nDump of debug contents of section %s:\n\n"),
- section->name);
-
- load_debug_info (file);
-
while (data < end)
{
DWARF2_Internal_LineInfo info;
@@ -2075,6 +2068,393 @@
return 1;
}
+typedef struct
+{
+ unsigned char *name;
+ unsigned int directory_index;
+ unsigned int modification_date;
+ unsigned int length;
+} File_Entry;
+
+
+/* Output a decoded representation of the .debug_line section */
+static int
+display_debug_lines_decoded(struct dwarf_section *section, unsigned char *data,
+ unsigned char *end)
+{
+
+ while (data < end)
+ {
+ /* This loop amounts to one iteration per compilation unit */
+ DWARF2_Internal_LineInfo info;
+ unsigned char *standard_opcodes;
+ unsigned char *end_of_sequence;
+ unsigned char *hdrptr;
+ int initial_length_size;
+ int offset_size;
+ int i;
+ File_Entry *file_table = NULL;
+ unsigned char **directory_table = NULL;
+ unsigned int prev_line = 0;
+
+ hdrptr = data;
+
+ /* Extract information from the Line Number Program Header. */
+ /* (6.2.4 in the DWarf3 doc) */
+
+ /* Get the length of this CU's line number information block. */
+ info.li_length = byte_get (hdrptr, 4);
+ hdrptr += 4;
+
+ if (info.li_length == 0xffffffff)
+ {
+ /* This section is 64-bit DWARF 3. */
+ info.li_length = byte_get (hdrptr, 8);
+ hdrptr += 8;
+ offset_size = 8;
+ initial_length_size = 12;
+ }
+ else
+ {
+ offset_size = 4;
+ initial_length_size = 4;
+ }
+
+ if (info.li_length + initial_length_size > section->size)
+ {
+ warn (_("The line info appears to be corrupt - "
+ "the section is too small\n"));
+ return 0;
+ }
+
+ /* Get this CU's Line Number Block version number. */
+ info.li_version = byte_get (hdrptr, 2);
+ hdrptr += 2;
+ if (info.li_version != 2 && info.li_version != 3)
+ {
+ warn (_("Only DWARF version 2 and 3 line info is currently "
+ "supported.\n"));
+ return 0;
+ }
+
+ info.li_prologue_length = byte_get (hdrptr, offset_size);
+ hdrptr += offset_size;
+ info.li_min_insn_length = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_default_is_stmt = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_line_base = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_line_range = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_opcode_base = byte_get (hdrptr, 1);
+ hdrptr++;
+
+ /* Sign extend the line base field. */
+ info.li_line_base <<= 24;
+ info.li_line_base >>= 24;
+
+ /* Find the end of this CU's Line Number Information Block. */
+ end_of_sequence = data + info.li_length + initial_length_size;
+
+ reset_state_machine (info.li_default_is_stmt);
+
+ /* Save a pointer to the contents of the Opcodes table. */
+ standard_opcodes = hdrptr;
+
+ /* Traverse the Directory table just to count entries. */
+ data = standard_opcodes + info.li_opcode_base - 1;
+ if (*data != 0)
+ {
+ unsigned int n_directories = 0;
+ unsigned char *ptr_directory_table = data;
+ int i;
+ while (*data != 0)
+ {
+ data += strlen ((char *) data) + 1;
+ n_directories++;
+ }
+ /* Go through the directory table again to save the directories. */
+ directory_table = (unsigned char **)malloc(n_directories*sizeof(unsigned char *));
+ if(directory_table == NULL)
+ {
+ fprintf(stderr, _("Failed to allocate memory for the directories"
+ "table. (%d entries)\n"), n_directories);
+ exit(-1);
+ }
+
+ i = 0;
+ while(*ptr_directory_table != 0)
+ {
+ directory_table[i] = ptr_directory_table;
+ ptr_directory_table += strlen ((char *) ptr_directory_table) + 1;
+ i++;
+ }
+ }
+ /* Skip the NUL at the end of the table. */
+ data++;
+
+ /* Traverse the File Name table just to count the entries. */
+ if (*data != 0)
+ {
+ unsigned int n_files = 0;
+ unsigned char *ptr_file_name_table = data;
+ int i;
+ while (*data != 0)
+ {
+ unsigned int bytes_read;
+ /* Name, directory index, last modification time, length of file */
+ data += strlen ((char *) data) + 1;
+ read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+
+ n_files++;
+ }
+
+ /* Go through the file table again to save the strings. */
+ file_table = malloc(n_files*sizeof(File_Entry));
+ if(file_table == NULL)
+ {
+ fprintf(stderr, "Failed to allocate memory for the sourcefile table."
+ "(%d entries)\n", n_files);
+ exit(-1);
+ }
+
+ i = 0;
+ while(*ptr_file_name_table != 0)
+ {
+ unsigned int bytes_read;
+
+ file_table[i].name = ptr_file_name_table;
+ ptr_file_name_table += strlen ((char *) ptr_file_name_table) + 1;
+
+ /* Not interested in directory, time or size */
+ file_table[i].directory_index = read_leb128(ptr_file_name_table,
+ & bytes_read, 0);
+ ptr_file_name_table += bytes_read;
+ file_table[i].modification_date = read_leb128(ptr_file_name_table, & bytes_read, 0);
+ ptr_file_name_table += bytes_read;
+ file_table[i].length = read_leb128(ptr_file_name_table, & bytes_read, 0);
+ ptr_file_name_table += bytes_read;
+ i++;
+ }
+ i = 0;
+
+ if(directory_table == NULL)
+ {
+ printf(_("%s:\n"), file_table[0].name);
+ }
+ else
+ {
+ printf(_("%s/%s:\n"), directory_table[0],
+ file_table[0].name);
+ }
+ }
+
+ /* Skip the NUL at the end of the table. */
+ data++;
+
+ /* This loop iterates through the Dwarf Line Number Program: */
+ while (data < end_of_sequence)
+ {
+ unsigned char op_code;
+ int adv;
+ unsigned long int uladv;
+ unsigned int bytes_read;
+ int is_special_opcode = 0;
+
+ op_code = *data++;
+ prev_line = state_machine_regs.line;
+
+ if (op_code >= info.li_opcode_base)
+ {
+ op_code -= info.li_opcode_base;
+ uladv = (op_code / info.li_line_range) * info.li_min_insn_length;
+ state_machine_regs.address += uladv;
+
+ adv = (op_code % info.li_line_range) + info.li_line_base;
+ state_machine_regs.line += adv;
+ is_special_opcode = 1;
+ }
+ else switch (op_code)
+ {
+ case DW_LNS_extended_op:
+ {
+ unsigned int ext_op_code_len;
+ unsigned int bytes_read;
+ unsigned char ext_op_code;
+ unsigned char *op_code_data = data;
+
+ ext_op_code_len = read_leb128(op_code_data, &bytes_read, 0);
+ op_code_data += bytes_read;
+
+ if(ext_op_code_len == 0)
+ {
+ warn (_("badly formed extended line op encountered!\n"));
+ break;
+ }
+ ext_op_code_len += bytes_read;
+ ext_op_code = *op_code_data++;
+ switch (ext_op_code)
+ {
+ case DW_LNE_end_sequence:
+ reset_state_machine (info.li_default_is_stmt);
+ break;
+ case DW_LNE_set_address:
+ state_machine_regs.address =
+ byte_get (op_code_data, ext_op_code_len - bytes_read - 1);
+ break;
+ case DW_LNE_define_file:
+ {
+ unsigned int dir_index = 0;
+ ++state_machine_regs.last_file_entry;
+ op_code_data += strlen ((char *) op_code_data) + 1;
+ dir_index = read_leb128 (op_code_data, & bytes_read, 0);
+ op_code_data += bytes_read;
+ read_leb128 (op_code_data, & bytes_read, 0);
+ op_code_data += bytes_read;
+ read_leb128 (op_code_data, & bytes_read, 0);
+
+ printf(_("%s:\n"), directory_table[dir_index]);
+ break;
+ }
+ default:
+ printf (_("UNKNOWN: length %d\n"), ext_op_code_len - bytes_read);
+ break;
+ }
+ data += ext_op_code_len;
+ break;
+ }
+ case DW_LNS_copy:
+ break;
+
+ case DW_LNS_advance_pc:
+ uladv = read_leb128 (data, & bytes_read, 0);
+ uladv *= info.li_min_insn_length;
+ data += bytes_read;
+ state_machine_regs.address += uladv;
+ break;
+
+ case DW_LNS_advance_line:
+ adv = read_leb128 (data, & bytes_read, 1);
+ data += bytes_read;
+ state_machine_regs.line += adv;
+ break;
+
+ case DW_LNS_set_file:
+ adv = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ state_machine_regs.file = adv;
+ printf(_("%s/%s:\n"),
+ directory_table[file_table[state_machine_regs.file - 1].directory_index],
+ file_table[state_machine_regs.file - 1].name);
+ break;
+
+ case DW_LNS_set_column:
+ uladv = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ state_machine_regs.column = uladv;
+ break;
+
+ case DW_LNS_negate_stmt:
+ adv = state_machine_regs.is_stmt;
+ adv = ! adv;
+ state_machine_regs.is_stmt = adv;
+ break;
+
+ case DW_LNS_set_basic_block:
+ state_machine_regs.basic_block = 1;
+ break;
+
+ case DW_LNS_const_add_pc:
+ uladv = (((255 - info.li_opcode_base) / info.li_line_range)
+ * info.li_min_insn_length);
+ state_machine_regs.address += uladv;
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ uladv = byte_get (data, 2);
+ data += 2;
+ state_machine_regs.address += uladv;
+ break;
+
+ case DW_LNS_set_prologue_end:
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ break;
+
+ case DW_LNS_set_isa:
+ uladv = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ printf (_(" Set ISA to %lu\n"), uladv);
+ break;
+
+ default:
+ printf (_(" Unknown opcode %d with operands: "), op_code);
+
+ for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
+ {
+ printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0),
+ i == 1 ? "" : ", ");
+ data += bytes_read;
+ }
+ putchar ('\n');
+ break;
+ }
+
+ // Only Special opcodes, DW_LNS_copy and DW_LNE_end_sequence adds a row
+ // to the DWARF address/line matrix
+ if( (is_special_opcode) || (op_code == DW_LNE_end_sequence) ||
+ (op_code == DW_LNS_copy) )
+ {
+ printf(_("%s:%d:%d\t0x%08lx\n"), file_table[state_machine_regs.file - 1].name,
+ state_machine_regs.line, state_machine_regs.column,
+ state_machine_regs.address);
+ }
+ }
+ free(file_table);
+ file_table = NULL;
+ free(directory_table);
+ directory_table = NULL;
+ putchar ('\n');
+ }
+
+ return 1;
+}
+
+static int
+display_debug_lines (struct dwarf_section *section, void *file)
+{
+ unsigned char *start = section->start;
+ unsigned char *data = start;
+ unsigned char *end = start + section->size;
+ int retValRaw = 0;
+ int retValDecoded = 0;
+
+ printf (_("\nDump of debug contents of section %s:\n\n"),
+ section->name);
+
+ load_debug_info (file);
+
+ if (do_debug_lines)
+ retValRaw = display_debug_lines_raw(section, data, end);
+ if (do_debug_lines_addresses)
+ retValDecoded = display_debug_lines_decoded(section, data, end);
+
+ if( (do_debug_lines && !retValRaw) ||
+ (do_debug_lines_addresses && !retValDecoded) )
+ {
+ return 0;
+ }
+ else
+ return 1;
+}
+
static int
display_debug_pubnames (struct dwarf_section *section,
void *file ATTRIBUTE_UNUSED)
Index: binutils/dwarf.h
===================================================================
RCS file: /cvs/src/src/binutils/dwarf.h,v
retrieving revision 1.1
diff -u -r1.1 dwarf.h
--- binutils/dwarf.h 30 Sep 2005 14:55:05 -0000 1.1
+++ binutils/dwarf.h 25 Feb 2007 15:08:32 -0000
@@ -99,6 +99,7 @@
extern int do_debug_info;
extern int do_debug_abbrevs;
extern int do_debug_lines;
+extern int do_debug_lines_addresses;
extern int do_debug_pubnames;
extern int do_debug_aranges;
extern int do_debug_ranges;
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.360
diff -u -r1.360 readelf.c
--- binutils/readelf.c 17 Feb 2007 13:33:54 -0000 1.360
+++ binutils/readelf.c 25 Feb 2007 15:08:36 -0000
@@ -2969,10 +2969,13 @@
break;
case 'l':
- case 'L':
do_debug_lines = 1;
break;
+ case 'L':
+ do_debug_lines_addresses = 1;
+ break;
+
case 'p':
case 'P':
do_debug_pubnames = 1;
@@ -4155,17 +4158,18 @@
else if (section->sh_type == SHT_RELA)
CHECK_ENTSIZE (section, i, Rela);
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 || do_debug_ranges)
- && const_strneq (name, ".debug_"))
+ || do_debug_lines || do_debug_lines_addresses || do_debug_pubnames
+ || do_debug_aranges || do_debug_frames || do_debug_macinfo
+ || do_debug_str || do_debug_loc || do_debug_ranges)
+ && const_strneq (name, ".debug_"))
{
name += 7;
if (do_debugging
|| (do_debug_info && streq (name, "info"))
|| (do_debug_abbrevs && streq (name, "abbrev"))
- || (do_debug_lines && streq (name, "line"))
+ || ( (do_debug_lines || do_debug_lines_addresses)
+ && streq (name, "line"))
|| (do_debug_pubnames && streq (name, "pubnames"))
|| (do_debug_aranges && streq (name, "aranges"))
|| (do_debug_ranges && streq (name, "ranges"))