* elflink.c (_bfd_elf_gc_mark_extra_sections): Remove mark from
authorNick Clifton <nickc@redhat.com>
Mon, 29 Apr 2013 13:38:59 +0000 (13:38 +0000)
committerNick Clifton <nickc@redhat.com>
Mon, 29 Apr 2013 13:38:59 +0000 (13:38 +0000)
fragmented .debug_line sections associated with unmarked code
sections.

* dwarf.c (read_debug_line_header): New function.  Reads in a
header in a .debug_line section.
(display_debug_lines_raw): Use new function.  Handle fragmentary
.debug_line sections.
(display_debug_lines_decoded): Likewise.
* readelf.c (process_section_headers): Handle fragmenatry
.debug_line sections.
(display_debug_section): Likewise.

* as.c (Options): Add -gdwarf-sections.
(parse_args): Likewise.
* as.h (flag_dwarf_sections): Declare.
* dwarf2dbg.c (emit_fixed_inc_line_addr): Skip section changes.
(process_entries): When -gdwarf-sections is enabled generate
fragmentary .debug_line sections.
(out_debug_line): Set the section for the .debug_line section end
symbol.
* doc/as.texinfo: Document -gdwarf-sections.
* NEWS: Mention -gdwarf-sections.

* gas/elf/dwarf2-3.d: Fix expected readelf output.

* scripttempl/DWARF.sc: Add support for .debug_line.* and
.debug_line_end.

15 files changed:
bfd/ChangeLog
bfd/elflink.c
binutils/ChangeLog
binutils/dwarf.c
binutils/readelf.c
gas/ChangeLog
gas/NEWS
gas/as.c
gas/as.h
gas/doc/as.texinfo
gas/dwarf2dbg.c
gas/testsuite/ChangeLog
gas/testsuite/gas/elf/dwarf2-3.d
ld/ChangeLog
ld/scripttempl/DWARF.sc

index 6c5739a..06bdfe7 100644 (file)
@@ -1,3 +1,9 @@
+2013-04-29  Nick Clifton  <nickc@redhat.com>
+
+       * elflink.c (_bfd_elf_gc_mark_extra_sections): Remove mark from
+       fragmented .debug_line sections associated with unmarked code
+       sections.
+
 2013-04-29  Will Newton  <will.newton@linaro.org>
 
        * elf32-arm.c (elf32_arm_populate_plt_entry): Call
index 313d89e..84ac1f2 100644 (file)
@@ -11814,23 +11814,30 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
     {
       asection *isec;
       bfd_boolean some_kept;
+      bfd_boolean debug_frag_seen;
 
       if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
        continue;
 
-      /* Ensure all linker created sections are kept, and see whether
-        any other section is already marked.  */
-      some_kept = FALSE;
+      /* Ensure all linker created sections are kept,
+        see if any other section is already marked,
+        and note if we have any fragmented debug sections.  */
+      debug_frag_seen = some_kept = FALSE;
       for (isec = ibfd->sections; isec != NULL; isec = isec->next)
        {
          if ((isec->flags & SEC_LINKER_CREATED) != 0)
            isec->gc_mark = 1;
          else if (isec->gc_mark)
            some_kept = TRUE;
+
+         if (debug_frag_seen == FALSE
+             && (isec->flags & SEC_DEBUGGING)
+             && CONST_STRNEQ (isec->name, ".debug_line."))
+           debug_frag_seen = TRUE;
        }
 
       /* If no section in this file will be kept, then we can
-        toss out debug sections.  */
+        toss out the debug and special sections.  */
       if (!some_kept)
        continue;
 
@@ -11842,6 +11849,45 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
            && ((isec->flags & SEC_DEBUGGING) != 0
                || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0))
          isec->gc_mark = 1;
+
+      if (! debug_frag_seen)
+       continue;
+
+      /* Look for CODE sections which are going to be discarded,
+        and find and discard any fragmented debug sections which
+        are associated with that code section.  */
+      for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+       if ((isec->flags & SEC_CODE) != 0
+           && isec->gc_mark == 0)
+         {
+           unsigned int ilen;
+           asection *dsec;
+
+           ilen = strlen (isec->name);
+
+           /* Association is determined by the name of the debug section
+              containing the name of the code section as a suffix.  For
+              example .debug_line.text.foo is a debug section associated
+              with .text.foo.  */
+           for (dsec = ibfd->sections; dsec != NULL; dsec = dsec->next)
+             {
+               unsigned int dlen;
+
+               if (dsec->gc_mark == 0
+                   || (dsec->flags & SEC_DEBUGGING) == 0)
+                 continue;
+
+               dlen = strlen (dsec->name);
+
+               if (dlen > ilen
+                   && strncmp (dsec->name + (dlen - ilen),
+                               isec->name, ilen) == 0)
+                 {
+                   dsec->gc_mark = 0;
+                   break;
+                 }
+             }
+         }
     }
   return TRUE;
 }
index 1731ca4..58f7657 100644 (file)
@@ -1,3 +1,14 @@
+2013-04-29  Nick Clifton  <nickc@redhat.com>
+
+       * dwarf.c (read_debug_line_header): New function.  Reads in a
+       header in a .debug_line section.
+       (display_debug_lines_raw): Use new function.  Handle fragmentary
+       .debug_line sections.
+       (display_debug_lines_decoded): Likewise.
+       * readelf.c (process_section_headers): Handle fragmenatry
+       .debug_line sections.
+       (display_debug_section): Likewise.
+
 2013-04-26  Ian Lance Taylor  <iant@google.com>
 
        * MAINTAINERS: Add myself and Cary as gold maintainers.
index 2f877e7..b11169b 100644 (file)
@@ -2546,37 +2546,33 @@ load_debug_info (void * file)
   return 0;
 }
 
-static int
-display_debug_lines_raw (struct dwarf_section *section,
-                        unsigned char *data,
-                         unsigned char *end)
-{
-  unsigned char *start = section->start;
-
-  printf (_("Raw dump of debug contents of section %s:\n\n"),
-          section->name);
+/* Read a DWARF .debug_line section header starting at DATA.
+   Upon success returns an updated DATA pointer and the LINFO
+   structure and the END_OF_SEQUENCE pointer will be filled in.
+   Otherwise returns NULL.  */
 
-  while (data < end)
-    {
-      DWARF2_Internal_LineInfo linfo;
-      unsigned char *standard_opcodes;
-      unsigned char *end_of_sequence;
-      unsigned char *hdrptr;
-      unsigned long hdroff;
-      int initial_length_size;
-      int offset_size;
-      int i;
+static unsigned char *
+read_debug_line_header (struct dwarf_section * section,
+                       unsigned char * data,
+                       unsigned char * end,
+                       DWARF2_Internal_LineInfo * linfo,
+                       unsigned char ** end_of_sequence)
+{
+  unsigned char *hdrptr;
+  unsigned int offset_size;
+  unsigned int initial_length_size;
 
+  /* Extract information from the Line Number Program Header.
+     (section 6.2.4 in the Dwarf3 doc).  */
       hdrptr = data;
-      hdroff = hdrptr - start;
 
-      /* Check the length of the block.  */
-      SAFE_BYTE_GET_AND_INC (linfo.li_length, hdrptr, 4, end);
+  /* Get and check the length of the block.  */
+  SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 4, end);
 
-      if (linfo.li_length == 0xffffffff)
+  if (linfo->li_length == 0xffffffff)
        {
          /* This section is 64-bit DWARF 3.  */
-         SAFE_BYTE_GET_AND_INC (linfo.li_length, hdrptr, 8, end);
+      SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 8, end);
          offset_size = 8;
          initial_length_size = 12;
        }
@@ -2586,315 +2582,381 @@ display_debug_lines_raw (struct dwarf_section *section,
          initial_length_size = 4;
        }
 
-      if (linfo.li_length + initial_length_size > section->size)
+  if (linfo->li_length + initial_length_size > section->size)
        {
-         warn
-           (_("The information in section %s appears to be corrupt - the section is too small\n"),
-            section->name);
-         return 0;
+      /* If the length is just a bias against the initial_length_size then
+        this means that the field has a relocation against it which has not
+        been applied.  (Ie we are dealing with an object file, not a linked
+        binary).  Do not complain but instead assume that the rest of the
+        section applies to this particular header.  */
+      if (linfo->li_length == - initial_length_size)
+       {
+         linfo->li_length = section->size - initial_length_size;
        }
+      else
+       {
+         warn (_("The line info appears to be corrupt - "
+                 "the section is too small\n"));
+         return NULL;
+       }
+       }
+
+  /* Get and check the version number.  */
+  SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end);
 
