This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFA/dwarf] Anonymous nested function causes SEGV during psymbol read
- From: Joel Brobecker <brobecker at adacore dot com>
- To: gdb-patches at sourceware dot org
- Date: Thu, 18 Feb 2010 14:02:04 -0500
- Subject: [RFA/dwarf] Anonymous nested function causes SEGV during psymbol read
Hello,
One of the AdaCore engineers reported a GDB crash while debugging
optimized code. This is the first problem that I found...
According to the DWARF3 standard, a function always has a name attribute
(Section 3.3 - Subroutine and Entry Point Entries). The only exception
is when a DW_AT_abstract_origin attribute is provided, in which case
the name may be inherited from the referenced DIE.
The problem occured because our compiler generated a subprogram DIE
for a nested function where the name attribute was missing (and no
abstract-origin either). Our code in add_partial_symbol is not
prepared to deal with the situation, and happily just tries to compute
the length of the (NULL) function name.
This normally cannot happen, because there is already a guard in
scan_partial_symbols, where we (silently!) ignore anonymous dies,
including anonymous subprograms. Unfortunately, there is a flaw that
affects Ada and other languages that allow nested subprograms. For
nested subprograms, we do not go through scan_partial_symbols and
thus we are missing the name check.
This patch adds the name check in the nested subprogram case.
A complaint was initially added, but then it seemed inconsistent
to emit that complaint for nested subprograms only. I suggest
we either do not emit them at all, or we emit them for both cases.
One other option that just occurred to me while typing this message is
to still create the partial symbol, but with a dummy name. Something
like "<anonymous>" or "<function-name-missing>". However, I think we need
to be careful to do the same when creating the associated symbol...
Right now, we simply ignore them:
/* Ignore functions with missing or empty names and functions with
missing or invalid low and high pc attributes. */
if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL))
return;
(and the way things are implemented, this also applies to nested
subprograms).
gdb/ChangeLog:
* dwarf2read.c (add_partial_subprogram): If the subprogram does not
have a name, do not create the associated partial symbol.
gdb/testsuite/ChangeLog:
* gdb.dwarf2/dw2-anonymous-func.S: New file.
* gdb.dwarf2/dw2-anonymous-func.exp: New testcase.
Tested on x86_64-linux, no regression. Note that the testcase also
verifies that the psymtab->symtab conversion does not crash (this is
the purpose of the "list file1.txt:1" test.
OK to apply?
Thanks,
--
Joel
---
gdb/dwarf2read.c | 5 +-
gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.S | 237 +++++++++++++++++++++++
gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.exp | 53 +++++
3 files changed, 294 insertions(+), 1 deletions(-)
create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.S
create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.exp
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index a05c946..25de83d 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2698,7 +2698,10 @@ add_partial_subprogram (struct partial_die_info *pdi,
pdi->lowpc, pdi->highpc - 1,
cu->per_cu->psymtab);
}
- if (!pdi->is_declaration)
+ /* Ignore subprograms that do not have a name. Such entries
+ are incorrect, according to the DWARF standard, and we need
+ a function name to create the associated partial symbol. */
+ if (!pdi->is_declaration && pdi->name)
add_partial_symbol (pdi, cu);
}
}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.S b/gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.S
new file mode 100644
index 0000000..5db1985
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.S
@@ -0,0 +1,237 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Test a minimal file containing DWARF-2 information. This test also
+ serves as a skeleton for other DWARF-2 tests. Most other tests will
+ not be this extensively itemized and commented... */
+
+/* Dummy function to provide debug information for. */
+
+ .text
+.Lbegin_text1:
+ .globl func_cu1
+ .type func_cu1, %function
+func_cu1:
+.Lbegin_func_cu1:
+ .int 0
+.Lend_func_cu1:
+ .size func_cu1, .-func_cu1
+ .globl func_cu2
+ .type func_cu2, %function
+func_cu2:
+.Lbegin_func_cu2:
+ .int 0
+.Lend_func_cu2:
+ .size func_cu2, .-func_cu2
+.Lend_text1:
+
+/* Debug information */
+
+ .section .debug_info
+.Lcu1_begin:
+ /* CU header */
+ .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */
+.Lcu1_start:
+ .2byte 2 /* DWARF Version */
+ .4byte .Labbrev1_begin /* Offset into abbrev section */
+ .byte 4 /* Pointer size */
+
+ /* CU die */
+ .uleb128 1 /* Abbrev: DW_TAG_compile_unit */
+ .4byte .Lline1_begin /* DW_AT_stmt_list */
+ .4byte .Lend_text1 /* DW_AT_high_pc */
+ .4byte .Lbegin_text1 /* DW_AT_low_pc */
+ .ascii "file1.txt\0" /* DW_AT_name */
+ .ascii "GNU C 3.3.3\0" /* DW_AT_producer */
+ .byte 0x0d /* DW_AT_language (Ada95) */
+
+ /* func_cu1 */
+ .uleb128 2 /* Abbrev: DW_TAG_subprogram */
+ .byte 1 /* DW_AT_external */
+ .byte 1 /* DW_AT_decl_file */
+ .byte 2 /* DW_AT_decl_line */
+ .ascii "func_cu1\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .4byte .Lbegin_func_cu1 /* DW_AT_low_pc */
+ .4byte .Lend_func_cu1 /* DW_AT_high_pc */
+ .byte 1 /* DW_AT_frame_base: length */
+ .byte 0x55 /* DW_AT_frame_base: DW_OP_reg5 */
+ /* func_cu2 */
+ .uleb128 4 /* Abbrev: DW_TAG_subprogram */
+ .byte 1 /* DW_AT_external */
+ .byte 1 /* DW_AT_decl_file */
+ .byte 2 /* DW_AT_decl_line */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .4byte .Lbegin_func_cu2 /* DW_AT_low_pc */
+ .4byte .Lend_func_cu2 /* DW_AT_high_pc */
+ .byte 1 /* DW_AT_frame_base: length */
+ .byte 0x55 /* DW_AT_frame_base: DW_OP_reg5 */
+ .byte 0x0 /* End of children of func_cu1 */
+
+.Ltype_int:
+ .uleb128 3 /* Abbrev: DW_TAG_base_type */
+ .ascii "int\0" /* DW_AT_name */
+ .byte 4 /* DW_AT_byte_size */
+ .byte 5 /* DW_AT_encoding */
+
+ .byte 0 /* End of children of CU */
+
+.Lcu1_end:
+
+/* Abbrev table */
+ .section .debug_abbrev
+.Labbrev1_begin:
+ .uleb128 1 /* Abbrev code */
+ .uleb128 0x11 /* DW_TAG_compile_unit */
+ .byte 1 /* has_children */
+ .uleb128 0x10 /* DW_AT_stmt_list */
+ .uleb128 0x6 /* DW_FORM_data4 */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 2 /* Abbrev code */
+ .uleb128 0x2e /* DW_TAG_subprogram */
+ .byte 1 /* has_children */
+ .uleb128 0x3f /* DW_AT_external */
+ .uleb128 0xc /* DW_FORM_flag */
+ .uleb128 0x3a /* DW_AT_decl_file */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3b /* DW_AT_decl_line */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x40 /* DW_AT_frame_base */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 3 /* Abbrev code */
+ .uleb128 0x24 /* DW_TAG_base_type */
+ .byte 0 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0xb /* DW_AT_byte_size */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3e /* DW_AT_encoding */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 4 /* Abbrev code */
+ .uleb128 0x2e /* DW_TAG_subprogram */
+ .byte 0 /* has_children */
+ .uleb128 0x3f /* DW_AT_external */
+ .uleb128 0xc /* DW_FORM_flag */
+ .uleb128 0x3a /* DW_AT_decl_file */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3b /* DW_AT_decl_line */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x40 /* DW_AT_frame_base */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+/* Line table */
+ .section .debug_line
+.Lline1_begin:
+ .4byte .Lline1_end - .Lline1_start /* Initial length */
+.Lline1_start:
+ .2byte 2 /* Version */
+ .4byte .Lline1_lines - .Lline1_hdr /* header_length */
+.Lline1_hdr:
+ .byte 1 /* Minimum insn length */
+ .byte 1 /* default_is_stmt */
+ .byte 1 /* line_base */
+ .byte 1 /* line_range */
+ .byte 0x10 /* opcode_base */
+
+ /* Standard lengths */
+ .byte 0
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 0
+
+ /* Include directories */
+ .byte 0
+
+ /* File names */
+ .ascii "file1.txt\0"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+
+ .byte 0
+
+.Lline1_lines:
+ .byte 0 /* DW_LNE_set_address */
+ .uleb128 5
+ .byte 2
+ .4byte .Lbegin_func_cu1
+
+ .byte 3 /* DW_LNS_advance_line */
+ .sleb128 3 /* ... to 4 */
+
+ .byte 1 /* DW_LNS_copy */
+
+ .byte 1 /* DW_LNS_copy (second time as an end-of-prologue marker) */
+
+ .byte 0 /* DW_LNE_set_address */
+ .uleb128 5
+ .byte 2
+ .4byte .Lend_func_cu1
+
+ .byte 0 /* DW_LNE_end_of_sequence */
+ .uleb128 1
+ .byte 1
+
+.Lline1_end:
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.exp b/gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.exp
new file mode 100644
index 0000000..10662eb
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.exp
@@ -0,0 +1,53 @@
+# Copyright 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Minimal DWARF-2 unit test
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+
+set testfile "dw2-anonymous-func"
+set dwarf_srcfile "file1.txt"
+set srcfile ${testfile}.S
+set binfile ${objdir}/${subdir}/${testfile}.x
+
+if { [gdb_compile "${srcdir}/${subdir}/main.c" "main.o" object {debug}] != "" } {
+ return -1
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${testfile}.o" object {nodebug}] != "" } {
+ return -1
+}
+
+if { [gdb_compile "${testfile}.o main.o" "${binfile}" executable {debug}] != "" } {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Force the debugger to create the file1.txt symtab, to make sure that
+# the debugger does not crash doing so.
+gdb_test "list file1.txt:1" "File 1 Line 1.*File 1 Line 8" "list file1.txt"
--
1.6.3.3