Allow gdb to find debug symbols file by build-id for PE file format also

This promotes BFD's struct elf_build_id to the generic struct bfd_build_id,
populated when an ELF or PE BFD is read.

gdb is updated to use that, and to use the build-id to find symbols for PE files
also.

There is currently no generic way to extract the build-id from an object file,
perhaps an option to objdump to do this might make sense?

On x86_64-pc-cygwin, gdb's sepdebug.exp changes:

-# of unsupported tests          1
+# of expected passes            90

I don't seem to get consistent testsuite runs on i686-linux-gnu, but there
don't appear to be any regressions.

bfd/ChangeLog:

2015-06-10  Jon Turney  <jon.turney@dronecode.org.uk>

	* elf-bfd.h : Remove struct elf_build_id.
	* bfd.c : Add struct bfd_build_id.
	* bfd-in2.h: Regenerate.
	* elf.c (elfobj_grok_gnu_build_id): Update to use bfd_build_id.
	* libpei.h: Add protoype and macros for
	bfd_XXi_slurp_codeview_record.
	* peXXigen.c (_bfd_XXi_slurp_codeview_record): Make public
	* peicode.h (pe_bfd_read_buildid): Add.
	(pe_bfd_object_p): Use pe_bfd_read_buildid().

gdb/ChangeLog:

2015-06-10  Jon Turney  <jon.turney@dronecode.org.uk>

	* build-id.c: Don't include elf-bfd.h.
	(build_id_bfd_get): Use bfd_build_id.
	(build_id_verify): Ditto.
	* build-id.h: Ditto.
	(find_separate_debug_file_by_buildid): Ditto.
	* python/py-objfile.c: Don't include elf-bfd.h.
	(objfpy_get_build_id) Use bfd_build_id.
	(objfpy_build_id_matches, objfpy_lookup_objfile_by_build_id): Ditto.
	* coffread.c: Include build-id.h.
	(coff_symfile_read): Try find_separate_debug_file_by_buildid.

gdb/doc/ChangeLog:

2015-06-10  Jon Turney  <jon.turney@dronecode.org.uk>

	* gdb.texinfo (Separate Debug Files): Document that PE is also
	supported.

gdb/testsuite/ChangeLog:

2015-06-10  Jon Turney  <jon.turney@dronecode.org.uk>

	* gdb.base/sepdebug.exp: Add EXEEXT where needed.
	* lib/gdb.exp (get_build_id): Teach how to extract build-id from a
	PE file.
	* lib/future.exp (gdb_find_objdump): Add gdb_find_objdump.

Signed-off-by: Jon Turney <jon.turney@dronecode.org.uk>
This commit is contained in:
Jon Turney 2015-04-07 20:49:08 +01:00
parent f20c58f51f
commit c74f7d1c6c
19 changed files with 231 additions and 66 deletions

View File

@ -1,3 +1,15 @@
2015-06-10 Jon Turney <jon.turney@dronecode.org.uk>
* elf-bfd.h : Remove struct elf_build_id.
* bfd.c : Add struct bfd_build_id.
* bfd-in2.h: Regenerate.
* elf.c (elfobj_grok_gnu_build_id): Update to use bfd_build_id.
* libpei.h: Add protoype and macros for
bfd_XXi_slurp_codeview_record.
* peXXigen.c (_bfd_XXi_slurp_codeview_record): Make public
* peicode.h (pe_bfd_read_buildid): Add.
(pe_bfd_object_p): Use pe_bfd_read_buildid().
2015-06-15 Renlin Li <renlin.li@arm.com>
* reloc.c (BFD_RELOC_AARCH64_LD64_GOTOFF_LO15): New entry.

View File

@ -6326,6 +6326,12 @@ enum bfd_plugin_format
bfd_plugin_no = 2
};
struct bfd_build_id
{
size_t size;
bfd_byte data[1];
};
struct bfd
{
/* The filename the application opened the BFD with. */
@ -6610,6 +6616,9 @@ struct bfd
struct objalloc *, but we use void * to avoid requiring the inclusion
of objalloc.h. */
void *memory;
/* For input BFDs, the build ID, if the object has one. */
const struct bfd_build_id *build_id;
};
/* See note beside bfd_set_section_userdata. */

View File

