Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* Re: [RFC/dwarf-2] Add support for included files
@ 2004-04-07 16:05 Jim Blandy
  2004-04-13  5:20 ` Joel Brobecker
  0 siblings, 1 reply; 22+ messages in thread
From: Jim Blandy @ 2004-04-07 16:05 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Daniel Jacobowitz, Eli Zaretskii, gdb-patches


Picking up a dropped thread from January:

http://sources.redhat.com/ml/gdb-patches/2004-01/msg00015.html

Some comments:

It's fine for GDB core code to assume that the psymtabs mention every
source file in the program.  They're supposed to.  The whole purpose
of the psymtabs is to act as an index for the full symbol information,
so that without taking the time/memory to read full symbols, we can at
least find the compilation unit we do need to read.  If that index
doesn't mention a source file, then it's incomplete.

I'm not too enthusiastic about Eli's suggestion that we put off
scanning for source file names until we get a filename we can't find.
It would help: we can find source files most of the time already, and
when the second scan was needed, it wouldn't be any more work than
what Joel's proposing we do every time.  But it's adding a third phase
to debug reading; I'd prefer to fix this problem without architectural
changes like that, if it's practical.

The original motivation for introducing psymtabs at all was speed:
GDB's startup time was, believe it or not, CPU-bound.  By constructing
only partial symtabs at startup time, we avoided parsing types
(essentially).  How does this patch affect the time GDB takes to start
up on itself?  (If you had some monster program lying around, that
would be better, but if all we've got is a brute...)

If it makes a big speed difference, then let's try ignoring
DW_LNE_define_file, not scanning the line number program, and just
entering the files given in the file_names table as psymtabs.  GCC
doesn't generate DW_LNE_define_file.  If that is much faster, then I
think it'll be okay.

(It's interesting to note that, since DW_LNE_define_file exists, the
mechanisms Dwarf 3 provides for "accelerated access" are insufficient:
there's no way to build a complete index of source file names without
reading the line tables.)


^ permalink raw reply	[flat|nested] 22+ messages in thread
* Re: [RFC/dwarf-2] Add support for included files
@ 2004-05-03 22:15 Andrew Pinski
  2004-05-04  0:15 ` Joel Brobecker
  0 siblings, 1 reply; 22+ messages in thread
From: Andrew Pinski @ 2004-05-03 22:15 UTC (permalink / raw)
  To: gdb-patches, J. Brobecker; +Cc: Andrew Pinski

I try to test building gdb with the mainline of gcc and it fails
to compile with the following error:

/home/gates/pinskia/src/gnu/combinesources/src/gdb/dwarf2read.c: In 
function `dwarf2_create_include_psymtab':
/home/gates/pinskia/src/gnu/combinesources/src/gdb/dwarf2read.c:1244: 
error: invalid lvalue in assignment

Could you fix the problem, please?

Thanks,
Andrew Pinski


2004-04-30  J. Brobecker  <brobecker@gnat.com>

         * dwarf2read.c (line_header): Add new included_p field in
         field file_names.
         (partial_die_info): New field has_stmt_list. New field 
line_offset.
         (dwarf2_create_include_psymtab): New function.
         (dwarf2_build_include_psymtabs): New function.
         (add_file_name): Add forward declaration. Initialize new field.
         (dwarf_decode_lines): Add new parameter. Enhance this procedure
         to be able to determine the list of files included by the
         given unit, and build their associated psymtabs.
         (dwarf2_build_psymtabs_hard): Build the psymtabs for the 
included
         files as well.
         (psymtab_to_symtab_1): Build the symtabs of all dependencies as 
well.
         (read_file_scope): Update call to dwarf_decode_lines.
         (read_partial_die): Handle DW_AT_stmt_list attributes.


^ permalink raw reply	[flat|nested] 22+ messages in thread
* [RFC/dwarf-2] Add support for included files
@ 2004-01-02  7:25 Joel Brobecker
  2004-01-02 14:18 ` Daniel Jacobowitz
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Joel Brobecker @ 2004-01-02  7:25 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 4290 bytes --]

Hello,

