diff mbox

[v5,7/8] Validate symbol file using build-id [updated]

Message ID 20140321163411.GA11618@host2.jankratochvil.net
State Committed
Headers show

Commit Message

Jan Kratochvil March 21, 2014, 4:34 p.m. UTC
Hi all,

sending just this one patch part updated.

The ^# part is just a diff against the last v5 post.


Thanks,
Jan


#diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
#index c2683f4..bf1fada 100644
#--- a/gdb/doc/gdb.texinfo
#+++ b/gdb/doc/gdb.texinfo
#@@ -17121,28 +17121,30 @@ discarded.
# 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:
#+@value{GDBN} expects the build-ids of each shared library and its corresponding
#+symbol file to be identical.  If they are not identical, then by default
#+@value{GDBN} will @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-force'.
#+  warning: Shared object "libfoo.so.1" could not be validated (inferior
#+  build ID 2bc1745e does not match symbol file build ID a08f8767) and
#+  will be ignored; or use 'set solib-build-id-force'.
# @end smallexample
# 
# Turning on 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-force'.
#+  warning: Shared object "libfoo.so.1" could not be validated (inferior
#+  build ID 2bc1745e is not identical to symbol file build ID a08f8767)
#+  but it is being loaded due to 'set solib-build-id-force'.
# @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{on}) or
#-disables (@var{mode} is @code{off}) 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{off}.
#+If inferior build-id is present but it does not match symbol file build-id
#+(or the symbol file build-id is not present) then this setting enables
#+(@var{mode} is @code{on}) or disables (@var{mode} is @code{off}) loading of
#+such symbol file.  On systems where build-id is not present in the inferior
#+system this setting has no effect.  The default value is @code{off}.
# 
# Loading non-matching symbol file may confuse debugging including breakage
# of backtrace output.
#diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
#index 65d8746..7551d49 100644
#--- a/gdb/solib-svr4.c
#+++ b/gdb/solib-svr4.c
#@@ -993,8 +993,8 @@ svr4_validate (const struct so_list *const so)
#       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"),
#+      return xstrprintf (_("inferior build ID is %s "
#+			   "but symbol file does not have build ID"),
# 			 remote_hex);
#     }
# 
#@@ -1011,8 +1011,8 @@ svr4_validate (const struct so_list *const so)
#       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"),
#+      return xstrprintf (_("inferior build ID %s "
#+			   "is not identical to symbol file build ID %s"),
# 			 remote_hex, local_hex);
#     }
# 