@ -51,6 +51,12 @@ CODE_FRAGMENT
. bfd_plugin_no = 2
. };
.
.struct bfd_build_id
. {
. size_t size;
. bfd_byte data[1];
. };
.
.struct bfd
.{
. {* The filename the application opened the BFD with. *}
@ -335,6 +341,9 @@ CODE_FRAGMENT
. struct objalloc *, but we use void * to avoid requiring the inclusion
. of objalloc.h. *}
. void *memory;
.
. {* For input BFDs, the build ID, if the object has one. *}
. const struct bfd_build_id *build_id;
.};
.
.{* See note beside bfd_set_section_userdata. *}

View File

@ -1563,13 +1563,6 @@ struct sdt_note
bfd_byte data[1];
};
/* NT_GNU_BUILD_ID note type info for input BFDs. */
struct elf_build_id
{
size_t size;
bfd_byte data[1];
};
/* tdata information grabbed from an elf core file. */
struct core_elf_obj_tdata
{
@ -1704,9 +1697,6 @@ struct elf_obj_tdata
obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES];
obj_attribute_list *other_obj_attributes[2];
/* NT_GNU_BUILD_ID note type. */
struct elf_build_id *build_id;
/* Linked-list containing information about every Systemtap section
found in the object file. Each section corresponds to one entry
in the list. */

View File

@ -9116,18 +9116,18 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
static bfd_boolean
elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note)
{
struct elf_obj_tdata *t;
struct bfd_build_id* build_id;
if (note->descsz == 0)
return FALSE;
t = elf_tdata (abfd);
t->build_id = bfd_alloc (abfd, sizeof (*t->build_id) - 1 + note->descsz);
if (t->build_id == NULL)
build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) - 1 + note->descsz);
if (build_id == NULL)
return FALSE;
t->build_id->size = note->descsz;
memcpy (t->build_id->data, note->descdata, note->descsz);
build_id->size = note->descsz;
memcpy (build_id->data, note->descdata, note->descsz);
abfd->build_id = build_id;
return TRUE;
}

View File

