Re: [patch] validate binary before use

Aleksandar Ristovski
2013-04-05T13:03:17Z

[-- Attachment #1: Type: text/plain, Size: 2413 bytes --]

Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7

The problems I listed below are not addressed, this is simply rebased.

On 13-04-04 09:03 AM, Aleksandar Ristovski wrote:
> On 13-04-04 04:13 AM, Jan Kratochvil wrote:
>> On Thu, 04 Apr 2013 04:03:43 +0200, Aleksandar Ristovski wrote:
>>> Actually, as I think about this more, we can not use section from
>>> possibly unrelated bfd to read build-id in native debugging case. At
>>> a minimum, we can not store such build-id as abfd may not even
>>> relate to what's in target's memory.
>>
>> Why?
>>
>> If the target shared library does not match then GDB will read some
>> random
>> memory. The target shared library may not even have any build-id.
>>
>> As the build-id has 160 bits there is 1:2^160 probability of a false
>> positive,
>> that is safe enough.
>
> The problem is, we could 'remember' build-id that is garbage. I will add
> checking for GNU\0 and note type, and then the likelihood that somewhat
> random memory will match namesz, name and type will be very low (though
> the likelihood has nothing to do with the 160 bits of build-id; build-id
> is not necessarily 160 bits either).
>
> The rest of the e-mail applies:
>
>>
>>
>>> The chunk of code that is in svr4_relocate_section_addresses in the
>> you probably mean solib_map_sections
>>
>>> latest version of the patch needs to go back to svr4_validate, and
>>> not store build-id.
>>
>>
>> I do not understand this whole mail, it would be best to provide a
>> countercase
>> where the current patchset does not behave correctly.
>
>
> The above should explain why is current patchset incorrect (in
> particular patch #7).
>
> The rest is about design and duplicated functionality. The functionality
> of gdbserver where it fetches the list is exactly the same what -nat can
> do; in fact this could be the same code; and then solib-svr4.c deals
> only with TARGET_OBJECT_LIBRARIES_SVR4. The infrastructure is in place.
>
> Impact on solib-svr4.c: svr4_validate would be exactly as it is now,
> simply check. svr4_relocate_section_addresses would not need the kludge
> for reading build-id, there would be only one path of getting build-id.
>
> Not to be neglected is that by doing so, it would be possible to look
> for the debug binary directly, by using build-id instead of opening
> objfile and then looking for separate_debug_fie.
>
>
> ---
> Aleksandar
>
>

[-- Attachment #2: 0007-Validate-symbol-file-using-build-id.patch --]
[-- Type: text/x-patch, Size: 15423 bytes --]

From d09617b44e2d4619065c23d44d4b661b6cb829a9 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 16:05:19 -0400
Subject: [PATCH 7/8] Validate symbol file using build-id.

* 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-sunos.c (_initialize_sunos_solib): Ditto.
* solib-svr4.c (svr4_validate): New function.
(library_list_start_library): Parse 'build-id' attribute.
(svr4_library_attributes): Add 'build-id' attribute.
(svr4_relocate_section_addresses): Read build-id from target
memory.
(_initialize_svr4_solib): Assign validate value.
* solib-svr4.h (DYNAMIC_NAME): New define.
(NOTE_GNU_BUILD_ID_NAME): New define.
* solib-target.c (solib.h): Include.
(_initialize_solib_target): Assign validate value.
* solib.c (solib_map_sections): Use ops->validate.
(free_so): Free build_id.
(solib_validate): New function.
* solib.h (solib_validate): New declaration.
* solist.h (so_list): New fields 'build_idsz' and 'build_id'.
(target_so_ops): New field 'validate'.
---
gdb/solib-darwin.c | 1 +
gdb/solib-dsbt.c | 1 +
gdb/solib-frv.c | 1 +
gdb/solib-ia64-hpux.c | 1 +
gdb/solib-irix.c | 1 +
gdb/solib-osf.c | 1 +
gdb/solib-pa64.c | 1 +
gdb/solib-som.c | 1 +
gdb/solib-spu.c | 1 +
gdb/solib-sunos.c | 1 +
gdb/solib-svr4.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++
gdb/solib-svr4.h | 3 ++
gdb/solib-target.c | 2 ++
gdb/solib.c | 20 +++++++++++
gdb/solib.h | 4 +++
gdb/solist.h | 14 ++++++++
16 files changed, 144 insertions(+)

diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index b9a4be1..ff57016 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 = default_solib_validate;
}
diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
index ea2acd1..9728470 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 = 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 57e418f..5621b2a 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 = 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 67085d7..6fb146c 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 = default_solib_validate;

return ops;
}
diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c
index af3e7d6..871fb19 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 d05c5c1..5b1cd0b 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 f646cfb..795bcda 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 ff7fbaa..cc2d344 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 = default_solib_validate;
}

