From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26899 invoked by alias); 28 Oct 2009 18:50:42 -0000 Received: (qmail 26877 invoked by uid 22791); 28 Oct 2009 18:50:40 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL,BAYES_00,SARE_SUB_LEAD_CHAR2,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 28 Oct 2009 18:50:36 +0000 Received: (qmail 14139 invoked from network); 28 Oct 2009 18:50:33 -0000 Received: from unknown (HELO orlando) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 28 Oct 2009 18:50:33 -0000 From: Pedro Alves To: gdb-patches@sourceware.org Subject: --gc-section leftovers workaround. Date: Wed, 28 Oct 2009 18:50:00 -0000 User-Agent: KMail/1.9.10 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200910281851.01364.pedro@codesourcery.com> X-IsSubscribed: yes 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: 2009-10/txt/msg00672.txt.bz2 With --gc-sections, gnu ld zeros out the start addresses of unreferences FDEs, but leaves them behind. On targets where addresses near 0 are valid, GDB can easily confuse these leftovers for the valid FDEs, ending up with invalid debug info loaded for such low addresses. Since this is a problem that has beein in the field for a while, an FSF GDB workaround seems appropriate, given that it is a simple workaround --- give preference to FDEs that do not start at zero when overlaps are detected. Given that we now sort and bsearch FDEs, GDB is already giving such preference as a side effect, but the code that discards duplicate FDEs could be discarding the valid FDEs at 0, and keep an FDE that should have been garbage collected. This patch makes the overlap check explicit so as to avoid that. Tested on arm-none-eabi where it fixed the problem, and on x86_64-unknown-linux-gnu. Applied. -- Pedro Alves 2009-10-28 Pedro Alves * dwarf2-frame.c (dwarf2_build_frame_info): Discard --gc-section leftover FDEs. --- gdb/dwarf2-frame.c | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) Index: src/gdb/dwarf2-frame.c =================================================================== --- src.orig/gdb/dwarf2-frame.c 2009-10-23 19:05:16.000000000 +0100 +++ src/gdb/dwarf2-frame.c 2009-10-28 17:15:10.000000000 +0000 @@ -2101,7 +2101,8 @@ dwarf2_build_frame_info (struct objfile if (fde_table.num_entries != 0) { struct dwarf2_fde_table *fde_table2; - int i, j; + struct dwarf2_fde *fde_prev = NULL; + int i; /* Prepare FDE table for lookups. */ qsort (fde_table.entries, fde_table.num_entries, @@ -2110,22 +2111,39 @@ dwarf2_build_frame_info (struct objfile /* Copy fde_table to obstack: it is needed at runtime. */ fde_table2 = (struct dwarf2_fde_table *) obstack_alloc (&objfile->objfile_obstack, sizeof (*fde_table2)); + fde_table2->num_entries = 0; /* Since we'll be doing bsearch, squeeze out identical (except for eh_frame_p) fde entries so bsearch result is predictable. */ - for (i = 0, j = 0; j < fde_table.num_entries; ++i) - { - const int k = j; - - obstack_grow (&objfile->objfile_obstack, &fde_table.entries[j], - sizeof (fde_table.entries[0])); - while (++j < fde_table.num_entries - && (fde_table.entries[k]->initial_location - == fde_table.entries[j]->initial_location)) - /* Skip. */; - } + for (i = 0; i < fde_table.num_entries; i++) + { + struct dwarf2_fde *fde = fde_table.entries[i]; + + /* Check for leftovers from --gc-sections. The GNU linker + sets the relevant symbols to zero, but doesn't zero the + FDE *end* ranges because there's no relocation there. + It's (offset, length), not (start, end). On targets + where address zero is just another valid address this can + be a problem, since the FDEs appear to be non-empty in + the output --- we could pick out the wrong FDE. To work + around this, when overlaps are detected, we prefer FDEs + that do not start at zero. */ + if (fde->initial_location == 0 + && (i + 1) < fde_table.num_entries + && ((fde_table.entries[i + 1])->initial_location + < fde->initial_location + fde->address_range)) + continue; + + if (fde_prev != NULL + && fde_prev->initial_location == fde->initial_location) + continue; + + obstack_grow (&objfile->objfile_obstack, &fde_table.entries[i], + sizeof (fde_table.entries[0])); + ++fde_table2->num_entries; + fde_prev = fde; + } fde_table2->entries = obstack_finish (&objfile->objfile_obstack); - fde_table2->num_entries = i; set_objfile_data (objfile, dwarf2_frame_objfile_data, fde_table2); /* Discard the original fde_table. */