diff --git a/gdb/NEWS b/gdb/NEWS
index a45aaa6..28c319e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -52,8 +52,8 @@ show validate-build-id
 * 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.
+     each library and one optional attribute 'main-build-id'.  GDB does
+     not load binaries with build-id that does not match such attribute.
 
 *** Changes in GDB 7.10
 
diff --git a/gdb/build-id.c b/gdb/build-id.c
index 48839cc..289c356 100644
--- a/gdb/build-id.c
+++ b/gdb/build-id.c
@@ -62,7 +62,7 @@ build_id_bfd_get (bfd *abfd)
 /* See build-id.h.  */
 
 int
-build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check)
+build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check, int advice)
 {
   const struct bfd_build_id *found;
   char *message, *check_hex;
@@ -93,9 +93,12 @@ build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check)
     return 1;
   back_to = make_cleanup (xfree, message);
 
-  warning (_("Symbol file \"%s\" could not be validated (%s) and "
-	     "will be ignored; or use 'set validate-build-id off'."),
-	   bfd_get_filename (abfd), message);
+  if (!advice)
+    warning ("%s", message);
+  else
+    warning (_("Symbol file \"%s\" could not be validated (%s) and "
+	       "will be ignored; or use 'set validate-build-id off'."),
+	     bfd_get_filename (abfd), message);
   do_cleanups (back_to);
   return 0;
 }
diff --git a/gdb/build-id.h b/gdb/build-id.h
index bb93df2..bb5e65d 100644
--- a/gdb/build-id.h
+++ b/gdb/build-id.h
@@ -25,10 +25,11 @@
 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.  */
+   Otherwise, issue a warning and return false.  Boolean ADVICE says whether
+   the warning should suggest to user there is the 'validate-build-id' flag.  */
 