-      /* Check its version number.  */
-      SAFE_BYTE_GET_AND_INC (linfo.li_version, hdrptr, 2, end);
-      if (linfo.li_version != 2
-         && linfo.li_version != 3
-         && linfo.li_version != 4)
+  if (linfo->li_version != 2
+      && linfo->li_version != 3
+      && linfo->li_version != 4)
        {
          warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n"));
-         return 0;
+      return NULL;
        }
 
-      SAFE_BYTE_GET_AND_INC (linfo.li_prologue_length, hdrptr, offset_size, end);
-      SAFE_BYTE_GET_AND_INC (linfo.li_min_insn_length, hdrptr, 1, end);
+  SAFE_BYTE_GET_AND_INC (linfo->li_prologue_length, hdrptr, offset_size, end);
+  SAFE_BYTE_GET_AND_INC (linfo->li_min_insn_length, hdrptr, 1, end);
 
-      if (linfo.li_version >= 4)
+  if (linfo->li_version >= 4)
        {
-         SAFE_BYTE_GET_AND_INC (linfo.li_max_ops_per_insn, hdrptr, 1, end);
+      SAFE_BYTE_GET_AND_INC (linfo->li_max_ops_per_insn, hdrptr, 1, end);
 
-         if (linfo.li_max_ops_per_insn == 0)
+      if (linfo->li_max_ops_per_insn == 0)
            {
              warn (_("Invalid maximum operations per insn.\n"));
-             return 0;
+         return NULL;
            }
        }
       else
-       linfo.li_max_ops_per_insn = 1;
+    linfo->li_max_ops_per_insn = 1;
 
-      SAFE_BYTE_GET_AND_INC (linfo.li_default_is_stmt, hdrptr, 1, end);
-      SAFE_BYTE_GET_AND_INC (linfo.li_line_base, hdrptr, 1, end);
-      SAFE_BYTE_GET_AND_INC (linfo.li_line_range, hdrptr, 1, end);
-      SAFE_BYTE_GET_AND_INC (linfo.li_opcode_base, hdrptr, 1, end);
+  SAFE_BYTE_GET_AND_INC (linfo->li_default_is_stmt, hdrptr, 1, end);
+  SAFE_BYTE_GET_AND_INC (linfo->li_line_base, hdrptr, 1, end);
+  SAFE_BYTE_GET_AND_INC (linfo->li_line_range, hdrptr, 1, end);
+  SAFE_BYTE_GET_AND_INC (linfo->li_opcode_base, hdrptr, 1, end);
 
       /* Sign extend the line base field.  */
-      linfo.li_line_base <<= 24;
-      linfo.li_line_base >>= 24;
-
-      printf (_("  Offset:                      0x%lx\n"), hdroff);
-      printf (_("  Length:                      %ld\n"), (long) linfo.li_length);
-      printf (_("  DWARF Version:               %d\n"), linfo.li_version);
-      printf (_("  Prologue Length:             %d\n"), linfo.li_prologue_length);
-      printf (_("  Minimum Instruction Length:  %d\n"), linfo.li_min_insn_length);
-      if (linfo.li_version >= 4)
-       printf (_("  Maximum Ops per Instruction: %d\n"), linfo.li_max_ops_per_insn);
-      printf (_("  Initial value of 'is_stmt':  %d\n"), linfo.li_default_is_stmt);
-      printf (_("  Line Base:                   %d\n"), linfo.li_line_base);
-      printf (_("  Line Range:                  %d\n"), linfo.li_line_range);
-      printf (_("  Opcode Base:                 %d\n"), linfo.li_opcode_base);
-
-      end_of_sequence = data + linfo.li_length + initial_length_size;
+  linfo->li_line_base <<= 24;
+  linfo->li_line_base >>= 24;
 
-      reset_state_machine (linfo.li_default_is_stmt);
-
-      /* Display the contents of the Opcodes table.  */
-      standard_opcodes = hdrptr;
+  * end_of_sequence = data + linfo->li_length + initial_length_size;
+  return hdrptr;
+}
 