void
diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
index 7be5232..4cc343b 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-sunos.c b/gdb/solib-sunos.c
index 5863fc2..71c8ee3 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 = default_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 601e34d..023927a 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -871,6 +871,29 @@ 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 int
+svr4_validate (const struct so_list *const so)
+{
+ gdb_assert (so != NULL);
+
+ if (so->abfd == NULL)
+ return 1;
+
+ 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;
+
+ if (so->build_id != NULL)
+ return elf_tdata (so->abfd)->build_id->size == so->build_idsz
+ && memcmp (so->build_id, elf_tdata (so->abfd)->build_id->data,
+ elf_tdata (so->abfd)->build_id->size) == 0;
+ return 1;
+}
+
/* 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 +1022,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 +1036,26 @@ 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)
+ {
+ new_elem->build_id = xmalloc (hex_build_id_len / 2);
+ new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id,
+ hex_build_id_len);
+ if (new_elem->build_idsz != (hex_build_id_len / 2))
+ {
+ warning (_("Gdbserver returned invalid hex encoded build_id '%s'"
+ "(%zu/%zu)\n"),
+ hex_build_id, hex_build_id_len, 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 +1090,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 }
};

@@ -2274,10 +2321,53 @@ static void
svr4_relocate_section_addresses (struct so_list *so,
struct target_section *sec)
{
+ ULONGEST bfd_sect_size;
+
sec->addr = svr4_truncate_ptr (sec->addr + lm_addr_check (so,
sec->bfd));
sec->endaddr = svr4_truncate_ptr (sec->endaddr + lm_addr_check (so,
sec->bfd));
+
+ if (so->build_id == NULL)
+ {
+ /* Get build_id from NOTE_GNU_BUILD_ID_NAME section. */
+ bfd_sect_size = bfd_get_section_size (sec->the_bfd_section);
+
+ if ((sec->the_bfd_section->flags & SEC_LOAD) == SEC_LOAD
+ && bfd_sect_size != 0
+ && strcmp (bfd_section_name (sec->bfd, sec->the_bfd_section),
+ NOTE_GNU_BUILD_ID_NAME) == 0)
+ {
+ CORE_ADDR build_id_offs;
+ const enum bfd_endian byte_order
+ = gdbarch_byte_order (target_gdbarch ());
+ gdb_byte *const note_raw = xmalloc (bfd_sect_size);
+ const Elf_External_Note *const note = (void *) note_raw;
+
+ if (target_read_memory (sec->addr, note_raw, bfd_sect_size) == 0)
+ {
+ const ULONGEST descsz
+ = extract_unsigned_integer ((gdb_byte *) note->descsz, 4,
+ byte_order);
+ ULONGEST namesz;
+
+ namesz = extract_unsigned_integer ((gdb_byte *) note->namesz, 4,
+ byte_order);
+ if (descsz == elf_tdata (so->abfd)->build_id->size)
+ {
+ /* Rounded to next sizeof (ElfXX_Word) which happens
+ to be 4 for both Elf32 and Elf64. */
+ namesz = (namesz + 3) & ~((ULONGEST) 3);
+ build_id_offs = sizeof (note->namesz) + sizeof (note->descsz)
+ + sizeof (note->type) + namesz;
+ so->build_id = xmalloc (descsz);
+ so->build_idsz = descsz;
+ memcpy (so->build_id, note_raw + build_id_offs, descsz);
+ }
+ }
+ xfree (note_raw);
+ }
+ }
}
\f

@@ -2458,4 +2548,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..ed82218 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 = 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 8129c0f..89503ab 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -495,6 +495,17 @@ solib_map_sections (struct so_list *so)
}
}

+ 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;
+ }
+
/* Add the shared object's sections to the current set of file
section tables. Do this immediately after mapping the object so
that later nodes in the list can query this object, as is needed
@@ -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
+default_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..670949a 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 default_solib_validate (const struct so_list *so);
+
#endif /* SOLIB_H */
diff --git a/gdb/solist.h b/gdb/solist.h
index f784fc3..72e003d 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -75,6 +75,16 @@ 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. */
+ size_t build_idsz;
+ gdb_byte *build_id;
};

struct target_so_ops
@@ -148,6 +158,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

