David Mosberger <davidm@hpl.hp.com>
authorRichard Henderson <rth@redhat.com>
Thu, 3 Jun 1999 02:46:47 +0000 (02:46 +0000)
committerRichard Henderson <rth@redhat.com>
Thu, 3 Jun 1999 02:46:47 +0000 (02:46 +0000)
        * dwarf2.c (struct line_info): Add member END_SEQUENCE to keep
        track of end_sequence markers.
        (add_line_info): Add END_SEQUENCE arg.
        (decode_line_info): Don't try to infer lo_pc and hi_pc from the
        debug-line info---it doesn't work right if a compilation unit
        consists of multiple discontiguous code-sequences.  It would be
        worthwhile to optimize for the common case where a compilation
        unit results in a contiguous set of code sequences, but this is
        quite tricky to get right for arbitrary DWARF2 files.
        (lookup_address_in_line_info_table): Don't use the last line entry
        for a compilation unit for anything with an address higher than
        this line entry.  Also, check for end_sequence markers to
        correctly handle discontinuities.
        (_bfd_dwarf2_find_nearest_line): When checking previously loaded
        compilation units, check all compilation units with each->high==0
        just like when reading compilation units.
        * dwarf2.c (decode_line_info): Initialize table->files and
        table->last_line to NULL to avoid segfaults due to random
        values in these members.
        (concat_filename): Check for out-of-range file number before
        indexing filename table.  Segfaults suck.
        * dwarf2.c (decode_line_info): Don't truncate address to least
        significant 32 bits (breaks 64 bit targets).
        (lookup_address_in_function_table): Ditto.
        (comp_unit_contains_address): Ditto.

bfd/ChangeLog
bfd/dwarf2.c

index 1b33f40d06d4964e33b81af44983f34ce14f9fa7..3f1bae4a456ee231aa090958977a1a084f573256 100644 (file)
@@ -1,3 +1,33 @@
+1999-06-03  David Mosberger  <davidm@hpl.hp.com>
+
+       * dwarf2.c (struct line_info): Add member END_SEQUENCE to keep
+       track of end_sequence markers.
+       (add_line_info): Add END_SEQUENCE arg.
+       (decode_line_info): Don't try to infer lo_pc and hi_pc from the
+       debug-line info---it doesn't work right if a compilation unit
+       consists of multiple discontiguous code-sequences.  It would be
+       worthwhile to optimize for the common case where a compilation
+       unit results in a contiguous set of code sequences, but this is
+       quite tricky to get right for arbitrary DWARF2 files.
+       (lookup_address_in_line_info_table): Don't use the last line entry
+       for a compilation unit for anything with an address higher than
+       this line entry.  Also, check for end_sequence markers to
+       correctly handle discontinuities.
+       (_bfd_dwarf2_find_nearest_line): When checking previously loaded
+       compilation units, check all compilation units with each->high==0
+       just like when reading compilation units.
+
+       * dwarf2.c (decode_line_info): Initialize table->files and
+       table->last_line to NULL to avoid segfaults due to random
+       values in these members.
+       (concat_filename): Check for out-of-range file number before
+       indexing filename table.  Segfaults suck.
+
+       * dwarf2.c (decode_line_info): Don't truncate address to least
+       significant 32 bits (breaks 64 bit targets).
+       (lookup_address_in_function_table): Ditto.
+       (comp_unit_contains_address): Ditto.
+
 1999-06-02  Mark Mitchell  <Mark Mitchell <mark@codesourcery.com>>
 
        * elf32-mips.c (elf_mips_howto_table): Add R_MIPS_JALR.