-extern int build_id_verify (bfd *abfd,
-			    size_t check_len, const bfd_byte *check);
+extern int build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check,
+			    int advice);
 
 extern struct file_location
   build_id_to_file (size_t build_id_len, const bfd_byte *build_id,
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index fa30007..40f0f14 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18109,6 +18109,41 @@ 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 binaries (shared libraries or main executable) and symbol files
+(for all of those) may contain unique build-id.  @value{GDBN} expects
+the build-ids of each binary 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: Symbol file "libfoo.so.1" could not be validated (inferior
+  build ID 66f87872 is not identical to symbol file "libfoo.so.1" build
+  ID df81e8db) and will be ignored; or use 'set validate-build-id off'.
+@end smallexample
+
+Turning off this setting would load such symbol file without any warning.
+
+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
@@ -39763,7 +39798,9 @@ address the file was prelinked to during the library load.
 
 Additionally the single @code{main-lm} attribute specifies address of
 @code{struct link_map} used for the main executable.  This parameter is used
-for TLS access and its presence is optional.
+for TLS access and its presence is optional.  Similarly the single
+@code{main-build-id} optional attribute specifies hex encoded
+@code{NT_GNU_BUILD_ID} note for the main executable.
 
 @value{GDBN} must be linked with the Expat library to support XML
 SVR4 library lists.  @xref{Expat}.
@@ -39772,7 +39809,8 @@ A simple memory map, with two loaded libraries (which do not use prelink),
 looks like this:
 
 @smallexample
-<library-list-svr4 version="1.0" main-lm="0xe4f8f8">
+<library-list-svr4 version="1.0" main-lm="0xe4f8f8"
+    main-build-id="b96b2f6fbfb7d144b676cb66f56b6100">
   <library name="/lib/ld-linux.so.2" lm="0xe4f51c" l_addr="0xe2d000"
            l_ld="0xe4eefc"/>
   <library name="/lib/libc.so.6" lm="0xe4fbe8" l_addr="0x154000"
@@ -39785,8 +39823,9 @@ The format of an SVR4 library list is described by this DTD:
 @smallexample
 <!-- library-list-svr4: Root element with versioning -->
 <!ELEMENT library-list-svr4  (library)*>
-<!ATTLIST library-list-svr4  version  CDATA   #FIXED  "1.0">
-<!ATTLIST library-list-svr4  main-lm  CDATA   #IMPLIED>
+<!ATTLIST library-list-svr4  version       CDATA   #FIXED  "1.0">
+<!ATTLIST library-list-svr4  main-lm       CDATA   #IMPLIED>
+<!ATTLIST library-list-svr4  main-build-id CDATA   #IMPLIED>
 <!ELEMENT library            EMPTY>
 <!ATTLIST library            name     CDATA   #REQUIRED>
 <!ATTLIST library            lm       CDATA   #REQUIRED>
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 3fb446f..d6054e9 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2498,7 +2498,7 @@ dwarf2_get_dwz_file (void)
   dwz_bfd = gdb_bfd_open (filename, gnutarget, -1);
   if (dwz_bfd != NULL)
     {
-      if (!build_id_verify (dwz_bfd, buildid_len, buildid))
+      if (!build_id_verify (dwz_bfd, buildid_len, buildid, 1 /* advice */))
 	{
 	  gdb_bfd_unref (dwz_bfd);
 	  dwz_bfd = NULL;
diff --git a/gdb/exec.c b/gdb/exec.c
index 056516b..dc39ed2 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -35,6 +35,7 @@
 #include "progspace.h"
 #include "gdb_bfd.h"
 #include "gcore.h"
+#include "build-id.h"
 
 #include <fcntl.h>
 #include "readline/readline.h"
@@ -143,11 +144,16 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
 {
   char *exec_file, *full_exec_path = NULL;
   struct cleanup *old_chain = save_current_program_space ();
+  size_t build_idsz;
+  gdb_byte *build_id;
 
   /* Switch over temporarily, while reading executable and
      symbols.  */
   set_current_program_space (inf->pspace);
 
+  solib_main_build_id (&build_idsz, &build_id);
+  make_cleanup (xfree, build_id);
+
   /* Try to determine a filename from the process itself.  */
   exec_file = target_pid_to_exec_file (inf->pid);
   if (exec_file != NULL)
@@ -155,8 +161,7 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
       /* If gdb_sysroot is not empty and the discovered filename
 	 is absolute then prefix the filename with gdb_sysroot.  */
       if (*gdb_sysroot != '\0' && IS_ABSOLUTE_PATH (exec_file))
-	full_exec_path = exec_file_find (exec_file, 0 /* build_idsz */,
-					 NULL /* build_id */, NULL);
+	full_exec_path = exec_file_find (exec_file, build_idsz, build_id, NULL);
 
       if (full_exec_path == NULL)
 	{
@@ -167,8 +172,8 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
 	     Attempt to qualify the filename against the source path.
 	     (If that fails, we'll just fall back on the original
 	     filename.  Not much more we can do...)  */
-	  if (!source_full_path_of (exec_file, 0 /* build_idsz */,
-				    NULL /* build_id */, &full_exec_path))
+	  if (!source_full_path_of (exec_file, build_idsz, build_id,
+				    &full_exec_path))
 	    full_exec_path = xstrdup (exec_file);
 	}
     }
@@ -179,6 +184,7 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
 	warning (_("Detected exec-file mismatch on %s.  Running %s; Loaded %s"),
 		 target_pid_to_str (pid_to_ptid (inf->pid)),
 		 full_exec_path, exec_filename);
+      build_id_verify (exec_bfd, build_idsz, build_id, 0 /* advice */);
       reopen_exec_file ();
     }
   else if (full_exec_path != NULL)
@@ -194,6 +200,9 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
 		   "Running %s; Loaded %s"),
 		 target_pid_to_str (pid_to_ptid (inf->pid)),
 		 full_exec_path, symbol_filename);
+
+      build_id_verify (symfile_objfile->obfd, build_idsz, build_id,
+		       0 /* advice */);
     }
   else if (full_exec_path != NULL)
     symbol_file_add_main (0, full_exec_path, from_tty);
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index 5741f03..27799a6 100644
--- a/gdb/features/library-list-svr4.dtd
+++ b/gdb/features/library-list-svr4.dtd
@@ -6,8 +6,9 @@
 
 <!-- library-list-svr4: Root element with versioning -->
 <!ELEMENT library-list-svr4  (library)*>
