From patchwork Sun Jul 12 19:29:11 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kratochvil X-Patchwork-Id: 7654 Received: (qmail 67159 invoked by alias); 12 Jul 2015 19:29:26 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 67141 invoked by uid 89); 12 Jul 2015 19:29:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=AWL, BAYES_50, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Sun, 12 Jul 2015 19:29:21 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id 2B8F591EA5; Sun, 12 Jul 2015 19:29:20 +0000 (UTC) Received: from host1.jankratochvil.net (ovpn-116-41.ams2.redhat.com [10.36.116.41]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t6CJTBmY027019 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Sun, 12 Jul 2015 15:29:14 -0400 Date: Sun, 12 Jul 2015 21:29:11 +0200 From: Jan Kratochvil To: Pedro Alves Cc: Doug Evans , gdb-patches , Aleksandar Ristovski , Eli Zaretskii Subject: [PATCH v9 09/10] Validate symbol file using build-id Message-ID: <20150712192911.GB12553@host1.jankratochvil.net> References: <20150614192542.18346.87859.stgit@host1.jankratochvil.net> <20150614192655.18346.17075.stgit@host1.jankratochvil.net> <20150621101644.GA12733@host1.jankratochvil.net> <20150623204702.GA2156@host1.jankratochvil.net> <559D3749.9010200@redhat.com> <20150712190921.GA8682@host1.jankratochvil.net> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20150712190921.GA8682@host1.jankratochvil.net> User-Agent: Mutt/1.5.23 (2014-03-12) X-IsSubscribed: yes On Sun, 12 Jul 2015 21:09:21 +0200, Jan Kratochvil wrote: > On Wed, 08 Jul 2015 16:44:25 +0200, Pedro Alves wrote: > > Doug Evans wrote: > > > > > >> > If so, having solib in the option name is confusing. > > >> > > > >> > set build-id-force > > >> > or > > >> > set require-build-id-match > > >> > or some such would be clearer. > > > > "build-id-force" sound odd to me. The latter sounds OK, > > as would "set build-id-validation on/off/...". > > OK, I will change it to "set build-id-validation on/off/...". It required some language changes as it reversed its on<->off meaning, therefore Ccing Eli. Jan Hi, consumer part of the "build-id" attribute. Approved by: https://sourceware.org/ml/gdb-patches/2014-05/msg00424.html Jan gdb/ChangeLog 2014-02-26 Aleksandar Ristovski Validate symbol file using build-id. * NEWS (Changes since GDB 7.9): Add 'set solib-build-id-validation' and 'show solib-build-id-validation'. 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 (solib_build_id_validation, show_solib_build_id_validation): New. (solib_map_sections): Use ops->validate. (clear_so): Free build_id. (default_solib_validate): New function. (_initialize_solib): Add "solib-build-id-validation". * 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 2014-03-02 Jan Kratochvil * gdb.texinfo (Files): Add 'set solib-build-id-validation' and 'show solib-build-id-validation'. --- gdb/NEWS | 12 ++++++ gdb/doc/gdb.texinfo | 38 +++++++++++++++++++ gdb/solib-darwin.c | 1 + gdb/solib-dsbt.c | 1 + gdb/solib-frv.c | 1 + gdb/solib-spu.c | 1 + gdb/solib-svr4.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/solib-target.c | 2 + gdb/solib.c | 64 +++++++++++++++++++++++++++++++- gdb/solib.h | 4 ++ gdb/solist.h | 18 +++++++++ 11 files changed, 244 insertions(+), 1 deletion(-) diff --git a/gdb/NEWS b/gdb/NEWS index 7ce9758..b07c973 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -194,6 +194,12 @@ maint set|show btrace pt skip-pad Set and show whether PAD packets are skipped when computing the packet history. +set solib-build-id-validation (on|off) +show solib-build-id-validation + 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. + * The command 'thread apply all' can now support new option '-ascending' to call its specified command for all threads in ascending order. @@ -277,6 +283,12 @@ fork-events and vfork-events features in qSupported * GDB now supports access to vector registers on S/390 GNU/Linux targets. +* 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. + * Removed command line options -xdb HP-UX XDB compatibility mode. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 932c38d..b017a6d 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -17950,6 +17950,44 @@ libraries that were loaded by explicit user requests are not discarded. @end table +@table @code +@kindex set solib-build-id-validation +@cindex override @value{GDBN} build-id check +@item set solib-build-id-validation @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 solib-build-id-validation 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 solib-build-id-validation 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 solib-build-id-validation +@item show solib-build-id-validation +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 diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index f96841f..9309c35 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -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; } diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c index 7da5833..9fe6533 100644 --- a/gdb/solib-dsbt.c +++ b/gdb/solib-dsbt.c @@ -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, diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c index f7ef38b..b768146 100644 --- a/gdb/solib-frv.c +++ b/gdb/solib-frv.c @@ -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, diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c index 44fbf91..d162884 100644 --- a/gdb/solib-spu.c +++ b/gdb/solib-spu.c @@ -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); diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 909dfb7..71522c6 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -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; } diff --git a/gdb/solib-target.c b/gdb/solib-target.c index f14363a..13cbd26 100644 --- a/gdb/solib-target.c +++ b/gdb/solib-target.c @@ -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. */ diff --git a/gdb/solib.c b/gdb/solib.c index eb933c0..2ab8b80 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -518,6 +518,20 @@ solib_bfd_open (char *pathname) return abfd; } +/* Boolean for command 'set solib-build-id-validation'. */ +static int solib_build_id_validation = 1; + +/* Implement 'show solib-build-id-validation'. */ + +static void +show_solib_build_id_validation (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 (solib_build_id_validation) + { + warning (_("Shared object \"%s\" could not be validated (%s) and " + "will be ignored; " + "or use 'set solib-build-id-validation 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 solib-build-id-validation 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 ("solib-build-id-validation", class_support, + &solib_build_id_validation, _("\ +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_solib_build_id_validation, + &setlist, &showlist); + } diff --git a/gdb/solib.h b/gdb/solib.h index 336971d..c3bf529 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -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 */ diff --git a/gdb/solist.h b/gdb/solist.h index 7021f5c..e6e74af 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -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 *). */