]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add support for DWARF-5 and experimental two-level line number tables.
authorCary Coutant <ccoutant@google.com>
Wed, 7 Jan 2015 00:56:43 +0000 (16:56 -0800)
committerCary Coutant <ccoutant@google.com>
Tue, 31 Mar 2015 17:51:10 +0000 (10:51 -0700)
http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables

2015-01-06  Cary Coutant  <ccoutant@google.com>

binutils/
* dwarf.h (struct DWARF2_Internal_LineInfo): Add li_address_size and
li_segment_size.
* dwarf.c (struct State_Machine_Registers): Add discriminator,
context, and subprogram.
(reset_state_machine): Likewise.
(logicals_table, logicals_allocated, logicals_count): New variables.
(free_logicals): New function.
(append_logical): New function.
(process_extended_line_op): Add is_logical parameter; track
discriminator.
(fetch_indirect_string): Correct boundary check.
(fetch_indirect_line_string): New function.
(fetch_indexed_string): Corrrect boundary check.
(DWARF2_LINE_EXPERIMENTAL_VERSION): New macro.
(read_debug_line_header): Add pinitial_length_size, poffset_size
parameters.  Update all callers.  Check for new line table versions.
Read li_address_size and li_segment_size.
(display_directory_table_v4): New function, factored out from
display_debug_lines_raw.
(display_file_name_table_v4): Likewise.
(display_dir_file_table_v5): New function.
(display_line_program): New function, factored out from
display_debug_lines_raw.
(display_debug_lines_raw): Support new line table versions.
(display_debug_lines_decoded): Add missing newline to warning.
(display_debug_lines): Load .debug_line_str section.
(debug_displays): Add .debug_line_str section.
* dwarf.h (dwarf_section_display_enum): Add line_str.
* readelf.c (process_section_headers): Add .debug_line_str.

binutils/dwarf.c
binutils/dwarf.h
binutils/readelf.c

index 588414081a3078a3c6b82dd86b1e7b5bd38ebefd..0e33e9958f795265ec40ba44de59e6e447df3c9c 100644 (file)
@@ -387,6 +387,9 @@ typedef struct State_Machine_Registers
   unsigned int file;
   unsigned int line;
   unsigned int column;
+  unsigned int discriminator;
+  unsigned int context;
+  unsigned int subprogram;
   int is_stmt;
   int basic_block;
   unsigned char op_index;
@@ -406,19 +409,65 @@ reset_state_machine (int is_stmt)
   state_machine_regs.file = 1;
   state_machine_regs.line = 1;
   state_machine_regs.column = 0;
+  state_machine_regs.discriminator = 0;
+  state_machine_regs.context = 0;
+  state_machine_regs.subprogram = 0;
   state_machine_regs.is_stmt = is_stmt;
   state_machine_regs.basic_block = 0;
   state_machine_regs.end_sequence = 0;
   state_machine_regs.last_file_entry = 0;
 }
 