gdb/
2014-02-26  Aleksandar Ristovski  <aristovski@qnx.com
	Jan Kratochvil  <jan.kratochvil@redhat.com>
    
	Validate symbol file using build-id.
	* NEWS (Changes since GDB 7.7): Add 'set solib-build-id-force'
	and 'show solib-build-id-force'.  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-ia64-hpux.c (ia64_hpux_target_so_ops): Ditto.
	* solib-irix.c (_initialize_irix_solib): Ditto.
	* solib-osf.c (_initialize_osf_solib): Ditto.
	* solib-pa64.c (_initialize_pa64_solib): Ditto.
	* solib-som.c (_initialize_som_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.
	(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_force, show_solib_build_id_force): New.
	(solib_map_sections): Use ops->validate.
	(clear_so): Free build_id.
	(default_solib_validate): New function.
	(_initialize_solib): Add "solib-build-id-force".
	* 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/
2014-03-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
    
	* gdb.texinfo (Files): Add 'set solib-build-id-force'
	and 'show solib-build-id-force'.

Comments

Eli Zaretskii March 21, 2014, 4:52 p.m. UTC | #1
> Date: Fri, 21 Mar 2014 17:34:11 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, Aleksandar Ristovski <ARistovski@qnx.com>
> 
> sending just this one patch part updated.
> 
> The ^# part is just a diff against the last v5 post.

Thanks, the documentation part is OK.
diff mbox

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 2a384ba..629cc13 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -43,6 +43,12 @@  maint ada show ignore-descriptive-types
   the user manual for more details on descriptive types and the intended
   usage of this option.
 
+set solib-build-id-force (on|off)
+show solib-build-id-force
+  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 (on) or disables (off) loading of such symbol file.
+
 * New features in the GDB remote stub, GDBserver
 
   ** New option --debug-format=option1[,option2,...] allows one to add
@@ -51,6 +57,10 @@  maint ada show ignore-descriptive-types
      Timestamps can also be turned on with the
      "monitor set debug-format timestamps" command from GDB.
 
+  ** 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.
+
 * The 'record instruction-history' command now starts counting instructions
   at one.  This also affects the instruction ranges reported by the
   'record function-call-history' command when given the /i modifier.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index d73af9a..bf1fada 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17114,6 +17114,46 @@  libraries that were loaded by explicit user requests are not
 discarded.
 @end table
 
+@table @code
+@kindex set solib-build-id-force
+@cindex override @value{GDBN} build-id check
+@item set solib-build-id-force @var{mode}
+Setting to override @value{GDBN} build-id check.
+
+Inferior shared libraries and symbol files may contain unique build-id.
+@value{GDBN} expects the build-ids of each shared library and its corresponding
+symbol file to be identical.  If they are not identical, then by default
+@value{GDBN} will @value{GDBN} will ignore symbol files with non-matching
+build-id while printing:
+
+@smallexample
+  warning: Shared object "libfoo.so.1" could not be validated (inferior
+  build ID 2bc1745e does not match symbol file build ID a08f8767) and
+  will be ignored; or use 'set solib-build-id-force'.
+@end smallexample
+
+Turning on this setting would load such symbol file while still printing:
+
+@smallexample
+  warning: Shared object "libfoo.so.1" could not be validated (inferior
+  build ID 2bc1745e is not identical to symbol file build ID a08f8767)
+  but it is being loaded due to 'set solib-build-id-force'.
+@end smallexample
+
+If inferior build-id is present but it does not match symbol file build-id
+(or the symbol file build-id is not present) then this setting enables
+(@var{mode} is @code{on}) or disables (@var{mode} is @code{off}) loading of
+such symbol file.  On systems where build-id is not present in the inferior
+system this setting has no effect.  The default value is @code{off}.
+
+Loading non-matching symbol file may confuse debugging including breakage
+of backtrace output.
+
+@kindex show solib-build-id-force
+@item show solib-build-id-force
+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 a9989ea..11de7cd 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -653,4 +653,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 0217a94..35223dd 100644
--- a/gdb/solib-dsbt.c
+++ b/gdb/solib-dsbt.c
@@ -1078,6 +1078,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 9724a3c..18a4aba 100644
--- a/gdb/solib-frv.c
+++ b/gdb/solib-frv.c
@@ -1181,6 +1181,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-ia64-hpux.c b/gdb/solib-ia64-hpux.c
index b53caa8..a39bb03 100644
--- a/gdb/solib-ia64-hpux.c
+++ b/gdb/solib-ia64-hpux.c
@@ -688,6 +688,7 @@  ia64_hpux_target_so_ops (void)
   ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object;
   ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code;
   ops->bfd_open = solib_bfd_open;
+  ops->validate = default_solib_validate;
 
   return ops;
 }
diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c
index 6266ee0..1f126a3 100644
--- a/gdb/solib-irix.c
+++ b/gdb/solib-irix.c
@@ -652,4 +652,5 @@  _initialize_irix_solib (void)
   irix_so_ops.open_symbol_file_object = irix_open_symbol_file_object;
   irix_so_ops.in_dynsym_resolve_code = irix_in_dynsym_resolve_code;
   irix_so_ops.bfd_open = solib_bfd_open;
+  irix_so_ops.validate = default_solib_validate;
 }
diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c
index 90a26e8..5490f83 100644
--- a/gdb/solib-osf.c
+++ b/gdb/solib-osf.c
@@ -633,6 +633,7 @@  _initialize_osf_solib (void)
   osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object;
   osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code;
   osf_so_ops.bfd_open = solib_bfd_open;
+  osf_so_ops.validate = default_solib_validate;
 
   /* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops.  */
   current_target_so_ops = &osf_so_ops;
diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c
index 099e1e7..da8a294 100644
--- a/gdb/solib-pa64.c
+++ b/gdb/solib-pa64.c
@@ -621,6 +621,7 @@  _initialize_pa64_solib (void)
   pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object;
   pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code;
   pa64_so_ops.bfd_open = solib_bfd_open;
+  pa64_so_ops.validate = default_solib_validate;
 
   memset (&dld_cache, 0, sizeof (dld_cache));
 }
diff --git a/gdb/solib-som.c b/gdb/solib-som.c
index cba50d1..ed2cbfe 100644
--- a/gdb/solib-som.c
+++ b/gdb/solib-som.c
@@ -816,6 +816,7 @@  _initialize_som_solib (void)
   som_so_ops.open_symbol_file_object = som_open_symbol_file_object;
   som_so_ops.in_dynsym_resolve_code = som_in_dynsym_resolve_code;
   som_so_ops.bfd_open = solib_bfd_open;
+  som_so_ops.validate = default_solib_validate;
 }
 
 void
diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
index 1c574b5..8385205 100644
--- a/gdb/solib-spu.c
+++ b/gdb/solib-spu.c
@@ -521,6 +521,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 0da5692..7551d49 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -47,6 +47,9 @@ 
 #include "exceptions.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);
@@ -959,6 +962,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.  */
+
+static char *
+svr4_validate (const struct so_list *const so)
+{
+  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)
+      || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour)
+    return NULL;
+
+  /* GDB has verified the local file really does not contain the build ID.  */
+  if (elf_tdata (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 (_("inferior build ID is %s "
+			   "but symbol file does not have build ID"),
+			 remote_hex);
+    }
+
+  local_id = elf_tdata (so->abfd)->build_id->data;
+  local_idsz = elf_tdata (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 (_("inferior build ID %s "
+			   "is not identical to symbol file 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
@@ -1124,6 +1185,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);
@@ -1135,6 +1199,25 @@  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 && (hex_build_id_len & 1U) == 0)
+	{
+	  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)
+	    {
+	      xfree (new_elem->build_id);
+	      new_elem->build_id = NULL;
+	      new_elem->build_idsz = 0;
+	    }
+	}
+    }
 
   *list->tailp = new_elem;
   list->tailp = &new_elem->next;
@@ -1169,6 +1252,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 }
 };
 
@@ -3166,4 +3250,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 bb34e4b..23b2d06 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"
 
 #include <string.h>
 
@@ -502,6 +503,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 3350bfd..83366ae 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -454,6 +454,20 @@  solib_bfd_open (char *pathname)
   return abfd;
 }
 
+/* Boolean for command 'set solib-build-id-force'.  */
+static int solib_build_id_force = 0;
+
+/* Implement 'show solib-build-id-force'.  */
+
+static void
+show_solib_build_id_force (struct ui_file *file, int from_tty,
+			   struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Loading of shared libraries "
+			    "with non-matching build-id 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
@@ -470,7 +484,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;
@@ -486,6 +500,27 @@  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_force)
+	{
+	  warning (_("Shared object \"%s\" could not be validated (%s) and "
+	             "will be ignored; or use 'set solib-build-id-force'."),
+		   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-force'."),
+	       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
@@ -562,6 +597,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);
@@ -1523,6 +1561,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
@@ -1579,4 +1625,18 @@  PATH and LD_LIBRARY_PATH."),
 				     reload_shared_libraries,
 				     show_solib_search_path,
 				     &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("solib-build-id-force", class_support,
+			   &solib_build_id_force, _("\
+Set loading of shared libraries with non-matching build-id."), _("\
+Show loading of shared libraries with non-matching build-id."), _("\
+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 (on) or disables (off) 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_force,
+			   &setlist, &showlist);
+
 }
diff --git a/gdb/solib.h b/gdb/solib.h
index 29fe8f7..ab0dccd 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 ac1b1a7..10b67ee 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -75,6 +75,22 @@  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 in raw format, contains verbatim contents of
+       .note.gnu.build-id including note header.  This is actual
+       BUILD_ID which comes either from the remote target via qXfer
+       packet or via reading target memory.  Therefore, it may differ
+       from the build-id of the associated bfd.  In a normal
+       scenario, this so would soon lose its abfd due to failed
+       validation.
+       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 +184,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 *).  */