-<!ATTLIST library-list-svr4  version  CDATA   #FIXED  "1.0">
-<!ATTLIST library-list-svr4  main-lm  CDATA   #IMPLIED>
+<!ATTLIST library-list-svr4  version       CDATA   #FIXED  "1.0">
+<!ATTLIST library-list-svr4  main-lm       CDATA   #IMPLIED>
+<!ATTLIST library-list-svr4  main-build-id CDATA   #IMPLIED>
 
 <!ELEMENT library            EMPTY>
 <!ATTLIST library            name     CDATA   #REQUIRED>
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index ee8563e..6783dc2 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -6915,8 +6915,25 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
 	 exited above due to failed get_r_debug.  */
       if (lm_prev == 0)
 	{
+	  const char *hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
 	  sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
 	  p = p + strlen (p);
+
+	  if (hex_enc_build_id != NULL)
+	    {
+	      while (allocated
+		     < p - document + 200 + strlen (hex_enc_build_id))
+		{
+		  /* Expand to guarantee sufficient storage.  */
+		  uintptr_t document_len = p - document;
+
+		  document = xrealloc (document, 2 * allocated);
+		  allocated *= 2;
+		  p = document + document_len;
+		}
+	      p += sprintf (p, " main-build-id=\"%s\"", hex_enc_build_id);
+	    }
 	}
       else
 	{
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 858b942..fd83128 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -358,6 +358,8 @@ struct svr4_info
 
   /* Load map address for the main executable.  */
   CORE_ADDR main_lm_addr;
+  size_t main_build_idsz;
+  gdb_byte *main_build_id;
 
   CORE_ADDR interp_text_sect_low;
   CORE_ADDR interp_text_sect_high;
@@ -1087,6 +1089,9 @@ struct svr4_library_list
   /* Inferior address of struct link_map used for the main executable.  It is
      NULL if not known.  */
   CORE_ADDR main_lm;
+
+  size_t main_build_idsz;
+  gdb_byte *main_build_id;
 };
 
 /* Implementation for target_so_ops.free_so.  */
