bug-gdb
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

PATCH: DWARF2 macinfo-related fixes for gdb and gcc


From: Alan Curry
Subject: PATCH: DWARF2 macinfo-related fixes for gdb and gcc
Date: Tue, 18 Oct 2005 08:25:23 -0000

[skip to the end if you just want the patches without the storyline]

Jochen Voss writes the following:
>
>when trying to debug one of my programs I encountered a case where gdb
>crashed on the command "break main" before my programm was even
>started.  The problem occurs on a powerpc machine.

After investigating, I don't see anything ppc-specific about this bug.
The actual occurrence of the segfault may vary between architectures, but
that's just because some may get lucky when dereferencing the bad pointer.

>    http://seehuhn.de/data/gdb-bug           - the binary
>    http://seehuhn.de/data/gdb-bug.i         - the preprocessed source
[...]
>    (gdb) break main
>    Segmentation fault

It also has nothing to do with setting a breakpoint, or with your main
function. You can also try "print main", "break load_matrix", ... the key is
convincing gdb that it needs to parse the debugging symbols.

>2) Regenerating the binary.  The binary gdb-bug was compiled from
>gdb-bug.i using the following two commands:
>
>    address@hidden [~/y] gcc -ggdb3 -c gdb-bug.i
>    address@hidden [~/y] gcc -ggdb3 -o gdb-bug gdb-bug.o -lm -llapack -lblas 
> -lg2c

When done with gcc 3.3 or 3.4, the resulting executable does not segfault
gdb. I can see from your binary that you were using Debian's gcc 4.0.1-1. I
can also reproduce the bug with the current upstream source, 4.0.2. (gcc 4.0
hasn't made it into Debian stable yet).

Also, your use of -ggdb3 is an important part of reproducing the bug. Normal
-g doesn't include debugging information for macros, and that's where the
problem is. (-gdwarf-2 -g3 is also sufficient, or just -g3 since DWARF2 seems
to be the default format now)

To see what is going wrong, do a "readelf -w gdb-bug.o" and look at the
.debug_macinfo section. You'll see that it references sources files by
number, starting at 1 and ending at 47:

  ...
  DW_MACINFO_start_file - lineno: 21 filenum: 46
  DW_MACINFO_end_file
  DW_MACINFO_start_file - lineno: 22 filenum: 47

Those filenums refer to "The File Name Table" (located earlier in the
readelf -w output). If you take a look at The File Name Table, you'll see
that it has only 46 entries. And that's why gdb segfaults. Now we know how to
fix gdb: make it check that filenum is in the proper range.

But we want to fix the bad debugging information, not just the segfault. Go
back to the .debug_macinfo section, look closer, and you'll see that there
are no references to filenum 16. It goes 1,2,3,...15,17,18,...47 (some
numbers are repeated because files get #included more than once, but if you
look just at the first appearance of each number, they are in order.)

When gcc was building this table of #included files, it was also keeping
track of #includes for error reporting purposes. There are 2 lists of
#included files: one for errors and warnings, and the other for DWARF2
debugging information. The missing file number 16 corresponds to the special
pseudo-file "<built-in>" in the list of source files. "<built-in>" is omitted
from the DWARF2 file table because it's not an actual file.

There is a function called maybe_emit_file() in gcc, which assigns the
filenums, and takes care of mapping the file numbers in the main file list
to the file numbers in the DWARF2 list. Someone forgot to use the return
value of maybe_emit_file() when creating the DW_MACINFO_start_file record, so
what should be a reference to file number 16 comes out instead as a reference
to file number 17. After the 16th entry, every filenum is 1 larger than it
should be. The reference to file number 47 should really be a reference to
file number 46.

Because all file numbers after the missing one are off by 1, most of the
macro debugging information is going to be referring to the wrong file. So
even if gdb doesn't segfault, it's still going to report the wrong origin for
macros defined after the bug's trigger point (file 16 in the sample).

It would be possible to make gdb detect an out-of-sequence filenum and
automatically adjust it and all of the following filenums, with a warning
message like "Detected GCC 4.0.<=2 macinfo breakage, working around it". My
patch doesn't go that far; it just prevents the segfault.

Here are the patches. In case of mail corruption, they're also here:
http://world.std.com/~pacman/gcc4-dwarf-macinfo.diff
http://world.std.com/~pacman/gdb-macinfo-segfault.diff

--- gdb-6.3.orig/gdb/dwarf2read.c       2005-10-17 23:22:46.000000000 -0500
+++ gdb-6.3/gdb/dwarf2read.c    2005-10-18 00:38:48.000000000 -0500
@@ -9087,9 +9087,14 @@
             file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
             mac_ptr += bytes_read;
 
-            current_file = macro_start_file (file, line,
-                                             current_file, comp_dir,
-                                             lh, cu->objfile);
+            if (file > lh->num_file_names)
+              warning ("macro debug info references file %d, "
+                       "but file table only contains %u entries.",
+                       file, lh->num_file_names);
+            else
+              current_file = macro_start_file (file, line,
+                                               current_file, comp_dir,
+                                               lh, cu->objfile);
           }
           break;
 

--- gcc-4.0.2.orig/gcc/dwarf2out.c      2005-09-01 09:04:38.000000000 -0500
+++ gcc-4.0.2/gcc/dwarf2out.c   2005-10-17 22:19:47.000000000 -0500
@@ -13339,8 +13339,7 @@
       dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
       dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
                                   lineno);
-      maybe_emit_file (lookup_filename (filename));
-      dw2_asm_output_data_uleb128 (lookup_filename (filename),
+      dw2_asm_output_data_uleb128 (maybe_emit_file (lookup_filename 
(filename)),
                                   "Filename we just started");
     }
 }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]