This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] decoded output of .debug_line from readelf -wL


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"))

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]