@ -238,6 +238,7 @@
#define _bfd_XXi_swap_debugdir_in _bfd_pex64i_swap_debugdir_in
#define _bfd_XXi_swap_debugdir_out _bfd_pex64i_swap_debugdir_out
#define _bfd_XXi_write_codeview_record _bfd_pex64i_write_codeview_record
#define _bfd_XXi_slurp_codeview_record _bfd_pex64i_slurp_codeview_record
#elif defined COFF_WITH_pep
@ -272,6 +273,7 @@
#define _bfd_XXi_swap_debugdir_in _bfd_pepi_swap_debugdir_in
#define _bfd_XXi_swap_debugdir_out _bfd_pepi_swap_debugdir_out
#define _bfd_XXi_write_codeview_record _bfd_pepi_write_codeview_record
#define _bfd_XXi_slurp_codeview_record _bfd_pepi_slurp_codeview_record
#else /* !COFF_WITH_pep */
@ -306,6 +308,7 @@
#define _bfd_XXi_swap_debugdir_in _bfd_pei_swap_debugdir_in
#define _bfd_XXi_swap_debugdir_out _bfd_pei_swap_debugdir_out
#define _bfd_XXi_write_codeview_record _bfd_pei_write_codeview_record
#define _bfd_XXi_slurp_codeview_record _bfd_pei_slurp_codeview_record
#endif /* !COFF_WITH_pep */
@ -351,6 +354,7 @@ bfd_boolean _bfd_XXi_final_link_postscript (bfd *, struct coff_final_link_info *
void _bfd_XXi_swap_debugdir_in (bfd *, void *, void *);
unsigned _bfd_XXi_swap_debugdir_out (bfd *, void *, void *);
unsigned _bfd_XXi_write_codeview_record (bfd *, file_ptr, CODEVIEW_INFO *);
CODEVIEW_INFO * _bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo);
/* The following are needed only for ONE of pe or pei, but don't
otherwise vary; peicode.h fixes up ifdefs but we provide the

View File

@ -1140,7 +1140,7 @@ _bfd_XXi_swap_debugdir_out (bfd * abfd, void * inp, void * extp)
return sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
}
static CODEVIEW_INFO *
CODEVIEW_INFO *
_bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo)
{
char buffer[256+1];

View File

@ -1255,6 +1255,87 @@ pe_ILF_object_p (bfd * abfd)
return abfd->xvec;
}
static void
pe_bfd_read_buildid(bfd *abfd)
{
pe_data_type *pe = pe_data (abfd);
struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr;
asection *section;
bfd_byte *data = 0;
bfd_size_type dataoff;
unsigned int i;
bfd_vma addr = extra->DataDirectory[PE_DEBUG_DATA].VirtualAddress;
bfd_size_type size = extra->DataDirectory[PE_DEBUG_DATA].Size;
if (size == 0)
return;
addr += extra->ImageBase;
/* Search for the section containing the DebugDirectory */
for (section = abfd->sections; section != NULL; section = section->next)
{
if ((addr >= section->vma) && (addr < (section->vma + section->size)))
break;
}
if (section == NULL)
{
return;
}
else if (!(section->flags & SEC_HAS_CONTENTS))
{
return;
}
dataoff = addr - section->vma;
/* Read the whole section. */
if (!bfd_malloc_and_get_section (abfd, section, &data))
{
if (data != NULL)
free (data);
return;
}
/* Search for a CodeView entry in the DebugDirectory */
for (i = 0; i < size / sizeof (struct external_IMAGE_DEBUG_DIRECTORY); i++)
{
struct external_IMAGE_DEBUG_DIRECTORY *ext
= &((struct external_IMAGE_DEBUG_DIRECTORY *)(data + dataoff))[i];
struct internal_IMAGE_DEBUG_DIRECTORY idd;
_bfd_XXi_swap_debugdir_in (abfd, ext, &idd);
if (idd.Type == PE_IMAGE_DEBUG_TYPE_CODEVIEW)
{
char buffer[256 + 1];
CODEVIEW_INFO *cvinfo = (CODEVIEW_INFO *) buffer;
/*
The debug entry doesn't have to have to be in a section, in which
case AddressOfRawData is 0, so always use PointerToRawData.
*/
if (_bfd_XXi_slurp_codeview_record (abfd,
(file_ptr) idd.PointerToRawData,
idd.SizeOfData, cvinfo))
{
struct bfd_build_id* build_id = bfd_alloc(abfd,
sizeof(struct bfd_build_id) + cvinfo->SignatureLength);
if (build_id)
{
build_id->size = cvinfo->SignatureLength;
memcpy(build_id->data, cvinfo->Signature,
cvinfo->SignatureLength);
abfd->build_id = build_id;
}
}
break;
}
}
}
static const bfd_target *
pe_bfd_object_p (bfd * abfd)
{
@ -1265,6 +1346,7 @@ pe_bfd_object_p (bfd * abfd)
struct internal_aouthdr internal_a;
file_ptr opt_hdr_size;
file_ptr offset;
const bfd_target *result;
/* Detect if this a Microsoft Import Library Format element. */
/* First read the beginning of the header. */
@ -1358,10 +1440,20 @@ pe_bfd_object_p (bfd * abfd)
return NULL;
}
return coff_real_object_p (abfd, internal_f.f_nscns, &internal_f,
(opt_hdr_size != 0
? &internal_a
: (struct internal_aouthdr *) NULL));
result = coff_real_object_p (abfd, internal_f.f_nscns, &internal_f,
(opt_hdr_size != 0
? &internal_a
: (struct internal_aouthdr *) NULL));
if (result)
{
/* Now the whole header has been processed, see if there is a build-id */
pe_bfd_read_buildid(abfd);
}
return result;
}
#define coff_object_p pe_bfd_object_p

View File

@ -1,3 +1,16 @@
2015-06-10 Jon Turney <jon.turney@dronecode.org.uk>
* build-id.c: Don't include elf-bfd.h.
(build_id_bfd_get): Use bfd_build_id.
(build_id_verify): Ditto.
* build-id.h: Ditto.
(find_separate_debug_file_by_buildid): Ditto.
* python/py-objfile.c: Don't include elf-bfd.h.
(objfpy_get_build_id) Use bfd_build_id.
(objfpy_build_id_matches, objfpy_lookup_objfile_by_build_id): Ditto.
* coffread.c: Include build-id.h.
(coff_symfile_read): Try find_separate_debug_file_by_buildid.
2015-06-03 Jon Turney <jon.turney@dronecode.org.uk>
* windows-nat.c (do_windows_fetch_inferior_registers)

View File

@ -19,7 +19,6 @@
#include "defs.h"
#include "bfd.h"
#include "elf-bfd.h"
#include "gdb_bfd.h"
#include "build-id.h"
#include "gdb_vecs.h"
@ -30,19 +29,17 @@
/* See build-id.h. */
const struct elf_build_id *
const struct bfd_build_id *
build_id_bfd_get (bfd *abfd)
{
if (!bfd_check_format (abfd, bfd_object)
|| bfd_get_flavour (abfd) != bfd_target_elf_flavour
/* Although this is ELF_specific, it is safe to do in generic
code because it does not rely on any ELF-specific symbols at
link time, and if the ELF code is not available in BFD, then
ABFD will not have the ELF flavour. */
|| elf_tdata (abfd)->build_id == NULL)
if (!bfd_check_format (abfd, bfd_object))
return NULL;
return elf_tdata (abfd)->build_id;
if (abfd->build_id != NULL)
return abfd->build_id;
/* No build-id */
return NULL;
}
/* See build-id.h. */
@ -50,7 +47,7 @@ build_id_bfd_get (bfd *abfd)
int
build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check)
{
const struct elf_build_id *found;
const struct bfd_build_id *found;
int retval = 0;
found = build_id_bfd_get (abfd);
@ -139,7 +136,7 @@ build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
char *
find_separate_debug_file_by_buildid (struct objfile *objfile)
{
const struct elf_build_id *build_id;
const struct bfd_build_id *build_id;
build_id = build_id_bfd_get (objfile->obfd);
if (build_id != NULL)

View File

@ -22,7 +22,7 @@
/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */
extern const struct elf_build_id *build_id_bfd_get (bfd *abfd);
extern const struct bfd_build_id *build_id_bfd_get (bfd *abfd);
/* Return true if ABFD has NT_GNU_BUILD_ID matching the CHECK value.
Otherwise, issue a warning and return false. */

View File

@ -41,6 +41,7 @@
#include "coff-pe-read.h"
#include "psymtab.h"
#include "build-id.h"
extern void _initialize_coffread (void);
@ -738,7 +739,10 @@ coff_symfile_read (struct objfile *objfile, int symfile_flags)
{
char *debugfile;
debugfile = find_separate_debug_file_by_debuglink (objfile);
debugfile = find_separate_debug_file_by_buildid (objfile);
if (debugfile == NULL)
debugfile = find_separate_debug_file_by_debuglink (objfile);
make_cleanup (xfree, debugfile);
if (debugfile)

View File

@ -1,3 +1,8 @@
2015-06-10 Jon Turney <jon.turney@dronecode.org.uk>
* gdb.texinfo (Separate Debug Files): Document that PE is also
supported.
2015-06-13 Andrew Burgess <andrew.burgess@embecosm.com>
* gdb.texinfo (TUI Commands): Bring all 'tui reg' commands into a

View File

@ -18170,7 +18170,7 @@ the executable and the debug file came from the same build.
@item
The executable contains a @dfn{build ID}, a unique bit string that is
also present in the corresponding debug info file. (This is supported
only on some operating systems, notably those which use the ELF format
only on some operating systems, when using the ELF or PE file formats
for binary files and the @sc{gnu} Binutils.) For more details about
this feature, see the description of the @option{--build-id}
command-line option in @ref{Options, , Command Line Options, ld.info,

View File

@ -23,7 +23,6 @@
#include "objfiles.h"
#include "language.h"
#include "build-id.h"
#include "elf-bfd.h"
#include "symtab.h"
typedef struct
@ -134,7 +133,7 @@ objfpy_get_build_id (PyObject *self, void *closure)
{
objfile_object *obj = (objfile_object *) self;
struct objfile *objfile = obj->objfile;
const struct elf_build_id *build_id = NULL;
const struct bfd_build_id *build_id = NULL;
OBJFPY_REQUIRE_VALID (obj);
@ -484,7 +483,7 @@ objfpy_build_id_ok (const char *string)
It is assumed that objfpy_build_id_ok (string) returns TRUE. */
static int
objfpy_build_id_matches (const struct elf_build_id *build_id,
objfpy_build_id_matches (const struct bfd_build_id *build_id,
const char *string)
{
size_t i;
@ -542,7 +541,7 @@ objfpy_lookup_objfile_by_build_id (const char *build_id)
ALL_OBJFILES (objfile)
{
const struct elf_build_id *obfd_build_id;
const struct bfd_build_id *obfd_build_id;
if (objfile->obfd == NULL)
continue;

View File

@ -1,3 +1,10 @@
2015-06-10 Jon Turney <jon.turney@dronecode.org.uk>
* gdb.base/sepdebug.exp: Add EXEEXT where needed.
* lib/gdb.exp (get_build_id): Teach how to extract build-id from a
PE file.
* lib/future.exp (gdb_find_objdump): Add gdb_find_objdump.
2015-06-12 Antoine Tremblay <antoine.tremblay@ericsson.com>
PR breakpoints/16465

View File

@ -42,7 +42,7 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb
# the name of a debuginfo only file. This file will be stored in the
# gdb.base/ subdirectory.
if [gdb_gnu_strip_debug $binfile] {
if [gdb_gnu_strip_debug $binfile$EXEEXT] {
# check that you have a recent version of strip and objcopy installed
unsupported "cannot produce separate debug info files"
return -1
@ -60,7 +60,7 @@ set new_name [standard_output_file ${testfile}${EXEEXT}]
remote_exec build "rm -rf [file dirname $new_name]"
remote_exec build "mkdir [file dirname $new_name]"
remote_exec build "ln -s ${binfile} $new_name"
remote_exec build "ln -s ${binfile}${EXEEXT} $new_name"
clean_restart ${testfile}${EXEEXT}
if { $gdb_file_cmd_debug_info != "debug" } then {
fail "No debug information found."
@ -716,10 +716,10 @@ proc test_different_dir {type test_different_dir xfail} {
# the "set debug-file-directory" command.
set different_dir [standard_output_file ${testfile}.dir]
set debugfile "${different_dir}/[standard_output_file ${testfile}.debug]"
set debugfile "${different_dir}/[standard_output_file ${testfile}${EXEEXT}.debug]"
remote_exec build "rm -rf $different_dir"
remote_exec build "mkdir -p [file dirname $debugfile]"
remote_exec build "mv -f [standard_output_file ${testfile}.debug] $debugfile"
remote_exec build "mv -f [standard_output_file ${testfile}${EXEEXT}.debug] $debugfile"
test_different_dir debuglink $different_dir 0
@ -727,7 +727,7 @@ test_different_dir debuglink $different_dir 0
# Test CRC mismatch is reported.
if {[build_executable sepdebug.exp sepdebug2 sepdebug2.c debug] != -1
&& ![gdb_gnu_strip_debug [standard_output_file sepdebug2]]} {
&& ![gdb_gnu_strip_debug [standard_output_file sepdebug2]$EXEEXT]} {
remote_exec build "cp ${debugfile} [standard_output_file sepdebug2.debug]"
@ -743,7 +743,7 @@ if {[build_executable sepdebug.exp sepdebug2 sepdebug2.c debug] != -1
# NT_GNU_BUILD_ID / .note.gnu.build-id test:
set build_id_debug_filename [build_id_debug_filename_get $binfile]
set build_id_debug_filename [build_id_debug_filename_get $binfile$EXEEXT]
if ![string compare $build_id_debug_filename ""] then {
unsupported "build-id is not supported by the compiler"

View File

@ -104,6 +104,17 @@ proc gdb_find_objcopy {} {
return $objcopy
}
# find target objdump
proc gdb_find_objdump {} {
global OBJDUMP_FOR_TARGET
if [info exists OBJDUMP_FOR_TARGET] {
set objdump $OBJDUMP_FOR_TARGET
} else {
set objdump [transform objdump]
}
return $objdump
}
proc gdb_find_readelf {} {
global READELF_FOR_TARGET
if [info exists READELF_FOR_TARGET] {

View File

@ -4539,28 +4539,41 @@ gdb_caching_proc gdb_has_argv0 {
# Returns "" if there is none.
proc get_build_id { filename } {
set tmp [standard_output_file "${filename}-tmp"]
set objcopy_program [gdb_find_objcopy]
set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $filename $tmp" output]
verbose "result is $result"
verbose "output is $output"
if {$result == 1} {
return ""
if { ([istarget "*-*-mingw*"]
|| [istarget *-*-cygwin*]) } {
set objdump_program [gdb_find_objdump]
set result [catch {set data [exec $objdump_program -p $filename | grep signature | cut "-d " -f4]} output]
verbose "result is $result"
verbose "output is $output"
if {$result == 1} {
return ""
}
return $data
}
set fi [open $tmp]
fconfigure $fi -translation binary
# Skip the NOTE header.
read $fi 16
set data [read $fi]
close $fi
file delete $tmp
if ![string compare $data ""] then {
return ""
else
{
set tmp [standard_output_file "${filename}-tmp"]
set objcopy_program [gdb_find_objcopy]
set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $filename $tmp" output]
verbose "result is $result"
verbose "output is $output"
if {$result == 1} {
return ""
}
set fi [open $tmp]
fconfigure $fi -translation binary
# Skip the NOTE header.
read $fi 16
set data [read $fi]
close $fi
file delete $tmp
if ![string compare $data ""] then {
return ""
}
# Convert it to hex.
binary scan $data H* data
return $data
}
# Convert it to hex.
binary scan $data H* data
return $data
}
# Return the build-id hex string (usually 160 bits as 40 hex characters)