This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [patch] validate binary before use
- From: Aleksandar Ristovski <aristovski at qnx dot com>
- Cc: Jan Kratochvil <jan dot kratochvil at redhat dot com>, "gdb-patches at sourceware dot org" <gdb-patches at sourceware dot org>, Pedro Alves <palves at redhat dot com>
- Date: Wed, 27 Feb 2013 12:30:57 -0500
- Subject: Re: [patch] validate binary before use
- Newsgroups: gmane.comp.gdb.patches
- References: <50D4C49A.6040502@qnx.com> <50D8B37A.20001@qnx.com> <20121225073709.GA11349@host2.jankratochvil.net> <50DCAA5C.3000301@qnx.com> <20121227205924.GA5109@host2.jankratochvil.net> <50DCB787.6020601@qnx.com> <20121227211328.GA5739@host2.jankratochvil.net> <50DCBBD1.7000707@qnx.com> <5107F591.304@qnx.com> <20130131063518.GA3027@host2.jankratochvil.net> <510A7EB0.90702@qnx.com> <51278A2A.9000802@qnx.com>
On 13-02-22 10:09 AM, Aleksandar Ristovski wrote:
On 13-01-31 09:24 AM, Aleksandar Ristovski wrote:
On 13-01-31 01:35 AM, Jan Kratochvil wrote:
Therefore there should be new build_id field in struct so_list where
svr4_current_sos_via_xfer_libraries will put it from gdbserver. In
local mode
it should remain mostly as you wrote it / as suggested in the review
as there
is currently no easy non-Linux way how to find PT_NOTE without bfd at
hand.
Ok, I can add this. Will be included in the new patch.
I have added build-id to gdbserver response. Patch is posted here:
http://sourceware.org/ml/gdb-patches/2013-02/msg00590.html
Here is new solib validate patch utilizing build-id returned from the
gdbserver when available.
This patch depends on:
http://sourceware.org/ml/gdb-patches/2013-02/msg00692.html
Thanks,
Aleksandar
ChangeLog followed by testsuite changelog:
DATE Aleksandar Ristovski <aristovski@qnx.com>
* Makefile.in (HFILES_NO_SRCDIR): Add linux-maps.h and linux-maps.c.
* common/common-utils.c (TARGET_CHAR_BIT): Define if not defined.
(HOST_CHAR_BIT): Ditto.
(ctype.h): Include.
(string.h): Include.
(assert.h): Include.
(HIGH_BYTE_POSN): Moved from utils.c.
(is_digit_in_base): Ditto.
(digit_to_int): Ditto.
(strtoulst): Ditto.
(fromhex): Moved from remote.c.
(hex2bin): Ditto.
(tohex): Ditto.
(bin2hex): Ditto.
* common/common-utils.h (strtoulst): Moved from utils.h.
(tohex): New declaration.
(fromhex): Ditto.
(hex2bin): Ditto.
(bin2hex): Ditto.
* common/xml-utils.h (xml_hex_encode_text): Declare.
* config/i386/linux.mk (NATDEPFILES): Add linux-maps.o.
* config/i386/linux64.mh (NATDEPFILES): Add linux-maps.o.
* features/library-list-svr4.dtd (build-id): New attribute.
* gdbserver/Makefile.in (linux-maps.o): New.
* gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o.
* gdbserver/linux-low.c (linux-maps.h): Include.
(find_memory_region_callback_data): New structure definition.
(find_memory_region_callback): New forward declaration.
(find_memory_region_callback): New function.
(get_hex_build_id): New function.
(linux_qxfer_libraries_svr4): Add hex encoded build-id to the reply.
* remote-utils.c (common-utils.h): Include.
(fromhex): Moved to common-utils.c.
(unhexify): Use hex2bin.
(tohex): Moved to common-utils.c.
(hexify): Use bin2hex.
* linux-tdep.c (linux-maps.h): Include.
(read_mapping): Moved to linux-maps.c.
(linux_find_memory_region_ftype): Moved to linux-maps.h.
(linux_find_memory_regions_full): Moved to linux-maps.c.
(linux_find_memory_regions): Check for fake_pid_p to match
functionality of original linux_find_memory_regions_full.
(linux_make_mappings_corefile_notes): Ditto.
* remote.c (tohex): Remove forward declaration.
(fromhex): Ditto.
(hex2bin): Ditto.
(bin2hex): Ditto.
(fromhex): Move implementation to common-utils.c
(hex2bin): Ditto.
(tohex): Ditto.
(bin2hex): Ditto.
* tracepoint.c (hex2bin): Remove declaration.
(bin2hex): Ditto.
* utils.c (HIGH_BYTE_POSN): Moved to common-utils.c.
(is_digit_in_base): Ditto.
(digit_to_int): Ditto.
(strtoulst): Ditto.
* utils.h (strtoulst): Moved to common-utils.h.
testsuite/ChangeLog:
* gdb.base/solib-mismatch-lib.c: New file.
* gdb.base/solib-mismatch-libmod.c: Ditto. *
* gdb.base/solib-mismatch.c: Ditto. *
* gdb.base/solib-mismatch.exp: Ditto.
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 780ba09..79d2b3e 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -295,6 +295,9 @@ hex2bin (const char *hex, gdb_byte *bin, size_t count)
{
size_t i;
+ if (count == 0)
+ count = (strlen (hex) + 1) / 2;
+
for (i = 0; i < count; i++)
{
int hi, lo;
@@ -305,7 +308,6 @@ hex2bin (const char *hex, gdb_byte *bin, size_t count)
{
/* Hex string is short, or of uneven length or malformed.
Return the count that has been converted so far. */
- warning (_("Malformed hex encoded string: '%s'\n"), hex);
return i;
}
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 4589f19..96c9ece 100644
--- a/gdb/mips-linux-tdep.c
+++ b/gdb/mips-linux-tdep.c
@@ -1495,6 +1495,8 @@ mips_linux_init_abi (struct gdbarch_info info,
mips_svr4_so_ops.in_dynsym_resolve_code
= mips_linux_in_dynsym_resolve_code;
}
+ if (mips_svr4_so_ops.validate == NULL)
+ mips_svr4_so_ops.validate = solib_validate;
set_solib_ops (gdbarch, &mips_svr4_so_ops);
set_gdbarch_write_pc (gdbarch, mips_linux_write_pc);
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index 0fc6fe0..92dc41a 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -1324,6 +1324,8 @@ ppc_linux_init_abi (struct gdbarch_info info,
powerpc_so_ops.in_dynsym_resolve_code =
powerpc_linux_in_dynsym_resolve_code;
}
+ if (powerpc_so_ops.validate == NULL)
+ powerpc_so_ops.validate = solib_validate;
set_solib_ops (gdbarch, &powerpc_so_ops);
set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index 93212bd..cb0b941 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -647,4 +647,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 = solib_validate;
}
diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
index c41326b..f7382ac 100644
--- a/gdb/solib-dsbt.c
+++ b/gdb/solib-dsbt.c
@@ -1182,6 +1182,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 = 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 57e418f..e8de6ed 100644
--- a/gdb/solib-frv.c
+++ b/gdb/solib-frv.c
@@ -1182,6 +1182,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 = 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 67085d7..b5d3b6b 100644
--- a/gdb/solib-ia64-hpux.c
+++ b/gdb/solib-ia64-hpux.c
@@ -686,6 +686,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 = solib_validate;
return ops;
}
diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c
index af3e7d6..642e973 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 = solib_validate;
}
diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c
index d05c5c1..f7298e3 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 = 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 eb27b40..101455a 100644
--- a/gdb/solib-pa64.c
+++ b/gdb/solib-pa64.c
@@ -623,6 +623,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 = solib_validate;
memset (&dld_cache, 0, sizeof (dld_cache));
}
diff --git a/gdb/solib-som.c b/gdb/solib-som.c
index bd763b8..e430e13 100644
--- a/gdb/solib-som.c
+++ b/gdb/solib-som.c
@@ -811,6 +811,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 = solib_validate;
}
void
diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
index 6eb45a5..58ea391 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 = solib_validate;
}
set_solib_ops (gdbarch, &spu_so_ops);
diff --git a/gdb/solib-sunos.c b/gdb/solib-sunos.c
index 5863fc2..fec2e9a 100644
--- a/gdb/solib-sunos.c
+++ b/gdb/solib-sunos.c
@@ -738,6 +738,7 @@ _initialize_sunos_solib (void)
sunos_so_ops.open_symbol_file_object = open_symbol_file_object;
sunos_so_ops.in_dynsym_resolve_code = sunos_in_dynsym_resolve_code;
sunos_so_ops.bfd_open = solib_bfd_open;
+ sunos_so_ops.validate = solib_validate;
/* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */
current_target_so_ops = &sunos_so_ops;
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 0f70097..34525dd 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -189,7 +189,7 @@ has_lm_dynamic_from_link_map (void)
}
static CORE_ADDR
-lm_addr_check (struct so_list *so, bfd *abfd)
+lm_addr_check (const struct so_list *so, bfd *abfd)
{
if (!so->lm_info->l_addr_p)
{
@@ -871,6 +871,87 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
return (name_lm >= vaddr && name_lm < vaddr + size);
}
+
+/* If build-id exists, compare it with target in-memory contents.
+ Return 1 if they match, 0 if they don't.
+ If there was no build-id, return 1 (could not be verified). */
+
+static int
+svr4_validate_build_id (const struct so_list *const so)
+{
+ asection *asect;
+ int res = 1;
+ size_t size;
+ const CORE_ADDR l_addr = lm_addr_check (so, so->abfd);
+
+ if (!bfd_check_format (so->abfd, bfd_object)
+ || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour
+ || elf_tdata (so->abfd)->build_id == NULL)
+ return 1;
+
+ asect = bfd_get_section_by_name (so->abfd, NOTE_GNU_BUILD_ID_NAME);
+
+ if (!asect || !so->lm_info->l_addr_p)
+ {
+ if (info_verbose)
+ warning (_("Could not verify '%s' section.\n"),
+ NOTE_GNU_BUILD_ID_NAME);
+ return 1;
+ }
+
+ size = bfd_get_section_size (asect);
+
+ if ((asect->flags & SEC_LOAD) == SEC_LOAD && size != 0)
+ {
+ gdb_byte *build_id = so->build_id;
+ size_t build_idsz = so->build_idsz;
+ gdb_byte *const data = xmalloc (size);
+ struct cleanup *const cleanups = make_cleanup (xfree, data);
+ /* Zero based vma, after undoing link script non zero base
+ and/or prelinked rebasing. */
+ const CORE_ADDR sect_lma = l_addr + bfd_section_vma (so->abfd, asect);
+
+ /* Relocated or not, contents will be corectly loaded from
+ the file by bfd library. */
+ bfd_get_section_contents ((bfd *) so->abfd, asect, data, 0, size);
+
+ if (build_id == NULL)
+ {
+ build_idsz = size;
+ build_id = xmalloc (size);
+ make_cleanup (xfree, build_id);
+ if (target_read_memory (sect_lma, build_id, size) != 0)
+ {
+ build_id = NULL;
+ res = -1;
+ }
+ }
+
+ if (build_id != NULL)
+ res = size == build_idsz
+ && memcmp (build_id, data, size) == 0;
+
+ if (res == -1 && info_verbose)
+ warning (_("Could not verify section %s\n"), NOTE_GNU_BUILD_ID_NAME);
+
+ do_cleanups (cleanups);
+ }
+
+ return res != 0;
+}
+
+/* Validate SO by checking whether opened file matches
+ in-memory object. */
+
+static int
+svr4_validate (const struct so_list *const so)
+{
+ gdb_assert (so != NULL);
+ gdb_assert (so->abfd != NULL);
+
+ return svr4_validate_build_id (so);
+}
+
/* Implement the "open_symbol_file_object" target_so_ops method.
If no open symbol file, attempt to locate and open the main symbol
@@ -999,6 +1080,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 = XZALLOC (struct so_list);
@@ -1010,6 +1094,20 @@ 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 && strlen (hex_build_id) > 0)
+ {
+ new_elem->build_id = xmalloc (strlen (hex_build_id) / 2 + 1);
+ new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id, 0);
+ if (new_elem->build_idsz != (strlen (hex_build_id) / 2))
+ {
+ warning (_("Gdbserver returned invalid hex encoded build_id '%s'"
+ "(%zu/%zu)\n"),
+ hex_build_id, strlen (hex_build_id), 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;
@@ -1044,6 +1142,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_NONE, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
@@ -2458,4 +2557,5 @@ _initialize_svr4_solib (void)
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
+ svr4_so_ops.validate = svr4_validate;
}
diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h
index 66a06e1..ba17dbe 100644
--- a/gdb/solib-svr4.h
+++ b/gdb/solib-svr4.h
@@ -20,6 +20,9 @@
#ifndef SOLIB_SVR4_H
#define SOLIB_SVR4_H
+#define DYNAMIC_NAME ".dynamic"
+#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id"
+
struct objfile;
struct target_so_ops;
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index d897bc0..f43037a 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 "gdb_string.h"
@@ -500,6 +501,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 = 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 8129c0f..0d68373 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -477,6 +477,17 @@ solib_map_sections (struct so_list *so)
bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ()));
}
+ gdb_assert (ops->validate != NULL);
+
+ if (!ops->validate (so))
+ {
+ warning (_("Shared object \"%s\" could not be validated and will be ignored."),
+ so->so_name);
+ gdb_bfd_unref (so->abfd);
+ so->abfd = NULL;
+ return 0;
+ }
+
for (p = so->sections; p < so->sections_end; p++)
{
/* Relocate the section binding addresses as recorded in the shared
@@ -551,6 +562,7 @@ free_so (struct so_list *so)
{
struct target_so_ops *ops = solib_ops (target_gdbarch ());
+ xfree (so->build_id);
free_so_symbols (so);
ops->free_so (so);
@@ -1448,6 +1460,14 @@ gdb_bfd_lookup_symbol (bfd *abfd,
return symaddr;
}
+/* Default implementation does not perform any validation. */
+
+int
+solib_validate (const struct so_list *const so)
+{
+ return 1; /* No validation. */
+}
+
extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */
void
diff --git a/gdb/solib.h b/gdb/solib.h
index b811866..ae42e9d 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -90,4 +90,8 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
void *),
void *data);
+/* Default validation always returns 1. */
+
+extern int solib_validate (const struct so_list *so);
+
#endif /* SOLIB_H */
diff --git a/gdb/solist.h b/gdb/solist.h
index f784fc3..5eaa442 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -75,6 +75,14 @@ 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. 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
+ actual build-id from the associated bfd. In a normal scenario,
+ this so would soon lose its abfd due to failed validation. */
+ size_t build_idsz;
+ gdb_byte *build_id;
};
struct target_so_ops
@@ -148,6 +156,10 @@ struct target_so_ops
core file (in particular, for readonly sections). */
int (*keep_data_in_core) (CORE_ADDR vaddr,
unsigned long size);
+
+ /* Return 0 if SO does not match target SO it is supposed to
+ represent. Return 1 otherwise. */
+ int (*validate) (const struct so_list *so);
};
/* Free the memory associated with a (so_list *). */
--
1.7.10.4
diff --git a/gdb/testsuite/gdb.base/solib-mismatch-lib.c b/gdb/testsuite/gdb.base/solib-mismatch-lib.c
new file mode 100644
index 0000000..19f1545
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-mismatch-lib.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 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/>. */
+
+
+int _bar = 42;
+
+int bar(void)
+{
+ return _bar + 21;
+}
+
+int foo(void)
+{
+ return _bar;
+}
diff --git a/gdb/testsuite/gdb.base/solib-mismatch-libmod.c b/gdb/testsuite/gdb.base/solib-mismatch-libmod.c
new file mode 100644
index 0000000..3b025a8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-mismatch-libmod.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 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/>. */
+
+
+int _bar = 21;
+
+int bar(void)
+{
+ return 42 - _bar;
+}
+
+int foo(void)
+{
+ return 24 + bar();
+}
diff --git a/gdb/testsuite/gdb.base/solib-mismatch.c b/gdb/testsuite/gdb.base/solib-mismatch.c
new file mode 100644
index 0000000..85a2784
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-mismatch.c
@@ -0,0 +1,59 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 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 <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#define lib "./solib-mismatch.so"
+
+
+/* First argument is working directory. */
+
+int main(int argc, char *argv[])
+{
+ void *h;
+ int (*foo)(void);
+ char buff[1024];
+
+ if (argc < 2)
+ {
+ printf ("ERROR - CWD not provided\n");
+ return 1;
+ }
+
+ if (chdir (argv[1]) != 0)
+ {
+ printf ("ERROR - Could not cd to '%s'\n", argv[1]);
+ return 1;
+ }
+
+ h = dlopen(lib, RTLD_NOW);
+
+ if (h == NULL)
+ {
+ printf ("ERROR - could not open lib %s\n", lib);
+ return 1;
+ }
+ foo = dlsym(h, "foo");
+ printf ("foo: %p\n", foo); /* set breakpoint 1 here */
+ dlclose(h);
+ return 0;
+}
+
diff --git a/gdb/testsuite/gdb.base/solib-mismatch.exp b/gdb/testsuite/gdb.base/solib-mismatch.exp
new file mode 100644
index 0000000..c2192a5
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-mismatch.exp
@@ -0,0 +1,186 @@
+# Copyright 2013 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/>. */
+
+# are we on a target board
+standard_testfile
+set executable $testfile
+
+# Test overview:
+# generate two shared objects. 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 shared object.
+
+if { [get_compiler_info] } {
+ untested ${testfile}.exp
+}
+
+# First version of the object, to be loaded by ld
+set srclibfilerun ${testfile}-lib.c
+# Modified version of the object to be loaded by gdb
+# Code in -libmod.c is tuned so it gives a mismatch but
+# leaves .dynamic at the same point.
+set srclibfilegdb ${testfile}-libmod.c
+
+# So file name:
+set binlibfilebase ${testfile}.so
+
+# Setup run directory (where program is run from)
+# It contains executable and '-lib' version of the library.
+set binlibfiledirrun ${objdir}/${subdir}/${testfile}_wd
+set binlibfilerun ${binlibfiledirrun}/${binlibfilebase}
+
+# Second solib version is in current directory, '-libmod' version.
+set binlibfiledirgdb ${objdir}/${subdir}
+set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase}
+
+# Executeable
+set srcfile ${testfile}.c
+set executable ${testfile}
+set objfile ${objdir}/${subdir}/${executable}.o
+set binfile ${objdir}/${subdir}/${executable}
+
+send_user "Current WD: [eval pwd]\r\n"
+
+file mkdir "${binlibfiledirrun}"
+
+if { ![istarget "*-*-nto-*"] } {
+ set exec_opts [list debug shlib_load]
+}
+
+if { [prepare_for_testing $testfile.exp $executable $srcfile $exec_opts] != 0 } {
+ untested ${testfile}.exp
+ return -1
+}
+
+if { [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilerun}" "${binlibfilerun}" [list debug ldflags=-Wl,-soname,${binlibfilebase},--build-id]] != ""
+ || [gdb_gnu_strip_debug "${binlibfilerun}"]
+ || [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilegdb}" "${binlibfilegdb}" [list debug ldflags=-Wl,-soname,${binlibfilebase},--build-id]] != "" } {
+ untested ${testfile}.exp
+ return -1
+}
+
+proc solib_matching_test { solibfile symsloaded } {
+ global gdb_prompt
+ global testfile
+ global executable
+ global srcdir
+ global subdir
+ global binlibfiledirrun
+ global binlibfiledirgdb
+ global srcfile
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+
+ send_gdb "set verbose 1\n"
+ send_gdb "file \"${binlibfiledirrun}/${executable}\"\n"
+ send_gdb "set solib-search-path \"${binlibfiledirgdb}\"\n"
+ send_gdb "cd ${binlibfiledirgdb}\n"
+ send_gdb "show solib-search-path\n"
+ send_gdb "set auto-solib-add off\n"
+ send_gdb "set args \"${binlibfiledirrun}\"\n"
+ send_gdb "set verbose 1\n"
+
+ set bp_location [gdb_get_line_number "set breakpoint 1 here"]
+
+ send_gdb "tbreak ${srcfile}:${bp_location}\n"
+ gdb_expect {
+ -re ".*Temporary breakpoint.*${gdb_prompt} $" {
+ }
+ default {
+ untested "${testfile}: Failed to set temp. breakpoint at ${bp_location}"
+ return -1
+ }
+ }
+
+ send_gdb "run\r\n"
+ gdb_expect {
+ -re "Starting program.*${gdb_prompt} $" {
+ }
+ default {
+ untested "${testfile}: Failed to hit breakpoint at ${bp_location}"
+ return -1
+ }
+ }
+
+ send_gdb "sharedlibrary\n"
+ gdb_expect {
+ -re ".*${gdb_prompt} $" {
+ }
+ default {
+ untested "${testfile}: sharedlibrary failure"
+ return -1
+ }
+ }
+
+ gdb_test "info sharedlibrary ${solibfile}" \
+ ".*From.*To.*Syms.*Read.*Shared.*\r\n.*${symsloaded}.*" \
+ "Symbols for ${solibfile} loaded: expected '${symsloaded}'"
+
+ send_gdb "p/x foo\n"
+ gdb_expect {
+ -re ".*${gdb_prompt} $" {
+#Nothing, just drain the buffer
+ }
+ default {
+ untested "${testfile}: Failed 'info symbol foo'"
+ return -1
+ }
+ }
+
+ send_gdb "detach\n"
+ gdb_expect {
+ -re ".*Detaching from program.*${executable}.*${gdb_prompt} $" {
+#Nothing, just drain the buffer
+ }
+ default {
+ untested "${testfile}: Could not detach from ${testpid}"
+ return -1
+ }
+ }
+ return 0
+}
+
+# Copy binary to working dir so it pulls in the library from that dir
+# (by the virtue of $ORIGIN).
+file copy -force "${binlibfiledirgdb}/${executable}" \
+ "${binlibfiledirrun}/${executable}"
+
+# Test unstripped, .dynamic matching
+send_user "test unstripped, .dynamic matching\r\n"
+solib_matching_test "${binlibfilebase}" "No"
+
+# Test --only-keep-debug, .dynamic matching so
+send_user "test --only-keep-debug\r\n"
+# Keep original so for debugging purposes
+file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig"
+set objcopy_program [transform objcopy]
+set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"]
+if {$result != 0} {
+ untested "${testfile} test --only-keep-debug"
+ return -1
+}
+solib_matching_test "${binlibfilebase}" "No"
+
+# Now test it does not mis-invalidate matching libraries
+send_user "test matching libraries\r\n"
+# Keep previous so for debugging puroses
+file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig1"
+# Copy loaded so over the one gdb will find
+file copy -force "${binlibfilerun}" "${binlibfilegdb}"
+solib_matching_test "${binlibfilebase}" "Yes"
+
+
--
1.7.10.4