Validate symbol file using build-id

Consumer part of the "build-id" attribute.

gdb/ChangeLog
2015-07-15  Aleksandar Ristovski  <aristovski@qnx.com
	    Jan Kratochvil  <jan.kratochvil@redhat.com>

	Validate symbol file using build-id.
	* NEWS (Changes since GDB 7.10): Add 'set validate-build-id'
	and 'show validate-build-id'.  Add build-id attribute.
	* solib-darwin.c (_initialize_darwin_solib): Assign validate value.
	* solib-dsbt.c (_initialize_dsbt_solib): Ditto.
	* solib-frv.c (_initialize_frv_solib): Ditto.
	* solib-spu.c (set_spu_solib_ops): Ditto.
	* solib-svr4.c: Include rsp-low.h.
	(NOTE_GNU_BUILD_ID_NAME): New define.
	(svr4_validate): New function.
	(svr4_copy_library_list): Duplicate field build_id.
	(library_list_start_library): Parse 'build-id' attribute.
	(svr4_library_attributes): Add 'build-id' attribute.
	(_initialize_svr4_solib): Assign validate value.
	* solib-target.c (solib.h): Include.
	(_initialize_solib_target): Assign validate value.
	* solib.c (validate_build_id, show_validate_build_id): New.
	(solib_map_sections): Use ops->validate.
	(clear_so): Free build_id.
	(default_solib_validate): New function.
	(_initialize_solib): Add "validate-build-id".
	* solib.h (default_solib_validate): New declaration.
	* solist.h (struct so_list): New fields 'build_idsz' and 'build_id'.
	(target_so_ops): New field 'validate'.

gdb/doc/ChangeLog
2015-07-15  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.texinfo (Files): Add 'set validate-build-id'
	and 'show validate-build-id'.
This commit is contained in:
Jan Kratochvil 2015-07-15 17:37:28 +02:00
parent 700ca40f6f
commit ca5268b6be
13 changed files with 279 additions and 1 deletions

View File

@ -1,3 +1,31 @@
2015-07-15 Aleksandar Ristovski <aristovski@qnx.com
Jan Kratochvil <jan.kratochvil@redhat.com>
Validate symbol file using build-id.
* NEWS (Changes since GDB 7.10): Add 'set validate-build-id'
and 'show validate-build-id'. Add build-id attribute.
* solib-darwin.c (_initialize_darwin_solib): Assign validate value.
* solib-dsbt.c (_initialize_dsbt_solib): Ditto.
* solib-frv.c (_initialize_frv_solib): Ditto.
* solib-spu.c (set_spu_solib_ops): Ditto.
* solib-svr4.c: Include rsp-low.h.
(NOTE_GNU_BUILD_ID_NAME): New define.
(svr4_validate): New function.
(svr4_copy_library_list): Duplicate field build_id.
(library_list_start_library): Parse 'build-id' attribute.
(svr4_library_attributes): Add 'build-id' attribute.
(_initialize_svr4_solib): Assign validate value.
* solib-target.c (solib.h): Include.
(_initialize_solib_target): Assign validate value.
* solib.c (validate_build_id, show_validate_build_id): New.
(solib_map_sections): Use ops->validate.
(clear_so): Free build_id.
(default_solib_validate): New function.
(_initialize_solib): Add "validate-build-id".
* solib.h (default_solib_validate): New declaration.
* solist.h (struct so_list): New fields 'build_idsz' and 'build_id'.
(target_so_ops): New field 'validate'.
2015-07-15 Aleksandar Ristovski <aristovski@qnx.com
Jan Kratochvil <jan.kratochvil@redhat.com>

View File

@ -5,6 +5,20 @@
* Support for tracepoints on aarch64-linux was added in GDBserver.
* New options
set validate-build-id (on|off)
show validate-build-id
Inferior shared library and symbol file may contain unique build-id.
If both build-ids are present but they do not match then this setting
enables (off) or disables (on) loading of such symbol file.
* New features in the GDB remote stub, GDBserver
** library-list-svr4 contains also optional attribute 'build-id' for
each library. GDB does not load library with build-id that
does not match such attribute.
*** Changes in GDB 7.10
* Support for process record-replay and reverse debugging on aarch64*-linux*

View File