+/* Build a logicals table for reference when reading the actuals table.  */
+
+static SMR *logicals_table = NULL;
+static unsigned int logicals_allocated = 0;
+static unsigned int logicals_count = 0;
+
+static void
+free_logicals (void)
+{
+  free (logicals_table);
+  logicals_allocated = 0;
+  logicals_count = 0;
+  logicals_table = NULL;
+}
+
+static void
+append_logical (void)
+{
+  if (logicals_allocated == 0)
+    {
+      logicals_allocated = 4;
+      logicals_table = (SMR *) xmalloc (logicals_allocated * sizeof (SMR));
+    }
+  if (logicals_count >= logicals_allocated)
+    {
+      logicals_allocated *= 2;
+      logicals_table = (SMR *)
+         xrealloc (logicals_table, logicals_allocated * sizeof (SMR));
+    }
+  logicals_table[logicals_count++] = state_machine_regs;
+  printf (_("\t\tLogical %u: 0x%s[%u] file %u line %u discrim %u context %u subprog %u is_stmt %d\n"),
+         logicals_count,
+         dwarf_vmatoa ("x", state_machine_regs.address),
+         state_machine_regs.op_index,
+         state_machine_regs.file,
+         state_machine_regs.line,
+         state_machine_regs.discriminator,
+         state_machine_regs.context,
+         state_machine_regs.subprogram,
+         state_machine_regs.is_stmt);
+}
+
 /* Handled an extend line op.
    Returns the number of bytes read.  */
 
 static int
 process_extended_line_op (unsigned char * data,
                          int is_stmt,
-                         unsigned char * end)
+                         unsigned char * end,
+                         int is_logical)
 {
   unsigned char op_code;
   unsigned int bytes_read;
@@ -445,6 +494,8 @@ process_extended_line_op (unsigned char * data,
     {
     case DW_LNE_end_sequence:
       printf (_("End of Sequence\n\n"));
+      if (is_logical)
+       append_logical ();
       reset_state_machine (is_stmt);
       break;
 
@@ -483,8 +534,14 @@ process_extended_line_op (unsigned char * data,
       break;
 
     case DW_LNE_set_discriminator:
-      printf (_("set Discriminator to %s\n"),
-             dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
+      {
+       unsigned int discrim;
+
+       discrim = read_uleb128 (data, & bytes_read, end);
+       data += bytes_read;
+       printf (_("set Discriminator to %u\n"), discrim);
+       state_machine_regs.discriminator = discrim;
+      }
       break;
 
     /* HP extensions.  */
@@ -597,7 +654,7 @@ fetch_indirect_string (dwarf_vma offset)
   if (section->start == NULL)
     return (const unsigned char *) _("<no .debug_str section>");
 
-  if (offset > section->size)
+  if (offset >= section->size)
     {
       warn (_("DW_FORM_strp offset too big: %s\n"),
            dwarf_vmatoa ("x", offset));
@@ -607,6 +664,24 @@ fetch_indirect_string (dwarf_vma offset)
   return (const unsigned char *) section->start + offset;
 }
 
+static const unsigned char *
+fetch_indirect_line_string (dwarf_vma offset)
+{
+  struct dwarf_section *section = &debug_displays [line_str].section;
+
+  if (section->start == NULL)
+    return (const unsigned char *) _("<no .debug_line_str section>");
+
+  if (offset >= section->size)
+    {
+      warn (_("DW_FORM_line_strp offset too big: %s\n"),
+           dwarf_vmatoa ("x", offset));
+      return (const unsigned char *) _("<offset is too big>");
+    }
+
+  return (const unsigned char *) section->start + offset;
+}
+
 static const char *
 fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
                      dwarf_vma offset_size, int dwo)
@@ -624,7 +699,7 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
 
   if (this_set != NULL)
     index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS];
-  if (index_offset > index_section->size)
+  if (index_offset + offset_size > index_section->size)
     {
       warn (_("DW_FORM_GNU_str_index offset too big: %s\n"),
            dwarf_vmatoa ("x", index_offset));
@@ -637,7 +712,7 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
 
   str_offset = byte_get (index_section->start + index_offset, offset_size);
   str_offset -= str_section->address;
-  if (str_offset > str_section->size)
+  if (str_offset >= str_section->size)
     {
       warn (_("DW_FORM_GNU_str_index indirect offset too big: %s\n"),
            dwarf_vmatoa ("x", str_offset));
@@ -2721,6 +2796,10 @@ load_debug_info (void * file)
   return 0;
 }
 
+/* Experimental DWARF 5 extensions.
+   See http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables.  */
+#define DWARF2_LINE_EXPERIMENTAL_VERSION 0xf006
+
 /* 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.
@@ -2731,7 +2810,9 @@ 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 ** end_of_sequence,
+                       unsigned int * pinitial_length_size,
+                       unsigned int * poffset_size)
 {
   unsigned char *hdrptr;
   unsigned int offset_size;
@@ -2756,6 +2837,8 @@ read_debug_line_header (struct dwarf_section * section,
       offset_size = 4;
       initial_length_size = 4;
     }
+  *pinitial_length_size = initial_length_size;
+  *poffset_size = offset_size;
 
   if (linfo->li_length + initial_length_size > section->size)
     {
@@ -2778,15 +2861,30 @@ read_debug_line_header (struct dwarf_section * section,
   /* Get and check the version number.  */
   SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end);
 
+  /* Version 0xf006 is for experimental two-level line tables.  */
   if (linfo->li_version != 2
       && linfo->li_version != 3
-      && linfo->li_version != 4)
+      && linfo->li_version != 4
+      && linfo->li_version != 5
+      && linfo->li_version != DWARF2_LINE_EXPERIMENTAL_VERSION)
     {
-      warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n"));
+      warn (_("Only DWARF versions 2-5 line info are currently supported.\n"));
       return NULL;
     }
 
+  if (linfo->li_version < 5)
+    {
+      linfo->li_address_size = 0;
+      linfo->li_segment_size = 0;
+    }
+  else if (linfo->li_version != DWARF2_LINE_EXPERIMENTAL_VERSION)
+    {
+      SAFE_BYTE_GET_AND_INC (linfo->li_address_size, hdrptr, 1, end);
+      SAFE_BYTE_GET_AND_INC (linfo->li_segment_size, 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)
@@ -2820,12 +2918,473 @@ read_debug_line_header (struct dwarf_section * section,
   return hdrptr;
 }
 
+static void
+display_directory_table_v4 (unsigned char *start, unsigned char *end,
+                           unsigned char **pdata)
+{
+  unsigned char *data = *pdata;
+  unsigned int last_dir_entry = 0;
+
+  if (*data == 0)
+    printf (_("\n The Directory Table is empty.\n"));
+  else
+    {
+      printf (_("\n The Directory Table (offset 0x%lx):\n"),
+             (long)(data - start));
+
+      while (data < end && *data != 0)
+       {
+         printf ("  %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data);
+
+         data += strnlen ((char *) data, end - data) + 1;
+       }
+    }
+
+  /* Skip the NUL at the end of the table.  */
+  *pdata = data + 1;
+}
+
+static void
+display_file_name_table_v4 (unsigned char *start, unsigned char *end,
+                           unsigned char **pdata)
+{
+  unsigned char *data = *pdata;
+
+  if (*data == 0)
+    printf (_("\n The File Name Table is empty.\n"));
+  else
+    {
+      printf (_("\n The File Name Table (offset 0x%lx):\n"),
+             (long)(data - start));
+      printf (_("  Entry\tDir\tTime\tSize\tName\n"));
+
+      while (data < end && *data != 0)
+       {
+         unsigned char *name;
+         unsigned int bytes_read;
+
+         printf ("  %d\t", ++state_machine_regs.last_file_entry);
+         name = data;
+         data += strnlen ((char *) data, end - data) + 1;
+
+         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", (int)(end - name), name);
+
+         if (data == end)
+           {
+             warn (_("Corrupt file name table entry\n"));
+             break;
+           }
+       }
+    }
+
+  /* Skip the NUL at the end of the table.  */
+  *pdata = data + 1;
+}
+
+static int
+display_dir_file_table_v5 (unsigned char *start, unsigned char *end,
+                          unsigned char **pdata, char *table_name,
+                          unsigned int offset_size)
+{
+  unsigned char *data = *pdata;
+  unsigned int bytes_read;
+  unsigned int format_count;
+  unsigned int *content_types;
+  unsigned int *content_forms;
+  unsigned int entry_count;
+  unsigned int i, j;
+  const unsigned char *name;
+  dwarf_vma offset;
+  unsigned int val;
+
+  format_count = read_uleb128 (data, & bytes_read, end);
+  data += bytes_read;
+  content_types = (unsigned int *) xmalloc (format_count *
+                                           sizeof (unsigned int));
+  content_forms = (unsigned int *) xmalloc (format_count *
+                                           sizeof (unsigned int));
+  for (j = 0; j < format_count; j++)
+    {
+      content_types[j] = read_uleb128 (data, & bytes_read, end);
+      data += bytes_read;
+      content_forms[j] = read_uleb128 (data, & bytes_read, end);
+      data += bytes_read;
+    }
+
+  entry_count = read_uleb128 (data, & bytes_read, end);
+  data += bytes_read;
+
+  if (entry_count == 0)
+    printf (_("\n The %s Table is empty.\n"), table_name);
+  else
+    {
+      printf (_("\n The %s Table (offset 0x%lx):\n"),
+             table_name, (long)(data - start));
+
+      printf (_("  Entry"));
+      for (j = 0; j < format_count; j++)
+       {
+         printf ("\t");
+         switch (content_types[j])
+           {
+           case DW_LNCT_path:
+             printf (_("Path"));
+             break;
+           case DW_LNCT_subprogram_name:
+             printf (_("Name"));
+             break;
+           case DW_LNCT_directory_index:
+             printf (_("Dir"));
+             break;
+           case DW_LNCT_decl_file:
+             printf (_("File"));
+             break;
+           case DW_LNCT_decl_line:
+             printf (_("Line"));
+             break;
+           }
+       }
+      printf ("\n");
+    }
+
+  for (i = 0; i < entry_count; i++)
+    {
+      printf ("  %d", i + 1);
+      for (j = 0; j < format_count; j++)
+       {
+         if (data >= end)
+           break;
+         switch (content_forms[j])
+           {
+           case DW_FORM_string:
+             printf ("\t%.*s", (int) (end - data), data);
+             data += strnlen ((char *) data, end - data) + 1;
+             break;
+           case DW_FORM_line_strp:
+             SAFE_BYTE_GET_AND_INC (offset, data, offset_size, end);
+             name = fetch_indirect_line_string (offset);
+             printf ("\t%s", name);
+             break;
+           case DW_FORM_udata:
+             val = read_uleb128 (data, & bytes_read, end);
+             data += bytes_read;
+             printf ("\t%u", val);
+             break;
+           default:
+             printf ("\t%s", _("(unrecognized FORM code)"));
+             data = end;
+             break;
+           }
+       }
+      printf ("\n");
+
+      /* PR 17512: file: 002-132094-0.004.  */
+      if (data >= end - 1)
+       break;
+    }
+
+  free (content_types);
+  free (content_forms);
+
+  *pdata = data;
+  return entry_count;
+}
+
+static void
+display_line_program (unsigned char *start, unsigned char *end,
+                     unsigned char **pdata, char *table_name,
+                     DWARF2_Internal_LineInfo *linfo,
+                     unsigned char *standard_opcodes,
+                     int is_logical)
+{
+  unsigned char *data = *pdata;
+
+  if (data >= end)
+    {
+      printf (_(" No %s.\n"), table_name);
+      return;
+    }
+
+  printf (" %s:\n", table_name);
+
+  while (data < end)
+    {
+      unsigned char op_code;
+      dwarf_signed_vma adv;
+      dwarf_vma uladv;
+      unsigned int bytes_read;
+      unsigned int logical;
+      int i;
+
+      printf ("  [0x%08lx]", (long)(data - start));
+
+      op_code = *data++;
+
+      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);
+         if (is_logical)
+           append_logical ();
+         state_machine_regs.discriminator = 0;
+       }
+      else
+       {
+         switch (op_code)
+            {
+            case DW_LNS_extended_op:
+              data += process_extended_line_op (data, linfo->li_default_is_stmt,
+                                                end, is_logical);
+              break;
+
+            case DW_LNS_copy:
+              printf (_("  Copy\n"));
+              if (is_logical)
+                append_logical ();
+              state_machine_regs.discriminator = 0;
+              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;
+
+            case DW_LNS_set_subprogram:
+            /* This opcode is aliased with:  */
+            /* case DW_LNS_set_address_from_logical:  */
+              if (is_logical)
+                {
+                  /* DW_LNS_set_subprogram */
+                  state_machine_regs.context = 0;
+                  state_machine_regs.subprogram = read_uleb128 (data, & bytes_read, end);
+                  data += bytes_read;
+                  printf (_("  Set subprogram to %u and reset context to 0\n"),
+                          state_machine_regs.subprogram);
+                }
+              else
+                {
+                  /* DW_LNS_set_address_from_logical */
+                  adv = read_sleb128 (data, & bytes_read, end);
+                  data += bytes_read;
+                  state_machine_regs.line += adv;
+                  logical = state_machine_regs.line;
+                  if (logical - 1 < logicals_count)
+                    {
+                      state_machine_regs.address = logicals_table[logical - 1].address;
+                      state_machine_regs.op_index = logicals_table[logical - 1].op_index;
+                    }
+                  else
+                    warn (_("Logical row number outside range of logicals table\n"));
+                  printf (_("  Advance Line by %s to %u and set address from logical to 0x%s[%u]\n"),
+                          dwarf_vmatoa ("d", adv),
+                          logical,
+                          dwarf_vmatoa ("x", state_machine_regs.address),
+                          state_machine_regs.op_index);
+                }
+              break;
+
+            case DW_LNS_inlined_call:
+              adv = read_sleb128 (data, & bytes_read, end);
+              data += bytes_read;
+              state_machine_regs.context = logicals_count + adv;
+              state_machine_regs.subprogram = read_uleb128 (data, & bytes_read, end);
+              data += bytes_read;
+              printf (_("  Set context to %u and subprogram to %u\n"),
+                      state_machine_regs.context,
+                      state_machine_regs.subprogram);
+              break;
+
+            case DW_LNS_pop_context:
+              logical = state_machine_regs.context;
+              printf (_("  Pop context to logical %u\n"), logical);
+              if (logical - 1 < logicals_count)
+                {
+                  state_machine_regs.file = logicals_table[logical - 1].file;
+                  state_machine_regs.line = logicals_table[logical - 1].line;
+                  state_machine_regs.column = logicals_table[logical - 1].column;
+                  state_machine_regs.discriminator = logicals_table[logical - 1].discriminator;
+                  state_machine_regs.is_stmt = logicals_table[logical - 1].is_stmt;
+                  state_machine_regs.context = logicals_table[logical - 1].context;
+                  state_machine_regs.subprogram = logicals_table[logical - 1].subprogram;
+                }
+              else
+                warn (_("Context register outside range of logicals table\n"));
+              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');
+  *pdata = data;
+}
+
 static int
 display_debug_lines_raw (struct dwarf_section *section,
                         unsigned char *data,
                         unsigned char *end)
 {
   unsigned char *start = section->start;
+  unsigned int initial_length_size;
+  unsigned int offset_size;
 
   printf (_("Raw dump of debug contents of section %s:\n\n"),
          section->name);
@@ -2834,10 +3393,15 @@ display_debug_lines_raw (struct dwarf_section *section,
     {
       static DWARF2_Internal_LineInfo saved_linfo;
       DWARF2_Internal_LineInfo linfo;
+      unsigned int logicals_table_offset = 0;
+      unsigned int actuals_table_offset = 0;
+      unsigned char *end_of_header_length;
       unsigned char *standard_opcodes;
+      unsigned char *start_of_line_program;
+      unsigned char *end_of_logicals;
       unsigned char *end_of_sequence;
-      unsigned int last_dir_entry = 0;
       int i;
+      unsigned char *hdrptr = NULL;
 
       if (const_strneq (section->name, ".debug_line.")
          /* Note: the following does not apply to .debug_line.dwo sections.
@@ -2854,7 +3418,9 @@ display_debug_lines_raw (struct dwarf_section *section,
             Since the section is a fragment it does not have the details
             needed to fill out a LineInfo structure, so instead we use the
             details from the last full debug_line section that we processed.  */
+         start_of_line_program = data;
          end_of_sequence = end;
+         end_of_logicals = end;
          standard_opcodes = NULL;
          linfo = saved_linfo;
          /* PR 17531: file: 0522b371.  */
@@ -2867,15 +3433,21 @@ display_debug_lines_raw (struct dwarf_section *section,
        }
       else
        {
-         unsigned char * hdrptr;
-
          if ((hdrptr = read_debug_line_header (section, data, end, & linfo,
-                                               & end_of_sequence)) == NULL)
+                                               & end_of_sequence,
+                                               & initial_length_size,
+                                               & offset_size)) == NULL)
            return 0;
 
          printf (_("  Offset:                      0x%lx\n"), (long)(data - start));
          printf (_("  Length:                      %ld\n"), (long) linfo.li_length);
          printf (_("  DWARF Version:               %d\n"), linfo.li_version);
+         if (linfo.li_version >= 5
+             && linfo.li_version != DWARF2_LINE_EXPERIMENTAL_VERSION)
+           {
+             printf (_("  Address Size:                %u\n"), linfo.li_address_size);
+             printf (_("  Segment Size:                %u\n"), linfo.li_segment_size);
+           }
          printf (_("  Prologue Length:             %d\n"), (int) linfo.li_prologue_length);
          printf (_("  Minimum Instruction Length:  %d\n"), linfo.li_min_insn_length);
          if (linfo.li_version >= 4)
@@ -2885,6 +3457,13 @@ display_debug_lines_raw (struct dwarf_section *section,
          printf (_("  Line Range:                  %d\n"), linfo.li_line_range);
          printf (_("  Opcode Base:                 %d\n"), linfo.li_opcode_base);
 
+         end_of_header_length = data + initial_length_size + 2 + offset_size;
+         if (linfo.li_version >= 5
+             && linfo.li_version != DWARF2_LINE_EXPERIMENTAL_VERSION)
+           end_of_header_length += 2;
+         start_of_line_program = end_of_header_length + linfo.li_prologue_length;
+         end_of_logicals = end;
+
          /* PR 17512: file: 1665-6428-0.004.  */
          if (linfo.li_line_range == 0)
            {
@@ -2909,265 +3488,100 @@ display_debug_lines_raw (struct dwarf_section *section,
          for (i = 1; i < linfo.li_opcode_base; i++)
            printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
 
-         /* Display the contents of the Directory table.  */
          data = standard_opcodes + linfo.li_opcode_base - 1;
 
-         if (*data == 0)
-           printf (_("\n The Directory Table is empty.\n"));
-         else
+         if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION)
            {
-             printf (_("\n The Directory Table (offset 0x%lx):\n"),
-                     (long)(data - start));
+             /* Skip the fake directory and filename table.  */
+             data += 2;
 
-             while (data < end && *data != 0)
-               {
-                 printf ("  %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data);
+             /* Skip the fake extended opcode that wraps the rest
+                of the section.  */
+             data += 5;
 
-                 data += strnlen ((char *) data, end - data) + 1;
-               }
+             /* Read the logicals table offset and actuals table offset.  */
+             SAFE_BYTE_GET_AND_INC (logicals_table_offset, data, offset_size, end);
+             SAFE_BYTE_GET_AND_INC (actuals_table_offset, data, offset_size, end);
 
-             /* PR 17512: file: 002-132094-0.004.  */
-             if (data >= end - 1)
-               break;
-           }
+             start_of_line_program = end_of_header_length + logicals_table_offset;
 
-         /* Skip the NUL at the end of the table.  */
-         data++;
+             if (actuals_table_offset > 0)
+               end_of_logicals = end_of_header_length + actuals_table_offset;
 
-         /* 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 (offset 0x%lx):\n"),
-                     (long)(data - start));
-             printf (_("  Entry\tDir\tTime\tSize\tName\n"));
+             putchar ('\n');
+             printf (_("  Logicals Table Offset:       0x%x\n"), logicals_table_offset);
+             printf (_("  Actuals Table Offset:        0x%x\n"), actuals_table_offset);
+           }
 
-             while (data < end && *data != 0)
-               {
-                 unsigned char *name;
-                 unsigned int bytes_read;
+         /* Display the contents of the Directory table.  */
+         if (linfo.li_version >= 5)
+           display_dir_file_table_v5 (start, end, &data, _("Directory"),
+                                      offset_size);
+         else
+           display_directory_table_v4 (start, end, &data);
 
-                 printf ("  %d\t", ++state_machine_regs.last_file_entry);
-                 name = data;
-                 data += strnlen ((char *) data, end - data) + 1;
+         /* PR 17512: file: 002-132094-0.004.  */
+         if (data >= end - 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", (int)(end - name), name);
+         /* Display the contents of the File Name table.  */
+         if (linfo.li_version >= 5)
+           {
+             unsigned int count;
 
-                 if (data == end)
-                   {
-                     warn (_("Corrupt file name table entry\n"));
-                     break;
-                   }
-               }
+             count = display_dir_file_table_v5 (start, end, &data,
+                                                _("File Name"), offset_size);
+             state_machine_regs.last_file_entry = count - 1;
            }
+         else
+           display_file_name_table_v4 (start, end, &data);
+
+         /* Display the contents of the Subprogram table.  */
+         if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION)
+           display_dir_file_table_v5 (start, end, &data, _("Subprogram"),
+                                      offset_size);
 
-         /* Skip the NUL at the end of the table.  */
-         data++;
          putchar ('\n');
          saved_linfo = linfo;
        }
 
-      /* Now display the statements.  */
-      if (data >= end_of_sequence)
-       printf (_(" No Line Number Statements.\n"));
-      else
-       {
-         printf (_(" Line Number Statements:\n"));
-
-         while (data < end_of_sequence)
+      if (data > start_of_line_program)
+       warn (_("Line table header is longer than header_length indicates\n"));
+      else if (data < start_of_line_program)
+       warn (_("Line table header is shorter than header_length indicates\n"));
+      data = start_of_line_program;
+
+      if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION
+          && hdrptr != NULL
+          && actuals_table_offset > 0)
+        {
+          if (end_of_logicals > end)
            {
-             unsigned char op_code;
-             dwarf_signed_vma adv;
-             dwarf_vma uladv;
-             unsigned int bytes_read;
-
-             printf ("  [0x%08lx]", (long)(data - start));
-
-             op_code = *data++;
-
-             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)
-                    {
-                    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;
-                    }
+             warn (_("Actuals table offset %s extends beyond end of section\n"),
+                   dwarf_vmatoa ("u", actuals_table_offset));
+             end_of_logicals = end;
            }
-         putchar ('\n');
-       }
+          display_line_program (start, end_of_logicals, &data,
+                               _("Logicals Statements"),
+                               &linfo, standard_opcodes, 1);
+          if (data > end_of_logicals)
+           warn (_("Logicals table is longer than actuals_table_offset indicates\n"));
+          else if (data < end_of_logicals)
+           warn (_("Line table header is shorter than actuals_table_offset indicates\n"));
+          data = end_of_logicals;
+         reset_state_machine (linfo.li_default_is_stmt);
+          display_line_program (start, end_of_sequence, &data,
+                               _("Actuals Statements"),
+                               &linfo, standard_opcodes, 0);
+          free_logicals ();
+        }
+      else
+        {
+          display_line_program (start, end_of_sequence, &data,
+                               _("Line Number Statements"),
+                               &linfo, standard_opcodes, 0);
+        }
+
     }
 
   return 1;
@@ -3189,6 +3603,8 @@ display_debug_lines_decoded (struct dwarf_section *section,
                             unsigned char *end)
 {
   static DWARF2_Internal_LineInfo saved_linfo;
+  unsigned int initial_length_size;
+  unsigned int offset_size;
 
   printf (_("Decoded dump of debug contents of section %s:\n\n"),
          section->name);
@@ -3227,7 +3643,9 @@ display_debug_lines_decoded (struct dwarf_section *section,
          unsigned char *hdrptr;
 
          if ((hdrptr = read_debug_line_header (section, data, end, & linfo,
-                                               & end_of_sequence)) == NULL)
+                                               & end_of_sequence,
+                                               & initial_length_size,
+                                               & offset_size)) == NULL)
              return 0;
 
          /* PR 17531: file: 0522b371.  */
@@ -3651,7 +4069,7 @@ display_debug_lines_decoded (struct dwarf_section *section,
 }
 
 static int
-display_debug_lines (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED)
+display_debug_lines (struct dwarf_section *section, void *file)
 {
   unsigned char *data = section->start;
   unsigned char *end = data + section->size;
@@ -3661,6 +4079,8 @@ display_debug_lines (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED)
   if (do_debug_lines == 0)
     do_debug_lines |= FLAG_DEBUG_LINES_RAW;
 
+  load_debug_section (line_str, file);
+
   if (do_debug_lines & FLAG_DEBUG_LINES_RAW)
     retValRaw = display_debug_lines_raw (section, data, end);
 
@@ -7550,6 +7970,8 @@ struct dwarf_section_display debug_displays[] =
     display_debug_macro,    &do_debug_macinfo, 1 },
   { { ".debug_str",        ".zdebug_str",      NULL, NULL, 0, 0, 0, NULL },
     display_debug_str,     &do_debug_str,      0 },
+  { { ".debug_line_str",    ".zdebug_line_str",        NULL, NULL, 0, 0, 0, NULL },
+    display_debug_str,     &do_debug_str,      0 },
   { { ".debug_loc",        ".zdebug_loc",      NULL, NULL, 0, 0, 0, NULL },
     display_debug_loc,     &do_debug_loc,      1 },
   { { ".debug_pubtypes",    ".zdebug_pubtypes",        NULL, NULL, 0, 0, 0, NULL },
index 45f99277dbf63665d58f952b18ded9e16f5e2c3b..ce626de89fd5da94e549f384dc29cafd892bad94 100644 (file)
@@ -27,6 +27,8 @@ typedef struct
 {
   dwarf_vma     li_length;
   unsigned short li_version;
+  unsigned char  li_address_size;
+  unsigned char  li_segment_size;
   dwarf_vma      li_prologue_length;
   unsigned char  li_min_insn_length;
   unsigned char  li_max_ops_per_insn;
@@ -83,6 +85,7 @@ enum dwarf_section_display_enum
   macinfo,
   macro,
   str,
+  line_str,
   loc,
   pubtypes,
   gnu_pubtypes,
index 17d4fd48413719f6d34e26e53db640a79746e320..4044d296721c66ae2c462e11ce4616eaa63c2215 100644 (file)
@@ -5557,6 +5557,7 @@ process_section_headers (FILE * file)
              || (do_debug_macinfo  && const_strneq (name, "macinfo"))
              || (do_debug_macinfo  && const_strneq (name, "macro"))
              || (do_debug_str      && const_strneq (name, "str"))
+             || (do_debug_str      && const_strneq (name, "line_str"))
              || (do_debug_loc      && const_strneq (name, "loc"))
              || (do_debug_addr     && const_strneq (name, "addr"))
              || (do_debug_cu_index && const_strneq (name, "cu_index"))