Re: [patch] validate binary before use

Aleksandar Ristovski
2013-01-29T16:15:37Z

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

New reworked patch uses build-id.

The patch attached contains both code and test.

Thanks,

Aleksandar Ristovski
QNX Software Systems

ChangeLog:

<date> Aleksandar Ristovski <aristovski@qnx.com>

* mips-linux-tdep.c (mips_linux_init_abi): Assign validate value.
* ppc-linux-tdep.c (ppc_linux_init_abi): Ditto.
* solib-darwin.c (_initialize_darwin_solib): Ditto.
* 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 (lm_addr_check): Add const for SO type.
(svr4_keep_data_in_core): Remove unused variable and assignment.
(svr4_unrelocated_vma): New function.
(svr4_validate_build_id): New function.
(svr4_validate): New function.
(svr4_read_so_list): Remove unused variable.
(_initialize_svr4_solib): Assign validate value.
* solib-svr4.h (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.
(solib_validate): New function.
* solib.h (solib_validate): New declaration.
* solist.h (target_so_ops): New field 'validate'.
* target.c (target_verify_memory): Add fallback using
target_read_memory.

testsuite/ChangeLog
<date> Aleksandar Ristovski <aristovski@qnx.com>

* 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.

[-- Attachment #2: solib-validate-201301291046.patch --]
[-- Type: text/x-patch, Size: 27164 bytes --]

Index: gdb/mips-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-linux-tdep.c,v
retrieving revision 1.97
diff -u -p -r1.97 mips-linux-tdep.c
--- gdb/mips-linux-tdep.c 1 Jan 2013 06:32:47 -0000 1.97
+++ gdb/mips-linux-tdep.c 29 Jan 2013 15:46:39 -0000
@@ -1495,6 +1495,8 @@ mips_linux_init_abi (struct gdbarch_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);
Index: gdb/ppc-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-tdep.c,v
retrieving revision 1.141
diff -u -p -r1.141 ppc-linux-tdep.c
--- gdb/ppc-linux-tdep.c 1 Jan 2013 06:32:49 -0000 1.141
+++ gdb/ppc-linux-tdep.c 29 Jan 2013 15:46:39 -0000
@@ -1732,6 +1732,8 @@ ppc_linux_init_abi (struct gdbarch_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);
Index: gdb/solib-darwin.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-darwin.c,v
retrieving revision 1.35
diff -u -p -r1.35 solib-darwin.c
--- gdb/solib-darwin.c 1 Jan 2013 06:32:50 -0000 1.35
+++ gdb/solib-darwin.c 29 Jan 2013 15:46:39 -0000
@@ -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;
}
Index: gdb/solib-dsbt.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-dsbt.c,v
retrieving revision 1.9
diff -u -p -r1.9 solib-dsbt.c
--- gdb/solib-dsbt.c 1 Jan 2013 06:32:50 -0000 1.9
+++ gdb/solib-dsbt.c 29 Jan 2013 15:46:39 -0000
@@ -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,
Index: gdb/solib-frv.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-frv.c,v
retrieving revision 1.49
diff -u -p -r1.49 solib-frv.c
--- gdb/solib-frv.c 1 Jan 2013 06:32:50 -0000 1.49
+++ gdb/solib-frv.c 29 Jan 2013 15:46:39 -0000
@@ -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,
Index: gdb/solib-ia64-hpux.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-ia64-hpux.c,v
retrieving revision 1.6
diff -u -p -r1.6 solib-ia64-hpux.c
--- gdb/solib-ia64-hpux.c 1 Jan 2013 06:32:50 -0000 1.6
+++ gdb/solib-ia64-hpux.c 29 Jan 2013 15:46:39 -0000
@@ -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;
}
Index: gdb/solib-irix.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-irix.c,v
retrieving revision 1.46
diff -u -p -r1.46 solib-irix.c
--- gdb/solib-irix.c 1 Jan 2013 06:32:50 -0000 1.46
+++ gdb/solib-irix.c 29 Jan 2013 15:46:39 -0000
@@ -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;
}
Index: gdb/solib-osf.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-osf.c,v
retrieving revision 1.38
diff -u -p -r1.38 solib-osf.c
--- gdb/solib-osf.c 1 Jan 2013 06:32:50 -0000 1.38
+++ gdb/solib-osf.c 29 Jan 2013 15:46:39 -0000
@@ -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;
Index: gdb/solib-pa64.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-pa64.c,v
retrieving revision 1.40
diff -u -p -r1.40 solib-pa64.c
--- gdb/solib-pa64.c 1 Jan 2013 06:32:51 -0000 1.40
+++ gdb/solib-pa64.c 29 Jan 2013 15:46:39 -0000
@@ -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));
}
Index: gdb/solib-som.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-som.c,v
retrieving revision 1.39
diff -u -p -r1.39 solib-som.c
--- gdb/solib-som.c 1 Jan 2013 06:32:51 -0000 1.39
+++ gdb/solib-som.c 29 Jan 2013 15:46:39 -0000
@@ -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
Index: gdb/solib-spu.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-spu.c,v
retrieving revision 1.24
diff -u -p -r1.24 solib-spu.c
--- gdb/solib-spu.c 1 Jan 2013 06:32:51 -0000 1.24
+++ gdb/solib-spu.c 29 Jan 2013 15:46:39 -0000
@@ -519,6 +519,7 @@ set_spu_solib_ops (struct gdbarch *gdbar
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);
Index: gdb/solib-sunos.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-sunos.c,v
retrieving revision 1.51
diff -u -p -r1.51 solib-sunos.c
--- gdb/solib-sunos.c 1 Jan 2013 06:32:51 -0000 1.51
+++ gdb/solib-sunos.c 29 Jan 2013 15:46:39 -0000
@@ -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;
Index: gdb/solib-svr4.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-svr4.c,v
retrieving revision 1.172
diff -u -p -r1.172 solib-svr4.c
--- gdb/solib-svr4.c 1 Jan 2013 06:32:51 -0000 1.172
+++ gdb/solib-svr4.c 29 Jan 2013 15:46:39 -0000
@@ -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)
{
@@ -848,7 +848,6 @@ svr4_keep_data_in_core (CORE_ADDR vaddr,
CORE_ADDR ldsomap;
struct so_list *new;
struct cleanup *old_chain;
- struct link_map_offsets *lmo;
CORE_ADDR name_lm;

info = get_svr4_info ();
@@ -862,7 +861,6 @@ svr4_keep_data_in_core (CORE_ADDR vaddr,
if (!ldsomap)
return 0;

- lmo = svr4_fetch_link_map_offsets ();
new = XZALLOC (struct so_list);
old_chain = make_cleanup (xfree, new);
new->lm_info = lm_info_read (ldsomap);
@@ -873,6 +871,110 @@ svr4_keep_data_in_core (CORE_ADDR vaddr,
return (name_lm >= vaddr && name_lm < vaddr + size);
}

+/* Find containing segment for the section and calculate section's
+ offset. */
+static CORE_ADDR
+svr4_unrelocated_vma (const bfd *const abfd, const asection *const asect)
+{
+ const Elf_Internal_Ehdr *const ehdr = elf_tdata (abfd)->elf_header;
+ const Elf_Internal_Phdr *const phdr = elf_tdata (abfd)->phdr;
+ CORE_ADDR phdr_base = 0;
+ int phdr_base_p = 0;
+ int i;
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ {
+ if (phdr[i].p_type == PT_LOAD)
+ {
+ if (!phdr_base_p)
+ {
+ /* First PT_LOAD serves as the base. */
+ phdr_base = phdr[i].p_vaddr;
+ phdr_base_p = 1;
+ }
+ if (phdr[i].p_vaddr <= asect->vma
+ && (phdr[i].p_vaddr + phdr[i].p_memsz) > asect->vma)
+ {
+ if (phdr_base_p)
+ return (asect->vma - phdr_base);
+ else
+ return (asect->vma - phdr[i].p_vaddr);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* 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)
+{
+ const asection *asect;
+ int i, res = 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;
+
+ for (asect = so->abfd->sections; asect != NULL; asect = asect->next)
+ {
+ if ((asect->flags & SEC_LOAD) == SEC_LOAD)
+ {
+ const char *const sectname = bfd_get_section_name (so->abfd, asect);
+ const bfd_size_type size = bfd_get_section_size (asect);
+
+ if (size != 0 && strcmp (sectname, NOTE_GNU_BUILD_ID_NAME) == 0)
+ {
+ gdb_byte *const data = xmalloc (size);
+ /* Real load base, not the offset from a possibly rebased
+ object. */
+ const CORE_ADDR so_base_addr = so->lm_info->l_addr_inferior;
+ /* Zero based vma, after undoing link script non zero base
+ and/or prelinked rebasing. */
+ const CORE_ADDR sect_vma_offset
+ = svr4_unrelocated_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,
+ (asection *)asect, data, 0,
+ size);
+ /* Section vma is unrelocated. If SO_BASE_ADDR is zero, then
+ use ASECT->VMA as-is. If not, then use offset + base addr. */
+ res = target_verify_memory (data, (so_base_addr > 0)?
+ so_base_addr + sect_vma_offset
+ : asect->vma,
+ size);
+ xfree (data);
+
+ if (res == -1 && info_verbose)
+ warning (_("Could not verify section %s\n"),
+ NOTE_GNU_BUILD_ID_NAME);
+ }
+ }
+ }
+
+ 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
@@ -1175,7 +1277,6 @@ svr4_read_so_list (CORE_ADDR lm, struct

for (; lm != 0; prev_lm = lm, lm = next_lm)
{
- struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
struct so_list *new;
struct cleanup *old_chain;
int errcode;
@@ -2461,4 +2562,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;
}
Index: gdb/solib-svr4.h
===================================================================
RCS file: /cvs/src/src/gdb/solib-svr4.h,v
retrieving revision 1.24
diff -u -p -r1.24 solib-svr4.h
--- gdb/solib-svr4.h 1 Jan 2013 06:32:51 -0000 1.24
+++ gdb/solib-svr4.h 29 Jan 2013 15:46:39 -0000
@@ -84,4 +84,7 @@ extern struct link_map_offsets *svr4_lp6
SVR4 run time loader. */
int svr4_in_dynsym_resolve_code (CORE_ADDR pc);

+
+#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id"
+
#endif /* solib-svr4.h */
Index: gdb/solib-target.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-target.c,v
retrieving revision 1.26
diff -u -p -r1.26 solib-target.c
--- gdb/solib-target.c 1 Jan 2013 06:32:51 -0000 1.26
+++ gdb/solib-target.c 29 Jan 2013 15:46:39 -0000
@@ -25,6 +25,7 @@
#include "target.h"
#include "vec.h"
#include "solib-target.h"
+#include "solib.h"

#include "gdb_string.h"

@@ -501,6 +502,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. */
Index: gdb/solib.c
===================================================================
RCS file: /cvs/src/src/gdb/solib.c,v
retrieving revision 1.169
diff -u -p -r1.169 solib.c
--- gdb/solib.c 1 Jan 2013 06:32:51 -0000 1.169
+++ gdb/solib.c 29 Jan 2013 15:46:39 -0000
@@ -495,6 +495,17 @@ solib_map_sections (struct so_list *so)
}
}

+ gdb_assert (ops->validate != NULL);
+
+ if (!ops->validate (so))
+ {
+ warning (_("Shared object could not be validated and will be ignored: %s."),
+ so->abfd->filename);
+ 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
@@ -1448,6 +1459,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
Index: gdb/solib.h
===================================================================
RCS file: /cvs/src/src/gdb/solib.h,v
retrieving revision 1.34
diff -u -p -r1.34 solib.h
--- gdb/solib.h 1 Jan 2013 06:32:51 -0000 1.34
+++ gdb/solib.h 29 Jan 2013 15:46:39 -0000
@@ -90,4 +90,8 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_f
void *),
void *data);

+/* Default validation always returns 1. */
+
+extern int solib_validate (const struct so_list *so);
+
#endif /* SOLIB_H */
Index: gdb/solist.h
===================================================================
RCS file: /cvs/src/src/gdb/solist.h,v
retrieving revision 1.38
diff -u -p -r1.38 solist.h
--- gdb/solist.h 1 Jan 2013 06:32:51 -0000 1.38
+++ gdb/solist.h 29 Jan 2013 15:46:39 -0000
@@ -148,6 +148,11 @@ 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 *). */
Index: gdb/target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.318
diff -u -p -r1.318 target.c
--- gdb/target.c 1 Jan 2013 06:32:52 -0000 1.318
+++ gdb/target.c 29 Jan 2013 15:46:39 -0000
@@ -4045,12 +4045,14 @@ int
target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
{
struct target_ops *t;
+ gdb_byte *buff;
+ int retval = -1;

for (t = current_target.beneath; t != NULL; t = t->beneath)
{
if (t->to_verify_memory != NULL)
{
- int retval = t->to_verify_memory (t, data, memaddr, size);
+ retval = t->to_verify_memory (t, data, memaddr, size);

if (targetdebug)
fprintf_unfiltered (gdb_stdlog,
@@ -4062,7 +4064,23 @@ target_verify_memory (const gdb_byte *da
}
}

- tcomplain ();
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog,
+ "target_verify_memory (%s, %s) - use target_read_memory\n",
+ paddress (target_gdbarch (), memaddr),
+ pulongest (size));
+
+ /* Default: use memory reads and compare raw memory */
+ buff = xmalloc (size);
+
+ if (target_read_memory (memaddr, buff, size) == 0)
+ retval = (memcmp (buff, data, size) == 0);
+ else
+ retval = -1;
+
+ xfree (buff);
+
+ return retval;
}

/* The documentation for this function is in its prototype declaration in
Index: gdb/testsuite/gdb.base/solib-mismatch-lib.c
===================================================================
RCS file: gdb/testsuite/gdb.base/solib-mismatch-lib.c
diff -N gdb/testsuite/gdb.base/solib-mismatch-lib.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/solib-mismatch-lib.c 29 Jan 2013 15:46:40 -0000
@@ -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;
+}
Index: gdb/testsuite/gdb.base/solib-mismatch-libmod.c
===================================================================
RCS file: gdb/testsuite/gdb.base/solib-mismatch-libmod.c
diff -N gdb/testsuite/gdb.base/solib-mismatch-libmod.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/solib-mismatch-libmod.c 29 Jan 2013 15:46:40 -0000
@@ -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();
+}
Index: gdb/testsuite/gdb.base/solib-mismatch.c
===================================================================
RCS file: gdb/testsuite/gdb.base/solib-mismatch.c
diff -N gdb/testsuite/gdb.base/solib-mismatch.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/solib-mismatch.c 29 Jan 2013 15:46:40 -0000
@@ -0,0 +1,43 @@
+/* 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"
+
+
+int main(int argc, char *argv[])
+{
+ void *h = dlopen(lib, RTLD_NOW);
+ int (*foo)(void);
+
+ if (h == NULL)
+ {
+ printf("ERROR - could not open lib %s\n", lib);
+ return 1;
+ }
+ foo = dlsym(h, "foo");
+ printf("foo says: %d\n", (*foo)());
+ raise(SIGSTOP); /* Let gdb attach */
+ dlclose(h);
+ return 0;
+}
+
Index: gdb/testsuite/gdb.base/solib-mismatch.exp
===================================================================
RCS file: gdb/testsuite/gdb.base/solib-mismatch.exp
diff -N gdb/testsuite/gdb.base/solib-mismatch.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/solib-mismatch.exp 29 Jan 2013 15:46:40 -0000
@@ -0,0 +1,175 @@
+# 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
+set test "solib-mismatch"
+set testfile "solib-mismatch"
+
+# 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.
+
+# 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}/lib${testfile}
+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}
+
+file mkdir "${binlibfiledirrun}"
+
+set exec_opts [list debug additional_flags=-ldl]
+
+if [istarget "*-*-nto-*"] {
+ set exec_opts {}
+}
+
+# build the first test case
+if { [get_compiler_info]
+ || [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]] != ""
+ || [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object {debug}] != ""
+ || [gdb_compile "${objfile}" "${binfile}" executable ${exec_opts}] != "" } {
+ untested ${testfile}.exp
+ return -1
+}
+
+# Start with a fresh gdb
+
+# Start the exe. It will raise SIGSTOP on itself.
+send_user "Exec: $executable\r\n"
+set curdir [eval pwd]
+set dummy [eval cd "${binlibfiledirrun}"]
+set testpid [eval exec "../${executable}" &]
+send_user "You can now attach to $testpid\r\n"
+
+set dummy [eval cd "${binlibfiledirgdb}"]
+
+proc solib_matching_test { solibfile symsloaded } {
+ global gdb_prompt
+ global testpid
+ global test
+ global executable
+ global srcdir
+ global subdir
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${executable}
+
+ send_gdb "set auto-solib-add off\r\n"
+ gdb_expect {
+ -re "${gdb_prompt} $" {
+# Nothing, just drain the buffer
+ }
+ }
+
+# Test unstripped, .dynamic matching so
+ send_gdb "attach ${testpid}\r\n"
+ gdb_expect {
+ -re "Attaching to program:.*${executable}, process ${testpid}.*${gdb_prompt} $" {
+# Nothing
+ }
+ default {
+ untested "${test}: Could not attach to ${testpid}"
+ return -1
+ }
+ }
+
+ gdb_test_multiple "sharedlibrary" $test {
+ -re ".*${gdb_prompt} $" {
+ pass "Validate library detects mismatch"
+ }
+ default {
+ fail "${test}: sharedlibrary failure"
+ }
+ }
+
+ gdb_test "info sharedlibrary ${solibfile}" \
+ ".*From.*To.*Syms.*Read.*Shared.*\r\n0x\[0-9a-f\]+.*0x\[0-9a-f\]+.*${symsloaded}.*" \
+ "Symbols for ${solibfile} loaded: expected '${symsloaded}'"
+
+ send_gdb "detach\r\n"
+ gdb_expect {
+ -re ".*Detaching from program.*${executable}.*${gdb_prompt} $" {
+#Nothing, just drain the buffer
+ }
+ default {
+ untested "${test}: Could not detach from ${testpid}"
+ return -1
+ }
+ }
+ return 0
+}
+
+proc teardown {} {
+ global testpid
+
+ send_user "send SIGCONT to ${testpid}\r\n"
+ send_gdb "attach ${testpid}\r\n"
+ send_gdb "signal SIGCONT\r\n"
+ send_gdb "detach\r\n"
+ gdb_expect {
+ -re ".*" {
+#Nothing, just drain the buffer
+ }
+ }
+}
+
+# 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"
+set objcopy_program [transform objcopy]
+set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"]
+if {$result != 0} {
+ untested "${test} test --only-keep-debug"
+ set dummy [eval cd "${curdir}"]
+ return -1
+}
+solib_matching_test "${binlibfilebase}" "No"
+
+# Now test it does not mis-invalidate matching libraries
+send_user "test matching libraries\r\n"
+file copy -force "${binlibfilerun}" "${binlibfilegdb}"
+solib_matching_test "${binlibfilebase}" "Yes"
+
+send_user "cleanup\r\n"
+teardown
+set dummy [eval cd "${curdir}"]
+