@ -1,3 +1,8 @@
2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.texinfo (Files): Add 'set validate-build-id'
and 'show validate-build-id'.
2015-07-15 Aleksandar Ristovski <aristovski@qnx.com
Jan Kratochvil <jan.kratochvil@redhat.com>

View File

@ -17950,6 +17950,44 @@ libraries that were loaded by explicit user requests are not
discarded.
@end table
@table @code
@kindex set validate-build-id
@cindex override @value{GDBN} build-id check
@item set validate-build-id @var{mode}
Setting to override @value{GDBN} build-id check.
Inferior shared libraries and symbol files may contain unique build-id.
By default @value{GDBN} will ignore symbol files with non-matching build-id
while printing:
@smallexample
warning: Shared object "libfoo.so.1" could not be validated (remote
build ID 2bc1745e does not match local build ID a08f8767) and will be
ignored; or use 'set validate-build-id off'.
@end smallexample
Turning off this setting would load such symbol file while still printing:
@smallexample
warning: Shared object "libfoo.so.1" could not be validated (remote
build ID 2bc1745e does not match local build ID a08f8767) but it is
being loaded due to 'set validate-build-id off'.
@end smallexample
If remote build-id is present but it does not match local build-id (or local
build-id is not present) then this setting enables (@var{mode} is @code{off}) or
disables (@var{mode} is @code{on}) loading of such symbol file. On systems
where build-id is not present in the remote system this setting has no effect.
The default value is @code{on}.
Loading non-matching symbol file may confuse debugging including breakage
of backtrace output.
@kindex show validate-build-id
@item show validate-build-id
Display the current mode of build-id check override.
@end table
Sometimes you may wish that @value{GDBN} stops and gives you control
when any of shared library events happen. The best way to do this is
to use @code{catch load} and @code{catch unload} (@pxref{Set

View File

@ -634,4 +634,5 @@ _initialize_darwin_solib (void)
darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code;
darwin_so_ops.lookup_lib_global_symbol = darwin_lookup_lib_symbol;
darwin_so_ops.bfd_open = darwin_bfd_open;
darwin_so_ops.validate = default_solib_validate;
}

View File

@ -1080,6 +1080,7 @@ _initialize_dsbt_solib (void)
dsbt_so_ops.open_symbol_file_object = open_symbol_file_object;
dsbt_so_ops.in_dynsym_resolve_code = dsbt_in_dynsym_resolve_code;
dsbt_so_ops.bfd_open = solib_bfd_open;
dsbt_so_ops.validate = default_solib_validate;
/* Debug this file's internals. */
add_setshow_zuinteger_cmd ("solib-dsbt", class_maintenance,

View File

@ -1183,6 +1183,7 @@ _initialize_frv_solib (void)
frv_so_ops.open_symbol_file_object = open_symbol_file_object;
frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code;
frv_so_ops.bfd_open = solib_bfd_open;
frv_so_ops.validate = default_solib_validate;
/* Debug this file's internals. */
add_setshow_zuinteger_cmd ("solib-frv", class_maintenance,

View File

@ -519,6 +519,7 @@ set_spu_solib_ops (struct gdbarch *gdbarch)
spu_so_ops.current_sos = spu_current_sos;
spu_so_ops.bfd_open = spu_bfd_open;
spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol;
spu_so_ops.validate = default_solib_validate;
}
set_solib_ops (gdbarch, &spu_so_ops);

View File

@ -45,6 +45,9 @@
#include "auxv.h"
#include "gdb_bfd.h"
#include "probe.h"
#include "rsp-low.h"
#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id"
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
@ -970,6 +973,64 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
return (name_lm >= vaddr && name_lm < vaddr + size);
}
/* Validate SO by comparing build-id from the associated bfd and
corresponding build-id from target memory. Return NULL for success
or a string for error. Caller must call xfree for the error string. */
static char *
svr4_validate (const struct so_list *const so)
{
const bfd_byte *local_id;
size_t local_idsz;
gdb_assert (so != NULL);
/* Target doesn't support reporting the build ID or the remote shared library
does not have build ID. */
if (so->build_id == NULL)
return NULL;
/* Build ID may be present in the local file, just GDB is unable to retrieve
it. As it has been reported by gdbserver it is not FSF gdbserver. */
if (so->abfd == NULL
|| !bfd_check_format (so->abfd, bfd_object))
return NULL;
/* GDB has verified the local file really does not contain the build ID. */
if (so->abfd->build_id == NULL)
{
char *remote_hex;
remote_hex = alloca (so->build_idsz * 2 + 1);
bin2hex (so->build_id, remote_hex, so->build_idsz);
return xstrprintf (_("remote build ID is %s "
"but local file does not have build ID"),
remote_hex);
}
local_id = so->abfd->build_id->data;
local_idsz = so->abfd->build_id->size;
if (so->build_idsz != local_idsz
|| memcmp (so->build_id, local_id, so->build_idsz) != 0)
{
char *remote_hex, *local_hex;
remote_hex = alloca (so->build_idsz * 2 + 1);
bin2hex (so->build_id, remote_hex, so->build_idsz);
local_hex = alloca (local_idsz * 2 + 1);
bin2hex (local_id, local_hex, local_idsz);
return xstrprintf (_("remote build ID %s "
"does not match local build ID %s"),
remote_hex, local_hex);
}
/* Both build IDs are present and they match. */
return NULL;
}
/* Implement the "open_symbol_file_object" target_so_ops method.
If no open symbol file, attempt to locate and open the main symbol
@ -1108,6 +1169,12 @@ svr4_copy_library_list (struct so_list *src)
newobj->lm_info = xmalloc (sizeof (struct lm_info));
memcpy (newobj->lm_info, src->lm_info, sizeof (struct lm_info));
if (newobj->build_id != NULL)
{
newobj->build_id = xmalloc (src->build_idsz);
memcpy (newobj->build_id, src->build_id, src->build_idsz);
}
newobj->next = NULL;
*link = newobj;
link = &newobj->next;
@ -1135,6 +1202,9 @@ library_list_start_library (struct gdb_xml_parser *parser,
ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value;
ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value;
ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value;
const struct gdb_xml_value *const att_build_id
= xml_find_attribute (attributes, "build-id");
const char *const hex_build_id = att_build_id ? att_build_id->value : NULL;
struct so_list *new_elem;
new_elem = XCNEW (struct so_list);
@ -1146,6 +1216,37 @@ library_list_start_library (struct gdb_xml_parser *parser,
strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1);
new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0;
strcpy (new_elem->so_original_name, new_elem->so_name);
if (hex_build_id != NULL)
{
const size_t hex_build_id_len = strlen (hex_build_id);
if (hex_build_id_len == 0)
warning (_("Shared library \"%s\" received empty build-id "
"from gdbserver"), new_elem->so_original_name);
else if ((hex_build_id_len & 1U) != 0)
warning (_("Shared library \"%s\" received odd number "
"of build-id \"%s\" hex characters from gdbserver"),
new_elem->so_original_name, hex_build_id);
else
{
const size_t build_idsz = hex_build_id_len / 2;
new_elem->build_id = xmalloc (build_idsz);
new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id,
build_idsz);
if (new_elem->build_idsz != build_idsz)
{
warning (_("Shared library \"%s\" received invalid "
"build-id \"%s\" hex character at encoded byte "
"position %s (first as 0) from gdbserver"),
new_elem->so_original_name, hex_build_id,
pulongest (new_elem->build_idsz));
xfree (new_elem->build_id);
new_elem->build_id = NULL;
new_elem->build_idsz = 0;
}
}
}
*list->tailp = new_elem;
list->tailp = &new_elem->next;
@ -1180,6 +1281,7 @@ static const struct gdb_xml_attribute svr4_library_attributes[] =
{ "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
@ -3258,4 +3360,5 @@ _initialize_svr4_solib (void)
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
svr4_so_ops.handle_event = svr4_handle_solib_event;
svr4_so_ops.validate = svr4_validate;
}

View File

@ -25,6 +25,7 @@
#include "target.h"
#include "vec.h"
#include "solib-target.h"
#include "solib.h"
/* Private data for each loaded library. */
struct lm_info
@ -506,6 +507,7 @@ _initialize_solib_target (void)
solib_target_so_ops.in_dynsym_resolve_code
= solib_target_in_dynsym_resolve_code;
solib_target_so_ops.bfd_open = solib_bfd_open;
solib_target_so_ops.validate = default_solib_validate;
/* Set current_target_so_ops to solib_target_so_ops if not already
set. */

View File

@ -518,6 +518,20 @@ solib_bfd_open (char *pathname)
return abfd;
}
/* Boolean for command 'set validate-build-id'. */
static int validate_build_id = 1;
/* Implement 'show validate-build-id'. */
static void
show_validate_build_id (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Validation a build-id matches to load a shared "
"library is %s.\n"),
value);
}
/* Given a pointer to one of the shared objects in our list of mapped
objects, use the recorded name to open a bfd descriptor for the
object, build a section table, relocate all the section addresses
@ -534,7 +548,7 @@ static int
solib_map_sections (struct so_list *so)
{
const struct target_so_ops *ops = solib_ops (target_gdbarch ());
char *filename;
char *filename, *validate_error;
struct target_section *p;
struct cleanup *old_chain;
bfd *abfd;
@ -550,6 +564,29 @@ solib_map_sections (struct so_list *so)
/* Leave bfd open, core_xfer_memory and "info files" need it. */
so->abfd = abfd;
gdb_assert (ops->validate != NULL);
validate_error = ops->validate (so);
if (validate_error != NULL)
{
if (validate_build_id)
{
warning (_("Shared object \"%s\" could not be validated (%s) and "
"will be ignored; "
"or use 'set validate-build-id off'."),
so->so_name, validate_error);
xfree (validate_error);
gdb_bfd_unref (so->abfd);
so->abfd = NULL;
return 0;
}
warning (_("Shared object \"%s\" could not be validated (%s) "
"but it is being loaded due to "
"'set validate-build-id off'."),
so->so_name, validate_error);
xfree (validate_error);
}
/* Copy the full path name into so_name, allowing symbol_file_add
to find it later. This also affects the =library-loaded GDB/MI
event, and in particular the part of that notification providing
@ -626,6 +663,9 @@ clear_so (struct so_list *so)
of the symbol file. */
strcpy (so->so_name, so->so_original_name);
xfree (so->build_id);
so->build_id = NULL;
/* Do the same for target-specific data. */
if (ops->clear_so != NULL)
ops->clear_so (so);
@ -1657,6 +1697,14 @@ remove_user_added_objfile (struct objfile *objfile)
}
}
/* Default implementation does not perform any validation. */
char *
default_solib_validate (const struct so_list *const so)
{
return NULL; /* No validation. */
}
extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */
void
@ -1714,4 +1762,18 @@ PATH and LD_LIBRARY_PATH."),
reload_shared_libraries,
show_solib_search_path,
&setlist, &showlist);
add_setshow_boolean_cmd ("validate-build-id", class_support,
&validate_build_id, _("\
Set validation a build-id matches to load a shared library."), _("\
SHow validation a build-id matches to load a shared library."), _("\
Inferior shared library and symbol file may contain unique build-id.\n\
If both build-ids are present but they do not match then this setting\n\
enables (off) or disables (on) loading of such symbol file.\n\
Loading non-matching symbol file may confuse debugging including breakage\n\
of backtrace output."),
NULL,
show_validate_build_id,
&setlist, &showlist);
}