@@ -1175,13 +1180,13 @@ hex2bin_allocate (const char *hex, gdb_byte **binp, size_t *binszp,
   hex_len = strlen (hex);
   if (hex_len == 0)
     {
-      warning (_("Shared library \"%s\" received empty build-id "
+      warning (_("Binary file \"%s\" received empty build-id "
 		 "from gdbserver"), filename);
       return;
     }
   if ((hex_len & 1U) != 0)
     {
-      warning (_("Shared library \"%s\" received odd number "
+      warning (_("Binary file \"%s\" received odd number "
 		 "of build-id \"%s\" hex characters from gdbserver"),
 	       filename, hex);
       return;
@@ -1191,7 +1196,7 @@ hex2bin_allocate (const char *hex, gdb_byte **binp, size_t *binszp,
   *binszp = hex2bin (hex, *binp, binsz);
   if (*binszp != binsz)
     {
-      warning (_("Shared library \"%s\" received invalid "
+      warning (_("Binary file \"%s\" received invalid "
 		 "build-id \"%s\" hex character at encoded byte "
 		 "position %s (first as 0) from gdbserver"),
 	       filename, hex, pulongest (*binszp));
@@ -1245,6 +1250,10 @@ svr4_library_list_start_list (struct gdb_xml_parser *parser,
   struct svr4_library_list *list = user_data;
   const char *version = xml_find_attribute (attributes, "version")->value;
   struct gdb_xml_value *main_lm = xml_find_attribute (attributes, "main-lm");
+  const struct gdb_xml_value *const att_main_build_id
+    = xml_find_attribute (attributes, "main-build-id");
+  const char *const main_hex_build_id = (att_main_build_id
+					 ? att_main_build_id->value : NULL);
 
   if (strcmp (version, "1.0") != 0)
     gdb_xml_error (parser,
@@ -1253,6 +1262,8 @@ svr4_library_list_start_list (struct gdb_xml_parser *parser,
 
   if (main_lm)
     list->main_lm = *(ULONGEST *) main_lm->value;
+  hex2bin_allocate (main_hex_build_id, &list->main_build_id,
+		    &list->main_build_idsz, _("main executable"));
 }
 
 /* The allowed elements and attributes for an XML library list.
@@ -1282,6 +1293,7 @@ static const struct gdb_xml_attribute svr4_library_list_attributes[] =
 {
   { "version", GDB_XML_AF_NONE, NULL, NULL },
   { "main-lm", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { "main-build-id", GDB_XML_AF_OPTIONAL, NULL, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
@@ -1509,15 +1521,24 @@ svr4_current_sos_direct (struct svr4_info *info)
      Unfortunately statically linked inferiors will also fall back through this
      suboptimal code path.  */
 
+  library_list.main_build_id = NULL;
+  library_list.main_build_idsz = 0;
   info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
 							  NULL);
   if (info->using_xfer)
     {
       if (library_list.main_lm)
 	info->main_lm_addr = library_list.main_lm;
+      if (library_list.main_build_id != NULL)
+	{
+	  xfree (info->main_build_id);
+	  info->main_build_id = library_list.main_build_id;
+	  info->main_build_idsz = library_list.main_build_idsz;
+	}
 
       return library_list.head ? library_list.head : svr4_default_sos ();
     }
+  xfree (library_list.main_build_id);
 
   /* Always locate the debug struct, in case it has moved.  */
   info->debug_base = 0;
@@ -1576,6 +1597,25 @@ svr4_current_sos_1 (void)
   return svr4_current_sos_direct (info);
 }
 
+/* Implement svr4_so_ops's target_so_ops method main_build_id.  */
+
+static void
+svr4_main_build_id (size_t *build_idszp, gdb_byte **build_idp)
+{
+  struct svr4_info *info = get_svr4_info ();
+
+  /* If the solib list has been read and stored by the probes
+     interface then even main_build_id should be valid there.  */
+  if (info->solib_list == NULL)
+    svr4_current_sos_direct (info);
+
+  *build_idszp = info->main_build_idsz;
+  if (*build_idszp == 0)
+    *build_idp = NULL;
+  else
+    *build_idp = xmemdup (info->main_build_id, *build_idszp, *build_idszp);
+}
+
 /* Implement the "current_sos" target_so_ops method.  */
 
 static struct so_list *
@@ -3125,6 +3165,9 @@ svr4_clear_solib (void)
   info->debug_loader_offset = 0;
   xfree (info->debug_loader_name);
   info->debug_loader_name = NULL;
+  xfree (info->main_build_id);
+  info->main_build_id = NULL;
+  info->main_build_idsz = 0;
 }
 
 /* Clear any bits of ADDR that wouldn't fit in a target-format
@@ -3336,6 +3379,7 @@ _initialize_svr4_solib (void)
   svr4_so_ops.special_symbol_handling = svr4_special_symbol_handling;
   svr4_so_ops.current_sos = svr4_current_sos;
   svr4_so_ops.open_symbol_file_object = open_symbol_file_object;
+  svr4_so_ops.main_build_id = svr4_main_build_id;
   svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code;
   svr4_so_ops.bfd_open = solib_bfd_open;
   svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
diff --git a/gdb/solib.c b/gdb/solib.c
index 906cc5c..616cbc1 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1669,6 +1669,20 @@ solib_global_lookup (struct objfile *objfile,
   return (struct block_symbol) {NULL, NULL};
 }
 
+/* See solist.h.  */
+
+void
+solib_main_build_id (size_t *build_idszp, gdb_byte **build_idp)
+{
+  const struct target_so_ops *ops = ops = solib_ops (target_gdbarch ());
+
+  if (ops->main_build_id != NULL)
+    return ops->main_build_id (build_idszp, build_idp);
+
+  *build_idszp = 0;
+  *build_idp = NULL;
+}
+
 /* Lookup the value for a specific symbol from dynamic symbol table.  Look
    up symbol from ABFD.  MATCH_SYM is a callback function to determine
    whether to pick up a symbol.  DATA is the input of this callback
diff --git a/gdb/solist.h b/gdb/solist.h
index 34af30f..2947c6a 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -135,6 +135,13 @@ struct target_so_ops
        catch_errors requires a pointer argument.  */
     int (*open_symbol_file_object) (void *from_ttyp);
 
+    /* Report build-id of the main executable.  Both BUILD_IDSZP and
+       BUILD_IDP must not be NULL.  If returned *BUILD_IDSZP is zero
+       build-id is not known.  Returned *BUILD_IDP must be xfree-d by
+       the caller.  This pointer can be NULL, in which case this
+       functionality is not supported for this target.  */
+    void (*main_build_id) (size_t *build_idszp, gdb_byte **build_idp);
+
     /* Determine if PC lies in the dynamic symbol resolution code of
        the run time loader.  */
     int (*in_dynsym_resolve_code) (CORE_ADDR pc);
@@ -212,4 +219,7 @@ struct block_symbol solib_global_lookup (struct objfile *objfile,
 					    const char *name,
 					    const domain_enum domain);
 
+/* See target_so_ops's main_build_id.  */
+void solib_main_build_id (size_t *build_idszp, gdb_byte **build_idp);
+
 #endif
diff --git a/gdb/source.c b/gdb/source.c
index e5684da..6842c52 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -916,7 +916,7 @@ file_location_from_filename (const char *filename, enum openp_flags opts,
       return file;
     }
 
-  if (!build_id_verify (file.abfd, build_idsz, build_id))
+  if (!build_id_verify (file.abfd, build_idsz, build_id, 1 /* advice */))
     {
       do_cleanups (back_to);
       file_location_enoent (&file);
diff --git a/gdb/testsuite/gdb.base/main-mismatch-mod.c b/gdb/testsuite/gdb.base/main-mismatch-mod.c
new file mode 100644
index 0000000..83d0710
--- /dev/null
+++ b/gdb/testsuite/gdb.base/main-mismatch-mod.c
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <unistd.h>
+
+int _bar = 21;
+
+int
+bar (void)
+{
+  return 42 - _bar;
+}
+
+int
+foo (void)
+{
+  return 24 + bar();
+}
+
+int
+main (void)
+{
+  sleep (60);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/main-mismatch.c b/gdb/testsuite/gdb.base/main-mismatch.c
new file mode 100644
index 0000000..8ea17dc
--- /dev/null
+++ b/gdb/testsuite/gdb.base/main-mismatch.c
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <unistd.h>
+
+int _bar = 42;
+
+int
+bar (void)
+{
+  return _bar + 21;
+}
+
+int
+foo (void)
+{
+  return _bar;
+}
+
+int
+main (void)
+{
+  sleep (60);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/main-mismatch.exp b/gdb/testsuite/gdb.base/main-mismatch.exp
new file mode 100644
index 0000000..1aefab0
--- /dev/null
+++ b/gdb/testsuite/gdb.base/main-mismatch.exp
@@ -0,0 +1,158 @@
+# Copyright 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+standard_testfile
+
+if [is_remote target] {
+    untested "only local remote is currently supported"
+    return -1
+}
+if [is_remote host] {
+    untested "only local host is currently supported"
+    return -1
+}
+if [target_info exists use_gdb_stub] {
+    untested "only extended-remote target is supported for this test"
+    return -1
+}
+
+clean_restart
+
+if ![gdb_is_target_remote] {
+    untested "only gdbserver supports build-id reporting"
+    return -1
+}
+if ![target_is_gdbserver] {
+    untested "only FSF gdbserver supports build-id reporting"
+    return -1
+}
+
+# Test overview:
+#  generate two executable. One that will be used by the process
+#  and another, modified, that will be found by gdb. Gdb should
+#  detect the mismatch and refuse to use mismatched executable.
+
+# First version of the object.
+set srcmainfilerun ${testfile}.c
+
+# Modified version of the object.
+# Code in -mod.c is tuned so it gives a mismatch.
+set srcmainfilegdb ${testfile}-mod.c
+
+# So file name:
+set binmainfilebase {testfile}
+
+# Setup run directory (where program is run from)
+#   It contains the right executable.
+set binmainfiledirrun [standard_output_file ${testfile}_wd]
+set binmainfilerun ${binmainfiledirrun}/${binmainfilebase}
+
+# Second executable version is in current directory, '-mod' version.
+set binmainfiledirgdb [standard_output_file ""]
+set binmainfilegdb ${binmainfiledirgdb}/${binmainfilebase}
+
+file delete -force -- "${binmainfiledirrun}"
+file mkdir "${binmainfiledirrun}"
+
+set exec_opts {}
+lappend exec_opts "additional_flags=-DDIRNAME\=\"${binmainfiledirrun}\""
+lappend exec_opts "debug"
+lappend exec_opts "ldflags=-Wl,--build-id"
+
+if { [build_executable $testfile.exp $binmainfilerun $srcmainfilerun $exec_opts] != 0 } {
+    return -1
+}
+if { [build_executable $testfile.exp $binmainfilegdb $srcmainfilegdb $exec_opts] != 0 } {
+    return -1
+}
+
+set test_spawn_id [spawn_wait_for_attach $binmainfilerun]
+set testpid [spawn_id_get_pid $test_spawn_id]
+
+file copy -force $binmainfilerun $binmainfilerun-backup
+file copy -force $binmainfilegdb $binmainfilerun
+
+with_test_prefix "forced wrong executable" {
+    clean_restart $binmainfilerun
+
+    set test "attach"
+    gdb_test_multiple "attach $testpid" "$test" {
+	-re "Attaching to program: .*\r\nwarning: Detected exec-file mismatch .*\r\nwarning: inferior build ID .*\r\n$gdb_prompt $" {
+	    pass "$test"
+	}
+    }
+
+    gdb_test "detach"
+}
+
+with_test_prefix "unavailable autodetected executable" {
+    clean_restart
+
+    set test "attach"
+    gdb_test_multiple "attach $testpid" "$test" {
+	-re "Attaching to process $testpid\r\n.*\r\n$gdb_prompt $" {
+	    pass "$test"
+	}
+    }
+
+    set test "bt"
+    gdb_test_multiple $test $test {
+	-re " in main \[^\r\n\]*\r\n$gdb_prompt $" {
+	    fail $test
+	}
+	-re "\r\n$gdb_prompt $" {
+	    pass $test
+	}
+    }
+
+    gdb_test "detach"
+}
+
+# Test locating file by its build-id - if the regular filename does not match.
+# build-id file has to be a symlink - otherwise so_list->so_name shown in 'info
+# sharedlibrary' would contain the build-id hash and not the library name.
+set build_id_debug_relative [build_id_debug_filename_get $binmainfilerun-backup]
+if { ![regexp {^(.*)\.debug$} $build_id_debug_relative trash build_id_relative] } {
+    fail "strip debug $build_id_debug_relative"
+    return
+}
+set build_id_filename "${binmainfiledirrun}/$build_id_relative"
+file mkdir [file dirname $build_id_filename]
+remote_exec host "ln -sf $binmainfilerun-backup $build_id_filename"
+
+with_test_prefix "build-id autodetected executable" {
+    clean_restart
+
+    gdb_test_no_output "set debug-file-directory $binmainfiledirrun" "set debug-file-directory"
+
+    set test "attach"
+    gdb_test_multiple "attach $testpid" "$test" {
+	-re "\r\nwarning: Detected exec-file mismatch .*\r\n$gdb_prompt $" {
+	    fail "$test"
+	}
+	-re "\r\nwarning: inferior build ID .*\r\n$gdb_prompt $" {
+	    fail "$test"
+	}
+	-re "Attaching to process $testpid\r\n.*\r\n$gdb_prompt $" {
+	    pass "$test"
+	}
+    }
+
+    gdb_test "bt" " in main \[^\r\n\]*"
+
+    gdb_test "detach"
+}
+
+kill_wait_spawned_process $test_spawn_id
