mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-15 04:31:49 +08:00
9938d15a01
This moves dwarf2_get_dwz_file and some helper code to dwarf2/dwz.h. The main benefit of this is just shrinking dwarf2/read.c a little bit. gdb/ChangeLog 2021-03-06 Tom Tromey <tom@tromey.com> * dwarf2/sect-names.h (dwarf2_elf_names): Declare. * dwarf2/read.h (dwarf2_get_dwz_file): Move to dwz.h. * dwarf2/read.c (dwarf2_elf_names): No longer static. (locate_dwz_sections, dwz_search_other_debugdirs) (dwarf2_get_dwz_file): Move to dwz.c. * dwarf2/dwz.h (dwarf2_get_dwz_file): Move declaration from read.h. * dwarf2/dwz.c (locate_dwz_sections, dwz_search_other_debugdirs) (dwarf2_get_dwz_file): Move from read.c.
283 lines
8.4 KiB
C
283 lines
8.4 KiB
C
/* DWARF DWZ handling for GDB.
|
|
|
|
Copyright (C) 2003-2021 Free Software Foundation, Inc.
|
|
|
|
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/dwz.h"
|
|
|
|
#include "build-id.h"
|
|
#include "debuginfod-support.h"
|
|
#include "dwarf2/read.h"
|
|
#include "dwarf2/sect-names.h"
|
|
#include "filenames.h"
|
|
#include "gdb_bfd.h"
|
|
#include "gdbcore.h"
|
|
#include "gdbsupport/pathstuff.h"
|
|
#include "gdbsupport/scoped_fd.h"
|
|
|
|
const char *
|
|
dwz_file::read_string (struct objfile *objfile, LONGEST str_offset)
|
|
{
|
|
str.read (objfile);
|
|
|
|
if (str.buffer == NULL)
|
|
error (_("DW_FORM_GNU_strp_alt used without .debug_str "
|
|
"section [in module %s]"),
|
|
bfd_get_filename (dwz_bfd.get ()));
|
|
if (str_offset >= str.size)
|
|
error (_("DW_FORM_GNU_strp_alt pointing outside of "
|
|
".debug_str section [in module %s]"),
|
|
bfd_get_filename (dwz_bfd.get ()));
|
|
gdb_assert (HOST_CHAR_BIT == 8);
|
|
if (str.buffer[str_offset] == '\0')
|
|
return NULL;
|
|
return (const char *) (str.buffer + str_offset);
|
|
}
|
|
|
|
/* A helper function to find the sections for a .dwz file. */
|
|
|
|
static void
|
|
locate_dwz_sections (bfd *abfd, asection *sectp, dwz_file *dwz_file)
|
|
{
|
|
/* Note that we only support the standard ELF names, because .dwz
|
|
is ELF-only (at the time of writing). */
|
|
if (dwarf2_elf_names.abbrev.matches (sectp->name))
|
|
{
|
|
dwz_file->abbrev.s.section = sectp;
|
|
dwz_file->abbrev.size = bfd_section_size (sectp);
|
|
}
|
|
else if (dwarf2_elf_names.info.matches (sectp->name))
|
|
{
|
|
dwz_file->info.s.section = sectp;
|
|
dwz_file->info.size = bfd_section_size (sectp);
|
|
}
|
|
else if (dwarf2_elf_names.str.matches (sectp->name))
|
|
{
|
|
dwz_file->str.s.section = sectp;
|
|
dwz_file->str.size = bfd_section_size (sectp);
|
|
}
|
|
else if (dwarf2_elf_names.line.matches (sectp->name))
|
|
{
|
|
dwz_file->line.s.section = sectp;
|
|
dwz_file->line.size = bfd_section_size (sectp);
|
|
}
|
|
else if (dwarf2_elf_names.macro.matches (sectp->name))
|
|
{
|
|
dwz_file->macro.s.section = sectp;
|
|
dwz_file->macro.size = bfd_section_size (sectp);
|
|
}
|
|
else if (dwarf2_elf_names.gdb_index.matches (sectp->name))
|
|
{
|
|
dwz_file->gdb_index.s.section = sectp;
|
|
dwz_file->gdb_index.size = bfd_section_size (sectp);
|
|
}
|
|
else if (dwarf2_elf_names.debug_names.matches (sectp->name))
|
|
{
|
|
dwz_file->debug_names.s.section = sectp;
|
|
dwz_file->debug_names.size = bfd_section_size (sectp);
|
|
}
|
|
}
|
|
|
|
/* Attempt to find a .dwz file (whose full path is represented by
|
|
FILENAME) in all of the specified debug file directories provided.
|
|
|
|
Return the equivalent gdb_bfd_ref_ptr of the .dwz file found, or
|
|
nullptr if it could not find anything. */
|
|
|
|
static gdb_bfd_ref_ptr
|
|
dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid,
|
|
size_t buildid_len)
|
|
{
|
|
/* Let's assume that the path represented by FILENAME has the
|
|
"/.dwz/" subpath in it. This is what (most) GNU/Linux
|
|
distributions do, anyway. */
|
|
size_t dwz_pos = filename.find ("/.dwz/");
|
|
|
|
if (dwz_pos == std::string::npos)
|
|
return nullptr;
|
|
|
|
/* This is an obvious assertion, but it's here more to educate
|
|
future readers of this code that FILENAME at DWZ_POS *must*
|
|
contain a directory separator. */
|
|
gdb_assert (IS_DIR_SEPARATOR (filename[dwz_pos]));
|
|
|
|
gdb_bfd_ref_ptr dwz_bfd;
|
|
std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec
|
|
= dirnames_to_char_ptr_vec (debug_file_directory);
|
|
|
|
for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec)
|
|
{
|
|
/* The idea is to iterate over the
|
|
debug file directories provided by the user and
|
|
replace the hard-coded path in the "filename" by each
|
|
debug-file-directory.
|
|
|
|
For example, suppose that filename is:
|
|
|
|
/usr/lib/debug/.dwz/foo.dwz
|
|
|
|
And suppose that we have "$HOME/bar" as the
|
|
debug-file-directory. We would then adjust filename
|
|
to look like:
|
|
|
|
$HOME/bar/.dwz/foo.dwz
|
|
|
|
which would hopefully allow us to find the alt debug
|
|
file. */
|
|
std::string ddir = debugdir.get ();
|
|
|
|
if (ddir.empty ())
|
|
continue;
|
|
|
|
/* Make sure the current debug-file-directory ends with a
|
|
directory separator. This is needed because, if FILENAME
|
|
contains something like "/usr/lib/abcde/.dwz/foo.dwz" and
|
|
DDIR is "/usr/lib/abc", then could wrongfully skip it
|
|
below. */
|
|
if (!IS_DIR_SEPARATOR (ddir.back ()))
|
|
ddir += SLASH_STRING;
|
|
|
|
/* Check whether the beginning of FILENAME is DDIR. If it is,
|
|
then we are dealing with a file which we already attempted to
|
|
open before, so we just skip it and continue processing the
|
|
remaining debug file directories. */
|
|
if (filename.size () > ddir.size ()
|
|
&& filename.compare (0, ddir.size (), ddir) == 0)
|
|
continue;
|
|
|
|
/* Replace FILENAME's default debug-file-directory with
|
|
DDIR. */
|
|
std::string new_filename = ddir + &filename[dwz_pos + 1];
|
|
|
|
dwz_bfd = gdb_bfd_open (new_filename.c_str (), gnutarget);
|
|
|
|
if (dwz_bfd == nullptr)
|
|
continue;
|
|
|
|
if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
|
|
{
|
|
dwz_bfd.reset (nullptr);
|
|
continue;
|
|
}
|
|
|
|
/* Found it. */
|
|
break;
|
|
}
|
|
|
|
return dwz_bfd;
|
|
}
|
|
|
|
/* See dwz.h. */
|
|
|
|
struct dwz_file *
|
|
dwarf2_get_dwz_file (dwarf2_per_bfd *per_bfd, bool require)
|
|
{
|
|
bfd_size_type buildid_len_arg;
|
|
size_t buildid_len;
|
|
bfd_byte *buildid;
|
|
|
|
if (per_bfd->dwz_file != NULL)
|
|
return per_bfd->dwz_file.get ();
|
|
|
|
bfd_set_error (bfd_error_no_error);
|
|
gdb::unique_xmalloc_ptr<char> data
|
|
(bfd_get_alt_debug_link_info (per_bfd->obfd,
|
|
&buildid_len_arg, &buildid));
|
|
if (data == NULL)
|
|
{
|
|
if (bfd_get_error () == bfd_error_no_error)
|
|
{
|
|
if (!require)
|
|
return nullptr;
|
|
error (_("could not read '.gnu_debugaltlink' section"));
|
|
}
|
|
error (_("could not read '.gnu_debugaltlink' section: %s"),
|
|
bfd_errmsg (bfd_get_error ()));
|
|
}
|
|
|
|
gdb::unique_xmalloc_ptr<bfd_byte> buildid_holder (buildid);
|
|
|
|
buildid_len = (size_t) buildid_len_arg;
|
|
|
|
std::string filename = data.get ();
|
|
|
|
if (!IS_ABSOLUTE_PATH (filename.c_str ()))
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> abs
|
|
= gdb_realpath (bfd_get_filename (per_bfd->obfd));
|
|
|
|
filename = ldirname (abs.get ()) + SLASH_STRING + filename;
|
|
}
|
|
|
|
/* First try the file name given in the section. If that doesn't
|
|
work, try to use the build-id instead. */
|
|
gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename.c_str (), gnutarget));
|
|
if (dwz_bfd != NULL)
|
|
{
|
|
if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
|
|
dwz_bfd.reset (nullptr);
|
|
}
|
|
|
|
if (dwz_bfd == NULL)
|
|
dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid);
|
|
|
|
if (dwz_bfd == nullptr)
|
|
{
|
|
/* If the user has provided us with different
|
|
debug file directories, we can try them in order. */
|
|
dwz_bfd = dwz_search_other_debugdirs (filename, buildid, buildid_len);
|
|
}
|
|
|
|
if (dwz_bfd == nullptr)
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> alt_filename;
|
|
const char *origname = bfd_get_filename (per_bfd->obfd);
|
|
|
|
scoped_fd fd (debuginfod_debuginfo_query (buildid,
|
|
buildid_len,
|
|
origname,
|
|
&alt_filename));
|
|
|
|
if (fd.get () >= 0)
|
|
{
|
|
/* File successfully retrieved from server. */
|
|
dwz_bfd = gdb_bfd_open (alt_filename.get (), gnutarget);
|
|
|
|
if (dwz_bfd == nullptr)
|
|
warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
|
|
alt_filename.get ());
|
|
else if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
|
|
dwz_bfd.reset (nullptr);
|
|
}
|
|
}
|
|
|
|
if (dwz_bfd == NULL)
|
|
error (_("could not find '.gnu_debugaltlink' file for %s"),
|
|
bfd_get_filename (per_bfd->obfd));
|
|
|
|
std::unique_ptr<struct dwz_file> result
|
|
(new struct dwz_file (std::move (dwz_bfd)));
|
|
|
|
for (asection *sec : gdb_bfd_sections (result->dwz_bfd))
|
|
locate_dwz_sections (result->dwz_bfd.get (), sec, result.get ());
|
|
|
|
gdb_bfd_record_inclusion (per_bfd->obfd, result->dwz_bfd.get ());
|
|
per_bfd->dwz_file = std::move (result);
|
|
return per_bfd->dwz_file.get ();
|
|
}
|