Ada95 defines the notion of "separates", which allows a developper
to write the implementation of either a function or a package in
a separate file. Here is a small example:

foo.ads:

        package Foo is
           procedure Proc;
        end Foo;

foo.adb:

        Package body Foo is
           procedure Proc is separate;
                          ^^^^^^^^^^^
        End Foo;

And then the body for procedure "Proc", as a separate in foo-proc.adb:

        separate (Foo)
        ^^^^^^^^^^^^^^
        
        procedure Proc is
        begin
           null;
        end Proc;

This capability can be reproduced in C as well, using #include.
The following example is somewhat ugly with respect to the usual
coding practices, but does reproduce well the capability above:

hello.c:

        void
        say_hello (void)
        {
          printf ("Hello world.\n");
        }

foo.c:

        #include <stdio.h>
        
        #include "hello.c"    <--- Reproduces the "is separate"...
        
        int
        main (void)
        {
          say_hello ();
          return 0;
        }

We have noticed that, if compiled with dwarf-2, GDB is unable to
set a breakpoint inside hello.c using the file:lineno syntax:

        % gcc -gdwarf-2 foo.c -o foo
        % gdb foo
        (gdb) b hello.c:4
        No source file named hello.c.
        (gdb) list hello.c:4
        No source file named hello.c.

However, we can set the breakpoint using the function name:

        (gdb) b say_hello
        Breakpoint 1 at 0x804833e: file hello.c, line 4.

And then once this breakpoint is set, we can now insert the
breakpoint using the source location:

        (gdb) b hello.c:4
        Note: breakpoint 1 also set at pc 0x804833e.
        Breakpoint 2 at 0x804833e: file hello.c, line 4.
        (gdb) list hello.c:4
        1       void
        2       say_hello (void)
        3       {
        4         printf ("Hello world.\n");
        5       }

In Dwarf-2, the list of included files is linked to the line table.
First, we have "Line Number Program Header" which contains the "file
names" table. And then the program itself which uses the DW_LNS_set_file
opcode to change from file to file. There is also the DW_LNE_defile_file
opcode that can be used to define new files instead of using the "file
names" table.

Our problem here is that we don't process this line table when building
the partial symbols. Hence, we miss the list of included files, and
therefore do not create any partial symtab for them. The problem does
not exist with stabs because the N_SOL and line number information
are embedded inside the rest of the stabs data.

If we want to support the case above, I don't see any other way but to
scan the line table as well. I suggest a fast scan, although I don't
see a simple way to skip the opcodes and their data that are ignored
during our scan without having a good knowledge of the opcode we are
skipping. This makes the function that does the quick scan of the line
table almost as fat as the one that is used to build the GDB line
table, almost a copy except that we ignore most of what we read.