[-- Attachment #3: 0008-Tests-for-validate-symbol-file-using-build-id.patch --]
[-- Type: text/x-patch, Size: 10402 bytes --]

From e2463d80dc42cfef1fb233d19cdd1dfc752c8236 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 16:06:26 -0400
Subject: [PATCH 8/8] Tests for validate symbol file using build-id.

* gdb.base/solib-mismatch-lib.c: New file.
* gdb.base/solib-mismatch-libmod.c: New file.
* gdb.base/solib-mismatch.c: New file.
* gdb.base/solib-mismatch.exp: New file.
---
gdb/testsuite/gdb.base/solib-mismatch-lib.c | 29 +++++
gdb/testsuite/gdb.base/solib-mismatch-libmod.c | 29 +++++
gdb/testsuite/gdb.base/solib-mismatch.c | 68 ++++++++++
gdb/testsuite/gdb.base/solib-mismatch.exp | 157 ++++++++++++++++++++++++
4 files changed, 283 insertions(+)
create mode 100644 gdb/testsuite/gdb.base/solib-mismatch-lib.c
create mode 100644 gdb/testsuite/gdb.base/solib-mismatch-libmod.c
create mode 100644 gdb/testsuite/gdb.base/solib-mismatch.c
create mode 100644 gdb/testsuite/gdb.base/solib-mismatch.exp

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..8a7f58f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-mismatch.c
@@ -0,0 +1,68 @@
+/* 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>
+#include <string.h>
+
+/* The following defines must correspond to solib-mismatch.exp */
+
+#define DIRNAME "solib-mismatch_wd"
+#define LIB "./solib-mismatch.so"
+
+int main(int argc, char *argv[])
+{
+ void *h;
+ int (*foo)(void);
+ char buff[1024];
+ char *p;
+
+ p = strstr (argv[0], DIRNAME);
+
+ if (p == NULL)
+ {
+ printf ("ERROR - %s could not be found in argv[0]\n", DIRNAME);
+ return 1;
+ }
+
+ p += strlen (DIRNAME);
+
+ memcpy (buff, argv[0], p - argv[0]);
+
+ buff[p - argv[0]] = '\0';
+
+ if (chdir (buff) != 0)
+ {
+ printf ("ERROR - Could not cd to %s\n", buff);
+ 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"); /* 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..f26ac49
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-mismatch.exp
@@ -0,0 +1,157 @@
+# 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/>. */
+
+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 "get_compiler_info failed."
+}
+
+# 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 [standard_output_file ${testfile}_wd]
+set binlibfilerun ${binlibfiledirrun}/${binlibfilebase}
+
+# Second solib version is in current directory, '-libmod' version.
+set binlibfiledirgdb [standard_output_file ""]
+set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase}
+
+# Executeable
+set srcfile ${testfile}.c
+set executable ${testfile}
+set objfile [standard_output_file ${executable}.o]
+set binfile [standard_output_file ${executable}]
+
+send_user "Current WD: [eval pwd]\r\n"
+
+file mkdir "${binlibfiledirrun}"
+
+set exec_opts {}
+
+if { ![istarget "*-*-nto-*"] } {
+ set exec_opts [list debug shlib_load]
+}
+
+if { [prepare_for_testing $testfile.exp $executable $srcfile $exec_opts] != 0 } {
+ 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 "gdb_compile_shlib failed."
+ return -1
+}
+
+
+proc solib_matching_test { solibfile symsloaded msg } {
+ global gdb_prompt
+ global testfile
+ global executable
+ global srcdir
+ global subdir
+ global binlibfiledirrun
+ global binlibfiledirgdb
+ global srcfile
+
+ clean_restart ${binlibfiledirrun}/${executable}
+
+ send_gdb "set solib-search-path \"${binlibfiledirgdb}\"\n"
+ send_gdb "cd ${binlibfiledirgdb}\n"
+# Do not auto load shared libraries, the test needs to have control
+# over when the relevant output gets printed
+ send_gdb "set auto-solib-add off\n"
+
+ set bp_location [gdb_get_line_number "set breakpoint 1 here"]
+
+ gdb_breakpoint ${srcfile}:${bp_location} temporary no-message
+
+ gdb_run_cmd { ${binlibfiledirrun} }
+ gdb_expect {
+ -re "set breakpoint 1 here.*${gdb_prompt} $" {
+ }
+ default {
+ untested "${msg} - Failed to hit breakpoint at ${bp_location}"
+ return -1
+ }
+ }
+
+ send_gdb "sharedlibrary\n"
+ gdb_expect {
+ -re "${gdb_prompt} $" {
+ }
+ default {
+ untested "${msg} - sharedlibrary failure"
+ return -1
+ }
+ }
+
+ gdb_test "info sharedlibrary ${solibfile}" \
+ "From.*To.*Syms.*Read.*Shared.*\r\n.*${symsloaded}.*${solibfile}.*" \
+ "${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'"
+ 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
+solib_matching_test "${binlibfilebase}" "No" \
+ "test unstripped, .dynamic matching"
+
+# 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 "test --only-keep-debug"
+ return -1
+}
+
+# Test --only-keep-debug, .dynamic matching so
+solib_matching_test "${binlibfilebase}" "No" \
+ "test --only-keep-debug"
+
+# 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}"
+
+# Now test it does not mis-invalidate matching libraries
+solib_matching_test "${binlibfilebase}" "Yes" \
+ "test matching libraries"
+
+
+
--
1.7.10.4