From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29224 invoked by alias); 16 Mar 2010 21:19:15 -0000 Received: (qmail 29210 invoked by uid 22791); 16 Mar 2010 21:19:13 -0000 X-SWARE-Spam-Status: No, hits=-2.5 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 16 Mar 2010 21:19:07 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 205F52BAB05; Tue, 16 Mar 2010 17:19:06 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id K+RL8O9xSR5n; Tue, 16 Mar 2010 17:19:06 -0400 (EDT) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id AC3CA2BAAFA; Tue, 16 Mar 2010 17:19:05 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id 69160F5917; Tue, 16 Mar 2010 14:19:03 -0700 (PDT) Date: Tue, 16 Mar 2010 21:19:00 -0000 From: Joel Brobecker To: Tom Tromey Cc: gdb-patches@sourceware.org Subject: Re: [RFA/dwarf] Anonymous nested function causes SEGV during psymbol read Message-ID: <20100316211903.GE3830@adacore.com> References: <1266519724-4175-1-git-send-email-brobecker@adacore.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="7AUc2qLy4jB3hD7Z" Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.20 (2009-06-14) Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-03/txt/msg00611.txt.bz2 --7AUc2qLy4jB3hD7Z Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 738 > Joel> + /* Ignore subprograms that do not have a name. Such entries > Joel> + are incorrect, according to the DWARF standard, and we need > Joel> + a function name to create the associated partial symbol. */ > Joel> + if (!pdi->is_declaration && pdi->name) > Joel> add_partial_symbol (pdi, cu); > > I think it is worthwhile to call complaint for invalid DWARF. Thanks again for the feedback. Attached is a new version of the patch, with the complaints added. Since I also added a complaint for the non-nested case, I also extended the testcase to cover that case as well. I will leave the patch out for review for a while, and hopefully commit sometime next week, if there are no objections. -- Joel --7AUc2qLy4jB3hD7Z Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="dw2-anon-func.diff" Content-length: 12953 commit 22ada2cfef694620508dffa0e05a19e6b8d3da8c Author: Joel Brobecker Date: Wed Feb 17 07:29:04 2010 +0400 [dwarf] Anonymous nested function causes SEGV during psymbol read 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, and emits a complaint if missing. To be consistent, a complaint has also been added to cover the non-nested case. gdb/ChangeLog: * dwarf2read.c (scan_partial_symbols): Emit a complaint if PDI is a subprogram without a name attribute. (add_partial_subprogram): If the subprogram does not have a name, do not create the associated partial symbol but emit a complaint. 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. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 563cb18..b6e51ef 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -2241,6 +2241,12 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc, break; } } + else if (pdi->tag == DW_TAG_subprogram) + /* This is a subprogram DIE that does not have a name, which is + invalid. */ + complaint (&symfile_complaints, + _("missing name for DW_TAG_subprogram DIE at 321 %d"), + pdi->offset); /* If the die has a sibling, skip to the sibling. */ @@ -2572,8 +2578,17 @@ add_partial_subprogram (struct partial_die_info *pdi, pdi->highpc - 1 + baseaddr, cu->per_cu->psymtab); } - if (!pdi->is_declaration) - add_partial_symbol (pdi, cu); + if (!pdi->is_declaration) + { + if (pdi->name) + add_partial_symbol (pdi, cu); + else + /* This subprogram die is missing its name attribute, which + is illegal accordingly to the DWARF standard. */ + complaint (&symfile_complaints, + _("missing name for DW_TAG_subprogram DIE at %d"), + pdi->offset); + } } } 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..84552bf --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-anonymous-func.S @@ -0,0 +1,248 @@ +/* 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 . */ + +/* 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 */ + /* Nested function missing a name attribute. */ + .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 */ + + /* Non-nested function missing a name attribute. */ + .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 */ + +.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 . + +# 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" --7AUc2qLy4jB3hD7Z--