index 1ea7cffb3d9d0d39edde8b068446460c28b6bb70..3af16455ff85994f81c5fc59fa984a7700c6d2a2 100644 (file)
@@ -631,6 +631,7 @@ struct line_info {
   char* filename;
   unsigned int line;
   unsigned int column;
+  int end_sequence;            /* end of (sequential) code sequence */
 };
 
 struct fileinfo {
@@ -653,12 +654,13 @@ struct line_info_table {
 };
 
 static void 
-add_line_info (table, address, filename, line, column)
+add_line_info (table, address, filename, line, column, end_sequence)
      struct line_info_table* table;
      bfd_vma address;
      char* filename;
      unsigned int line;
      unsigned int column;
+     int end_sequence;
 {
   struct line_info* info = (struct line_info*)
     bfd_alloc (table->abfd, sizeof (struct line_info));
@@ -670,6 +672,7 @@ add_line_info (table, address, filename, line, column)
   info->filename = filename;
   info->line = line;
   info->column = column;
+  info->end_sequence = end_sequence;
 }
 
 static char* 
@@ -677,7 +680,16 @@ concat_filename (table, file)
      struct line_info_table* table;
      unsigned int file;
 {
-  char* filename = table->files[file - 1].name;
+  char* filename;
+
+  if (file - 1 >= table->num_files)
+    {
+      (*_bfd_error_handler) (_("Dwarf Error: mangled line number "
+                              "section (bad file number)."));
+      return "<unknown>";
+    }
+
+  filename = table->files[file - 1].name;
   if (*filename == '/')
     return filename;
 
@@ -708,6 +720,12 @@ decode_line_info (unit)
   unsigned int i, bytes_read;
   char *cur_file, *cur_dir;
   unsigned char op_code, extended_op, adj_opcode;
+#if 0
+  /* This optimization unfortunately does not work well on programs
+     that have multiple sections containing text (such as Linux which
+     uses .text, and .text.init, for example.  */
+  bfd_vma hi_pc = 0, lo_pc = ~ (bfd_vma) 0;
+#endif
 
   if (! dwarf_line_buffer)
     {
@@ -747,6 +765,9 @@ decode_line_info (unit)
   table->num_dirs = 0;
   table->dirs = NULL;
 
+  table->files = NULL;
+  table->last_line = NULL;
+
   line_ptr = dwarf_line_buffer + unit->line_offset;
 
   /* read in the prologue */
@@ -831,6 +852,7 @@ decode_line_info (unit)
       int is_stmt = lh.default_is_stmt;
       int basic_block = 0;
       int end_sequence = 0;
+      boolean first_time = true;
 
       /* Decode the table. */
       while (! end_sequence)
@@ -847,7 +869,7 @@ decode_line_info (unit)
                {
                case DW_LNE_end_sequence:
                  end_sequence = 1;
-                 add_line_info (table, address, filename, line, column);
+                 add_line_info (table, address, filename, line, column, end_sequence);
                  break;
                case DW_LNE_set_address:
                  address = read_address (unit, line_ptr);
@@ -884,7 +906,7 @@ decode_line_info (unit)
                }
              break;
            case DW_LNS_copy:
-             add_line_info (table, address, filename, line, column);
+             add_line_info (table, address, filename, line, column, 0);
              basic_block = 0;
              break;
            case DW_LNS_advance_pc:
@@ -918,7 +940,8 @@ decode_line_info (unit)
              basic_block = 1;
              break;
            case DW_LNS_const_add_pc:
-             address += (255 - lh.opcode_base) / lh.line_range;
+             address += lh.minimum_instruction_length
+                     * ((255 - lh.opcode_base) / lh.line_range);
              break;
            case DW_LNS_fixed_advance_pc:
              address += read_2_bytes (abfd, line_ptr);
@@ -930,11 +953,27 @@ decode_line_info (unit)
                * lh.minimum_instruction_length;
              line += lh.line_base + (adj_opcode % lh.line_range);
              /* append row to matrix using current values */
-             add_line_info (table, address, filename, line, column);
+             add_line_info (table, address, filename, line, column, 0);
              basic_block = 1;
            }
+#if 0
+         if (unit->high == 0)
+           {
+             if (address > hi_pc)
+               hi_pc = address;
+             if (address < lo_pc)
+               lo_pc = address;
+           }
+#endif
        }
     }
+#if 0
+  if (unit->high == 0 && hi_pc != 0)
+    {
+      unit->high = hi_pc;
+      unit->low = lo_pc;
+    }
+#endif
 
   return table;
 }
