mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-12 12:16:04 +08:00
1fd999d909
While messing with the Dwarf assembler (gdb/testsuite/lib/dwarf.exp) I managed to create an ELF which made use of DW_FORM_strp, but didn't include a .debug_str section. When I started GDB on this ELF, GDB crashed. I would have expected to get an error instead. I tracked this down to an unfortunate design choice in dwarf2_section_info, a class which wraps around a bfd section, and is used for reading in debug information. GBB creates many dwarf2_section_info objects, one for each debug section that might need to be read, then as we find the input bfd sections we associate them with the corresponding dwarf2_section_info. If no matching input bfd section is found then the dwarf2_section_info is left in an unassociated state, its internal bfd section pointer is null. If later GDB tries to read content from the dwarf2_section_info, for example, which trying to read the string associated with DW_FORM_strp, we spot that there is no associated bfd section and issue an error message. To make the users life easier, the error message includes the section name being looked for, and the bfd from which the section was obtained. However, we get the section name by calling bfd_section_name on the associated section, and we get the bfd filename by calling bfd_get_filename on the owner of the associated section. Of course, if there is no associated section then both the calls bfd_section_name and dwarf2_section_info::get_bfd_owner will result in undefined behaviour (e.g. a crash). The solution I propose in this patch is, I know, not ideal. I simply spot the case where there is no associated section, and print a simpler error message, leaving out the section name and filename. A better solution would involve redesigning dwarf2_section_info, we could associate each dwarf2_section_info with the initial bfd being parsed. We would then display this filename if there's nothing better to display (e.g. if we find a section in a dwo/dwp split dwarf file then we would probably use that filename in preference). Each dwarf2_section_info could also have the concept of the default section name that would be read for that section, for example, string data might appear in ".debug_str" or ".zdebug_str", but if neither is found, then it would probably be OK to just say ".debug_str" is missing. Anyway, I didn't do any of that redesign, I just wanted to stop GDB crashing for now, so instead we get this: Dwarf Error: DW_FORM_strp used without required section Which isn't the best, but in context, isn't too bad: Reading symbols from /path/to/executable... Dwarf Error: DW_FORM_strp used without required section (No debugging symbols found in /path/to/executable) I also added some asserts into dwarf2_section_info which should trigger before GDB crashes in future, if we trigger any other bad paths through this code. And there's a test for the specific issue I hit. gdb/ChangeLog: * dwarf2/section.c (dwarf2_section_info::get_bfd_owner): Add an assert. (dwarf2_section_info::get_file_name): Add an assert. (dwarf2_section_info::read_string): Display a minimal, sane error when the dwarf2_section_info is not associated with a bfd section. gdb/testsuite/ChangeLog: * gdb.dwarf2/dw2-using-debug-str.exp: Add an additional test.
215 lines
5.6 KiB
C
215 lines
5.6 KiB
C
/* DWARF 2 low-level section code
|
|
|
|
Copyright (C) 1994-2021 Free Software Foundation, Inc.
|
|
|
|
Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology,
|
|
Inc. with support from Florida State University (under contract
|
|
with the Ada Joint Program Office), and Silicon Graphics, Inc.
|
|
Initial contribution by Brent Benson, Harris Computer Systems, Inc.,
|
|
based on Fred Fish's (Cygnus Support) implementation of DWARF 1
|
|
support.
|
|
|
|
This file is part of GDB.
|
|
|
|
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/>. */
|
|
|
|
#include "defs.h"
|
|
#include "dwarf2/section.h"
|
|
#include "gdb_bfd.h"
|
|
#include "objfiles.h"
|
|
#include "complaints.h"
|
|
|
|
void
|
|
dwarf2_section_info::overflow_complaint () const
|
|
{
|
|
complaint (_("debug info runs off end of %s section"
|
|
" [in module %s]"),
|
|
get_name (), get_file_name ());
|
|
}
|
|
|
|
struct dwarf2_section_info *
|
|
dwarf2_section_info::get_containing_section () const
|
|
{
|
|
gdb_assert (is_virtual);
|
|
return s.containing_section;
|
|
}
|
|
|
|
struct bfd *
|
|
dwarf2_section_info::get_bfd_owner () const
|
|
{
|
|
const dwarf2_section_info *section = this;
|
|
if (is_virtual)
|
|
{
|
|
section = get_containing_section ();
|
|
gdb_assert (!section->is_virtual);
|
|
}
|
|
gdb_assert (section->s.section != nullptr);
|
|
return section->s.section->owner;
|
|
}
|
|
|
|
asection *
|
|
dwarf2_section_info::get_bfd_section () const
|
|
{
|
|
const dwarf2_section_info *section = this;
|
|
if (section->is_virtual)
|
|
{
|
|
section = get_containing_section ();
|
|
gdb_assert (!section->is_virtual);
|
|
}
|
|
return section->s.section;
|
|
}
|
|
|
|
const char *
|
|
dwarf2_section_info::get_name () const
|
|
{
|
|
asection *sectp = get_bfd_section ();
|
|
|
|
gdb_assert (sectp != NULL);
|
|
return bfd_section_name (sectp);
|
|
}
|
|
|
|
const char *
|
|
dwarf2_section_info::get_file_name () const
|
|
{
|
|
bfd *abfd = get_bfd_owner ();
|
|
|
|
gdb_assert (abfd != nullptr);
|
|
return bfd_get_filename (abfd);
|
|
}
|
|
|
|
int
|
|
dwarf2_section_info::get_id () const
|
|
{
|
|
asection *sectp = get_bfd_section ();
|
|
|
|
if (sectp == NULL)
|
|
return 0;
|
|
return sectp->id;
|
|
}
|
|
|
|
int
|
|
dwarf2_section_info::get_flags () const
|
|
{
|
|
asection *sectp = get_bfd_section ();
|
|
|
|
gdb_assert (sectp != NULL);
|
|
return bfd_section_flags (sectp);
|
|
}
|
|
|
|
bool
|
|
dwarf2_section_info::empty () const
|
|
{
|
|
if (is_virtual)
|
|
return size == 0;
|
|
return s.section == NULL || size == 0;
|
|
}
|
|
|
|
void
|
|
dwarf2_section_info::read (struct objfile *objfile)
|
|
{
|
|
asection *sectp;
|
|
bfd *abfd;
|
|
gdb_byte *buf, *retbuf;
|
|
|
|
if (readin)
|
|
return;
|
|
buffer = NULL;
|
|
readin = true;
|
|
|
|
if (empty ())
|
|
return;
|
|
|
|
sectp = get_bfd_section ();
|
|
|
|
/* If this is a virtual section we need to read in the real one first. */
|
|
if (is_virtual)
|
|
{
|
|
struct dwarf2_section_info *containing_section =
|
|
get_containing_section ();
|
|
|
|
gdb_assert (sectp != NULL);
|
|
if ((sectp->flags & SEC_RELOC) != 0)
|
|
{
|
|
error (_("Dwarf Error: DWP format V2 with relocations is not"
|
|
" supported in section %s [in module %s]"),
|
|
get_name (), get_file_name ());
|
|
}
|
|
containing_section->read (objfile);
|
|
/* Other code should have already caught virtual sections that don't
|
|
fit. */
|
|
gdb_assert (virtual_offset + size <= containing_section->size);
|
|
/* If the real section is empty or there was a problem reading the
|
|
section we shouldn't get here. */
|
|
gdb_assert (containing_section->buffer != NULL);
|
|
buffer = containing_section->buffer + virtual_offset;
|
|
return;
|
|
}
|
|
|
|
/* If the section has relocations, we must read it ourselves.
|
|
Otherwise we attach it to the BFD. */
|
|
if ((sectp->flags & SEC_RELOC) == 0)
|
|
{
|
|
buffer = gdb_bfd_map_section (sectp, &size);
|
|
return;
|
|
}
|
|
|
|
buf = (gdb_byte *) obstack_alloc (&objfile->objfile_obstack, size);
|
|
buffer = buf;
|
|
|
|
/* When debugging .o files, we may need to apply relocations; see
|
|
http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html .
|
|
We never compress sections in .o files, so we only need to
|
|
try this when the section is not compressed. */
|
|
retbuf = symfile_relocate_debug_section (objfile, sectp, buf);
|
|
if (retbuf != NULL)
|
|
{
|
|
buffer = retbuf;
|
|
return;
|
|
}
|
|
|
|
abfd = get_bfd_owner ();
|
|
gdb_assert (abfd != NULL);
|
|
|
|
if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
|
|
|| bfd_bread (buf, size, abfd) != size)
|
|
{
|
|
error (_("Dwarf Error: Can't read DWARF data"
|
|
" in section %s [in module %s]"),
|
|
bfd_section_name (sectp), bfd_get_filename (abfd));
|
|
}
|
|
}
|
|
|
|
const char *
|
|
dwarf2_section_info::read_string (struct objfile *objfile, LONGEST str_offset,
|
|
const char *form_name)
|
|
{
|
|
read (objfile);
|
|
if (buffer == NULL)
|
|
{
|
|
if (get_bfd_section () == nullptr)
|
|
error (_("Dwarf Error: %s used without required section"),
|
|
form_name);
|
|
else
|
|
error (_("Dwarf Error: %s used without %s section [in module %s]"),
|
|
form_name, get_name (), get_file_name ());
|
|
}
|
|
if (str_offset >= size)
|
|
error (_("%s pointing outside of %s section [in module %s]"),
|
|
form_name, get_name (), get_file_name ());
|
|
gdb_assert (HOST_CHAR_BIT == 8);
|
|
if (buffer[str_offset] == '\0')
|
|
return NULL;
|
|
return (const char *) (buffer + str_offset);
|
|
}
|