Basically, I just copy/pasted the code from dwarf_decode_lines(),
simplified it for partial symtab processing, and then called it
right after the compilation unit psymtab has been built. Currently,
the function scans the line number program, and records which files
of the "file names" table have really been included in the line program
(that's the "file_included" array).

Here is a patch against GDB 6.0 that I used as a proof of concept.
It does not handle the case where the compiler uses DW_LNE_defile_file
instead of the the "file names" table yet, but that will be taken care
of.  Would that be an acceptable approach to suggest for inclusion?

2004-01-02  Joel Brobecker  <brobecker@gnat.com>

        * dwarf2read.c (read_partial_die): Add new parameter.
        (scan_partial_symbols): Update call to read_partial_die.
        (dwarf2_add_include_psymtab): New function.
        (dwarf2_build_include_psymtabs): New function.
        (dwarf2_build_psymtabs_hard): Build the psymtabs for the
        included files as well.
        (psymtab_to_symtab_1): Build the symtab of all dependencies
        as well.

Thank you.
-- 
Joel

[-- Attachment #2: dwarf2read.c.diff --]
[-- Type: text/plain, Size: 10811 bytes --]

Index: dwarf2read.c
===================================================================
RCS file: /nile.c/cvs/Dev/gdb/gdb-6.0/gdb/dwarf2read.c,v
retrieving revision 1.5
diff -u -p -r1.5 dwarf2read.c
--- dwarf2read.c	19 Nov 2003 18:02:23 -0000	1.5
+++ dwarf2read.c	2 Jan 2004 07:10:08 -0000
@@ -693,7 +693,8 @@ static struct abbrev_info *dwarf2_lookup
 
 static char *read_partial_die (struct partial_die_info *,
 			       bfd *, char *,
-			       const struct comp_unit_head *);
+			       const struct comp_unit_head *,
+                               unsigned int *);
 
 static char *read_full_die (struct die_info **, bfd *, char *,
 			    const struct comp_unit_head *);
@@ -1196,6 +1197,195 @@ read_comp_unit_head (struct comp_unit_he
   return info_ptr;
 }
 
+static void
+dwarf2_add_include_psymtab (char *name,
+                            struct partial_symtab *pst,
+                            struct objfile *objfile)
+{
+  struct partial_symtab *subpst = allocate_psymtab (name, objfile);
+
+  /* Copy the private data from the main psymtab. */
+  subpst->section_offsets = pst->section_offsets;
+  PST_PRIVATE (subpst) =
+    (char *) obstack_alloc (&objfile->psymbol_obstack,
+                            sizeof (struct dwarf2_pinfo));
+  *PST_PRIVATE (subpst) = *PST_PRIVATE (pst);
+
+  subpst->textlow = 0;
+  subpst->texthigh = 0;
+
+  /* We could save slight bits of space by only making one of these,
+     shared by the entire set of include files.  FIXME-someday.  */
+  subpst->dependencies = (struct partial_symtab **)
+    obstack_alloc (&objfile->psymbol_obstack,
+                   sizeof (struct partial_symtab *));
+  subpst->dependencies[0] = pst;
+  subpst->number_of_dependencies = 1;
+
+  subpst->globals_offset = 0;
+  subpst->n_global_syms = 0;
+  subpst->statics_offset = 0;
+  subpst->n_static_syms = 0;
+
+  subpst->readin = 0;
+  subpst->symtab = 0;
+  subpst->read_symtab = pst->read_symtab;
+}
+
+static void
+dwarf2_build_include_psymtabs (struct comp_unit_head *cu_header,
+                               const unsigned int line_offset,
+                               struct partial_symtab *pst,
+                               struct objfile *objfile)
+{
+  bfd *abfd = objfile->obfd;
+  struct line_header *lh;
+  int file_index;
+  char *line_ptr;
+  char *line_end;
+  unsigned int bytes_read;
+  unsigned char op_code, extended_op, adj_opcode; // All used??? FIXME:JOEL
+  char *file_included;
+
+  lh = dwarf_decode_line_header (line_offset, abfd, cu_header);
+
+  if (lh == NULL)
+    return;  /* No includes...  */
+
+  line_ptr = lh->statement_program_start;
+  line_end = lh->statement_program_end;
+
+  /* FIXME: brobecker: Add comments.  */
+  file_included = alloca (lh->num_file_names * sizeof (char));
+  memset (file_included, 0, lh->num_file_names * sizeof (char));
+
+  /* Read the statement sequences until there's nothing left.  */
+  while (line_ptr < line_end)
+    {
+      /* state machine registers  */
+      int end_sequence = 0;
+
+      /* Decode the table. */
+      while (!end_sequence)
+	{
+	  op_code = read_1_byte (abfd, line_ptr);
+	  line_ptr += 1;
+
+	  if (op_code >= lh->opcode_base)
+	    {		/* Special operand.  Nothing else to read.  */
+	    }
+	  else switch (op_code)
+	    {
+	    case DW_LNS_extended_op:
+	      line_ptr += 1;	/* ignore length */
+	      extended_op = read_1_byte (abfd, line_ptr);
+	      line_ptr += 1;
+	      switch (extended_op)
+		{
+		case DW_LNE_end_sequence:
+		  end_sequence = 1;
+		  break;
+		case DW_LNE_set_address:
+		  read_address (abfd, line_ptr, cu_header, &bytes_read);
+		  line_ptr += bytes_read;
+		  break;
+		case DW_LNE_define_file:
+                  {
+                    // char *cur_file;
+                    // unsigned int dir_index, mod_time, length;
+                    
+                    // cur_file = read_string (abfd, line_ptr, &bytes_read);
+                    // line_ptr += bytes_read;
+                    // dir_index =
+                    //   read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+                    // line_ptr += bytes_read;
+                    // mod_time =
+                    //   read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+                    // line_ptr += bytes_read;
+                    // length =
+                    //   read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+                    // line_ptr += bytes_read;
+                    // add_file_name (lh, cur_file, dir_index, mod_time, length);
+                    /* Ignore for now, but the compiler is allowed to
+                       create the list of files via DW_LNE_define_file
+                       entries too.  We will likely need to take this
+                       into account someday.  */
+                    read_string (abfd, line_ptr, &bytes_read);
+                    line_ptr += bytes_read;
+                    read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+                    line_ptr += bytes_read;
+                    read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+                    line_ptr += bytes_read;
+                    read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+                    line_ptr += bytes_read;
+                  }
+		  break;
+		default:
+		  complaint (&symfile_complaints,
+			     "mangled .debug_line section");
+		  return;
+		}
+	      break;
+	    case DW_LNS_copy:
+	      break;
+	    case DW_LNS_advance_pc:
+	      read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+	      line_ptr += bytes_read;
+	      break;
+	    case DW_LNS_advance_line:
+	      read_signed_leb128 (abfd, line_ptr, &bytes_read);
+	      line_ptr += bytes_read;
+	      break;
+	    case DW_LNS_set_file:
+              {
+                /* lh->include_dirs and lh->file_names are 0-based,
+                   but the directory and file name numbers in the
+                   statement program are 1-based.  */
+                unsigned int file;
+
+                file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+                line_ptr += bytes_read;
+                file_included[file - 1] = 1;
+              }
+	      break;
+	    case DW_LNS_set_column:
+	      read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+	      line_ptr += bytes_read;
+	      break;
+	    case DW_LNS_negate_stmt:
+	      break;
+	    case DW_LNS_set_basic_block:
+	      break;
+	    case DW_LNS_const_add_pc:
+	      break;
+	    case DW_LNS_fixed_advance_pc:
+	      line_ptr += 2;
+	      break;
+	    default:
+	      {  /* Unknown standard opcode, ignore it.  */
+		int i;
+		for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++)
+		  {
+		    (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		    line_ptr += bytes_read;
+		  }
+	      }
+	    }
+	}
+    }
+
+  for (file_index = 0; file_index < lh->num_file_names; file_index++)
+    if (file_included[file_index] == 1)
+      {
+        char *include_name = lh->file_names [file_index].name;
+
+        if (strcmp (include_name, pst->filename) != 0)
+          dwarf2_add_include_psymtab (include_name, pst, objfile);
+      }
+
+  free_line_header (lh);
+}
+
 /* Build the partial symbol table by doing a quick pass through the
    .debug_info and .debug_abbrev sections.  */
 
@@ -1262,6 +1452,8 @@ dwarf2_build_psymtabs_hard (struct objfi
   while (info_ptr < dwarf_info_buffer + dwarf_info_size)
     {
       struct comp_unit_head cu_header;
+      unsigned int line_offset = 0;
+
       beg_of_comp_unit = info_ptr;
       info_ptr = read_comp_unit_head (&cu_header, info_ptr, abfd);
 
@@ -1307,7 +1499,7 @@ dwarf2_build_psymtabs_hard (struct objfi
 
       /* Read the compilation unit die */
       info_ptr = read_partial_die (&comp_unit_die, abfd, info_ptr,
-				   &cu_header);
+				   &cu_header, &line_offset);
 
       /* Set the language we're debugging */
       set_cu_language (comp_unit_die.language);
@@ -1373,6 +1565,10 @@ dwarf2_build_psymtabs_hard (struct objfi
 
       info_ptr = beg_of_comp_unit + cu_header.length 
                                   + cu_header.initial_length_size;
+
+      /* Get the list of files included in the current compilation unit,
+         and build a psymtab for each of them.  */
+      dwarf2_build_include_psymtabs (&cu_header, line_offset, pst, objfile);
     }
   do_cleanups (back_to);
 }
@@ -1421,7 +1617,7 @@ scan_partial_symbols (char *info_ptr, st
 
   while (nesting_level)
     {
-      info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu_header);
+      info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu_header, NULL);
 
       /* Anonymous namespaces have no name but are interesting.  */
 
@@ -1677,6 +1873,32 @@ psymtab_to_symtab_1 (struct partial_symt
   struct symtab *symtab;
   struct cleanup *back_to;
   struct attribute *attr;
+  int i;
+
+  for (i = 0; i < pst->number_of_dependencies; i++)
+    if (!pst->dependencies[i]->readin)
+      {
+        /* Inform about additional files that need to be read in.  */
+        if (info_verbose)
+          {
+            fputs_filtered (" ", gdb_stdout);
+            wrap_here ("");
+            fputs_filtered ("and ", gdb_stdout);
+            wrap_here ("");
+            printf_filtered ("%s...", pst->dependencies[i]->filename);
+            wrap_here ("");     /* Flush output */
+            gdb_flush (gdb_stdout);
+          }
+        psymtab_to_symtab_1 (pst->dependencies[i]);
+      }
+
+  if (pst->textlow == 0 && pst->texthigh == 0)
+    {
+      /* It's an include file, no symbols to read for it.
+         Everything is in the parent symtab.  */
+      pst->readin = 1;
+      return;
+    }
 
   /* Set local variables from the partial symbol table info.  */
   offset = DWARF_INFO_OFFSET (pst);
@@ -4001,7 +4223,8 @@ dwarf2_lookup_abbrev (unsigned int numbe
 
 static char *
 read_partial_die (struct partial_die_info *part_die, bfd *abfd,
-		  char *info_ptr, const struct comp_unit_head *cu_header)
+		  char *info_ptr, const struct comp_unit_head *cu_header,
+                  unsigned int *line_offset)
 {
   unsigned int abbrev_number, bytes_read, i;
   struct abbrev_info *abbrev;
@@ -4096,6 +4319,9 @@ read_partial_die (struct partial_die_inf
 	    part_die->sibling =
 	      dwarf_info_buffer + dwarf2_get_ref_die_offset (&attr);
 	  break;
+        case DW_AT_stmt_list:
+          if (line_offset != NULL)
+            *line_offset = DW_UNSND (&attr);
 	default:
 	  break;
 	}
@@ -4111,7 +4337,7 @@ read_partial_die (struct partial_die_inf
       int dummy;
 
       spec_ptr = dwarf_info_buffer + dwarf2_get_ref_die_offset (&spec_attr);
-      read_partial_die (&spec_die, abfd, spec_ptr, cu_header);
+      read_partial_die (&spec_die, abfd, spec_ptr, cu_header, NULL);
       if (spec_die.name)
 	{
 	  part_die->name = spec_die.name;

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2004-05-04  0:18 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-04-07 16:05 [RFC/dwarf-2] Add support for included files Jim Blandy
2004-04-13  5:20 ` Joel Brobecker
2004-04-14 19:10   ` Jim Blandy
2004-04-15 22:13     ` Joel Brobecker
2004-04-16  4:24       ` Jim Blandy
2004-04-16  4:28         ` Joel Brobecker
2004-04-16 23:08         ` Joel Brobecker
2004-04-29 23:32           ` Jim Blandy
2004-05-01  1:14             ` Joel Brobecker
2004-05-01  4:57               ` Jim Blandy
2004-05-03 16:25                 ` Joel Brobecker
  -- strict thread matches above, loose matches on Subject: below --
2004-05-03 22:15 Andrew Pinski
2004-05-04  0:15 ` Joel Brobecker
2004-05-04  0:18   ` Andrew Pinski
2004-01-02  7:25 Joel Brobecker
2004-01-02 14:18 ` Daniel Jacobowitz
2004-01-03 14:42   ` Joel Brobecker
2004-01-03 16:34     ` Eli Zaretskii
2004-01-03 17:47       ` Joel Brobecker
2004-01-02 14:45 ` Eli Zaretskii
2004-01-05 16:18 ` Andrew Cagney
2004-01-05 19:17   ` Joel Brobecker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox