Add support for locating separate debug info files via the build-id method.
PR binutils/20876 bfd * opncls.c (find_separate_debug_file): Add include_dirs parameter. Only include the directory part of the bfd's filename in search paths if include_dirs is true. Add a couple of extra locations for looking for debug files. ( bfd_follow_gnu_debuglink): Update invocation of find_separate_debug_file. (bfd_follow_gnu_debugaltlink): Likewise. (get_build_id): New function: Finds the build-id of the given bfd. (get_build_id_name): New function: Computes the name of the separate debug info file for a bfd, based upon its build-id. (check_build_id_file): New function: Checks to see if a separate debug info file exists at the given location, and that its build-id matches that of the original bfd. (bfd_follow_build_id_debuglink): New function: Finds a separate debug info file for a given bfd by using the build-id method. * dwarf2.c (_bfd_dwarf2_slurp_debug_info): Try using the build-id method of locating a separate debug info file before using the debuglink method. * bfd-in2.h: Regenerate. binutils * NEWS: Mention the new feature. * testsuite/binutils-all/objdump.exp (test_build_id_debuglink): New proc to test the location of separate debug info files using the build-id method.
This commit is contained in:
parent
620214f742
commit
2425a30e40
|
@ -1,3 +1,26 @@
|
|||
2017-01-12 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
PR binutils/20876
|
||||
* opncls.c (find_separate_debug_file): Add include_dirs
|
||||
parameter. Only include the directory part of the bfd's filename
|
||||
in search paths if include_dirs is true. Add a couple of extra
|
||||
locations for looking for debug files.
|
||||
( bfd_follow_gnu_debuglink): Update invocation of
|
||||
find_separate_debug_file.
|
||||
(bfd_follow_gnu_debugaltlink): Likewise.
|
||||
(get_build_id): New function: Finds the build-id of the given bfd.
|
||||
(get_build_id_name): New function: Computes the name of the
|
||||
separate debug info file for a bfd, based upon its build-id.
|
||||
(check_build_id_file): New function: Checks to see if a separate
|
||||
debug info file exists at the given location, and that its
|
||||
build-id matches that of the original bfd.
|
||||
(bfd_follow_build_id_debuglink): New function: Finds a separate
|
||||
debug info file for a given bfd by using the build-id method.
|
||||
* dwarf2.c (_bfd_dwarf2_slurp_debug_info): Try using the build-id
|
||||
method of locating a separate debug info file before using the
|
||||
debuglink method.
|
||||
* bfd-in2.h: Regenerate.
|
||||
|
||||
2017-01-11 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR ld/21038
|
||||
|
|
|
@ -1121,6 +1121,8 @@ struct bfd_section *bfd_create_gnu_debuglink_section
|
|||
bfd_boolean bfd_fill_in_gnu_debuglink_section
|
||||
(bfd *abfd, struct bfd_section *sect, const char *filename);
|
||||
|
||||
char *bfd_follow_build_id_debuglink (bfd *abfd, const char *dir);
|
||||
|
||||
/* Extracted from libbfd.c. */
|
||||
|
||||
/* Byte swapping macros for user section data. */
|
||||
|
|
|
@ -3921,7 +3921,11 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
|
|||
msec = find_debug_info (debug_bfd, debug_sections, NULL);
|
||||
if (msec == NULL && abfd == debug_bfd)
|
||||
{
|
||||
char * debug_filename = bfd_follow_gnu_debuglink (abfd, DEBUGDIR);
|
||||
char * debug_filename;
|
||||
|
||||
debug_filename = bfd_follow_build_id_debuglink (abfd, DEBUGDIR);
|
||||
if (debug_filename == NULL)
|
||||
debug_filename = bfd_follow_gnu_debuglink (abfd, DEBUGDIR);
|
||||
|
||||
if (debug_filename == NULL)
|
||||
/* No dwarf2 info, and no gnu_debuglink to follow.
|
||||
|
|
377
bfd/opncls.c
377
bfd/opncls.c
|
@ -25,6 +25,7 @@
|
|||
#include "objalloc.h"
|
||||
#include "libbfd.h"
|
||||
#include "libiberty.h"
|
||||
#include "elf-bfd.h"
|
||||
|
||||
#ifndef S_IXUSR
|
||||
#define S_IXUSR 0100 /* Execute by owner. */
|
||||
|
@ -1305,7 +1306,7 @@ INTERNAL_FUNCTION
|
|||
|
||||
SYNOPSIS
|
||||
bfd_boolean separate_alt_debug_file_exists
|
||||
(char *name, unsigned long crc32);
|
||||
(char *name, unsigned long buildid);
|
||||
|
||||
DESCRIPTION
|
||||
Checks to see if @var{name} is a file and if its BuildID
|
||||
|
@ -1336,17 +1337,21 @@ INTERNAL_FUNCTION
|
|||
find_separate_debug_file
|
||||
|
||||
SYNOPSIS
|
||||
char *find_separate_debug_file (bfd *abfd);
|
||||
char *find_separate_debug_file
|
||||
(bfd *abfd, const char *dir, bfd_boolean include_dirs,
|
||||
get_func_type get, check_func_type check);
|
||||
|
||||
DESCRIPTION
|
||||
Searches @var{abfd} for a section called @var{section_name} which
|
||||
is expected to contain a reference to a file containing separate
|
||||
debugging information. The function scans various locations in
|
||||
the filesystem, including the file tree rooted at
|
||||
@var{debug_file_directory}, and returns the first matching
|
||||
filename that it finds. If @var{check_crc} is TRUE then the
|
||||
contents of the file must also match the CRC value contained in
|
||||
@var{section_name}. Returns NULL if no valid file could be found.
|
||||
Searches for a debug information file corresponding to @var{abfd}.
|
||||
The name of the separate debug info file is returned by the @var{get}
|
||||
function. This function scans various fixed locations in the
|
||||
filesystem, including the file tree rooted at @var{dir}. If the
|
||||
@var{include_dirs} parameter is true then the directory components of
|
||||
@var{abfd}'s filename will be included in the searched locations.
|
||||
|
||||
Returns the filename of the first file to be found which receives a
|
||||
TRUE result from the @var{check} function. Returns NULL if no valid
|
||||
file could be found.
|
||||
*/
|
||||
|
||||
typedef char * (* get_func_type) (bfd *, unsigned long *);
|
||||
|
@ -1355,6 +1360,7 @@ typedef bfd_boolean (* check_func_type) (const char *, const unsigned long);
|
|||
static char *
|
||||
find_separate_debug_file (bfd * abfd,
|
||||
const char * debug_file_directory,
|
||||
bfd_boolean include_dirs,
|
||||
get_func_type get_func,
|
||||
check_func_type check_func)
|
||||
{
|
||||
|
@ -1389,18 +1395,27 @@ find_separate_debug_file (bfd * abfd,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
for (dirlen = strlen (abfd->filename); dirlen > 0; dirlen--)
|
||||
if (IS_DIR_SEPARATOR (abfd->filename[dirlen - 1]))
|
||||
break;
|
||||
|
||||
dir = (char *) bfd_malloc (dirlen + 1);
|
||||
if (dir == NULL)
|
||||
if (include_dirs)
|
||||
{
|
||||
free (base);
|
||||
return NULL;
|
||||
for (dirlen = strlen (abfd->filename); dirlen > 0; dirlen--)
|
||||
if (IS_DIR_SEPARATOR (abfd->filename[dirlen - 1]))
|
||||
break;
|
||||
|
||||
dir = (char *) bfd_malloc (dirlen + 1);
|
||||
if (dir == NULL)
|
||||
{
|
||||
free (base);
|
||||
return NULL;
|
||||
}
|
||||
memcpy (dir, abfd->filename, dirlen);
|
||||
dir[dirlen] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = (char *) bfd_malloc (1);
|
||||
* dir = 0;
|
||||
dirlen = 0;
|
||||
}
|
||||
memcpy (dir, abfd->filename, dirlen);
|
||||
dir[dirlen] = '\0';
|
||||
|
||||
/* Compute the canonical name of the bfd object with all symbolic links
|
||||
resolved, for use in the global debugfile directory. */
|
||||
|
@ -1410,38 +1425,78 @@ find_separate_debug_file (bfd * abfd,
|
|||
break;
|
||||
canon_dir[canon_dirlen] = '\0';
|
||||
|
||||
#ifndef EXTRA_DEBUG_ROOT1
|
||||
#define EXTRA_DEBUG_ROOT1 "/usr/lib/debug"
|
||||
#endif
|
||||
#ifndef EXTRA_DEBUG_ROOT2
|
||||
#define EXTRA_DEBUG_ROOT2 "/usr/lib/debug/usr"
|
||||
#endif
|
||||
|
||||
debugfile = (char *)
|
||||
bfd_malloc (strlen (debug_file_directory) + 1
|
||||
+ (canon_dirlen > dirlen ? canon_dirlen : dirlen)
|
||||
+ strlen (".debug/")
|
||||
#ifdef EXTRA_DEBUG_ROOT1
|
||||
+ strlen (EXTRA_DEBUG_ROOT1)
|
||||
#endif
|
||||
#ifdef EXTRA_DEBUG_ROOT2
|
||||
+ strlen (EXTRA_DEBUG_ROOT2)
|
||||
#endif
|
||||
+ strlen (base)
|
||||
+ 1);
|
||||
if (debugfile == NULL)
|
||||
goto found; /* Actually this returns NULL. */
|
||||
|
||||
/* First try in the same directory as the original file: */
|
||||
strcpy (debugfile, dir);
|
||||
strcat (debugfile, base);
|
||||
/* First try in the same directory as the original file.
|
||||
|
||||
FIXME: Strictly speaking if we are using the build-id method,
|
||||
(ie include_dirs == FALSE) then we should only check absolute
|
||||
paths, not relative ones like this one (and the next one).
|
||||
The check is left in however as this allows the binutils
|
||||
testsuite to exercise this feature without having to install
|
||||
a file into the root filesystem. (See binutils/testsuite/
|
||||
binutils-all/objdump.exp for the test). */
|
||||
sprintf (debugfile, "%s%s", dir, base);
|
||||
if (check_func (debugfile, crc32))
|
||||
goto found;
|
||||
|
||||
/* Then try in a subdirectory called .debug. */
|
||||
strcpy (debugfile, dir);
|
||||
strcat (debugfile, ".debug/");
|
||||
strcat (debugfile, base);
|
||||
|
||||
sprintf (debugfile, "%s.debug/%s", dir, base);
|
||||
if (check_func (debugfile, crc32))
|
||||
goto found;
|
||||
|
||||
#ifdef EXTRA_DEBUG_ROOT1
|
||||
/* Try the first extra debug file root. */
|
||||
sprintf (debugfile, "%s%s%s", EXTRA_DEBUG_ROOT1,
|
||||
include_dirs ? canon_dir : "/", base);
|
||||
if (check_func (debugfile, crc32))
|
||||
goto found;
|
||||
#endif
|
||||
|
||||
#ifdef EXTRA_DEBUG_ROOT2
|
||||
/* Try the second extra debug file root. */
|
||||
sprintf (debugfile, "%s%s%s", EXTRA_DEBUG_ROOT2,
|
||||
include_dirs ? canon_dir : "/", base);
|
||||
if (check_func (debugfile, crc32))
|
||||
goto found;
|
||||
#endif
|
||||
|
||||
/* Then try in the global debugfile directory. */
|
||||
strcpy (debugfile, debug_file_directory);
|
||||
dirlen = strlen (debug_file_directory) - 1;
|
||||
if (dirlen > 0
|
||||
&& debug_file_directory[dirlen] != '/'
|
||||
&& canon_dir[0] != '/')
|
||||
strcat (debugfile, "/");
|
||||
strcat (debugfile, canon_dir);
|
||||
if (include_dirs)
|
||||
{
|
||||
if (dirlen > 0
|
||||
&& debug_file_directory[dirlen] != '/'
|
||||
&& canon_dir[0] != '/')
|
||||
strcat (debugfile, "/");
|
||||
strcat (debugfile, canon_dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dirlen > 0 && debug_file_directory[dirlen] != '/')
|
||||
strcat (debugfile, "/");
|
||||
}
|
||||
strcat (debugfile, base);
|
||||
|
||||
if (check_func (debugfile, crc32))
|
||||
|
@ -1475,9 +1530,8 @@ DESCRIPTION
|
|||
locations, including the directory tree rooted at @var{dir}, and if
|
||||
found returns the full filename.
|
||||
|
||||
If @var{dir} is NULL, it will search a default path configured into
|
||||
libbfd at build time. [XXX this feature is not currently
|
||||
implemented].
|
||||
If @var{dir} is NULL, the search will take place starting at
|
||||
the current directory.
|
||||
|
||||
RETURNS
|
||||
<<NULL>> on any errors or failure to locate the .debug file,
|
||||
|
@ -1488,7 +1542,7 @@ RETURNS
|
|||
char *
|
||||
bfd_follow_gnu_debuglink (bfd *abfd, const char *dir)
|
||||
{
|
||||
return find_separate_debug_file (abfd, dir,
|
||||
return find_separate_debug_file (abfd, dir, TRUE,
|
||||
bfd_get_debug_link_info,
|
||||
separate_debug_file_exists);
|
||||
}
|
||||
|
@ -1522,14 +1576,13 @@ DESCRIPTION
|
|||
|
||||
Takes a BFD and searches it for a .gnu_debugaltlink section. If this
|
||||
section is found, it examines the section for the name of a file
|
||||
containing auxiliary debugging information. It then searches the
|
||||
containing auxiliary debugging information. It then searches the
|
||||
filesystem for this file in a set of standard locations, including
|
||||
the directory tree rooted at @var{dir}, and if found returns the
|
||||
full filename.
|
||||
|
||||
If @var{dir} is NULL, it will search a default path configured into
|
||||
libbfd at build time. [FIXME: This feature is not currently
|
||||
implemented].
|
||||
If @var{dir} is NULL, the search will take place starting at
|
||||
the current directory.
|
||||
|
||||
RETURNS
|
||||
<<NULL>> on any errors or failure to locate the debug file,
|
||||
|
@ -1540,7 +1593,7 @@ RETURNS
|
|||
char *
|
||||
bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir)
|
||||
{
|
||||
return find_separate_debug_file (abfd, dir,
|
||||
return find_separate_debug_file (abfd, dir, TRUE,
|
||||
get_alt_debug_link_info_shim,
|
||||
separate_alt_debug_file_exists);
|
||||
}
|
||||
|
@ -1695,3 +1748,245 @@ bfd_fill_in_gnu_debuglink_section (bfd *abfd,
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
INTERNAL_FUNCTION
|
||||
get_build_id
|
||||
|
||||
SYNOPSIS
|
||||
struct bfd_build_id * get_build_id
|
||||
(bfd *abfd);
|
||||
|
||||
DESCRIPTION
|
||||
Finds the build-id associated with @var{abfd}. If the build-id is
|
||||
extracted from the note section then a build-id structure is built
|
||||
for it, using memory allocated to @var{abfd}, and this is then
|
||||
attached to the @var{abfd}.
|
||||
|
||||
Returns a pointer to the build-id structure if a build-id could be
|
||||
found. If no build-id is found NULL is returned and error code is
|
||||
set.
|
||||
*/
|
||||
|
||||
static struct bfd_build_id *
|
||||
get_build_id (bfd *abfd)
|
||||
{
|
||||
struct bfd_build_id *build_id;
|
||||
Elf_Internal_Note inote;
|
||||
Elf_External_Note *enote;
|
||||
bfd_byte *contents;
|
||||
asection *sect;
|
||||
|
||||
BFD_ASSERT (abfd);
|
||||
|
||||
if (abfd->build_id && abfd->build_id->size > 0)
|
||||
/* Save some time by using the already computed build-id. */
|
||||
return (struct bfd_build_id *) abfd->build_id;
|
||||
|
||||
sect = bfd_get_section_by_name (abfd, ".note.gnu.build-id");
|
||||
if (sect == NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_debug_section);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: Should we support smaller build-id notes ? */
|
||||
if (bfd_get_section_size (sect) < 0x24)
|
||||
{
|
||||
bfd_set_error (bfd_error_invalid_operation);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!bfd_malloc_and_get_section (abfd, sect, & contents))
|
||||
{
|
||||
if (contents != NULL)
|
||||
free (contents);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enote = (Elf_External_Note *) contents;
|
||||
inote.type = H_GET_32 (abfd, enote->type);
|
||||
inote.namesz = H_GET_32 (abfd, enote->namesz);
|
||||
inote.namedata = enote->name;
|
||||
inote.descsz = H_GET_32 (abfd, enote->descsz);
|
||||
inote.descdata = inote.namedata + BFD_ALIGN (inote.namesz, 4);
|
||||
/* FIXME: Should we check for extra notes in this section ? */
|
||||
|
||||
if (inote.descsz == 0
|
||||
|| inote.type != NT_GNU_BUILD_ID
|
||||
|| inote.namesz != 4 /* sizeof "GNU" */
|
||||
|| strcmp (inote.namedata, "GNU") != 0)
|
||||
{
|
||||
free (contents);
|
||||
bfd_set_error (bfd_error_invalid_operation);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) + inote.descsz);
|
||||
if (build_id == NULL)
|
||||
{
|
||||
free (contents);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
build_id->size = inote.descsz;
|
||||
memcpy (build_id->data, inote.descdata, inote.descsz);
|
||||
abfd->build_id = build_id;
|
||||
free (contents);
|
||||
|
||||
return build_id;
|
||||
}
|
||||
|
||||
/*
|
||||
INTERNAL_FUNCTION
|
||||
get_build_id_name
|
||||
|
||||
SYNOPSIS
|
||||
char * get_build_id_name
|
||||
(bfd *abfd, unsigned long *build_id_out)
|
||||
|
||||
DESCRIPTION
|
||||
Searches @var{abfd} for a build-id, and then constructs a pathname
|
||||
from it. The path is computed as .build-id/NN/NN+NN.debug where
|
||||
NNNN+NN is the build-id value as a hexadecimal string.
|
||||
|
||||
Returns the constructed filename or NULL upon error.
|
||||
It is the caller's responsibility to free the memory used to hold the
|
||||
filename.
|
||||
If a filename is returned then the @var{build_id_out} parameter is
|
||||
set to a pointer to the build_id structure.
|
||||
*/
|
||||
|
||||
static char *
|
||||
get_build_id_name (bfd *abfd, unsigned long *build_id_out)
|
||||
{
|
||||
struct bfd_build_id *build_id;
|
||||
char *name;
|
||||
char *n;
|
||||
bfd_size_type s;
|
||||
bfd_byte *d;
|
||||
|
||||
if (abfd == NULL || abfd->filename == NULL || build_id_out == NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_invalid_operation);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
build_id = get_build_id (abfd);
|
||||
if (build_id == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Compute the debug pathname corresponding to the build-id. */
|
||||
name = bfd_malloc (strlen (".build-id/") + build_id->size * 2 + 2 + strlen (".debug"));
|
||||
if (name == NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
return NULL;
|
||||
}
|
||||
n = name;
|
||||
d = build_id->data;
|
||||
s = build_id->size;
|
||||
|
||||
n += sprintf (n, ".build-id/");
|
||||
n += sprintf (n, "%02x", (unsigned) *d++); s--;
|
||||
n += sprintf (n, "/");
|
||||
while (s--)
|
||||
n += sprintf (n, "%02x", (unsigned) *d++);
|
||||
n += sprintf (n, ".debug");
|
||||
|
||||
* build_id_out = (unsigned long) build_id;
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
INTERNAL_FUNCTION
|
||||
check_build_id_file
|
||||
|
||||
SYNOPSIS
|
||||
bfd_boolean check_build_id_file
|
||||
(char *name, unsigned long buildid);
|
||||
|
||||
DESCRIPTION
|
||||
Checks to see if @var{name} is a readable file and if its build-id
|
||||
matches @var{buildid}.
|
||||
|
||||
Returns TRUE if the file exists, is readable, and contains a build-id
|
||||
which matches @var{build-id}.
|
||||
*/
|
||||
|
||||
static bfd_boolean
|
||||
check_build_id_file (const char *name,
|
||||
const unsigned long buildid)
|
||||
{
|
||||
struct bfd_build_id *orig_build_id;
|
||||
struct bfd_build_id *build_id;
|
||||
bfd * file;
|
||||
bfd_boolean result;
|
||||
|
||||
BFD_ASSERT (name);
|
||||
BFD_ASSERT (buildid);
|
||||
|
||||
file = bfd_openr (name, NULL);
|
||||
if (file == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* If the file is an archive, process all of its elements. */
|
||||
if (! bfd_check_format (file, bfd_object))
|
||||
{
|
||||
bfd_close (file);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
build_id = get_build_id (file);
|
||||
if (build_id == NULL)
|
||||
{
|
||||
bfd_close (file);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
orig_build_id = (struct bfd_build_id *) buildid;
|
||||
|
||||
result = build_id->size == orig_build_id->size
|
||||
&& memcmp (build_id->data, orig_build_id->data, build_id->size) == 0;
|
||||
|
||||
(void) bfd_close (file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION
|
||||
bfd_follow_build_id_debuglink
|
||||
|
||||
SYNOPSIS
|
||||
char *bfd_follow_build_id_debuglink (bfd *abfd, const char *dir);
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Takes @var{abfd} and searches it for a .note.gnu.build-id section.
|
||||
If this section is found, it extracts the value of the NT_GNU_BUILD_ID
|
||||
note, which should be a hexadecimal value @var{NNNN+NN} (for
|
||||
32+ hex digits). It then searches the filesystem for a file named
|
||||
@var{.build-id/NN/NN+NN.debug} in a set of standard locations,
|
||||
including the directory tree rooted at @var{dir}. The filename
|
||||
of the first matching file to be found is returned. A matching
|
||||
file should contain a .note.gnu.build-id section with the same
|
||||
@var{NNNN+NN} note as @var{abfd}, although this check is currently
|
||||
not implemented.
|
||||
|
||||
If @var{dir} is NULL, the search will take place starting at
|
||||
the current directory.
|
||||
|
||||
RETURNS
|
||||
<<NULL>> on any errors or failure to locate the debug file,
|
||||
otherwise a pointer to a heap-allocated string containing the
|
||||
filename. The caller is responsible for freeing this string.
|
||||
*/
|
||||
|
||||
char *
|
||||
bfd_follow_build_id_debuglink (bfd *abfd, const char *dir)
|
||||
{
|
||||
return find_separate_debug_file (abfd, dir, FALSE,
|
||||
get_build_id_name,
|
||||
check_build_id_file);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2017-01-12 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
PR binutils/20876
|
||||
* NEWS: Mention the new feature.
|
||||
* testsuite/binutils-all/objdump.exp (test_build_id_debuglink):
|
||||
New proc to test the location of separate debug info files using
|
||||
the build-id method.
|
||||
|
||||
2017-01-10 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
PR 21034
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
-*- text -*-
|
||||
|
||||
* Add support for locating separate debug info files using the build-id
|
||||
method, where the separate file has a name based upon the build-id of
|
||||
the original file.
|
||||
|
||||
Changes in 2.28:
|
||||
|
||||
* This version of binutils fixes a problem with PowerPC VLE 16A and 16D
|
||||
|
|
|
@ -273,6 +273,86 @@ if { ![is_elf_format] } then {
|
|||
}
|
||||
}
|
||||
|
||||
proc test_build_id_debuglink {} {
|
||||
global srcdir
|
||||
global subdir
|
||||
global env
|
||||
global CC_FOR_TARGET
|
||||
global STRIP
|
||||
global OBJCOPY
|
||||
global OBJDUMP
|
||||
global CFLAGS_FOR_TARGET
|
||||
|
||||
set test "build-id-debuglink"
|
||||
if {![info exists CC_FOR_TARGET]} {
|
||||
set CC_FOR_TARGET $env(CC)
|
||||
}
|
||||
if { $CC_FOR_TARGET == "" } {
|
||||
unsupported $test
|
||||
return
|
||||
}
|
||||
|
||||
# Use a fixed build-id.
|
||||
set CFLAGS_FOR_TARGET "-g -Wl,--build-id=0x12345678abcdef01"
|
||||
|
||||
if { [target_compile $srcdir/$subdir/testprog.c tmpdir/testprog exectuable debug] != "" } {
|
||||
fail "$test (build)"
|
||||
return
|
||||
}
|
||||
|
||||
# FIXME: Do we need to restore CFLAGS_FOR_TARGET to its old value ?
|
||||
|
||||
if { [binutils_run $STRIP "--strip-debug --remove-section=.comment tmpdir/testprog -o tmpdir/testprog.strip"] != "" } {
|
||||
fail "$test (strip debug info)"
|
||||
return
|
||||
}
|
||||
|
||||
if { [binutils_run $OBJCOPY "--only-keep-debug tmpdir/testprog tmpdir/testprog.debug"] != "" } {
|
||||
fail "$test (create separate debug info file)"
|
||||
return
|
||||
}
|
||||
|
||||
set got [remote_exec host "mkdir -p .build-id/12" ]
|
||||
if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
|
||||
fail "$test (make debug directory)"
|
||||
return
|
||||
}
|
||||
|
||||
set got [remote_exec host "cp tmpdir/testprog.debug .build-id/12/345678abcdef01.debug"]
|
||||
if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
|
||||
fail "$test (copy debug info into debug directory)"
|
||||
return
|
||||
}
|
||||
|
||||
set got [remote_exec host "$OBJDUMP -Sl tmpdir/testprog.strip" "" "/dev/null" "tmpdir/testprog.strip.dump"]
|
||||
if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
|
||||
fail "$test (post strip dump)"
|
||||
return
|
||||
}
|
||||
|
||||
set src2 tmpdir/testprog.strip.dump
|
||||
verbose " grep -e testprog.c ${src2}"
|
||||
set status [remote_exec build grep "-e testprog.c ${src2}"]
|
||||
set exec_output [lindex $status 1]
|
||||
set exec_output [prune_warnings $exec_output]
|
||||
if [string match "" $exec_output] then {
|
||||
send_log "$exec_output\n"
|
||||
verbose "$exec_output" 1
|
||||
fail "$test (grepping for source file name in disassembly output)"
|
||||
} else {
|
||||
pass "$test"
|
||||
# Cleanup...
|
||||
set got [remote_exec host "rm .build-id/12/345678abcdef01.debug"]
|
||||
set got [remote_exec host "rmdir -p .build-id/12" ]
|
||||
set got [remote_exec host "rm tmpdir/testprog.strip.dump"]
|
||||
set got [remote_exec host "rm tmpdir/testprog.debug"]
|
||||
set got [remote_exec host "rm tmpdir/testprog.strip"]
|
||||
}
|
||||
}
|
||||
|
||||
if {[isnative] && [is_elf_format]} then {
|
||||
test_build_id_debuglink
|
||||
}
|
||||
|
||||
# Options which are not tested: -a -d -D -R -T -x -l --stabs
|
||||
# I don't see any generic way to test any of these other than -a.
|
||||
|
|
Loading…
Reference in New Issue