@@ -954,21 +993,25 @@ lookup_address_in_line_info_table (table,
      const char **filename_ptr;
      unsigned int *linenumber_ptr;
 {
+  struct line_info* next_line = table->last_line;
   struct line_info* each_line;
-  struct line_info* next_line;
   
-  for (next_line = 0, each_line = table->last_line;
-       each_line;
-       next_line = each_line, each_line = each_line->prev_line)
+  if (!next_line)
+    return false;
+
+  each_line = next_line->prev_line;
+
+  while (each_line && next_line)
     {
-      if (addr >= each_line->address
-         && (next_line == 0
-             || addr < next_line->address)) 
+      if (!each_line->end_sequence
+         && addr >= each_line->address && addr < next_line->address)
        {
          *filename_ptr = each_line->filename;
          *linenumber_ptr = each_line->line;
          return true;
        }
+      next_line = each_line;
+      each_line = each_line->prev_line;
     }
   
   return false;
@@ -1363,6 +1406,8 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
 
   struct comp_unit* each;
   
+  boolean found;
+
   *filename_ptr = NULL;
   *functionname_ptr = NULL;
   *linenumber_ptr = 0;
@@ -1404,14 +1449,20 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
 
       stash->info_ptr_end = stash->info_ptr + size;
 
-      /* FIXME:  There is a problem with the contents of the .debug_info section.
-        The 'low' and 'high' addresses of the comp_units are computed by relocs
-        against symbols in the .text segment.  We need these addresses in
-        order to determine the nearest line number, and so we have to resolve
-        the relocs.  There is a similar problem when the .debug_line section is
-        processed as well.
+      /* FIXME: There is a problem with the contents of the
+        .debug_info section.  The 'low' and 'high' addresses of the
+        comp_units are computed by relocs against symbols in the
+        .text segment.  We need these addresses in order to determine
+        the nearest line number, and so we have to resolve the
+        relocs.  There is a similar problem when the .debug_line
+        section is processed as well (e.g., there may be relocs
+        against the operand of the DW_LNE_set_address operator).
         
-        Unfortunately getting hold of the reloc information is hard... */
+        Unfortunately getting hold of the reloc information is hard...
+
+        For now, this means that disassembling object files (as
+        opposed to fully executables) does not always work as well as
+        we would like.  */
     }
   
   /* A null info_ptr indicates that there is no dwarf2 info 
@@ -1424,11 +1475,23 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
 
   for (each = stash->all_comp_units; each; each = each->next_unit)
     {
-      if (comp_unit_contains_address (each, addr))
-       return comp_unit_find_nearest_line (each, addr,
-                                           filename_ptr, 
-                                           functionname_ptr, 
-                                           linenumber_ptr);
+      if (each->high > 0)
+       {
+         if (comp_unit_contains_address (each, addr))
+           return comp_unit_find_nearest_line (each, addr,
+                                               filename_ptr, 
+                                               functionname_ptr, 
+                                               linenumber_ptr);
+       }
+      else
+       {
+         found = comp_unit_find_nearest_line (each, addr,
+                                               filename_ptr, 
+                                               functionname_ptr, 
+                                               linenumber_ptr);
+         if (found)
+           return true;
+       }
     }
 
   /* Read each remaining comp. units checking each as they are read. */
@@ -1451,11 +1514,28 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
              each->next_unit = stash->all_comp_units;
              stash->all_comp_units = each;
 
-             if (comp_unit_contains_address (each, addr))
-               return comp_unit_find_nearest_line (each, addr,
-                                                   filename_ptr, 
-                                                   functionname_ptr, 
-                                                   linenumber_ptr);
+             /* DW_AT_low_pc and DW_AT_high_pc are optional for
+                compilation units.  If we don't have them (i.e.,
+                unit->high == 0), we need to consult the line info
+                table to see if a compilation unit contains the given
+                address. */
+             if (each->high > 0)
+               {
+                 if (comp_unit_contains_address (each, addr))
+                   return comp_unit_find_nearest_line (each, addr,
+                                                      filename_ptr,
+                                                      functionname_ptr,
+                                                      linenumber_ptr);
+               }
+             else
+               {
+                 found = comp_unit_find_nearest_line (each, addr,
+                                                      filename_ptr,
+                                                      functionname_ptr,
+                                                      linenumber_ptr);
+                 if (found)
+                   return true;
+               }
            }
        }
     }