View File

@ -98,4 +98,8 @@ extern void update_solib_breakpoints (void);
extern void handle_solib_event (void);
/* Default validation always returns 1. */
extern char *default_solib_validate (const struct so_list *so);
#endif /* SOLIB_H */

View File

@ -75,6 +75,19 @@ struct so_list
There may not be just one (e.g. if two segments are relocated
differently); but this is only used for "info sharedlibrary". */
CORE_ADDR addr_low, addr_high;
/* Build id decoded from .note.gnu.build-id without note header. This is
actual BUILD_ID which comes either from the remote target via qXfer
packet or via reading target memory. Note that if there's a
mismatch with the associated bfd then so->abfd will be cleared.
Reading target memory should be done by following execution view
of the binary (following program headers in the case of ELF).
Computing address from the linking view (following ELF section
headers) may give incorrect build-id memory address despite the
symbols still match.
Such an example is a prelinked vs. unprelinked i386 ELF file. */
size_t build_idsz;
gdb_byte *build_id;
};
struct target_so_ops
@ -168,6 +181,11 @@ struct target_so_ops
NULL, in which case no specific preprocessing is necessary
for this target. */
void (*handle_event) (void);
/* Return NULL if SO does match target SO it is supposed to
represent. Otherwise return string describing why it does not match.
Caller has to free the string. */
char *(*validate) (const struct so_list *so);
};
/* Free the memory associated with a (so_list *). */