-      printf (_("\n Opcodes:\n"));
+static int
+display_debug_lines_raw (struct dwarf_section *section,
+                        unsigned char *data,
+                         unsigned char *end)
+{
+  unsigned char *start = section->start;
 
-      for (i = 1; i < linfo.li_opcode_base; i++)
-       printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
+  printf (_("Raw dump of debug contents of section %s:\n\n"),
+          section->name);
 
-      /* Display the contents of the Directory table.  */
-      data = standard_opcodes + linfo.li_opcode_base - 1;
+  while (data < end)
+    {
+      static DWARF2_Internal_LineInfo saved_linfo;
+      DWARF2_Internal_LineInfo linfo;
+      unsigned char *standard_opcodes;
+      unsigned char *end_of_sequence;
+       int i;
 
-      if (*data == 0)
-       printf (_("\n The Directory Table is empty.\n"));
-      else
+      if (const_strneq (section->name, ".debug_line."))
        {
-         printf (_("\n The Directory Table:\n"));
-
-         while (*data != 0)
-           {
-             printf ("  %s\n", data);
-
-             data += strnlen ((char *) data, end - data) + 1;
-           }
+         /* Sections named .debug_line.<foo> are fragments of a .debug_line
+            section containing just the Line Number Statements.  They are
+            created by the assembler and intended to be used alongside gcc's
+            -ffunction-sections command line option.  When the linker's
+            garbage collection decides to discard a .text.<foo> section it
+            can then also discard the line number information in .debug_line.<foo>.
+
+            Since the section is a fragmnent it does not have the details
+            needed to fill out a LineInfo structure, so instead we use the
+            details from the last one we processed.  */
+         end_of_sequence = end;
+         standard_opcodes = NULL;
+         linfo = saved_linfo;
+         reset_state_machine (linfo.li_default_is_stmt);
        }
-
-      /* Skip the NUL at the end of the table.  */
-      data++;
-
-      /* Display the contents of the File Name table.  */
-      if (*data == 0)
-       printf (_("\n The File Name Table is empty.\n"));
       else
        {
-         printf (_("\n The File Name Table:\n"));
-         printf (_("  Entry\tDir\tTime\tSize\tName\n"));
+         unsigned char * hdrptr;
 
-         while (*data != 0)
-           {
-             unsigned char *name;
-             unsigned int bytes_read;
+         if ((hdrptr = read_debug_line_header (section, data, end, & linfo,
+                                               & end_of_sequence)) == NULL)
+           return 0;
 
-             printf ("  %d\t", ++state_machine_regs.last_file_entry);
-             name = data;
-             data += strnlen ((char *) data, end - data) + 1;
+         printf (_("  Offset:                      0x%lx\n"), (long)(data - start));
+         printf (_("  Length:                      %ld\n"), (long) linfo.li_length);
+         printf (_("  DWARF Version:               %d\n"), linfo.li_version);
+         printf (_("  Prologue Length:             %d\n"), linfo.li_prologue_length);
+         printf (_("  Minimum Instruction Length:  %d\n"), linfo.li_min_insn_length);
+         if (linfo.li_version >= 4)
+           printf (_("  Maximum Ops per Instruction: %d\n"), linfo.li_max_ops_per_insn);
+         printf (_("  Initial value of 'is_stmt':  %d\n"), linfo.li_default_is_stmt);
+         printf (_("  Line Base:                   %d\n"), linfo.li_line_base);
+         printf (_("  Line Range:                  %d\n"), linfo.li_line_range);
+         printf (_("  Opcode Base:                 %d\n"), linfo.li_opcode_base);
 
-             printf ("%s\t",
-                     dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
-             data += bytes_read;
-             printf ("%s\t",
-                     dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
-             data += bytes_read;
-             printf ("%s\t",
-                     dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
-             data += bytes_read;
-             printf ("%s\n", name);
-
-             if (data == end)
-               {
-                 warn (_("Corrupt file name table entry\n"));
-                 break;
-               }
-           }
-       }
+         reset_state_machine (linfo.li_default_is_stmt);
 
-      /* Skip the NUL at the end of the table.  */
-      data++;
+         /* Display the contents of the Opcodes table.  */
+         standard_opcodes = hdrptr;
 
-      /* Now display the statements.  */
-      printf (_("\n Line Number Statements:\n"));
+         printf (_("\n Opcodes:\n"));
 
-      while (data < end_of_sequence)
-       {
-         unsigned char op_code;
-         dwarf_signed_vma adv;
-         dwarf_vma uladv;
-         unsigned int bytes_read;
+         for (i = 1; i < linfo.li_opcode_base; i++)
+           printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
 
-         op_code = *data++;
+         /* Display the contents of the Directory table.  */
+         data = standard_opcodes + linfo.li_opcode_base - 1;
 
-         if (op_code >= linfo.li_opcode_base)
-           {
-             op_code -= linfo.li_opcode_base;
-             uladv = (op_code / linfo.li_line_range);
-             if (linfo.li_max_ops_per_insn == 1)
-               {
-                 uladv *= linfo.li_min_insn_length;
-                 state_machine_regs.address += uladv;
-                 printf (_("  Special opcode %d: "
-                           "advance Address by %s to 0x%s"),
-                         op_code, dwarf_vmatoa ("u", uladv),
-                         dwarf_vmatoa ("x", state_machine_regs.address));
-               }
-             else
-               {
-                 state_machine_regs.address
-                   += ((state_machine_regs.op_index + uladv)
-                       / linfo.li_max_ops_per_insn)
-                      * linfo.li_min_insn_length;
-                 state_machine_regs.op_index
-                   = (state_machine_regs.op_index + uladv)
-                     % linfo.li_max_ops_per_insn;
-                 printf (_("  Special opcode %d: "
-                           "advance Address by %s to 0x%s[%d]"),
-                         op_code, dwarf_vmatoa ("u", uladv),
-                         dwarf_vmatoa ("x", state_machine_regs.address),
-                         state_machine_regs.op_index);
-               }
-             adv = (op_code % linfo.li_line_range) + linfo.li_line_base;
-             state_machine_regs.line += adv;
-             printf (_(" and Line by %s to %d\n"),
-                     dwarf_vmatoa ("d", adv), state_machine_regs.line);
-           }
-         else switch (op_code)
+         if (*data == 0)
+           printf (_("\n The Directory Table is empty.\n"));
+         else
            {
-           case DW_LNS_extended_op:
-             data += process_extended_line_op (data, linfo.li_default_is_stmt, end);
-             break;
+             printf (_("\n The Directory Table:\n"));
 
-           case DW_LNS_copy:
-             printf (_("  Copy\n"));
-             break;
-
-           case DW_LNS_advance_pc:
-             uladv = read_uleb128 (data, & bytes_read, end);
-             data += bytes_read;
-             if (linfo.li_max_ops_per_insn == 1)
+             while (*data != 0)
                {
-                 uladv *= linfo.li_min_insn_length;
-                 state_machine_regs.address += uladv;
-                 printf (_("  Advance PC by %s to 0x%s\n"),
-                         dwarf_vmatoa ("u", uladv),
-                         dwarf_vmatoa ("x", state_machine_regs.address));
-               }
-             else
-               {
-                 state_machine_regs.address
-                   += ((state_machine_regs.op_index + uladv)
-                       / linfo.li_max_ops_per_insn)
-                      * linfo.li_min_insn_length;
-                 state_machine_regs.op_index
-                   = (state_machine_regs.op_index + uladv)
-                     % linfo.li_max_ops_per_insn;
-                 printf (_("  Advance PC by %s to 0x%s[%d]\n"),
-                         dwarf_vmatoa ("u", uladv),
-                         dwarf_vmatoa ("x", state_machine_regs.address),
-                         state_machine_regs.op_index);
+                 printf ("  %s\n", data);
+
+                 data += strnlen ((char *) data, end - data) + 1;
                }
-             break;
+           }
 
-           case DW_LNS_advance_line:
-             adv = read_sleb128 (data, & bytes_read, end);
-             data += bytes_read;
-             state_machine_regs.line += adv;
-             printf (_("  Advance Line by %s to %d\n"),
-                       dwarf_vmatoa ("d", adv),
-                       state_machine_regs.line);
-             break;
+         /* Skip the NUL at the end of the table.  */
+         data++;
 
-           case DW_LNS_set_file:
-             adv = read_uleb128 (data, & bytes_read, end);
-             data += bytes_read;
-             printf (_("  Set File Name to entry %s in the File Name Table\n"),
-                     dwarf_vmatoa ("d", adv));
-             state_machine_regs.file = adv;
-             break;
+         /* Display the contents of the File Name table.  */
+         if (*data == 0)
+           printf (_("\n The File Name Table is empty.\n"));
+         else
+           {
+             printf (_("\n The File Name Table:\n"));
+             printf (_("  Entry\tDir\tTime\tSize\tName\n"));
 
-           case DW_LNS_set_column:
-             uladv = read_uleb128 (data, & bytes_read, end);
-             data += bytes_read;
-             printf (_("  Set column to %s\n"),
-                     dwarf_vmatoa ("u", uladv));
-             state_machine_regs.column = uladv;
-             break;
+             while (*data != 0)
+               {
+                 unsigned char *name;
+                 unsigned int bytes_read;
 
-           case DW_LNS_negate_stmt:
-             adv = state_machine_regs.is_stmt;
-             adv = ! adv;
-             printf (_("  Set is_stmt to %s\n"), dwarf_vmatoa ("d", adv));
-             state_machine_regs.is_stmt = adv;
-             break;
+                 printf ("  %d\t", ++state_machine_regs.last_file_entry);
+                 name = data;
+                 data += strnlen ((char *) data, end - data) + 1;
 
-           case DW_LNS_set_basic_block:
-             printf (_("  Set basic block\n"));
-             state_machine_regs.basic_block = 1;
-             break;
+                 printf ("%s\t",
+                         dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
+                 data += bytes_read;
+                 printf ("%s\t",
+                         dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
+                 data += bytes_read;
+                 printf ("%s\t",
+                         dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
+                 data += bytes_read;
+                 printf ("%s\n", name);
 
-           case DW_LNS_const_add_pc:
-             uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range);
-             if (linfo.li_max_ops_per_insn)
-               {
-                 uladv *= linfo.li_min_insn_length;
-                 state_machine_regs.address += uladv;
-                 printf (_("  Advance PC by constant %s to 0x%s\n"),
-                         dwarf_vmatoa ("u", uladv),
-                         dwarf_vmatoa ("x", state_machine_regs.address));
-               }
-             else
-               {
-                 state_machine_regs.address
-                   += ((state_machine_regs.op_index + uladv)
-                       / linfo.li_max_ops_per_insn)
-                      * linfo.li_min_insn_length;
-                 state_machine_regs.op_index
-                   = (state_machine_regs.op_index + uladv)
-                     % linfo.li_max_ops_per_insn;
-                 printf (_("  Advance PC by constant %s to 0x%s[%d]\n"),
-                         dwarf_vmatoa ("u", uladv),
-                         dwarf_vmatoa ("x", state_machine_regs.address),
-                         state_machine_regs.op_index);
+                 if (data == end)
+                   {
+                     warn (_("Corrupt file name table entry\n"));
+                     break;
+                   }
                }
-             break;
-
-           case DW_LNS_fixed_advance_pc:
-             SAFE_BYTE_GET_AND_INC (uladv, data, 2, end);
-             state_machine_regs.address += uladv;
-             state_machine_regs.op_index = 0;
-             printf (_("  Advance PC by fixed size amount %s to 0x%s\n"),
-                     dwarf_vmatoa ("u", uladv),
-                     dwarf_vmatoa ("x", state_machine_regs.address));
-             break;
+           }
 
-           case DW_LNS_set_prologue_end:
-             printf (_("  Set prologue_end to true\n"));
-             break;
+         /* Skip the NUL at the end of the table.  */
+         data++;
+         putchar ('\n');
+         saved_linfo = linfo;
+       }
 
-           case DW_LNS_set_epilogue_begin:
-             printf (_("  Set epilogue_begin to true\n"));
-             break;
+      /* Now display the statements.  */
+      if (data >= end_of_sequence)
+       printf (_(" No Line Number Statements.\n"));
+      else
+       {
+         printf (_(" Line Number Statements:\n"));
 
-           case DW_LNS_set_isa:
-             uladv = read_uleb128 (data, & bytes_read, end);
-             data += bytes_read;
-             printf (_("  Set ISA to %s\n"), dwarf_vmatoa ("u", uladv));
-             break;
+         while (data < end_of_sequence)
+           {
+             unsigned char op_code;
+             dwarf_signed_vma adv;
+             dwarf_vma uladv;
+             unsigned int bytes_read;
 
-           default:
-             printf (_("  Unknown opcode %d with operands: "), op_code);
+             op_code = *data++;
 
-             for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
+             if (op_code >= linfo.li_opcode_base)
                {
-                 printf ("0x%s%s", dwarf_vmatoa ("x", read_uleb128 (data,
-                                                                    &bytes_read, end)),
-                         i == 1 ? "" : ", ");
-                 data += bytes_read;
+                 op_code -= linfo.li_opcode_base;
+                 uladv = (op_code / linfo.li_line_range);
+                 if (linfo.li_max_ops_per_insn == 1)
+                   {
+                     uladv *= linfo.li_min_insn_length;
+                     state_machine_regs.address += uladv;
+                     printf (_("  Special opcode %d: "
+                               "advance Address by %s to 0x%s"),
+                             op_code, dwarf_vmatoa ("u", uladv),
+                             dwarf_vmatoa ("x", state_machine_regs.address));
+                   }
+                 else
+                   {
+                     state_machine_regs.address
+                       += ((state_machine_regs.op_index + uladv)
+                           / linfo.li_max_ops_per_insn)
+                       * linfo.li_min_insn_length;
+                     state_machine_regs.op_index
+                       = (state_machine_regs.op_index + uladv)
+                       % linfo.li_max_ops_per_insn;
+                     printf (_("  Special opcode %d: "
+                               "advance Address by %s to 0x%s[%d]"),
+                             op_code, dwarf_vmatoa ("u", uladv),
+                             dwarf_vmatoa ("x", state_machine_regs.address),
+                             state_machine_regs.op_index);
+                   }
+                 adv = (op_code % linfo.li_line_range) + linfo.li_line_base;
+                 state_machine_regs.line += adv;
+                 printf (_(" and Line by %s to %d\n"),
+                         dwarf_vmatoa ("d", adv), state_machine_regs.line);
                }
-             putchar ('\n');
-             break;
+             else switch (op_code)
+                    {
+                    case DW_LNS_extended_op:
+                      data += process_extended_line_op (data, linfo.li_default_is_stmt, end);
+                      break;
+
+                    case DW_LNS_copy:
+                      printf (_("  Copy\n"));
+                      break;
+
+                    case DW_LNS_advance_pc:
+                      uladv = read_uleb128 (data, & bytes_read, end);
+                      data += bytes_read;
+                      if (linfo.li_max_ops_per_insn == 1)
+                        {
+                          uladv *= linfo.li_min_insn_length;
+                          state_machine_regs.address += uladv;
+                          printf (_("  Advance PC by %s to 0x%s\n"),
+                                  dwarf_vmatoa ("u", uladv),
+                                  dwarf_vmatoa ("x", state_machine_regs.address));
+                        }
+                      else
+                        {
+                          state_machine_regs.address
+                            += ((state_machine_regs.op_index + uladv)
+                                / linfo.li_max_ops_per_insn)
+                            * linfo.li_min_insn_length;
+                          state_machine_regs.op_index
+                            = (state_machine_regs.op_index + uladv)
+                            % linfo.li_max_ops_per_insn;
+                          printf (_("  Advance PC by %s to 0x%s[%d]\n"),
+                                  dwarf_vmatoa ("u", uladv),
+                                  dwarf_vmatoa ("x", state_machine_regs.address),
+                                  state_machine_regs.op_index);
+                        }
+                      break;
+
+                    case DW_LNS_advance_line:
+                      adv = read_sleb128 (data, & bytes_read, end);
+                      data += bytes_read;
+                      state_machine_regs.line += adv;
+                      printf (_("  Advance Line by %s to %d\n"),
+                              dwarf_vmatoa ("d", adv),
+                              state_machine_regs.line);
+                      break;
+
+                    case DW_LNS_set_file:
+                      adv = read_uleb128 (data, & bytes_read, end);
+                      data += bytes_read;
+                      printf (_("  Set File Name to entry %s in the File Name Table\n"),
+                              dwarf_vmatoa ("d", adv));
+                      state_machine_regs.file = adv;
+                      break;
+
+                    case DW_LNS_set_column:
+                      uladv = read_uleb128 (data, & bytes_read, end);
+                      data += bytes_read;
+                      printf (_("  Set column to %s\n"),
+                              dwarf_vmatoa ("u", uladv));
+                      state_machine_regs.column = uladv;
+                      break;
+
+                    case DW_LNS_negate_stmt:
+                      adv = state_machine_regs.is_stmt;
+                      adv = ! adv;
+                      printf (_("  Set is_stmt to %s\n"), dwarf_vmatoa ("d", adv));
+                      state_machine_regs.is_stmt = adv;
+                      break;
+
+                    case DW_LNS_set_basic_block:
+                      printf (_("  Set basic block\n"));
+                      state_machine_regs.basic_block = 1;
+                      break;
+
+                    case DW_LNS_const_add_pc:
+                      uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range);
+                      if (linfo.li_max_ops_per_insn)
+                        {
+                          uladv *= linfo.li_min_insn_length;
+                          state_machine_regs.address += uladv;
+                          printf (_("  Advance PC by constant %s to 0x%s\n"),
+                                  dwarf_vmatoa ("u", uladv),
+                                  dwarf_vmatoa ("x", state_machine_regs.address));
+                        }
+                      else
+                        {
+                          state_machine_regs.address
+                            += ((state_machine_regs.op_index + uladv)
+                                / linfo.li_max_ops_per_insn)
+                            * linfo.li_min_insn_length;
+                          state_machine_regs.op_index
+                            = (state_machine_regs.op_index + uladv)
+                            % linfo.li_max_ops_per_insn;
+                          printf (_("  Advance PC by constant %s to 0x%s[%d]\n"),
+                                  dwarf_vmatoa ("u", uladv),
+                                  dwarf_vmatoa ("x", state_machine_regs.address),
+                                  state_machine_regs.op_index);
+                        }
+                      break;
+
+                    case DW_LNS_fixed_advance_pc:
+                      SAFE_BYTE_GET_AND_INC (uladv, data, 2, end);
+                      state_machine_regs.address += uladv;
+                      state_machine_regs.op_index = 0;
+                      printf (_("  Advance PC by fixed size amount %s to 0x%s\n"),
+                              dwarf_vmatoa ("u", uladv),
+                              dwarf_vmatoa ("x", state_machine_regs.address));
+                      break;
+
+                    case DW_LNS_set_prologue_end:
+                      printf (_("  Set prologue_end to true\n"));
+                      break;
+
+                    case DW_LNS_set_epilogue_begin:
+                      printf (_("  Set epilogue_begin to true\n"));
+                      break;
+
+                    case DW_LNS_set_isa:
+                      uladv = read_uleb128 (data, & bytes_read, end);
+                      data += bytes_read;
+                      printf (_("  Set ISA to %s\n"), dwarf_vmatoa ("u", uladv));
+                      break;
+
+                    default:
+                      printf (_("  Unknown opcode %d with operands: "), op_code);
+
+                      if (standard_opcodes != NULL)
+                        for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
+                          {
+                            printf ("0x%s%s", dwarf_vmatoa ("x", read_uleb128 (data,
+                                                                               &bytes_read, end)),
+                                    i == 1 ? "" : ", ");
+                            data += bytes_read;
+                          }
+                      putchar ('\n');
+                      break;
+                    }
            }
+         putchar ('\n');
        }
-      putchar ('\n');
     }
 
   return 1;
@@ -2915,6 +2977,8 @@ display_debug_lines_decoded (struct dwarf_section *section,
                             unsigned char *data,
                             unsigned char *end)
 {
+  static DWARF2_Internal_LineInfo saved_linfo;
+
   printf (_("Decoded dump of debug contents of section %s:\n\n"),
           section->name);
 
@@ -2924,183 +2988,142 @@ display_debug_lines_decoded (struct dwarf_section *section,
       DWARF2_Internal_LineInfo linfo;
       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 int n_files = 0;
       unsigned char **directory_table = NULL;
       unsigned int n_directories = 0;
 
-      hdrptr = data;
-
-      /* Extract information from the Line Number Program Header.
-        (section 6.2.4 in the Dwarf3 doc).  */
-
-      /* Get the length of this CU's line number information block.  */
-      SAFE_BYTE_GET_AND_INC (linfo.li_length, hdrptr, 4, end);
-
-      if (linfo.li_length == 0xffffffff)
+      if (const_strneq (section->name, ".debug_line."))
         {
-          /* This section is 64-bit DWARF 3.  */
-         SAFE_BYTE_GET_AND_INC (linfo.li_length, hdrptr, 8, end);
-          offset_size = 8;
-          initial_length_size = 12;
+         /* Sections named .debug_line.<foo> are fragments of a .debug_line
+            section containing just the Line Number Statements.  They are
+            created by the assembler and intended to be used alongside gcc's
+            -ffunction-sections command line option.  When the linker's
+            garbage collection decides to discard a .text.<foo> section it
+            can then also discard the line number information in .debug_line.<foo>.
+
+            Since the section is a fragmnent it does not have the details
+            needed to fill out a LineInfo structure, so instead we use the
+            details from the last one we processed.  */
+         end_of_sequence = end;
+         standard_opcodes = NULL;
+         linfo = saved_linfo;
+         reset_state_machine (linfo.li_default_is_stmt);
         }
       else
         {
-          offset_size = 4;
-          initial_length_size = 4;
-        }
-
-      if (linfo.li_length + initial_length_size > section->size)
-        {
-          warn (_("The line info appears to be corrupt - "
-                  "the section is too small\n"));
-          return 0;
-        }
+         unsigned char *hdrptr;
 
-      /* Get this CU's Line Number Block version number.  */
-      SAFE_BYTE_GET_AND_INC (linfo.li_version, hdrptr, 2, end);
-      if (linfo.li_version != 2
-         && linfo.li_version != 3
-         && linfo.li_version != 4)
-        {
-          warn (_("Only DWARF version 2, 3 and 4 line info is currently "
-                "supported.\n"));
-          return 0;
-        }
-
-      SAFE_BYTE_GET_AND_INC (linfo.li_prologue_length, hdrptr, offset_size, end);
-      SAFE_BYTE_GET_AND_INC (linfo.li_min_insn_length, hdrptr, 1, end);
-
-      if (linfo.li_version >= 4)
-       {
-         SAFE_BYTE_GET_AND_INC (linfo.li_max_ops_per_insn, hdrptr, 1, end);
-         if (linfo.li_max_ops_per_insn == 0)
-           {
-             warn (_("Invalid maximum operations per insn.\n"));
+         if ((hdrptr = read_debug_line_header (section, data, end, & linfo,
+                                               & end_of_sequence)) == NULL)
              return 0;
-           }
-       }
-      else
-       linfo.li_max_ops_per_insn = 1;
 
-      SAFE_BYTE_GET_AND_INC (linfo.li_default_is_stmt, hdrptr, 1, end);
-      SAFE_BYTE_GET_AND_INC (linfo.li_line_base, hdrptr, 1, end);
-      SAFE_BYTE_GET_AND_INC (linfo.li_line_range, hdrptr, 1, end);
-      SAFE_BYTE_GET_AND_INC (linfo.li_opcode_base, hdrptr, 1, end);
+         reset_state_machine (linfo.li_default_is_stmt);
 
-      /* Sign extend the line base field.  */
-      linfo.li_line_base <<= 24;
-      linfo.li_line_base >>= 24;
+         /* Save a pointer to the contents of the Opcodes table.  */
+         standard_opcodes = hdrptr;
 
-      /* Find the end of this CU's Line Number Information Block.  */
-      end_of_sequence = data + linfo.li_length + initial_length_size;
-
-      reset_state_machine (linfo.li_default_is_stmt);
+         /* Traverse the Directory table just to count entries.  */
+         data = standard_opcodes + linfo.li_opcode_base - 1;
+         if (*data != 0)
+           {
+             unsigned char *ptr_directory_table = data;
 
-      /* Save a pointer to the contents of the Opcodes table.  */
-      standard_opcodes = hdrptr;
+             while (*data != 0)
+               {
+                 data += strnlen ((char *) data, end - data) + 1;
+                 n_directories++;
+               }
 
-      /* Traverse the Directory table just to count entries.  */
-      data = standard_opcodes + linfo.li_opcode_base - 1;
-      if (*data != 0)
-        {
-          unsigned char *ptr_directory_table = data;
+             /* Go through the directory table again to save the directories.  */
+             directory_table = (unsigned char **)
+               xmalloc (n_directories * sizeof (unsigned char *));
 
-         while (*data != 0)
-           {
-             data += strnlen ((char *) data, end - data) + 1;
-             n_directories++;
+             i = 0;
+             while (*ptr_directory_table != 0)
+               {
+                 directory_table[i] = ptr_directory_table;
+                 ptr_directory_table += strnlen ((char *) ptr_directory_table,
+                                                 ptr_directory_table - end) + 1;
+                 i++;
+               }
            }
+         /* Skip the NUL at the end of the table.  */
+         data++;
 
-          /* Go through the directory table again to save the directories.  */
-          directory_table = (unsigned char **)
-              xmalloc (n_directories * sizeof (unsigned char *));
+         /* Traverse the File Name table just to count the entries.  */
+         if (*data != 0)
+           {
+             unsigned char *ptr_file_name_table = data;
 
-          i = 0;
-          while (*ptr_directory_table != 0)
-            {
-              directory_table[i] = ptr_directory_table;
-              ptr_directory_table += strnlen ((char *) ptr_directory_table,
-                                             ptr_directory_table - end) + 1;
-              i++;
-            }
-        }
-      /* Skip the NUL at the end of the table.  */
-      data++;
+             while (*data != 0)
+               {
+                 unsigned int bytes_read;
 
-      /* Traverse the File Name table just to count the entries.  */
-      if (*data != 0)
-        {
-          unsigned char *ptr_file_name_table = data;
+                 /* Skip Name, directory index, last modification time and length
+                    of file.  */
+                 data += strnlen ((char *) data, end - data) + 1;
+                 read_uleb128 (data, & bytes_read, end);
+                 data += bytes_read;
+                 read_uleb128 (data, & bytes_read, end);
+                 data += bytes_read;
+                 read_uleb128 (data, & bytes_read, end);
+                 data += bytes_read;
 
-          while (*data != 0)
-            {
-             unsigned int bytes_read;
+                 n_files++;
+               }
 
-              /* Skip Name, directory index, last modification time and length
-                 of file.  */
-              data += strnlen ((char *) data, end - data) + 1;
-              read_uleb128 (data, & bytes_read, end);
-              data += bytes_read;
-              read_uleb128 (data, & bytes_read, end);
-              data += bytes_read;
-              read_uleb128 (data, & bytes_read, end);
-              data += bytes_read;
-
-              n_files++;
-            }
+             /* Go through the file table again to save the strings.  */
+             file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry));
 
-          /* Go through the file table again to save the strings.  */
-          file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry));
+             i = 0;
+             while (*ptr_file_name_table != 0)
+               {
+                 unsigned int bytes_read;
+
+                 file_table[i].name = ptr_file_name_table;
+                 ptr_file_name_table += strnlen ((char *) ptr_file_name_table,
+                                                 end - ptr_file_name_table) + 1;
+
+                 /* We are not interested in directory, time or size.  */
+                 file_table[i].directory_index = read_uleb128 (ptr_file_name_table,
+                                                               & bytes_read, end);
+                 ptr_file_name_table += bytes_read;
+                 file_table[i].modification_date = read_uleb128 (ptr_file_name_table,
+                                                                 & bytes_read, end);
+                 ptr_file_name_table += bytes_read;
+                 file_table[i].length = read_uleb128 (ptr_file_name_table, & bytes_read, end);
+                 ptr_file_name_table += bytes_read;
+                 i++;
+               }
+             i = 0;
 
-          i = 0;
-          while (*ptr_file_name_table != 0)
-            {
-              unsigned int bytes_read;
-
-              file_table[i].name = ptr_file_name_table;
-              ptr_file_name_table += strnlen ((char *) ptr_file_name_table,
-                                             end - ptr_file_name_table) + 1;
-
-              /* We are not interested in directory, time or size.  */
-              file_table[i].directory_index = read_uleb128 (ptr_file_name_table,
-                                                           & bytes_read, end);
-              ptr_file_name_table += bytes_read;
-              file_table[i].modification_date = read_uleb128 (ptr_file_name_table,
-                                                             & bytes_read, end);
-              ptr_file_name_table += bytes_read;
-              file_table[i].length = read_uleb128 (ptr_file_name_table, & bytes_read, end);
-              ptr_file_name_table += bytes_read;
-              i++;
-            }
-          i = 0;
+             /* Print the Compilation Unit's name and a header.  */
+             if (directory_table == NULL)
+               {
+                 printf (_("CU: %s:\n"), file_table[0].name);
+                 printf (_("File name                            Line number    Starting address\n"));
+               }
+             else
+               {
+                 unsigned int ix = file_table[0].directory_index;
+                 const char *directory = ix ? (char *)directory_table[ix - 1] : ".";
 
-          /* Print the Compilation Unit's name and a header.  */
-          if (directory_table == NULL)
-            {
-              printf (_("CU: %s:\n"), file_table[0].name);
-              printf (_("File name                            Line number    Starting address\n"));
-            }
-          else
-            {
-              unsigned int ix = file_table[0].directory_index;
-              const char *directory = ix ? (char *)directory_table[ix - 1] : ".";
+                 if (do_wide || strlen (directory) < 76)
+                   printf (_("CU: %s/%s:\n"), directory, file_table[0].name);
+                 else
+                   printf ("%s:\n", file_table[0].name);
 
-              if (do_wide || strlen (directory) < 76)
-               printf (_("CU: %s/%s:\n"), directory, file_table[0].name);
-              else
-               printf ("%s:\n", file_table[0].name);
+                 printf (_("File name                            Line number    Starting address\n"));
+               }
+           }
 
-              printf (_("File name                            Line number    Starting address\n"));
-            }
-        }
+         /* Skip the NUL at the end of the table.  */
+         data++;
 
-      /* Skip the NUL at the end of the table.  */
-      data++;
+         saved_linfo = linfo;
+       }
 
       /* This loop iterates through the Dwarf Line Number Program.  */
       while (data < end_of_sequence)
@@ -3127,10 +3150,10 @@ display_debug_lines_decoded (struct dwarf_section *section,
                  state_machine_regs.address
                    += ((state_machine_regs.op_index + uladv)
                        / linfo.li_max_ops_per_insn)
-                      * linfo.li_min_insn_length;
+                   * linfo.li_min_insn_length;
                  state_machine_regs.op_index
                    = (state_machine_regs.op_index + uladv)
-                     % linfo.li_max_ops_per_insn;
+                   % linfo.li_max_ops_per_insn;
                }
 
               adv = (op_code % linfo.li_line_range) + linfo.li_line_base;
@@ -3138,190 +3161,193 @@ display_debug_lines_decoded (struct dwarf_section *section,
               is_special_opcode = 1;
             }
           else switch (op_code)
-            {
-            case DW_LNS_extended_op:
-              {
-                unsigned int ext_op_code_len;
-                unsigned char ext_op_code;
-                unsigned char *op_code_data = data;
-
-                ext_op_code_len = read_uleb128 (op_code_data, &bytes_read,
-                                               end_of_sequence);
-                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 (linfo.li_default_is_stmt);
-                    break;
-                  case DW_LNE_set_address:
-                   SAFE_BYTE_GET_AND_INC (state_machine_regs.address,
-                                          op_code_data, ext_op_code_len - bytes_read - 1,
-                                          end);
-                   state_machine_regs.op_index = 0;
-                    break;
-                  case DW_LNE_define_file:
-                    {
-                      file_table = (File_Entry *) xrealloc
-                        (file_table, (n_files + 1) * sizeof (File_Entry));
-
-                      ++state_machine_regs.last_file_entry;
-                      /* Source file name.  */
-                      file_table[n_files].name = op_code_data;
-                      op_code_data += strlen ((char *) op_code_data) + 1;
-                      /* Directory index.  */
-                      file_table[n_files].directory_index =
-                        read_uleb128 (op_code_data, & bytes_read,
-                                     end_of_sequence);
-                      op_code_data += bytes_read;
-                      /* Last modification time.  */
-                      file_table[n_files].modification_date =
-                        read_uleb128 (op_code_data, & bytes_read,
-                                     end_of_sequence);
-                      op_code_data += bytes_read;
-                      /* File length.  */
-                      file_table[n_files].length =
-                        read_uleb128 (op_code_data, & bytes_read,
-                                     end_of_sequence);
-
-                      n_files++;
-                      break;
-                    }
-                  case DW_LNE_set_discriminator:
-                  case DW_LNE_HP_set_sequence:
-                    /* Simply ignored.  */
-                    break;
-
-                  default:
-                    printf (_("UNKNOWN (%u): length %d\n"),
-                            ext_op_code, 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_uleb128 (data, & bytes_read, end);
-              data += bytes_read;
-             if (linfo.li_max_ops_per_insn == 1)
-               {
-                 uladv *= linfo.li_min_insn_length;
-                 state_machine_regs.address += uladv;
-               }
-             else
-               {
-                 state_machine_regs.address
-                   += ((state_machine_regs.op_index + uladv)
-                       / linfo.li_max_ops_per_insn)
-                      * linfo.li_min_insn_length;
-                 state_machine_regs.op_index
-                   = (state_machine_regs.op_index + uladv)
-                     % linfo.li_max_ops_per_insn;
-               }
-              break;
-
-            case DW_LNS_advance_line:
-              adv = read_sleb128 (data, & bytes_read, end);
-              data += bytes_read;
-              state_machine_regs.line += adv;
-              break;
-
-            case DW_LNS_set_file:
-              adv = read_uleb128 (data, & bytes_read, end);
-              data += bytes_read;
-              state_machine_regs.file = adv;
-              if (file_table[state_machine_regs.file - 1].directory_index == 0)
-                {
-                  /* If directory index is 0, that means current directory.  */
-                  printf ("\n./%s:[++]\n",
-                          file_table[state_machine_regs.file - 1].name);
-                }
-              else
-                {
-                  /* The directory index starts counting at 1.  */
-                  printf ("\n%s/%s:\n",
-                          directory_table[file_table[state_machine_regs.file - 1].directory_index - 1],
-                          file_table[state_machine_regs.file - 1].name);
-                }
-              break;
-
-            case DW_LNS_set_column:
-              uladv = read_uleb128 (data, & bytes_read, end);
-              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 - linfo.li_opcode_base) / linfo.li_line_range);
-             if (linfo.li_max_ops_per_insn == 1)
-               {
-                 uladv *= linfo.li_min_insn_length;
-                 state_machine_regs.address += uladv;
-               }
-             else
-               {
-                 state_machine_regs.address
-                   += ((state_machine_regs.op_index + uladv)
-                       / linfo.li_max_ops_per_insn)
-                      * linfo.li_min_insn_length;
-                 state_machine_regs.op_index
-                   = (state_machine_regs.op_index + uladv)
-                     % linfo.li_max_ops_per_insn;
-               }
-              break;
-
-            case DW_LNS_fixed_advance_pc:
-             SAFE_BYTE_GET_AND_INC (uladv, data, 2, end);
-              state_machine_regs.address += uladv;
-             state_machine_regs.op_index = 0;
-              break;
-
-            case DW_LNS_set_prologue_end:
-              break;
-
-            case DW_LNS_set_epilogue_begin:
-              break;
-
-            case DW_LNS_set_isa:
-              uladv = read_uleb128 (data, & bytes_read, end);
-              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%s%s", dwarf_vmatoa ("x", read_uleb128 (data,
-                                                                    &bytes_read, end)),
-                          i == 1 ? "" : ", ");
-                  data += bytes_read;
-                }
-              putchar ('\n');
-              break;
-            }
+                {
+                case DW_LNS_extended_op:
+                  {
+                    unsigned int ext_op_code_len;
+                    unsigned char ext_op_code;
+                    unsigned char *op_code_data = data;
+
+                    ext_op_code_len = read_uleb128 (op_code_data, &bytes_read,
+                                                    end_of_sequence);
+                    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 (linfo.li_default_is_stmt);
+                        break;
+                      case DW_LNE_set_address:
+                        SAFE_BYTE_GET_AND_INC (state_machine_regs.address,
+                                               op_code_data, ext_op_code_len - bytes_read - 1,
+                                               end);
+                        state_machine_regs.op_index = 0;
+                        break;
+                      case DW_LNE_define_file:
+                        {
+                          file_table = (File_Entry *) xrealloc
+                            (file_table, (n_files + 1) * sizeof (File_Entry));
+
+                          ++state_machine_regs.last_file_entry;
+                          /* Source file name.  */
+                          file_table[n_files].name = op_code_data;
+                          op_code_data += strlen ((char *) op_code_data) + 1;
+                          /* Directory index.  */
+                          file_table[n_files].directory_index =
+                            read_uleb128 (op_code_data, & bytes_read,
+                                          end_of_sequence);
+                          op_code_data += bytes_read;
+                          /* Last modification time.  */
+                          file_table[n_files].modification_date =
+                            read_uleb128 (op_code_data, & bytes_read,
+                                          end_of_sequence);
+                          op_code_data += bytes_read;
+                          /* File length.  */
+                          file_table[n_files].length =
+                            read_uleb128 (op_code_data, & bytes_read,
+                                          end_of_sequence);
+
+                          n_files++;
+                          break;
+                        }
+                      case DW_LNE_set_discriminator:
+                      case DW_LNE_HP_set_sequence:
+                        /* Simply ignored.  */
+                        break;
+
+                      default:
+                        printf (_("UNKNOWN (%u): length %d\n"),
+                                ext_op_code, 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_uleb128 (data, & bytes_read, end);
+                  data += bytes_read;
+                  if (linfo.li_max_ops_per_insn == 1)
+                    {
+                      uladv *= linfo.li_min_insn_length;
+                      state_machine_regs.address += uladv;
+                    }
+                  else
+                    {
+                      state_machine_regs.address
+                        += ((state_machine_regs.op_index + uladv)
+                            / linfo.li_max_ops_per_insn)
+                        * linfo.li_min_insn_length;
+                      state_machine_regs.op_index
+                        = (state_machine_regs.op_index + uladv)
+                        % linfo.li_max_ops_per_insn;
+                    }
+                  break;
+
+                case DW_LNS_advance_line:
+                  adv = read_sleb128 (data, & bytes_read, end);
+                  data += bytes_read;
+                  state_machine_regs.line += adv;
+                  break;
+
+                case DW_LNS_set_file:
+                  adv = read_uleb128 (data, & bytes_read, end);
+                  data += bytes_read;
+                  state_machine_regs.file = adv;
+
+                  if (file_table == NULL)
+                    printf (_("\n [Use file table entry %d]\n"), state_machine_regs.file - 1);
+                  else if (file_table[state_machine_regs.file - 1].directory_index == 0)
+                    /* If directory index is 0, that means current directory.  */
+                    printf ("\n./%s:[++]\n",
+                            file_table[state_machine_regs.file - 1].name);
+                  else if (directory_table == NULL)
+                    printf (_("\n [Use directory table entry %d]\n"),
+                            file_table[state_machine_regs.file - 1].directory_index - 1);
+                  else
+                    /* The directory index starts counting at 1.  */
+                    printf ("\n%s/%s:\n",
+                            directory_table[file_table[state_machine_regs.file - 1].directory_index - 1],
+                            file_table[state_machine_regs.file - 1].name);
+                  break;
+
+                case DW_LNS_set_column:
+                  uladv = read_uleb128 (data, & bytes_read, end);
+                  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 - linfo.li_opcode_base) / linfo.li_line_range);
+                  if (linfo.li_max_ops_per_insn == 1)
+                    {
+                      uladv *= linfo.li_min_insn_length;
+                      state_machine_regs.address += uladv;
+                    }
+                  else
+                    {
+                      state_machine_regs.address
+                        += ((state_machine_regs.op_index + uladv)
+                            / linfo.li_max_ops_per_insn)
+                        * linfo.li_min_insn_length;
+                      state_machine_regs.op_index
+                        = (state_machine_regs.op_index + uladv)
+                        % linfo.li_max_ops_per_insn;
+                    }
+                  break;
+
+                case DW_LNS_fixed_advance_pc:
+                  SAFE_BYTE_GET_AND_INC (uladv, data, 2, end);
+                  state_machine_regs.address += uladv;
+                  state_machine_regs.op_index = 0;
+                  break;
+
+                case DW_LNS_set_prologue_end:
+                  break;
+
+                case DW_LNS_set_epilogue_begin:
+                  break;
+
+                case DW_LNS_set_isa:
+                  uladv = read_uleb128 (data, & bytes_read, end);
+                  data += bytes_read;
+                  printf (_("  Set ISA to %lu\n"), uladv);
+                  break;
+
+                default:
+                  printf (_("  Unknown opcode %d with operands: "), op_code);
+
+                  if (standard_opcodes != NULL)
+                    for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
+                      {
+                        printf ("0x%s%s", dwarf_vmatoa ("x", read_uleb128 (data,
+                                                                           &bytes_read, end)),
+                                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.  */
@@ -3329,9 +3355,16 @@ display_debug_lines_decoded (struct dwarf_section *section,
              || (op_code == DW_LNS_copy))
             {
               const unsigned int MAX_FILENAME_LENGTH = 35;
-              char *fileName = (char *)file_table[state_machine_regs.file - 1].name;
+              char *fileName;
               char *newFileName = NULL;
-              size_t fileNameLength = strlen (fileName);
+              size_t fileNameLength;
+
+             if (file_table)
+               fileName = (char *) file_table[state_machine_regs.file - 1].name;
+             else
+               fileName = "<unknown>";
+
+             fileNameLength = strlen (fileName);
 
               if ((fileNameLength > MAX_FILENAME_LENGTH) && (!do_wide))
                 {
@@ -3378,10 +3411,21 @@ display_debug_lines_decoded (struct dwarf_section *section,
               free (newFileName);
             }
         }
-      free (file_table);
-      file_table = NULL;
-      free (directory_table);
-      directory_table = NULL;
+
+      if (file_table)
+       {
+         free (file_table);
+         file_table = NULL;
+         n_files = 0;
+       }
+
+      if (directory_table)
+       {
+         free (directory_table);
+         directory_table = NULL;
+         n_directories = 0;
+       }
+
       putchar ('\n');
     }
 
index b7607a0..a71bf94 100644 (file)
@@ -4838,7 +4838,8 @@ process_section_headers (FILE * file)
              || (do_debug_info     && const_strneq (name, "info"))
              || (do_debug_info     && const_strneq (name, "types"))
              || (do_debug_abbrevs  && const_strneq (name, "abbrev"))
-             || (do_debug_lines    && const_strneq (name, "line"))
+             || (do_debug_lines    && strcmp (name, "line") == 0)
+             || (do_debug_lines    && const_strneq (name, "line."))
              || (do_debug_pubnames && const_strneq (name, "pubnames"))
              || (do_debug_pubtypes && const_strneq (name, "pubtypes"))
              || (do_debug_aranges  && const_strneq (name, "aranges"))
@@ -10972,6 +10973,7 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file)
   /* See if we know how to display the contents of this section.  */
   for (i = 0; i < max; i++)
     if (streq (debug_displays[i].section.uncompressed_name, name)
+       || (i == line && const_strneq (name, ".debug_line."))
         || streq (debug_displays[i].section.compressed_name, name))
       {
        struct dwarf_section * sec = &debug_displays [i].section;
@@ -10980,7 +10982,9 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file)
        if (secondary)
          free_debug_section ((enum dwarf_section_display_enum) i);
 
-       if (streq (sec->uncompressed_name, name))
+       if (i == line && const_strneq (name, ".debug_line."))
+         sec->name = name;
+       else if (streq (sec->uncompressed_name, name))
          sec->name = sec->uncompressed_name;
        else
          sec->name = sec->compressed_name;
index 1eb995d..ec756d8 100644 (file)
@@ -1,3 +1,16 @@
+2013-04-29  Nick Clifton  <nickc@redhat.com>
+
+       * as.c (Options): Add -gdwarf-sections.
+       (parse_args): Likewise.
+       * as.h (flag_dwarf_sections): Declare.
+       * dwarf2dbg.c (emit_fixed_inc_line_addr): Skip section changes.
+       (process_entries): When -gdwarf-sections is enabled generate
+       fragmentary .debug_line sections.
+       (out_debug_line): Set the section for the .debug_line section end
+       symbol.
+       * doc/as.texinfo: Document -gdwarf-sections.
+       * NEWS: Mention -gdwarf-sections.
+
 2013-04-26  Christian Groessler  <chris@groessler.org>
 
        * config/tc-z8k.c (md_parse_option): Set z8k_target_from_cmdline
index f453b49..202db36 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add -gdwarf-sections command line option to enable per-code-section
+  generation of DWARF .debug_line sections.
+
 * Add support for Altera Nios II.
 
 * Add support for the Imagination Technologies Meta processor.
index 2caca70..1b1d34e 100644 (file)
--- a/gas/as.c
+++ b/gas/as.c
@@ -1,8 +1,5 @@
 /* as.c - GAS main program.
-   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011, 2012, 2013
-   Free Software Foundation, Inc.
+   Copyright 1987-2013 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -302,6 +299,8 @@ Options:\n\
   fprintf (stream, _("\
   --gdwarf-2              generate DWARF2 debugging information\n"));
   fprintf (stream, _("\
+  --gdwarf-sections       generate per-function section names for DWARF line information\n"));
+  fprintf (stream, _("\
   --hash-size=<value>     set the hash table size close to <value>\n"));
   fprintf (stream, _("\
   --help                  show this message and exit\n"));
@@ -443,6 +442,7 @@ parse_args (int * pargc, char *** pargv)
       OPTION_GSTABS,
       OPTION_GSTABS_PLUS,
       OPTION_GDWARF2,
+      OPTION_GDWARF_SECTIONS,
       OPTION_STRIP_LOCAL_ABSOLUTE,
       OPTION_TRADITIONAL_FORMAT,
       OPTION_WARN,
@@ -490,6 +490,7 @@ parse_args (int * pargc, char *** pargv)
     /* GCC uses --gdwarf-2 but GAS uses to use --gdwarf2,
        so we keep it here for backwards compatibility.  */
     ,{"gdwarf2", no_argument, NULL, OPTION_GDWARF2}
+    ,{"gdwarf-sections", no_argument, NULL, OPTION_GDWARF_SECTIONS}
     ,{"gen-debug", no_argument, NULL, 'g'}
     ,{"gstabs", no_argument, NULL, OPTION_GSTABS}
     ,{"gstabs+", no_argument, NULL, OPTION_GSTABS_PLUS}
@@ -753,6 +754,10 @@ This program has absolutely no warranty.\n"));
          debug_type = DEBUG_DWARF2;
          break;
 
+       case OPTION_GDWARF_SECTIONS:
+         flag_dwarf_sections = TRUE;
+         break;
+
        case 'J':
          flag_signed_overflow_ok = 1;
          break;
index 9cdf7ae..1fefee9 100644 (file)
--- a/gas/as.h
+++ b/gas/as.h
@@ -1,7 +1,5 @@
 /* as.h - global header file
-   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012
-   Free Software Foundation, Inc.
+   Copyright 1987-2013 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -417,6 +415,7 @@ enum debug_info_type
 
 extern enum debug_info_type debug_type;
 extern int use_gnu_debug_info_extensions;
+COMMON bfd_boolean flag_dwarf_sections;
 \f
 /* Maximum level of macro nesting.  */
 extern int max_macro_nest;
index 1476c14..9c55ef4 100644 (file)
@@ -1,7 +1,5 @@
 \input texinfo @c                               -*-Texinfo-*-
-@c  Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-@c  2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-@c  Free Software Foundation, Inc.
+@c  Copyright 1991-2013 Free Software Foundation, Inc.
 @c UPDATE!!  On future updates--
 @c   (1)   check for new machine-dep cmdline options in
 @c         md_parse_option definitions in config/tc-*.c
 This file documents the GNU Assembler "@value{AS}".
 
 @c man begin COPYRIGHT
-Copyright @copyright{} 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-2000, 2001, 2002, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
-Inc.
+Copyright @copyright{} 1991-2013 Free Software Foundation, Inc.
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3
@@ -153,9 +149,7 @@ done.
 @end tex
 
 @vskip 0pt plus 1filll
-Copyright @copyright{} 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-2000, 2001, 2002, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
-Inc.
+Copyright @copyright{} 1991-2013 Free Software Foundation, Inc.
 
       Permission is granted to copy, distribute and/or modify this document
       under the terms of the GNU Free Documentation License, Version 1.3
@@ -236,7 +230,8 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
  [@b{--compress-debug-sections}]  [@b{--nocompress-debug-sections}]
  [@b{--debug-prefix-map} @var{old}=@var{new}]
  [@b{--defsym} @var{sym}=@var{val}] [@b{-f}] [@b{-g}] [@b{--gstabs}]
- [@b{--gstabs+}] [@b{--gdwarf-2}] [@b{--help}] [@b{-I} @var{dir}] [@b{-J}]
+ [@b{--gstabs+}] [@b{--gdwarf-2}] [@b{--gdwarf-sections}]
+ [@b{--help}] [@b{-I} @var{dir}] [@b{-J}]
  [@b{-K}] [@b{-L}] [@b{--listing-lhs-width}=@var{NUM}]
  [@b{--listing-lhs-width2}=@var{NUM}] [@b{--listing-rhs-width}=@var{NUM}]
  [@b{--listing-cont-lines}=@var{NUM}] [@b{--keep-locals}] [@b{-o}
@@ -648,6 +643,15 @@ Generate DWARF2 debugging information for each assembler line.  This
 may help debugging assembler code, if the debugger can handle it.  Note---this
 option is only supported by some targets, not all of them.
 
+@item --gdwarf-sections
+Instead of creating a .debug_line section, create a series of
+.debug_line.@var{foo} sections where @var{foo} is the name of the
+corresponding code section.  For example a code section called @var{.text.func}
+will have its dwarf line number information placed into a section called
+@var{.debug_line.text.func}.  If the code section is just called @var{.text}
+then debug line section will still be called just @var{.debug_line} without any
+suffix.
+
 @item --size-check=error
 @itemx --size-check=warning
 Issue an error or warning for invalid ELF .size directive.
index 76b5fe0..df93bac 100644 (file)
@@ -1,6 +1,5 @@
 /* dwarf2dbg.c - DWARF2 debug support
-   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   Copyright 1999-2013 Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of GAS, the GNU Assembler.
@@ -1109,13 +1108,15 @@ emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag,
                          char *p, int len)
 {
   expressionS *pexp;
-  segT line_seg;
   char *end = p + len;
 
   /* Line number sequences cannot go backward in addresses.  This means
      we've incorrectly ordered the statements in the sequence.  */
   gas_assert ((offsetT) addr_delta >= 0);
 
+  /* Verify that we have kept in sync with size_fixed_inc_line_addr.  */
+  gas_assert (len == size_fixed_inc_line_addr (line_delta, addr_delta));
+
   /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.  */
   if (line_delta != INT_MAX)
     {
@@ -1124,7 +1125,6 @@ emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag,
     }
 
   pexp = symbol_get_value_expression (frag->fr_symbol);
-  line_seg = subseg_get (".debug_line", 0);
 
   /* The DW_LNS_fixed_advance_pc opcode has a 2-byte operand so it can
      advance the address by at most 64K.  Linker relaxation (without
@@ -1145,14 +1145,12 @@ emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag,
       exp.X_op = O_symbol;
       exp.X_add_symbol = to_sym;
       exp.X_add_number = 0;
-      subseg_change (line_seg, 0);
       emit_expr_fix (&exp, sizeof_address, frag, p);
       p += sizeof_address;
     }
   else
     {
       *p++ = DW_LNS_fixed_advance_pc;
-      subseg_change (line_seg, 0);
       emit_expr_fix (pexp, 2, frag, p);
       p += 2;
     }
@@ -1294,6 +1292,40 @@ process_entries (segT seg, struct line_entry *e)
   symbolS *last_lab = NULL, *lab;
   struct line_entry *next;
 
+  if (flag_dwarf_sections)
+    {
+      char * name;
+      const char * sec_name;
+
+      /* Switch to the relevent sub-section before we start to emit
+        the line number table.
+
+        FIXME: These sub-sections do not have a normal Line Number
+        Program Header, thus strictly speaking they are not valid
+        DWARF sections.  Unfortunately the DWARF standard assumes
+        a one-to-one relationship between compilation units and
+        line number tables.  Thus we have to have a .debug_line
+        section, as well as our sub-sections, and we have to ensure
+        that all of the sub-sections are merged into a proper
+        .debug_line section before a debugger sees them.  */
+        
+      sec_name = bfd_get_section_name (stdoutput, seg);
+      if (strcmp (sec_name, ".text") != 0)
+       {
+         unsigned int len;
+
+         len = strlen (sec_name);
+         name = xmalloc (len + 11 + 2);
+         sprintf (name, ".debug_line%s", sec_name);
+         subseg_set (subseg_get (name, FALSE), 0);
+       }
+      else
+       /* Don't create a .debug_line.text section -
+          that is redundant.  Instead just switch back to the
+          normal .debug_line section.  */
+       subseg_set (subseg_get (".debug_line", FALSE), 0);
+    }
+
   do
     {
       int line_delta;
@@ -1534,6 +1566,16 @@ out_debug_line (segT line_seg)
       as_warn ("dwarf line number information for %s ignored",
               segment_name (s->seg));
 
+  if (flag_dwarf_sections)
+    /* We have to switch to the special .debug_line_end section
+       before emitting the end-of-debug_line symbol.  The linker
+       script arranges for this section to be placed after all the
+       (potentially garbage collected) .debug_line.<foo> sections.
+       This section contains the line_end symbol which is used to
+       compute the size of the linked .debug_line section, as seen
+       in the DWARF Line Number header.  */
+    subseg_set (subseg_get (".debug_line_end", FALSE), 0);
+
   symbol_set_value_now (line_end);
 }
 
index 48ef178..ed42859 100644 (file)
@@ -1,3 +1,7 @@
+2013-04-29  Nick Clifton  <nickc@redhat.com>
+
+       * gas/elf/dwarf2-3.d: Fix expected readelf output.
+
 2013-04-24  H.J. Lu  <hongjiu.lu@intel.com>
 
        * gas/i386/rex.d: Skip x86_64-*-elf*.
index 0e728dd..0d6c580 100644 (file)
@@ -34,5 +34,5 @@ Raw dump of debug contents of section \.z?debug_line:
   Entry        Dir     Time    Size    Name
   1    0       0       0       /beginwarn.c
 
- Line Number Statements:
+ No Line Number Statements.
 
index 5ba44bb..7317e43 100644 (file)
@@ -1,3 +1,8 @@
+2013-04-29  Nick Clifton  <nickc@redhat.com>
+
+       * scripttempl/DWARF.sc: Add support for .debug_line.* and
+       .debug_line_end.
+
 2013-04-29  Yaakov Selkowitz  <yselkowitz@users.sourceforge.net>
 
        * emultempl/pe.em [cygwin]: Do not merge rdata with v2
index 008a9a1..89ff919 100644 (file)
@@ -18,7 +18,7 @@ cat <<EOF
   /* DWARF 2 */
   .debug_info     0 : { *(.debug_info${RELOCATING+ .gnu.linkonce.wi.*}) }
   .debug_abbrev   0 : { *(.debug_abbrev) }
-  .debug_line     0 : { *(.debug_line) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
   .debug_frame    0 : { *(.debug_frame) }
   .debug_str      0 : { *(.debug_str) }
   .debug_loc      0 : { *(.debug_loc) }