* [patch] validate binary before use
@ 2012-12-21 20:21 Aleksandar Ristovski
2012-12-24 19:57 ` Aleksandar Ristovski
2012-12-26 19:24 ` Poenitz Andre
0 siblings, 2 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2012-12-21 20:21 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2792 bytes --]
Hello all,
Currently gdb may use mismatched binary without complaining or noticing.
This is particularly often the case when debugging remote targets, or
multiple of, with multiple versions of libraries.
The situation is possible on self hosted as well.
For example, consider having:
1) a library called 'libso.so.1', with SONAME 'libso.so.1';
2) a program linked against it;
3) environment in which program can be executed and library from 1)
found by the dynamic linker;
4) modified libso.so.1, different from the one found by the dynamic
linker in 3), in the current working directory of gdb;
5) attach to process stared in 3) using gdb.
What happens is, gdb will happily use modified libso.so.1 from current
working directory without noticing the mismatch. This causes a lot of
confusion.
(I can elaborate on the example if needed).
Change introduces new target_so_ops function dedicated to performing
validation. If we have loaded and relocated the object, validation
fails, we throw away bfd and loading of the object fails.
The gist of the change is in solib-svr4.c and solib.c The rest are
mechanical changes to fill-in new field with valid value.
(for bonus points, solib-svr4.c now compiles without -Wno-unused)
Regression test suite shows no regressions. (tested on
x86_64-unknown-linux-gnu).
Thanks,
Aleksandar
ChangeLog:
<date> Aleksandar Ristovski <aristovski@qnx.com>
* solib-svr4.c (read_program_headers_from_bfd,
read_elf_header_from_bfd): Forward declare.
(svr4_keep_data_in_core): Remove unused variable.
(read_elf_header_from_target, read_program_headers_from_target,
svr4_validate_hdrs_match, svr4_validate): New function.
(svr4_read_so_list): Remove unused variable.
(read_elf_header_from_bfd): New function.
(_initialize_svr4_solib): Use svr4_validate.
* solib.c (solib_map_sections): Validate loaded SO.
(solib_validate): New function.
* solib.h (solib_validate): Declare.
* solist.h (target_so_ops): New field 'validate'.
* 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-target.c (solib.h): Include.
(_initialize_solib_target): Assign validate value.
[-- Attachment #2: solib-validate-201212211440.patch --]
[-- Type: text/x-patch, Size: 19493 bytes --]
Index: gdb/solib-svr4.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-svr4.c,v
retrieving revision 1.171
diff -u -p -r1.171 solib-svr4.c
--- gdb/solib-svr4.c 13 Dec 2012 21:29:50 -0000 1.171
+++ gdb/solib-svr4.c 21 Dec 2012 19:40:44 -0000
@@ -51,6 +51,8 @@
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static gdb_byte *read_program_headers_from_bfd (bfd *abfd, int *phdrs_size);
+static gdb_byte *read_elf_header_from_bfd (bfd *abfd, int *bfd_ehdr_size);
/* Link map info to include in an allocated so_list entry. */
@@ -849,7 +851,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 ();
@@ -863,7 +864,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);
@@ -874,6 +874,201 @@ svr4_keep_data_in_core (CORE_ADDR vaddr,
return (name_lm >= vaddr && name_lm < vaddr + size);
}
+
+/* Read elf header corresponding to SO from target memory.
+ Allocates memory for the returned value (which ought be
+ freed with xfree). Returns elf header size in *HDR_SIZE. */
+
+static gdb_byte *
+read_elf_header_from_target (const struct so_list *const so,
+ int *const hdr_size)
+{
+ const CORE_ADDR so_base_addr = so->lm_info->l_addr;
+ const int ptr_size
+ = builtin_type (target_gdbarch ())->builtin_data_ptr->length;
+ const gdb_byte elf_magic[] = { 0x7f, 'E', 'L', 'F' };
+ int status;
+ gdb_byte *ret;
+
+ if (!so->lm_info->l_addr_p)
+ {
+ warning (_("Unable to load elf header from target since shared object %s has not been relocated."), so->abfd->filename);
+ return NULL;
+ }
+
+ *hdr_size = (ptr_size == 4)? sizeof (Elf32_External_Ehdr)
+ : sizeof (Elf64_External_Ehdr);
+
+ ret = xzalloc (*hdr_size);
+
+ if (ret == NULL)
+ {
+ warning (_("Unable to load elf header from target due to out of memory."));
+ return NULL;
+ }
+
+ if ((status = target_read_memory (so_base_addr, ret, *hdr_size)) != 0)
+ {
+ warning (_("Unable to load elf header from target due to failed memory read at address %s"),
+ paddress (target_gdbarch (), so_base_addr));
+ xfree (ret);
+ return NULL;
+ }
+
+ /* Verify that we have actually read the header. */
+ if (memcmp (elf_magic, ret, 4) != 0)
+ {
+ warning (_("Unable to load elf header from target due to elf magic string mismatch."));
+ xfree (ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+
+/* Read program headers from target memory for a given shared object.
+ SO must have been relocated and its addr_low correctly set. */
+
+static gdb_byte *
+read_program_headers_from_target (const struct so_list *const so,
+ int *const phdrs_size)
+{
+ const CORE_ADDR so_base_addr = so->lm_info->l_addr;
+ const enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+ const int ptr_size
+ = builtin_type (target_gdbarch ())->builtin_data_ptr->length;
+ union ElfXX_Ehdr
+ {
+ Elf32_External_Ehdr _32;
+ Elf64_External_Ehdr _64;
+ } ELF_EHDR;
+ unsigned phnum, phentsize, phoff; /* In our byte order */
+ int ehdr_size;
+ int status;
+ gdb_byte *e_phnum, *e_phentsize, *e_phoff;
+ int e_phnum_len, e_phentsize_len, e_phoff_len;
+ gdb_byte *ret;
+
+ if (!so->lm_info->l_addr_p)
+ {
+ warning (_("Unable to load program headers from target since shared object %s has not been relocated."), so->abfd->filename);
+ return NULL;
+ }
+
+ ret = read_elf_header_from_target (so, &ehdr_size);
+
+ if (ret == NULL)
+ return NULL;
+
+ memcpy (&ELF_EHDR, ret, ehdr_size);
+ xfree (ret);
+
+ if (ptr_size == 4)
+ {
+ e_phnum = (gdb_byte *) &ELF_EHDR._32.e_phnum;
+ e_phnum_len = sizeof (ELF_EHDR._32.e_phnum);
+ e_phentsize = (gdb_byte *) &ELF_EHDR._32.e_phentsize;
+ e_phentsize_len = sizeof (ELF_EHDR._32.e_phentsize);
+ e_phoff = (gdb_byte *) &ELF_EHDR._32.e_phoff;
+ e_phoff_len = sizeof (ELF_EHDR._32.e_phoff);
+ }
+ else
+ {
+ e_phnum = (gdb_byte *) &ELF_EHDR._64.e_phnum;
+ e_phnum_len = sizeof (ELF_EHDR._64.e_phnum);
+ e_phentsize = (gdb_byte *) &ELF_EHDR._64.e_phentsize;
+ e_phentsize_len = sizeof (ELF_EHDR._64.e_phentsize);
+ e_phoff = (gdb_byte *) &ELF_EHDR._64.e_phoff;
+ e_phoff_len = sizeof (ELF_EHDR._64.e_phoff);
+ }
+
+ phnum = extract_unsigned_integer (e_phnum, e_phnum_len, byte_order);
+ phentsize = extract_unsigned_integer (e_phentsize, e_phentsize_len,
+ byte_order);
+ phoff = extract_unsigned_integer (e_phoff, e_phoff_len, byte_order);
+
+ *phdrs_size = phnum * phentsize;
+
+ ret = xzalloc (*phdrs_size);
+ if (ret == NULL)
+ {
+ warning (_("Unable to load target pheaders due to out of memory."));
+ return NULL;
+ }
+
+ if ((status = target_read_memory (so_base_addr + phoff, ret, *phdrs_size))
+ != 0)
+ {
+ memory_error (status, so_base_addr + phoff);
+ xfree (ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* Validate elf header and phdrs of SO->ABFD and in-memory match. */
+
+static int
+svr4_validate_hdrs_match (const struct so_list *const so)
+{
+ int mem_ehdr_size, bfd_ehdr_size;
+ int mem_phdrs_size, bfd_phdrs_size;
+ gdb_byte *mem_ehdr, *mem_phdrs = NULL;
+ gdb_byte *bfd_ehdr = NULL, *bfd_phdrs = NULL;
+ int ok = 1;
+
+ mem_ehdr = read_elf_header_from_target (so, &mem_ehdr_size);
+ if (mem_ehdr)
+ mem_phdrs = read_program_headers_from_target (so, &mem_phdrs_size);
+ if (mem_phdrs)
+ bfd_ehdr = read_elf_header_from_bfd (so->abfd, &bfd_ehdr_size);
+ if (bfd_ehdr)
+ bfd_phdrs = read_program_headers_from_bfd (so->abfd, &bfd_phdrs_size);
+
+ if (bfd_phdrs != NULL)
+ {
+ /* Finally, check. Since both memory and file representations
+ must match, it is o.k. to bit compare headers. */
+ if (bfd_ehdr_size != mem_ehdr_size
+ || memcmp (mem_ehdr, bfd_ehdr, mem_ehdr_size) != 0)
+ {
+ warning (_("Elf header does not match for %s"),
+ so->abfd->filename);
+ ok = 0;
+ }
+ else if (bfd_phdrs_size != mem_phdrs_size
+ || memcmp (mem_phdrs, bfd_phdrs, mem_phdrs_size) != 0)
+ {
+ warning (_("Program headers do not match for %s"),
+ so->abfd->filename);
+ ok = 0;
+ }
+ }
+ else
+ warning (_("Unable to validate binary match for %s"), so->abfd->filename);
+
+ xfree (bfd_phdrs);
+ xfree (bfd_ehdr);
+ xfree (mem_phdrs);
+ xfree (mem_ehdr);
+
+ return ok;
+}
+
+/* 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_hdrs_match (so);
+}
+
/* Implement the "open_symbol_file_object" target_so_ops method.
If no open symbol file, attempt to locate and open the main symbol
@@ -1176,7 +1371,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;
@@ -1741,6 +1935,36 @@ svr4_special_symbol_handling (void)
/* Nothing to do. */
}
+/* Read the ELF header from ABFD. Return the raw contents and
+ set *ELFHDR_SIZE to the size of the elf header. */
+
+static gdb_byte *
+read_elf_header_from_bfd (bfd *const abfd, int *const bfd_ehdr_size)
+{
+ const int ptr_size
+ = builtin_type (target_gdbarch ())->builtin_data_ptr->length;
+ const int ehdr_size = (ptr_size == 4)? sizeof (Elf32_External_Ehdr)
+ : sizeof (Elf64_External_Ehdr);
+ gdb_byte *const bfd_ehdr = xmalloc (ehdr_size);
+
+ if (bfd_ehdr == NULL)
+ {
+ warning (_("Unable to read raw elf header due to out of memory."));
+ return NULL;
+ }
+
+ *bfd_ehdr_size = ehdr_size;
+
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0
+ || bfd_bread (bfd_ehdr, ehdr_size, abfd) != ehdr_size)
+ {
+ warning (_("Unable to read raw elf header due to failed file operation."));
+ xfree (bfd_ehdr);
+ return NULL;
+ }
+ return bfd_ehdr;
+}
+
/* Read the ELF program headers from ABFD. Return the contents and
set *PHDRS_SIZE to the size of the program headers. */
@@ -2462,4 +2686,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.c
===================================================================
RCS file: /cvs/src/src/gdb/solib.c,v
retrieving revision 1.168
diff -u -p -r1.168 solib.c
--- gdb/solib.c 9 Nov 2012 19:58:01 -0000 1.168
+++ gdb/solib.c 21 Dec 2012 19:40:47 -0000
@@ -495,6 +495,15 @@ solib_map_sections (struct so_list *so)
}
}
+ 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 +1457,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.33
diff -u -p -r1.33 solib.h
--- gdb/solib.h 3 Feb 2012 15:19:37 -0000 1.33
+++ gdb/solib.h 21 Dec 2012 19:40:49 -0000
@@ -91,4 +91,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.37
diff -u -p -r1.37 solist.h
--- gdb/solist.h 4 Jan 2012 08:17:11 -0000 1.37
+++ gdb/solist.h 21 Dec 2012 19:40:51 -0000
@@ -149,6 +149,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/mips-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-linux-tdep.c,v
retrieving revision 1.96
diff -u -p -r1.96 mips-linux-tdep.c
--- gdb/mips-linux-tdep.c 9 Nov 2012 19:57:59 -0000 1.96
+++ gdb/mips-linux-tdep.c 21 Dec 2012 19:40:53 -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.140
diff -u -p -r1.140 ppc-linux-tdep.c
--- gdb/ppc-linux-tdep.c 8 Nov 2012 14:16:33 -0000 1.140
+++ gdb/ppc-linux-tdep.c 21 Dec 2012 19:40:55 -0000
@@ -1733,6 +1733,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.34
diff -u -p -r1.34 solib-darwin.c
--- gdb/solib-darwin.c 18 Dec 2012 06:19:54 -0000 1.34
+++ gdb/solib-darwin.c 21 Dec 2012 19:40:58 -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.8
diff -u -p -r1.8 solib-dsbt.c
--- gdb/solib-dsbt.c 9 Nov 2012 19:58:00 -0000 1.8
+++ gdb/solib-dsbt.c 21 Dec 2012 19:41:00 -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.48
diff -u -p -r1.48 solib-frv.c
--- gdb/solib-frv.c 9 Nov 2012 19:58:00 -0000 1.48
+++ gdb/solib-frv.c 21 Dec 2012 19:41:02 -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.5
diff -u -p -r1.5 solib-ia64-hpux.c
--- gdb/solib-ia64-hpux.c 9 Nov 2012 19:58:00 -0000 1.5
+++ gdb/solib-ia64-hpux.c 21 Dec 2012 19:41:04 -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.45
diff -u -p -r1.45 solib-irix.c
--- gdb/solib-irix.c 9 Nov 2012 19:58:00 -0000 1.45
+++ gdb/solib-irix.c 21 Dec 2012 19:41:06 -0000
@@ -653,4 +653,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.37
diff -u -p -r1.37 solib-osf.c
--- gdb/solib-osf.c 24 May 2012 16:51:36 -0000 1.37
+++ gdb/solib-osf.c 21 Dec 2012 19:41:09 -0000
@@ -634,6 +634,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.39
diff -u -p -r1.39 solib-pa64.c
--- gdb/solib-pa64.c 9 Nov 2012 19:58:01 -0000 1.39
+++ gdb/solib-pa64.c 21 Dec 2012 19:41:11 -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.38
diff -u -p -r1.38 solib-som.c
--- gdb/solib-som.c 9 Nov 2012 19:58:01 -0000 1.38
+++ gdb/solib-som.c 21 Dec 2012 19:41:13 -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.23
diff -u -p -r1.23 solib-spu.c
--- gdb/solib-spu.c 9 Nov 2012 19:58:01 -0000 1.23
+++ gdb/solib-spu.c 21 Dec 2012 19:41:15 -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.50
diff -u -p -r1.50 solib-sunos.c
--- gdb/solib-sunos.c 9 Nov 2012 19:58:01 -0000 1.50
+++ gdb/solib-sunos.c 21 Dec 2012 19:41:17 -0000
@@ -739,6 +739,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-target.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-target.c,v
retrieving revision 1.25
diff -u -p -r1.25 solib-target.c
--- gdb/solib-target.c 14 Dec 2012 23:27:13 -0000 1.25
+++ gdb/solib-target.c 21 Dec 2012 19:41:19 -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. */
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-21 20:21 [patch] validate binary before use Aleksandar Ristovski
@ 2012-12-24 19:57 ` Aleksandar Ristovski
2012-12-25 7:37 ` Jan Kratochvil
2012-12-26 19:24 ` Poenitz Andre
1 sibling, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2012-12-24 19:57 UTC (permalink / raw)
Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 3739 bytes --]
On 12-12-21 03:20 PM, Aleksandar Ristovski wrote:
> Hello all,
>
>
> Currently gdb may use mismatched binary without complaining or noticing.
> This is particularly often the case when debugging remote targets, or
> multiple of, with multiple versions of libraries.
>
> The situation is possible on self hosted as well.
>
> For example, consider having:
> 1) a library called 'libso.so.1', with SONAME 'libso.so.1';
> 2) a program linked against it;
> 3) environment in which program can be executed and library from 1)
> found by the dynamic linker;
> 4) modified libso.so.1, different from the one found by the dynamic
> linker in 3), in the current working directory of gdb;
> 5) attach to process stared in 3) using gdb.
>
> What happens is, gdb will happily use modified libso.so.1 from current
> working directory without noticing the mismatch. This causes a lot of
> confusion.
>
> (I can elaborate on the example if needed).
>
>
> Change introduces new target_so_ops function dedicated to performing
> validation. If we have loaded and relocated the object, validation
> fails, we throw away bfd and loading of the object fails.
>
> The gist of the change is in solib-svr4.c and solib.c The rest are
> mechanical changes to fill-in new field with valid value.
>
> (for bonus points, solib-svr4.c now compiles without -Wno-unused)
>
> Regression test suite shows no regressions. (tested on
> x86_64-unknown-linux-gnu).
>
>
While writing a testcase I realized the patch as posted did not work in
general cases. Comparing whole elf header and whole pheader is not an
option as they change depending on whether the binary is stripped and such.
New change log:
<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 (read_program_headers_from_bfd,
read_elf_header_from_bfd): Forward declare.
(lm_addr_check): New formal argument TRUSTED.
(svr4_keep_data_in_core): Remove unused variable.
(read_elf_header_from_target, read_program_headers_from_target,
svr4_validate_ehdr_match, svr4_validate_phdr_match,
svr4_validate_hdrs_match, svr4_validate): New function.
(svr4_read_so_list): Remove unused variable.
(enable_break): Pass TRUSTED to lm_addr_check.
(read_elf_header_from_bfd): New function.
(svr4_relocate_section_address): Pass TRUSTED to lm_addr_check.
(_initialize_svr4_solib): Use svr4_validate.
* solib-target.c (solib.h): Include.
(_initialize_solib_target): Assign validate value.
* solib.c (solib_map_sections): Validate loaded SO.
(solib_validate): New function.
* solib.h (solib_validate): Declare.
* solist.h (target_so_ops): New field 'validate'.
Test suite change log:
<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-libmod2.c: New file.
* gdb.base/solib-mismatch.c: New file.
* gdb.base/solib-mismatch.exp: New test for solib validation.
Updated patch, including tests attached.
Thank you,
Aleksandar
[-- Attachment #2: solib-validate-201212241437.patch --]
[-- Type: text/x-patch, Size: 33402 bytes --]
Index: gdb/mips-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-linux-tdep.c,v
retrieving revision 1.96
diff -u -p -r1.96 mips-linux-tdep.c
--- gdb/mips-linux-tdep.c 9 Nov 2012 19:57:59 -0000 1.96
+++ gdb/mips-linux-tdep.c 24 Dec 2012 19:37:16 -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.140
diff -u -p -r1.140 ppc-linux-tdep.c
--- gdb/ppc-linux-tdep.c 8 Nov 2012 14:16:33 -0000 1.140
+++ gdb/ppc-linux-tdep.c 24 Dec 2012 19:37:16 -0000
@@ -1733,6 +1733,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.34
diff -u -p -r1.34 solib-darwin.c
--- gdb/solib-darwin.c 18 Dec 2012 06:19:54 -0000 1.34
+++ gdb/solib-darwin.c 24 Dec 2012 19:37:16 -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.8
diff -u -p -r1.8 solib-dsbt.c
--- gdb/solib-dsbt.c 9 Nov 2012 19:58:00 -0000 1.8
+++ gdb/solib-dsbt.c 24 Dec 2012 19:37:16 -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.48
diff -u -p -r1.48 solib-frv.c
--- gdb/solib-frv.c 9 Nov 2012 19:58:00 -0000 1.48
+++ gdb/solib-frv.c 24 Dec 2012 19:37:16 -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.5
diff -u -p -r1.5 solib-ia64-hpux.c
--- gdb/solib-ia64-hpux.c 9 Nov 2012 19:58:00 -0000 1.5
+++ gdb/solib-ia64-hpux.c 24 Dec 2012 19:37:16 -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.45
diff -u -p -r1.45 solib-irix.c
--- gdb/solib-irix.c 9 Nov 2012 19:58:00 -0000 1.45
+++ gdb/solib-irix.c 24 Dec 2012 19:37:16 -0000
@@ -653,4 +653,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.37
diff -u -p -r1.37 solib-osf.c
--- gdb/solib-osf.c 24 May 2012 16:51:36 -0000 1.37
+++ gdb/solib-osf.c 24 Dec 2012 19:37:16 -0000
@@ -634,6 +634,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.39
diff -u -p -r1.39 solib-pa64.c
--- gdb/solib-pa64.c 9 Nov 2012 19:58:01 -0000 1.39
+++ gdb/solib-pa64.c 24 Dec 2012 19:37:16 -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.38
diff -u -p -r1.38 solib-som.c
--- gdb/solib-som.c 9 Nov 2012 19:58:01 -0000 1.38
+++ gdb/solib-som.c 24 Dec 2012 19:37:16 -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.23
diff -u -p -r1.23 solib-spu.c
--- gdb/solib-spu.c 9 Nov 2012 19:58:01 -0000 1.23
+++ gdb/solib-spu.c 24 Dec 2012 19:37:16 -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.50
diff -u -p -r1.50 solib-sunos.c
--- gdb/solib-sunos.c 9 Nov 2012 19:58:01 -0000 1.50
+++ gdb/solib-sunos.c 24 Dec 2012 19:37:16 -0000
@@ -739,6 +739,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.171
diff -u -p -r1.171 solib-svr4.c
--- gdb/solib-svr4.c 13 Dec 2012 21:29:50 -0000 1.171
+++ gdb/solib-svr4.c 24 Dec 2012 19:37:16 -0000
@@ -51,6 +51,8 @@
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static gdb_byte *read_program_headers_from_bfd (bfd *abfd, int *phdrs_size);
+static gdb_byte *read_elf_header_from_bfd (bfd *abfd, int *bfd_ehdr_size);
/* Link map info to include in an allocated so_list entry. */
@@ -190,13 +192,16 @@ 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, int *const trusted)
{
- if (!so->lm_info->l_addr_p)
+ if (!so->lm_info->l_addr_p || trusted != NULL)
{
struct bfd_section *dyninfo_sect;
CORE_ADDR l_addr, l_dynaddr, dynaddr;
+ if (trusted != NULL)
+ *trusted = 1;
+
l_addr = so->lm_info->l_addr_inferior;
if (! abfd || ! has_lm_dynamic_from_link_map ())
@@ -281,6 +286,11 @@ lm_addr_check (struct so_list *so, bfd *
warning (_(".dynamic section for \"%s\" "
"is not at the expected address "
"(wrong library or version mismatch?)"), so->so_name);
+
+ /* l_addr is something we calculated. Didn't exactly
+ * match what is expected, and caller wants to know about it */
+ if (trusted != NULL)
+ *trusted = 0;
}
}
@@ -849,7 +859,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 ();
@@ -863,7 +872,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);
@@ -874,6 +882,330 @@ svr4_keep_data_in_core (CORE_ADDR vaddr,
return (name_lm >= vaddr && name_lm < vaddr + size);
}
+
+/* Read elf header corresponding to SO from target memory.
+ Allocates memory for the returned value (which ought be
+ freed with xfree). Returns elf header size in *HDR_SIZE. */
+
+static gdb_byte *
+read_elf_header_from_target (const struct so_list *const so,
+ int *const hdr_size)
+{
+ int load_base_trusted = 0;
+ const CORE_ADDR so_base_addr = lm_addr_check (so, so->abfd,
+ &load_base_trusted);
+ const int ptr_size
+ = builtin_type (target_gdbarch ())->builtin_data_ptr->length;
+ const gdb_byte elf_magic[] = { 0x7f, 'E', 'L', 'F' };
+ int status;
+ gdb_byte *ret;
+
+ if (!load_base_trusted)
+ {
+ warning (_("Unable to load elf header from target as load base for %s could not be determined."),
+ so->abfd->filename);
+ return NULL;
+ }
+
+ if (!so->lm_info->l_addr_p)
+ {
+ warning (_("Unable to load elf header from target since shared object %s has not been relocated."),
+ so->abfd->filename);
+ return NULL;
+ }
+
+ *hdr_size = (ptr_size == 4)? sizeof (Elf32_External_Ehdr)
+ : sizeof (Elf64_External_Ehdr);
+
+ ret = xzalloc (*hdr_size);
+
+ if (ret == NULL)
+ {
+ warning (_("Unable to load elf header from target due to out of memory."));
+ return NULL;
+ }
+
+ if ((status = target_read_memory (so_base_addr, ret, *hdr_size)) != 0)
+ {
+ warning (_("Unable to load elf header from target due to failed memory read at address %s"),
+ paddress (target_gdbarch (), so_base_addr));
+ xfree (ret);
+ return NULL;
+ }
+
+ /* Verify that we have actually read the header. */
+ if (memcmp (elf_magic, ret, 4) != 0)
+ {
+ warning (_("Unable to load elf header from target due to elf magic string mismatch."));
+ xfree (ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+
+/* Read program headers from target memory for a given shared object.
+ SO must have been relocated and its addr_low correctly set. */
+
+static gdb_byte *
+read_program_headers_from_target (const struct so_list *const so,
+ int *const phdrs_size)
+{
+ int load_base_trusted = 0;
+ const CORE_ADDR so_base_addr = lm_addr_check (so, so->abfd,
+ &load_base_trusted);
+ const enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+ const int ptr_size
+ = builtin_type (target_gdbarch ())->builtin_data_ptr->length;
+ union ElfXX_Ehdr
+ {
+ Elf32_External_Ehdr _32;
+ Elf64_External_Ehdr _64;
+ } ELF_EHDR;
+ unsigned phnum, phentsize, phoff; /* In our byte order */
+ int ehdr_size;
+ int status;
+ gdb_byte *e_phnum, *e_phentsize, *e_phoff;
+ int e_phnum_len, e_phentsize_len, e_phoff_len;
+ gdb_byte *ret;
+
+ if (!load_base_trusted)
+ {
+ warning (_("Unable to load program headers from target for %s as load base could not be determined."),
+ so->abfd->filename);
+ return NULL;
+ }
+
+ if (!so->lm_info->l_addr_p)
+ {
+ warning (_("Unable to load program headers from target since shared object %s has not been relocated."), so->abfd->filename);
+ return NULL;
+ }
+
+ ret = read_elf_header_from_target (so, &ehdr_size);
+
+ if (ret == NULL)
+ return NULL;
+
+ memcpy (&ELF_EHDR, ret, ehdr_size);
+ xfree (ret);
+
+ if (ptr_size == 4)
+ {
+ e_phnum = (gdb_byte *) &ELF_EHDR._32.e_phnum;
+ e_phnum_len = sizeof (ELF_EHDR._32.e_phnum);
+ e_phentsize = (gdb_byte *) &ELF_EHDR._32.e_phentsize;
+ e_phentsize_len = sizeof (ELF_EHDR._32.e_phentsize);
+ e_phoff = (gdb_byte *) &ELF_EHDR._32.e_phoff;
+ e_phoff_len = sizeof (ELF_EHDR._32.e_phoff);
+ }
+ else
+ {
+ e_phnum = (gdb_byte *) &ELF_EHDR._64.e_phnum;
+ e_phnum_len = sizeof (ELF_EHDR._64.e_phnum);
+ e_phentsize = (gdb_byte *) &ELF_EHDR._64.e_phentsize;
+ e_phentsize_len = sizeof (ELF_EHDR._64.e_phentsize);
+ e_phoff = (gdb_byte *) &ELF_EHDR._64.e_phoff;
+ e_phoff_len = sizeof (ELF_EHDR._64.e_phoff);
+ }
+
+ phnum = extract_unsigned_integer (e_phnum, e_phnum_len, byte_order);
+ phentsize = extract_unsigned_integer (e_phentsize, e_phentsize_len,
+ byte_order);
+ phoff = extract_unsigned_integer (e_phoff, e_phoff_len, byte_order);
+
+ *phdrs_size = phnum * phentsize;
+
+ ret = xzalloc (*phdrs_size);
+ if (ret == NULL)
+ {
+ warning (_("Unable to load target pheaders due to out of memory."));
+ return NULL;
+ }
+
+ if ((status = target_read_memory (so_base_addr + phoff, ret, *phdrs_size))
+ != 0)
+ {
+ memory_error (status, so_base_addr + phoff);
+ xfree (ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static int
+svr4_validate_ehdr_match (const gdb_byte *const pehdr1,
+ const gdb_byte *const pehdr2)
+{
+ int ok = 1;
+ const int ptr_size
+ = builtin_type (target_gdbarch ())->builtin_data_ptr->length;
+ const union ElfXX_Ehdr
+ {
+ Elf32_External_Ehdr _32;
+ Elf64_External_Ehdr _64;
+ } *ehdr1, *ehdr2;
+
+ ehdr1 = (void*)pehdr1;
+ ehdr2 = (void*)pehdr2;
+
+ /* Magic */
+ ok = ok && memcmp (ehdr1, ehdr2, 4) == 0;
+
+ /* Compare fields that must match. Endian-ess does not matter as
+ both headers must be for the same architecture. */
+ if (ptr_size == 4)
+ {
+#define check(fld) \
+ ok = ok && memcmp (ehdr1->_32.fld, ehdr2->_32.fld, \
+ sizeof(ehdr1->_32.fld)) == 0
+ check (e_type);
+ check (e_machine);
+ check (e_version);
+ check (e_entry);
+ check (e_phoff);
+ check (e_flags);
+ check (e_ehsize);
+ check (e_phentsize);
+#undef check
+ }
+ else
+ {
+#define check(fld) \
+ ok = ok && memcmp (ehdr1->_64.fld, ehdr2->_64.fld, \
+ sizeof(ehdr1->_64.fld)) == 0
+ check (e_type);
+ check (e_machine);
+ check (e_version);
+ check (e_entry);
+ check (e_phoff);
+ check (e_flags);
+ check (e_ehsize);
+ check (e_phentsize);
+#undef check
+ }
+ return ok;
+}
+
+static int
+svr4_validate_phdr_match (const gdb_byte *const pphdr1,
+ const gdb_byte *const pphdr2, const int phdr_size)
+{
+ int ok = 1;
+ const int ptr_size
+ = builtin_type (target_gdbarch ())->builtin_data_ptr->length;
+ const union ElfXX_Phdr
+ {
+ Elf32_External_Phdr _32;
+ Elf64_External_Phdr _64;
+ } *phdr1, *phdr2;
+
+ phdr1 = (void*)pphdr1;
+ phdr2 = (void*)pphdr2;
+
+ /* Check fields of pheaders that remain the same even for
+ objcopy --only-keep-debug */
+
+ /* Compare fields that must match. Endian-ess does not matter as
+ both headers must be for the same architecture. */
+ if (ptr_size == 4)
+ {
+#define check(fld) \
+ ok = ok && memcmp (phdr1->_32.fld, phdr2->_32.fld, \
+ sizeof(phdr1->_32.fld)) == 0
+ check (p_type);
+ check (p_flags);
+ check (p_vaddr);
+ check (p_memsz);
+ check (p_align);
+#undef check
+ }
+ else
+ {
+#define check(fld) \
+ ok = ok && memcmp (phdr1->_64.fld, phdr2->_64.fld, \
+ sizeof(phdr1->_64.fld)) == 0
+ check (p_type);
+ check (p_flags);
+ check (p_vaddr);
+ check (p_memsz);
+ check (p_align);
+#undef check
+ }
+ return ok;
+}
+
+/* Validate elf header and phdrs of SO->ABFD and in-memory match. */
+
+static int
+svr4_validate_hdrs_match (const struct so_list *const so)
+{
+ int mem_ehdr_size, bfd_ehdr_size;
+ int mem_phdrs_size, bfd_phdrs_size;
+ gdb_byte *mem_ehdr, *mem_phdrs = NULL;
+ gdb_byte *bfd_ehdr = NULL, *bfd_phdrs = NULL;
+ int load_base_trusted = 0;
+ int ok = 1;
+
+ (void)lm_addr_check (so, so->abfd, &load_base_trusted);
+
+ if (!load_base_trusted)
+ return 0;
+
+ mem_ehdr = read_elf_header_from_target (so, &mem_ehdr_size);
+ if (mem_ehdr)
+ mem_phdrs = read_program_headers_from_target (so, &mem_phdrs_size);
+ if (mem_phdrs)
+ bfd_ehdr = read_elf_header_from_bfd (so->abfd, &bfd_ehdr_size);
+ if (bfd_ehdr)
+ bfd_phdrs = read_program_headers_from_bfd (so->abfd, &bfd_phdrs_size);
+
+ if (bfd_phdrs != NULL)
+ {
+ /* Finally, check. Since both memory and file representations
+ must match, it is o.k. to bit compare headers. */
+ if (bfd_ehdr_size != mem_ehdr_size
+ || svr4_validate_ehdr_match (mem_ehdr, bfd_ehdr) == 0)
+ {
+ warning (_("Elf header does not match for %s"),
+ so->abfd->filename);
+ ok = 0;
+ }
+ else if (bfd_phdrs_size != mem_phdrs_size
+ || svr4_validate_phdr_match (mem_phdrs, bfd_phdrs,
+ mem_phdrs_size) == 0)
+ {
+ warning (_("Program headers do not match for %s"),
+ so->abfd->filename);
+ ok = 0;
+ }
+ }
+ else
+ warning (_("Unable to validate binary match for %s"), so->abfd->filename);
+
+ xfree (bfd_phdrs);
+ xfree (bfd_ehdr);
+ xfree (mem_phdrs);
+ xfree (mem_ehdr);
+
+ return ok;
+}
+
+/* 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_hdrs_match (so);
+}
+
/* Implement the "open_symbol_file_object" target_so_ops method.
If no open symbol file, attempt to locate and open the main symbol
@@ -1176,7 +1508,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;
@@ -1577,7 +1908,7 @@ enable_break (struct svr4_info *info, in
{
load_addr_found = 1;
loader_found_in_list = 1;
- load_addr = lm_addr_check (so, tmp_bfd);
+ load_addr = lm_addr_check (so, tmp_bfd, NULL);
break;
}
so = so->next;
@@ -1741,6 +2072,36 @@ svr4_special_symbol_handling (void)
/* Nothing to do. */
}
+/* Read the ELF header from ABFD. Return the raw contents and
+ set *ELFHDR_SIZE to the size of the elf header. */
+
+static gdb_byte *
+read_elf_header_from_bfd (bfd *const abfd, int *const bfd_ehdr_size)
+{
+ const int ptr_size
+ = builtin_type (target_gdbarch ())->builtin_data_ptr->length;
+ const int ehdr_size = (ptr_size == 4)? sizeof (Elf32_External_Ehdr)
+ : sizeof (Elf64_External_Ehdr);
+ gdb_byte *const bfd_ehdr = xmalloc (ehdr_size);
+
+ if (bfd_ehdr == NULL)
+ {
+ warning (_("Unable to read raw elf header due to out of memory."));
+ return NULL;
+ }
+
+ *bfd_ehdr_size = ehdr_size;
+
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0
+ || bfd_bread (bfd_ehdr, ehdr_size, abfd) != ehdr_size)
+ {
+ warning (_("Unable to read raw elf header due to failed file operation."));
+ xfree (bfd_ehdr);
+ return NULL;
+ }
+ return bfd_ehdr;
+}
+
/* Read the ELF program headers from ABFD. Return the contents and
set *PHDRS_SIZE to the size of the program headers. */
@@ -2279,9 +2640,11 @@ svr4_relocate_section_addresses (struct
struct target_section *sec)
{
sec->addr = svr4_truncate_ptr (sec->addr + lm_addr_check (so,
- sec->bfd));
+ sec->bfd,
+ NULL));
sec->endaddr = svr4_truncate_ptr (sec->endaddr + lm_addr_check (so,
- sec->bfd));
+ sec->bfd,
+ NULL));
}
\f
@@ -2462,4 +2825,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-target.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-target.c,v
retrieving revision 1.25
diff -u -p -r1.25 solib-target.c
--- gdb/solib-target.c 14 Dec 2012 23:27:13 -0000 1.25
+++ gdb/solib-target.c 24 Dec 2012 19:37:16 -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.168
diff -u -p -r1.168 solib.c
--- gdb/solib.c 9 Nov 2012 19:58:01 -0000 1.168
+++ gdb/solib.c 24 Dec 2012 19:37:18 -0000
@@ -495,6 +495,15 @@ solib_map_sections (struct so_list *so)
}
}
+ 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 +1457,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.33
diff -u -p -r1.33 solib.h
--- gdb/solib.h 3 Feb 2012 15:19:37 -0000 1.33
+++ gdb/solib.h 24 Dec 2012 19:37:18 -0000
@@ -91,4 +91,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.37
diff -u -p -r1.37 solist.h
--- gdb/solist.h 4 Jan 2012 08:17:11 -0000 1.37
+++ gdb/solist.h 24 Dec 2012 19:37:18 -0000
@@ -149,6 +149,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/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 24 Dec 2012 19:37:18 -0000
@@ -0,0 +1,11 @@
+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 24 Dec 2012 19:37:18 -0000
@@ -0,0 +1,12 @@
+
+int _bar = 21;
+
+int bar(void)
+{
+ return 42 - _bar;
+}
+
+int foo(void)
+{
+ return 24 + bar();
+}
Index: gdb/testsuite/gdb.base/solib-mismatch-libmod2.c
===================================================================
RCS file: gdb/testsuite/gdb.base/solib-mismatch-libmod2.c
diff -N gdb/testsuite/gdb.base/solib-mismatch-libmod2.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/solib-mismatch-libmod2.c 24 Dec 2012 19:37:18 -0000
@@ -0,0 +1,11 @@
+
+int bar(void)
+{
+ return 42;
+}
+
+int foo(void)
+{
+ return 24;
+}
+
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 24 Dec 2012 19:37:18 -0000
@@ -0,0 +1,25 @@
+#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 24 Dec 2012 19:37:18 -0000
@@ -0,0 +1,190 @@
+# Copyright 2012 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
+# Modified version of the object to be loaded by gdb tuned
+# in such a way that .dynamic moves as well.
+set srclibfilegdb2 ${testfile}-libmod2.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}
+set binlibfilegdb2 "${binlibfiledirgdb}/${binlibfilebase}-2"
+
+# 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}]] != ""
+ || [gdb_gnu_strip_debug $binlibfilerun]
+ || [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilegdb}" "${binlibfilegdb}" [list debug ldflags=-Wl,-soname,${binlibfilebase}]] != ""
+ || [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilegdb2}" "${binlibfilegdb2}" [list debug ldflags=-Wl,-soname,${binlibfilebase}]] != ""
+ || [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.*\r\n0x\[0-9a-f\]+.*0x\[0-9a-f\]+.*${symsloaded}.*${solibfile}" \
+ "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
+}
+
+# Test unstripped, .dynamic matching
+solib_matching_test "${binlibfilebase}" "No"
+
+# Test --only-keep-debug, .dynamic matching so
+send_user "test --only-keep-debug"
+set objcopy_program [transform objcopy]
+set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"]
+if {$result != 0} {
+ untested "${test} test --only-keep-debug"
+ return -1
+}
+solib_matching_test "${binlibfilebase}" "No"
+
+# Test version -2 of mismatched library, the one w
+file copy -force "${binlibfilegdb2}" "${binlibfilegdb}"
+solib_matching_test ${binlibfilebase} "No"
+# Test --only-keep-debug, .dynamic matching so
+send_user "test --only-keep-debug"
+set objcopy_program [transform objcopy]
+set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"]
+if {$result != 0} {
+ untested "${test} test --only-keep-debug"
+ return -1
+}
+solib_matching_test "${binlibfilebase}" "No"
+
+# Now test it does not mis-validate matching libraries
+if { [gdb_compile_shlib "${curdir}/${srcdir}/${subdir}/${srclibfilerun}" "${binlibfilegdb}" [list debug ldflags=-Wl,-soname,${binlibfilebase}]] != "" } {
+ untested "${testfile}.exp: failed to build shared object?"
+ return -1
+}
+solib_matching_test "${binlibfilebase}" "Yes"
+if { [gdb_gnu_strip_debug $binlibfilegdb] } {
+ untested "${testfile}.exp: Strip failed. Further test impossible."
+ return -1
+}
+solib_matching_test "${binlibfilebase}" "Yes"
+if { [gdb_compile_shlib "${curdir}/${srcdir}/${subdir}/${srclibfilerun}" "${binlibfilegdb}" [list debug ldflags=-Wl,-soname,${binlibfilebase}]] != "" } {
+ untested "${testfile}.exp: failed to build shared object?"
+ return -1
+}
+set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"]
+if {$result != 0} {
+ untested "${test} test --only-keep-debug - matching lib"
+ return -1
+}
+solib_matching_test "${binlibfilebase}" "Yes"
+
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-24 19:57 ` Aleksandar Ristovski
@ 2012-12-25 7:37 ` Jan Kratochvil
2012-12-27 20:07 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2012-12-25 7:37 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Mon, 24 Dec 2012 20:56:42 +0100, Aleksandar Ristovski wrote:
> While writing a testcase I realized the patch as posted did not work
> in general cases. Comparing whole elf header and whole pheader is
> not an option as they change depending on whether the binary is
> stripped and such.
The checked fields like vaddr also do not match as the local file is commonly
nightly prelinked, unprelinked (after nightly update before prelink has run)
or nightly re-prelinked (see prelink(8)).
Such prelink-aware verification is already implemented in solib-svr4.c in
svr4_exec_displacement. GDB also handles correctly local symbol file in
a different prelink state than the debugged target.
But still I find this verification less reliable and more complicated than the
build-id verification I suggested.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* RE: [patch] validate binary before use
2012-12-21 20:21 [patch] validate binary before use Aleksandar Ristovski
2012-12-24 19:57 ` Aleksandar Ristovski
@ 2012-12-26 19:24 ` Poenitz Andre
2012-12-27 20:10 ` Aleksandar Ristovski
1 sibling, 1 reply; 47+ messages in thread
From: Poenitz Andre @ 2012-12-26 19:24 UTC (permalink / raw)
To: ext Aleksandar Ristovski, gdb-patches
Aleksandar Ristovski wrote:
> [...] Change introduces new target_so_ops function dedicated to performing
> validation. If we have loaded and relocated the object, validation
> fails, we throw away bfd and loading of the object fails. [...]
Does this change have any performance implications on the "normal"
use case, i.e. when all is set up and matches nicely?
Andre'
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-25 7:37 ` Jan Kratochvil
@ 2012-12-27 20:07 ` Aleksandar Ristovski
2012-12-27 20:59 ` Jan Kratochvil
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2012-12-27 20:07 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 12-12-25 02:37 AM, Jan Kratochvil wrote:
> On Mon, 24 Dec 2012 20:56:42 +0100, Aleksandar Ristovski wrote:
>> While writing a testcase I realized the patch as posted did not work
>> in general cases. Comparing whole elf header and whole pheader is
>> not an option as they change depending on whether the binary is
>> stripped and such.
>
> The checked fields like vaddr also do not match as the local file is commonly
> nightly prelinked, unprelinked (after nightly update before prelink has run)
> or nightly re-prelinked (see prelink(8)).
>
> Such prelink-aware verification is already implemented in solib-svr4.c in
> svr4_exec_displacement. GDB also handles correctly local symbol file in
> a different prelink state than the debugged target.
Ok, I will fix that.
>
> But still I find this verification less reliable and more complicated than the
> build-id verification I suggested.
>
build-id would be great if it was required by the standard and mapped
into loadable segments. AFAIK neither is true. I am after a generic
solution that will rely only on what's in the memory.
I will propose new patch addressing this and John Gilmore's comments (he
made them here: http://sourceware.org/ml/gdb/2012-12/msg00080.html) but
probably no sooner than mid-January.
---
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-26 19:24 ` Poenitz Andre
@ 2012-12-27 20:10 ` Aleksandar Ristovski
0 siblings, 0 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2012-12-27 20:10 UTC (permalink / raw)
To: Poenitz Andre; +Cc: gdb-patches
On 12-12-26 02:23 PM, Poenitz Andre wrote:
> Aleksandar Ristovski wrote:
>> [...] Change introduces new target_so_ops function dedicated to performing
>> validation. If we have loaded and relocated the object, validation
>> fails, we throw away bfd and loading of the object fails. [...]
>
> Does this change have any performance implications on the "normal"
> use case, i.e. when all is set up and matches nicely?
>
> Andre'
>
The idea is to have minimal performance impact. Worst case, if it turns
out to represent a performance issue it can always be made optional and
controlled by the user (I do not plan on making it optional ATM).
---
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-27 20:07 ` Aleksandar Ristovski
@ 2012-12-27 20:59 ` Jan Kratochvil
2012-12-27 21:03 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2012-12-27 20:59 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Thu, 27 Dec 2012 21:06:52 +0100, Aleksandar Ristovski wrote:
> build-id would be great if it was required by the standard
GDB can check if it exists and do something as a fallback if it does not exist.
Such as printing a warning and possibly also verifying the program headers, if
compatibility with binaries from old toolchain and/or toolchain without
configured ld --build-id is required in some situations (which I doubt).
> and mapped into loadable segments.
It is mapped, because one of its purposes is to get dumped into a core file.
In fact there is a special care to make it always present in the first page.
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 3] .note.gnu.build-id NOTE 00000000004002ac 0002ac 000024 00 A 0 0 4
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0d9db0 0x0d9db0 R E 0x200000
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-27 20:59 ` Jan Kratochvil
@ 2012-12-27 21:03 ` Aleksandar Ristovski
2012-12-27 21:13 ` Jan Kratochvil
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2012-12-27 21:03 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 12-12-27 03:59 PM, Jan Kratochvil wrote:
> On Thu, 27 Dec 2012 21:06:52 +0100, Aleksandar Ristovski wrote:
>> build-id would be great if it was required by the standard
>
> GDB can check if it exists and do something as a fallback if it does not exist.
> Such as printing a warning and possibly also verifying the program headers, if
> compatibility with binaries from old toolchain and/or toolchain without
> configured ld --build-id is required in some situations (which I doubt).
>
>
>> and mapped into loadable segments.
>
> It is mapped, because one of its purposes is to get dumped into a core file.
> In fact there is a special care to make it always present in the first page.
Ok I didn't know that (we are not using it). In any case, what I am
trying to do does not disqualify build-id (I'll use it in fact, if present).
Note also that I really want a solution that does *not* rely on section
headers but rather only on load-time required stuff.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-27 21:03 ` Aleksandar Ristovski
@ 2012-12-27 21:13 ` Jan Kratochvil
2012-12-27 21:21 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2012-12-27 21:13 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Thu, 27 Dec 2012 22:03:03 +0100, Aleksandar Ristovski wrote:
> In any case, what I am trying to do does not disqualify build-id
I understand that part but I find disappointing a feature designed
specifically for this purpose and already deployed for 5+ years is being IIUC
ignored.
> (I'll use it in fact, if present).
I do not see how you verify the NT_GNU_BUILD_ID content.
> Note also that I really want a solution that does *not* rely on
> section headers but rather only on load-time required stuff.
build-id specifically does not depend on any link-time data (sections) to be
usable for runtime core generations. It is (also) available from program
header PT_NOTE as NT_GNU_BUILD_ID.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-27 21:13 ` Jan Kratochvil
@ 2012-12-27 21:21 ` Aleksandar Ristovski
2013-01-29 16:15 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2012-12-27 21:21 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 12-12-27 04:13 PM, Jan Kratochvil wrote:
> On Thu, 27 Dec 2012 22:03:03 +0100, Aleksandar Ristovski wrote:
>> In any case, what I am trying to do does not disqualify build-id
>
> I understand that part but I find disappointing a feature designed
> specifically for this purpose and already deployed for 5+ years is being IIUC
> ignored.
>
>
>> (I'll use it in fact, if present).
>
> I do not see how you verify the NT_GNU_BUILD_ID content.
No, it's not done now in the current patch. I meant the new patch will.
>
>
>> Note also that I really want a solution that does *not* rely on
>> section headers but rather only on load-time required stuff.
>
> build-id specifically does not depend on any link-time data (sections) to be
> usable for runtime core generations. It is (also) available from program
> header PT_NOTE as NT_GNU_BUILD_ID.
That is great, thanks.
---
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2012-12-27 21:21 ` Aleksandar Ristovski
@ 2013-01-29 16:15 ` Aleksandar Ristovski
2013-01-30 19:17 ` Jan Kratochvil
2013-01-31 6:35 ` Jan Kratochvil
0 siblings, 2 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-01-29 16:15 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches
[-- 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}"]
+
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-01-29 16:15 ` Aleksandar Ristovski
@ 2013-01-30 19:17 ` Jan Kratochvil
2013-01-31 14:23 ` Aleksandar Ristovski
2013-01-31 6:35 ` Jan Kratochvil
1 sibling, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-01-30 19:17 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Tue, 29 Jan 2013 17:15:13 +0100, Aleksandar Ristovski wrote:
> 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
OK, I see currently target_so_ops methods are always valid and there is no
common initializer.
> @@ -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);
This part is OK as a "Code cleanup" but it should be checked in separately, it
is unrelated.
> @@ -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. */
Empty line after function comment.
> +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;
> +}
This function is not needed, see below.
> +
> +/* 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)
spaces->tab.
> + {
> + 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,
Just do not make 'asect' so const, then you will not need that '(asection *)'
cast.
> + 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)?
I do not see why to use target_verify_memory in this case.
target_verify_memory is there for large sections to compare only their 32-bit
checksum. But build-id is already only 20 bytes long, with the protocol
overhead the 4 vs. 20 bytes do not make a difference. And it needlessly
weakens the check, it also does some patching of target_verify_memory.
Just use target_read_memory and memcmp.
> + so_base_addr + sect_vma_offset
> + : asect->vma,
> + size);
so->abfd is not properly relocated (not sure why but it is so) but you can
iterate so->sections..so->sections_end which contains relocated ADDR (=target
VMA). Then you can drop the svr4_unrelocated_vma and other calculations
around.
> + xfree (data);
> +
> + if (res == -1 && info_verbose)
> + warning (_("Could not verify section %s\n"),
> + NOTE_GNU_BUILD_ID_NAME);
Here could be break;.
> + }
> + }
> + }
> +
> + return (res != 0);
Just:
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;
This is also unrelated "Code cleanup" to be checked in separately.
> @@ -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"
It is more common to place #define somewhere at the top of the file, not at
the bottom or between function declarations.
> +
> #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."),
Either without the trailing dot or the more common case:
_("Shared object '%s' could not be validated and will be ignored."),
> + so->abfd->filename);
There would be rather bfd_get_filename (so->abfd).
But GDB prints for shared libraries their so->so_name, it is also guaraneed to
be the same here.
> + 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. */
You provide two similar function comments, one in solib.c and one in solib.h.
There is s risk they become out of sync in the future. As solib.h already
contains comments at its functions I would keep the solib.h as is and replace
this solib.c comment by:
/* See solib.h for the function comment. */
> +
> +int
> +solib_validate (const struct so_list *const so)
> +{
> + return 1; /* No validation. */
Formatting:
/* No validation. */
return 1;
> +}
> +
> 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);
> +
> +
Single empty line only, not two.
> + /* 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;
As discussed at its call I do not find this change useful, to be dropped.
> }
>
> /* 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 */
No testcase should remain running indefinitely, there should be for example
sleep (60); otherwise there remain during various crashes stale processes on
the system.
But that should not be needed with process spawned from GDB.
> + 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"
Use the new macro standard_testfile instead.
> +
> +# 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}
Please keep the same prefix of all the files as ${testfile}...
(not lib${testfile}...)
> +set binlibfilerun ${binlibfiledirrun}/${binlibfilebase}
Use the new macro standard_output_file.
> +
> +# Second solib version is in current directory, '-libmod' version.
> +set binlibfiledirgdb ${objdir}/${subdir}
> +set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase}
Use the new macro standard_output_file.
> +
> +# Executeable
> +set srcfile ${testfile}.c
> +set executable ${testfile}
> +set objfile ${objdir}/${subdir}/${executable}.o
> +set binfile ${objdir}/${subdir}/${executable}
These get set by standard_testfile (except for $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
${testfile}.exp does not tell anything, use for example:
untested "Compilation failed.
> + return -1
> +}
> +
> +# Start with a fresh gdb
Remove the comment, there is no command for it here.
> +
> +# Start the exe. It will raise SIGSTOP on itself.
> +send_user "Exec: $executable\r\n"
dejagnu uses: verbose -log "Exec: $executable"
send_user also prints messages on screen during runtest, it should not (at
least it is not done in GDB testsuite).
> +set curdir [eval pwd]
Normal
set curdir [pwd]
works for me.
> +set dummy [eval cd "${binlibfiledirrun}"]
Normal
cd ${binlibfiledirrun}
works for me.
> +set testpid [eval exec "../${executable}" &]
The primary problem I have with the testcase is that it needlessly uses
separately spawned process for attach/detach. This makes the testcase
complicated, racy with testing system under load (I do not see any sleep here,
${executable} may be for example still in shell spawning ${executable} when
GDb attaches to it) and also fragile for leftover running processes.
I find it possible to test the feature just with normally "start"-ed process
from GDB.
In general always use only "cd" command in GDB, not in dejagnu.
And then you can:
* start the inferior, stop before dlopen
* "cd" in GDB to the other directory (libsolib-mismatch/).
* next "dlopen".
Now the inferior will use different current directory than GDB, while both
will load "./solib-mismatch.so".
> +send_user "You can now attach to $testpid\r\n"
verbose -log
> +
> +set dummy [eval cd "${binlibfiledirgdb}"]
Again, to be simplified.
But this leaves dejagnu in non-standard directory, current directory should be
always switched only temporarily as otherwise one forgets to restore it in
this or that exit path.
> +
> +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}
This block can be replaced by:
clean_restart ${executable}
> +
> + send_gdb "set auto-solib-add off\r\n"
> + gdb_expect {
> + -re "${gdb_prompt} $" {
> +# Nothing, just drain the buffer
> + }
> + }
send_gdb never needs to be used in general, it does not handle various corner
cases. In this case it is enough:
gdb_test_no_output "set auto-solib-add off"
The same applies to any send_gdb commands below.
> +
> +# 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
> + }
> + }
> +}
Hopefully no longer needed without attachments.
> +
> +# 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}"
Here is ${binlibfilegdb} and it is nowhere left. It makes troubleshooting
difficult, one has to modify the .exp file first to get the library for manual
testing. Keep some copy of it around.
> +solib_matching_test "${binlibfilebase}" "Yes"
> +
> +send_user "cleanup\r\n"
> +teardown
> +set dummy [eval cd "${curdir}"]
> +
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-01-29 16:15 ` Aleksandar Ristovski
2013-01-30 19:17 ` Jan Kratochvil
@ 2013-01-31 6:35 ` Jan Kratochvil
2013-01-31 14:24 ` Aleksandar Ristovski
1 sibling, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-01-31 6:35 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Tue, 29 Jan 2013 17:15:13 +0100, Aleksandar Ristovski wrote:
> --- 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))
When thinking about it this approach regresses back again performance with
gdbserver over high latency links. This is why the <library-list-svr4 /> XML
protocol has been put there. With ops->validate there will be
a round-trip-time requirement on very every library listed from gdbserver.
Therefore with gdbserver the current
p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
"l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
should be extended with hex-encoded build-id="..." parameter. gdbserver does
not have the bfd but it already iterates program headers in get_dynamic so it
can find PT_NOTE there.
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.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-01-30 19:17 ` Jan Kratochvil
@ 2013-01-31 14:23 ` Aleksandar Ristovski
2013-02-01 3:06 ` Jan Kratochvil
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-01-31 14:23 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
Thanks for the review. Please see some of my comments inlined.
On 13-01-30 02:16 PM, Jan Kratochvil wrote:
> On Tue, 29 Jan 2013 17:15:13 +0100, Aleksandar Ristovski wrote:
>> + /* 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)?
>
> I do not see why to use target_verify_memory in this case.
While your comment below is correct, I find, since we introduced
target_verify_memory already, this to be "more correct". Well, it is
equivalent to what you are suggesting and I was considering doing simply
read_memory/memcmp here, but then figured, target_verify_memory is more
semantically correct.
>
> target_verify_memory is there for large sections to compare only their 32-bit
> checksum. But build-id is already only 20 bytes long, with the protocol
> overhead the 4 vs. 20 bytes do not make a difference. And it needlessly
> weakens the check, it also does some patching of target_verify_memory.
> Just use target_read_memory and memcmp.
This is all true; however my opinion is that fallback in
target_verify_memory is correct implementation as it allows using
target_verify_memory where semantically suitable (like this place IMO)
regardless of whether actual target implements it or not (e.g. core
doesn't need to implement it; if it did, the implementation would
probably be exactly the same as the fallback).
>
>
>> + so_base_addr + sect_vma_offset
>> + : asect->vma,
>> + size);
>
> so->abfd is not properly relocated (not sure why but it is so) but you can
I find that l_addr_inferior remains to be 0 if prelinked object was not
relocated. I haven't looked at gnu ld, but I would expect it's missing
to set it correctly (this is misfortunate).
> iterate so->sections..so->sections_end which contains relocated ADDR (=target
> VMA). Then you can drop the svr4_unrelocated_vma and other calculations
> around.
Ok. I think this is what I tried first but then some testcases would
fail. Will revisit.
I will be posting new patch with other comments addressed, and please
provide feedback on the above.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-01-31 6:35 ` Jan Kratochvil
@ 2013-01-31 14:24 ` Aleksandar Ristovski
2013-02-22 15:09 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-01-31 14:24 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-01-31 01:35 AM, Jan Kratochvil wrote:
> On Tue, 29 Jan 2013 17:15:13 +0100, Aleksandar Ristovski wrote:
>> --- 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))
>
> When thinking about it this approach regresses back again performance with
> gdbserver over high latency links. This is why the <library-list-svr4 /> XML
> protocol has been put there. With ops->validate there will be
> a round-trip-time requirement on very every library listed from gdbserver.
>
> Therefore with gdbserver the current
> p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
> "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
> should be extended with hex-encoded build-id="..." parameter. gdbserver does
> not have the bfd but it already iterates program headers in get_dynamic so it
> can find PT_NOTE there.
>
> 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.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-01-31 14:23 ` Aleksandar Ristovski
@ 2013-02-01 3:06 ` Jan Kratochvil
2013-02-01 14:31 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-02-01 3:06 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Thu, 31 Jan 2013 15:23:07 +0100, Aleksandar Ristovski wrote:
> On 13-01-30 02:16 PM, Jan Kratochvil wrote:
> >On Tue, 29 Jan 2013 17:15:13 +0100, Aleksandar Ristovski wrote:
> >>+ /* 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)?
> >
> >I do not see why to use target_verify_memory in this case.
>
> While your comment below is correct, I find, since we introduced
> target_verify_memory already, this to be "more correct". Well, it is
> equivalent to what you are suggesting and I was considering doing
> simply read_memory/memcmp here, but then figured,
> target_verify_memory is more semantically correct.
>
> >
> >target_verify_memory is there for large sections to compare only their 32-bit
> >checksum. But build-id is already only 20 bytes long, with the protocol
> >overhead the 4 vs. 20 bytes do not make a difference. And it needlessly
> >weakens the check, it also does some patching of target_verify_memory.
> >Just use target_read_memory and memcmp.
>
> This is all true; however my opinion is that fallback in
> target_verify_memory is correct implementation as it allows using
> target_verify_memory where semantically suitable (like this place
> IMO) regardless of whether actual target implements it or not (e.g.
> core doesn't need to implement it; if it did, the implementation
> would probably be exactly the same as the fallback).
This is a bit nitpicking, primarily I do not see there much difference and we
avoid dealing with target_verify_memory in this patch.
target_read_memory is already always implemented by the target.
With gdbserver <library-list-svr4/> protocol the build-id itself seems to me
to be the natural way how to identify the library. While it could also send
a 32-bit CRC in the XML protocol the build-id looks as more universal even for
other possible GDB extensions in the future.
And thus optimizing local solib-svr4.c usage by 16 bytes saved by the 32-bit
CRC seems off-topic to me, (1) it will work needlessly differently in both
cases (vs. gdbserver) and (2) non-gdbserver usage is going to be deprecated so
this is just a temporary code anyway.
Besides that target_verify_memory fallback should be put into
default_verify_memory function and installed in to_verify_memory in all
targets except that remote.c remote_verify_memory. target_* functions should
be just dispatchers, not the implementations. (Yes, C++ would be easier.)
> I find that l_addr_inferior
l_addr should be used, not l_addr_inferior. (Although one should not use
rather either.)
> remains to be 0 if prelinked object was
> not relocated. I haven't looked at gnu ld, but I would expect it's
> missing to set it correctly (this is misfortunate).
This behavior is correct. Changing it would break all the tools around.
l_addr just has wrong comment in glibc. I have pinged now the fix:
[patch] Fix l_addr comment
http://sourceware.org/ml/libc-alpha/2011-09/msg00151.html
> >iterate so->sections..so->sections_end which contains relocated ADDR (=target
> >VMA). Then you can drop the svr4_unrelocated_vma and other calculations
> >around.
>
> Ok. I think this is what I tried first but then some testcases would
> fail. Will revisit.
There may be other issues but I am not aware of those.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-01 3:06 ` Jan Kratochvil
@ 2013-02-01 14:31 ` Aleksandar Ristovski
2013-02-01 20:43 ` Jan Kratochvil
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-02-01 14:31 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-01-31 10:06 PM, Jan Kratochvil wrote:
> On Thu, 31 Jan 2013 15:23:07 +0100, Aleksandar Ristovski wrote:
>> On 13-01-30 02:16 PM, Jan Kratochvil wrote:
>>> On Tue, 29 Jan 2013 17:15:13 +0100, Aleksandar Ristovski wrote:
>>>> + /* 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)?
>>>
>>> I do not see why to use target_verify_memory in this case.
>>
>> While your comment below is correct, I find, since we introduced
>> target_verify_memory already, this to be "more correct". Well, it is
>> equivalent to what you are suggesting and I was considering doing
>> simply read_memory/memcmp here, but then figured,
>> target_verify_memory is more semantically correct.
>>
>>>
>>> target_verify_memory is there for large sections to compare only their 32-bit
>>> checksum. But build-id is already only 20 bytes long, with the protocol
>>> overhead the 4 vs. 20 bytes do not make a difference. And it needlessly
>>> weakens the check, it also does some patching of target_verify_memory.
>>> Just use target_read_memory and memcmp.
>>
>> This is all true; however my opinion is that fallback in
>> target_verify_memory is correct implementation as it allows using
>> target_verify_memory where semantically suitable (like this place
>> IMO) regardless of whether actual target implements it or not (e.g.
>> core doesn't need to implement it; if it did, the implementation
>> would probably be exactly the same as the fallback).
>
> This is a bit nitpicking, primarily I do not see there much difference and we
> avoid dealing with target_verify_memory in this patch.
>
> target_read_memory is already always implemented by the target.
>
> With gdbserver <library-list-svr4/> protocol the build-id itself seems to me
> to be the natural way how to identify the library. While it could also send
> a 32-bit CRC in the XML protocol the build-id looks as more universal even for
> other possible GDB extensions in the future.
My primary reason for 'verify' is not optimization but the semantics.
But I see no point in insisting on it, I will use read_memory/memcmp.
>
> And thus optimizing local solib-svr4.c usage by 16 bytes saved by the 32-bit
> CRC seems off-topic to me, (1) it will work needlessly differently in both
> cases (vs. gdbserver) and (2) non-gdbserver usage is going to be deprecated so
> this is just a temporary code anyway.
No, the code is not going to be deprecated as long as core target is in
the gdb and not implemented as e.g. external agent talking to gdb via
remote protocol.
>
> Besides that target_verify_memory fallback should be put into
> default_verify_memory function and installed in to_verify_memory in all
> targets except that remote.c remote_verify_memory. target_* functions should
> be just dispatchers, not the implementations. (Yes, C++ would be easier.)
Sure - I will drop this part.
>
>
>> I find that l_addr_inferior
>
> l_addr should be used, not l_addr_inferior. (Although one should not use
> rather either.)
In this case, in the approach you commented on, l_addr_inferior was
appropriate as I wanted to "relocate" it directly (this is why I
calculated offset from the base) as opposed to applying calculated
offset l_addr. But it may not be applicable any more if asection->addr
proves to be reliable.
>
>
>> remains to be 0 if prelinked object was
>> not relocated. I haven't looked at gnu ld, but I would expect it's
>> missing to set it correctly (this is misfortunate).
>
> This behavior is correct. Changing it would break all the tools around.
<offtopic>
If you say so. IMO it is less than ideal, it should specify l_addr as
expected and make prelink transparent. Like this, it special cases
meaning of this field, which is common and across many systems happens
to always have the same meaning (except when 'successful' prelinking
happens).
</offtopic>
> l_addr just has wrong comment in glibc. I have pinged now the fix:
> [patch] Fix l_addr comment
> http://sourceware.org/ml/libc-alpha/2011-09/msg00151.html
>
>
>>> iterate so->sections..so->sections_end which contains relocated ADDR (=target
>>> VMA). Then you can drop the svr4_unrelocated_vma and other calculations
>>> around.
>>
>> Ok. I think this is what I tried first but then some testcases would
>> fail. Will revisit.
>
> There may be other issues but I am not aware of those.
I will be posting new patch soon.
---
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-01 14:31 ` Aleksandar Ristovski
@ 2013-02-01 20:43 ` Jan Kratochvil
2013-02-01 21:32 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-02-01 20:43 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Fri, 01 Feb 2013 15:31:27 +0100, Aleksandar Ristovski wrote:
> On 13-01-31 10:06 PM, Jan Kratochvil wrote:
> >This behavior is correct. Changing it would break all the tools around.
>
> <offtopic>
> If you say so. IMO it is less than ideal, it should specify l_addr
> as expected and make prelink transparent. Like this, it special
> cases meaning of this field, which is common and across many systems
> happens to always have the same meaning (except when 'successful'
> prelinking happens).
> </offtopic>
FYI on gdbserver/linux-low.c get_phdr_phnum_from_proc_auxv finds PHDR_MEMADDR
which is the absolute L_ADDR form you ask for.
Just solib-svr4.c tries to be (is it?) cross-OS compatible so it does not have
this PHDR_MEMADDR value available.
Regards,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-01 20:43 ` Jan Kratochvil
@ 2013-02-01 21:32 ` Aleksandar Ristovski
2013-02-02 12:25 ` Jan Kratochvil
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-02-01 21:32 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-02-01 03:04 PM, Jan Kratochvil wrote:
> On Fri, 01 Feb 2013 15:31:27 +0100, Aleksandar Ristovski wrote:
>> On 13-01-31 10:06 PM, Jan Kratochvil wrote:
>>> This behavior is correct. Changing it would break all the tools around.
>>
>> <offtopic>
>> If you say so. IMO it is less than ideal, it should specify l_addr
>> as expected and make prelink transparent. Like this, it special
>> cases meaning of this field, which is common and across many systems
>> happens to always have the same meaning (except when 'successful'
>> prelinking happens).
>> </offtopic>
>
> FYI on gdbserver/linux-low.c get_phdr_phnum_from_proc_auxv finds PHDR_MEMADDR
> which is the absolute L_ADDR form you ask for.
>
> Just solib-svr4.c tries to be (is it?) cross-OS compatible so it does not have
> this PHDR_MEMADDR value available.
<still-offtopic>
To avoid any misunderstanding: I am not emotional about this topic at
all. Take what follows as a light-weight hallway conversation over a coffee:
I will not claim familiarity with how linux works, but auxv typically
has information for the executable only, not the shared objects (i.e.
auxv is the "connecting link" between process loader and dynamic linker
- interpreter). For shared objects, however, this can not be used
because the information is not there. Dynamic linker does not add
anything to auxv nor does auxv have entries for e.g. load base of any of
the shared objects.
To be clear: I am very familiar with how this works on Neutrino and the
preceding and following claims come from that and *not* from gnu/ld
familiarity. If it's different on gnu/linux, let me know.
Using auxv is fairly os-agnostic as long as an os is svr4-like.
solib-svr4.c uses auxv via target_auxv_search, nothing wrong with that.
But again, this applies to exe only. Auxv does not have any information
about arbitrary shared objects executable links against - that is
entirely ld's business and not process loader's.
Therefore, the only clue for deterministic and straight forward
relocation calculus for a tool like gdb is l_addr from the link map. If
gnu ld is not setting it up when "successful prelink" happens it is
making a mistake: 0 load base may be legitimate and true in some cases
on some systems. Furhter, it unnecessary introduces this difference when
it would probably change very little (nothing?) if it set it up
correctly to what the load base really is, just as it does for
"unsuccessful" prelinks or non-prelinked objects.
</still-offtopic>
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-01 21:32 ` Aleksandar Ristovski
@ 2013-02-02 12:25 ` Jan Kratochvil
2013-02-21 21:00 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-02-02 12:25 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Fri, 01 Feb 2013 22:31:41 +0100, Aleksandar Ristovski wrote:
> I will not claim familiarity with how linux works, but auxv
> typically has information for the executable only, not the shared
> objects
OK, sorry, my comment was not appropriate, I remembered the function which
finally end up in GDB incorrectly.
If you are interested in shared library base VMA you could take link_map->l_ld
and search /proc/PID/maps where it is located, subtract mapping offset and you
get the base VMA where ELF headers starts. This is possible in
gdbserver/linux-low.c but not possible in solib-svr4.c (which is cross-OS).
gdbserver/linux-low.c currently does such computation for the main executable
but it does not do it for any of the shared libraries.
From ELF headers one can find Program headers, PT_NOTE and the build-id.
BTW your patch currently verifies only shared libraries. I do not request so
but a complete solution could verify also build-id of the executable.
> Therefore, the only clue for deterministic and straight forward
> relocation calculus for a tool like gdb is l_addr from the link map.
Not from l_addr but l_ld is an absolute address of the DYNAMIC
segment/section. From that one can derive something but only with
/proc/PID/maps one can derive the ELF header VMA.
> If gnu ld
BTW this is more ld.so (PT_INTERP, /lib64/ld-linux-x86-64.so.2), not
/usr/bin/ld.
> is not setting it up when "successful prelink" happens it
> is making a mistake:
As I said it is not a mistake but it was rather an incorrect comment at
l_addr. l_addr is now officially defined as:
+ ElfW(Addr) l_addr; /* Difference between the address in the ELF
+ file and the addresses in memory. */
http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=542f94662e8235d9917b0783df70bcdf9d729503
> 0 load base may be legitimate and true in some
> cases on some systems. Furhter, it unnecessary introduces this
> difference when it would probably change very little (nothing?) if
> it set it up correctly to what the load base really is,
Setting it to the absolute address would break tools like GDB which already
expect it is the "difference" described above.
> just as it does for "unsuccessful" prelinks or non-prelinked objects.
It is not just "0 or the address". It can be arbitrary number if you prelink a
library to address X and X is not free upon its loading so it gets placed at Y.
Then L_ADDR is set to "Y - X" which is none of X, Y or 0.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-02 12:25 ` Jan Kratochvil
@ 2013-02-21 21:00 ` Aleksandar Ristovski
2013-02-21 21:07 ` Jan Kratochvil
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-02-21 21:00 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-02-02 07:25 AM, Jan Kratochvil wrote:
> On Fri, 01 Feb 2013 22:31:41 +0100, Aleksandar Ristovski wrote:
>> I will not claim familiarity with how linux works, but auxv
>> typically has information for the executable only, not the shared
>> objects
>
> OK, sorry, my comment was not appropriate, I remembered the function which
> finally end up in GDB incorrectly.
>
> If you are interested in shared library base VMA you could take link_map->l_ld
> and search /proc/PID/maps where it is located, subtract mapping offset and you
> get the base VMA where ELF headers starts. This is possible in
> gdbserver/linux-low.c but not possible in solib-svr4.c (which is cross-OS).
No, I will use l_addr if it works.
>
> gdbserver/linux-low.c currently does such computation for the main executable
> but it does not do it for any of the shared libraries.
>
> From ELF headers one can find Program headers, PT_NOTE and the build-id.
>
> BTW your patch currently verifies only shared libraries. I do not request so
> but a complete solution could verify also build-id of the executable.
>
That is deliberate since executable is already being validated. What
should be done is turn it into a 'reject' instead of a warning when a
mismatch is detected. The code paths are sufficiently different for
executable and other shared objects that executable validation can be
done in a separate patch.
>
>> Therefore, the only clue for deterministic and straight forward
>> relocation calculus for a tool like gdb is l_addr from the link map.
>
> Not from l_addr but l_ld is an absolute address of the DYNAMIC
> segment/section. From that one can derive something but only with
> /proc/PID/maps one can derive the ELF header VMA.
>
>
>> If gnu ld
>
> BTW this is more ld.so (PT_INTERP, /lib64/ld-linux-x86-64.so.2), not
> /usr/bin/ld.
Sorry, I didn't think there could have been any confusion - yes, we are
talking about dynamic linker, not link editor, I should have been clearer.
>
>
>> is not setting it up when "successful prelink" happens it
>> is making a mistake:
>
> As I said it is not a mistake but it was rather an incorrect comment at
> l_addr. l_addr is now officially defined as:
> + ElfW(Addr) l_addr; /* Difference between the address in the ELF
> + file and the addresses in memory. */
> http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=542f94662e8235d9917b0783df70bcdf9d729503
>
Yes, your new comment makes it clearer, but doesn't change my first
observation: this is a mistake.
>
>> 0 load base may be legitimate and true in some
>> cases on some systems. Furhter, it unnecessary introduces this
>> difference when it would probably change very little (nothing?) if
>> it set it up correctly to what the load base really is,
>
> Setting it to the absolute address would break tools like GDB which already
> expect it is the "difference" described above.
We set it to absolute load address - the sole purpose of link_map is to
allow kernel-agnostic (therefore /proc/ agnostic) way of traversing the
list of shared objects. Dynamic linker can have whatever internal
structures it wants to keep e.g. displacement (l_addr for gnu).
We do it in the logical way: l_addr is where the object is mapped, which
corresponds to first PT_LOAD. l_ld is, as on gnu (based on gdb code),
relocated address of dynamic section.
>
>
>> just as it does for "unsuccessful" prelinks or non-prelinked objects.
>
> It is not just "0 or the address". It can be arbitrary number if you prelink a
> library to address X and X is not free upon its loading so it gets placed at Y.
> Then L_ADDR is set to "Y - X" which is none of X, Y or 0.
The prelinking here introduces unnecessary confusion. Correct term would
be base address. Base address can be changed in the link-editor linker
script or with link-editor command line options. Dynamic linker is free
to load such shared object (providing it is shared i.e. DYN) at an
arbitrary, correctly aligned, virtual address. Hence 'load address' term
and differentiation between it and virtual address from pheaders.
This, however, has little to do with the semantics of l_addr which, as I
already stated, should be load base and not displacement.
In any case, this does not concern me too much, though I will try to
propose a patch where l_addr semantics will be configurable in the OS
abi somehow - something for another day.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-21 21:00 ` Aleksandar Ristovski
@ 2013-02-21 21:07 ` Jan Kratochvil
0 siblings, 0 replies; 47+ messages in thread
From: Jan Kratochvil @ 2013-02-21 21:07 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Thu, 21 Feb 2013 22:00:37 +0100, Aleksandar Ristovski wrote:
> This, however, has little to do with the semantics of l_addr which,
> as I already stated, should be load base and not displacement.
When we talk about GDB internal value lm_info->l_addr then sure I agree it
could be the absolute address. This would be a separate "code cleanup" (=with
no GDB functionality impact) patch. If it simplifies the GDB code then sure
it is a win. If not then it is worth a discussion, matching glibc's l_addr
meaning also makes sense (at least ot me).
(I will check more of the mail later.)
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-01-31 14:24 ` Aleksandar Ristovski
@ 2013-02-22 15:09 ` Aleksandar Ristovski
2013-02-27 17:42 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-02-22 15:09 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches
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
I will be posting renewed "validate binary before use" patch which uses
build-id from gdbserver here soon.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-22 15:09 ` Aleksandar Ristovski
@ 2013-02-27 17:42 ` Aleksandar Ristovski
2013-02-27 18:14 ` Aleksandar Ristovski
2013-03-22 16:58 ` Aleksandar Ristovski
0 siblings, 2 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-02-27 17:42 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches, Pedro Alves
[-- Attachment #1: Type: text/plain, Size: 3723 bytes --]
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.
[-- Attachment #2: solib-validate-201302271227.patch --]
[-- Type: text/x-patch, Size: 14748 bytes --]
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
[-- Attachment #3: solib-validate-test-201302271228.patch --]
[-- Type: text/x-patch, Size: 9976 bytes --]
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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-27 17:42 ` Aleksandar Ristovski
@ 2013-02-27 18:14 ` Aleksandar Ristovski
2013-03-22 16:58 ` Aleksandar Ristovski
1 sibling, 0 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-02-27 18:14 UTC (permalink / raw)
To: gdb-patches; +Cc: Jan Kratochvil, gdb-patches, Pedro Alves
[-- Attachment #1: Type: text/plain, Size: 3723 bytes --]
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.
[-- Attachment #2: solib-validate-201302271227.patch --]
[-- Type: text/x-patch, Size: 14748 bytes --]
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
[-- Attachment #3: solib-validate-test-201302271228.patch --]
[-- Type: text/x-patch, Size: 9976 bytes --]
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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-03-22 16:58 ` Aleksandar Ristovski
@ 2013-03-22 14:45 ` Aleksandar Ristovski
2013-03-28 20:56 ` Jan Kratochvil
1 sibling, 0 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 14:45 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches, Pedro Alves
[-- Attachment #1: Type: text/plain, Size: 1660 bytes --]
(depends on the gdbserver changes:
http://sourceware.org/ml/gdb-patches/2013-03/msg00838.html)
ChangeLog:
* 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_validate_build_id): New function.
(svr4_validate): New function.
(library_list_start_library): Parse 'build-id' attribute.
(svr4_library_pattributes): Add 'build-id' attribute.
(_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'.
Test ChangeLog:
* 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.
Thanks,
Aleksandar
[-- Attachment #2: 0007-Validate-symbol-file-using-build-id.patch --]
[-- Type: text/x-patch, Size: 14285 bytes --]
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 2ebe2fe..2e950b6 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 b9a4be1..b588f86 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 ea2acd1..c5f84f3 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 f646cfb..06749d0 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 = solib_validate;
memset (&dld_cache, 0, sizeof (dld_cache));
}
diff --git a/gdb/solib-som.c b/gdb/solib-som.c
index ff7fbaa..0d68aac 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 7be5232..94b9a36 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..9dd9cab 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,7 +1080,11 @@ 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;
+ size_t hex_build_id_len;
new_elem = XZALLOC (struct so_list);
new_elem->lm_info = XZALLOC (struct lm_info);
@@ -1010,6 +1095,21 @@ 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 && (hex_build_id_len = strlen (hex_build_id)) > 0)
+ {
+ new_elem->build_id = xmalloc (hex_build_id_len / 2 + 1);
+ 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 +1144,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 +2559,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..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: 9976 bytes --]
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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-02-27 17:42 ` Aleksandar Ristovski
2013-02-27 18:14 ` Aleksandar Ristovski
@ 2013-03-22 16:58 ` Aleksandar Ristovski
2013-03-22 14:45 ` Aleksandar Ristovski
2013-03-28 20:56 ` Jan Kratochvil
1 sibling, 2 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 16:58 UTC (permalink / raw)
To: gdb-patches; +Cc: Jan Kratochvil, gdb-patches, Pedro Alves
[-- Attachment #1: Type: text/plain, Size: 1660 bytes --]
(depends on the gdbserver changes:
http://sourceware.org/ml/gdb-patches/2013-03/msg00838.html)
ChangeLog:
* 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_validate_build_id): New function.
(svr4_validate): New function.
(library_list_start_library): Parse 'build-id' attribute.
(svr4_library_pattributes): Add 'build-id' attribute.
(_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'.
Test ChangeLog:
* 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.
Thanks,
Aleksandar
[-- Attachment #2: 0007-Validate-symbol-file-using-build-id.patch --]
[-- Type: text/x-patch, Size: 14285 bytes --]
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 2ebe2fe..2e950b6 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 b9a4be1..b588f86 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 ea2acd1..c5f84f3 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 f646cfb..06749d0 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 = solib_validate;
memset (&dld_cache, 0, sizeof (dld_cache));
}
diff --git a/gdb/solib-som.c b/gdb/solib-som.c
index ff7fbaa..0d68aac 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 7be5232..94b9a36 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..9dd9cab 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,7 +1080,11 @@ 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;
+ size_t hex_build_id_len;
new_elem = XZALLOC (struct so_list);
new_elem->lm_info = XZALLOC (struct lm_info);
@@ -1010,6 +1095,21 @@ 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 && (hex_build_id_len = strlen (hex_build_id)) > 0)
+ {
+ new_elem->build_id = xmalloc (hex_build_id_len / 2 + 1);
+ 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 +1144,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 +2559,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..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: 9976 bytes --]
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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-03-22 16:58 ` Aleksandar Ristovski
2013-03-22 14:45 ` Aleksandar Ristovski
@ 2013-03-28 20:56 ` Jan Kratochvil
2013-04-02 17:25 ` Aleksandar Ristovski
1 sibling, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-03-28 20:56 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches, Pedro Alves
On Fri, 22 Mar 2013 14:12:18 +0100, Aleksandar Ristovski wrote:
> (depends on the gdbserver changes:
> http://sourceware.org/ml/gdb-patches/2013-03/msg00838.html)
>
> ChangeLog:
>
>
> * 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_validate_build_id): New function.
> (svr4_validate): New function.
> (library_list_start_library): Parse 'build-id' attribute.
> (svr4_library_pattributes): Add 'build-id' attribute.
> (_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'.
>
>
>
> Test ChangeLog:
> * 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.
>
>
> Thanks,
>
> Aleksandar
>
> diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
> index 2ebe2fe..2e950b6 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;
I do not see why this override should be done. There is above:
mips_svr4_so_ops = svr4_so_ops;
so unless you have a specific reason why the verification cannot work for MIPS
- and such reason should be put in a comment there - just remove these two
'+' linse.
> 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;
Likewise.
> 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 b9a4be1..b588f86 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 ea2acd1..c5f84f3 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 f646cfb..06749d0 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 = solib_validate;
>
> memset (&dld_cache, 0, sizeof (dld_cache));
> }
> diff --git a/gdb/solib-som.c b/gdb/solib-som.c
> index ff7fbaa..0d68aac 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 7be5232..94b9a36 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;
In whis case the override of SVR4_SO_OPS.VALIDATE seems as a safe bet, Ulrich
Weigand could test if it works with SPU but for the initial check-in I find it
OK as you wrote it.
> }
>
> 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..9dd9cab 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)
Such change is OK although it needs to be checked in separately.
> {
> 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)
If you are used to it then OK but for GDB one does not have to make 'const'
even the variables themselves ('so'), that does not bring much benefits.
This is everywhere in the patch.
> +{
> + asection *asect;
> + int res = 1;
> + size_t size;
There are multiple sizes around, please call it "asect_size" or somehow
similar to see this "size" is for the section.
> + const CORE_ADDR l_addr = lm_addr_check (so, so->abfd);
Move this variable to the inner block where it is used, its computation
possibly would not be used.
> +
> + 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)
Coding style for pointer comparison according to doc/gdbinte.texinfo:
if (asect == NULL || !so->lm_info->l_addr_p)
But that l_addr_p check is not needed, drop it, lm_addr_check cannot fail,
l_addr_p is only internal field for lm_addr_check.
> + {
> + 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;
You never set so->build_id anywhere so it will be always NULL.
But in fact I do not see why there exists so->build_id at all. It is only
verified once when loading the library and then if it remains loaded one can
pick the build_id from elf_tdata (so->abfd)->build_id which has been already
verified as matching.
So just drop so->build_id, it is a duplcate to elf_tdata (so->abfd)->build_id.
> + 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. */
I do not understand this comment but as the code will change I prefer
a removal of the comment or a new/different comment.
> + const CORE_ADDR sect_lma = l_addr + bfd_section_vma (so->abfd, asect);
"lma" is irrelevant here, it needs to be VMA as you do runtime
target_read_memory for that address.
I won't argue if the expression is right or wrong but it at least looks as
a duplication of computation done for target_section->addr:
* Move the 'ops->validate (se)' call in solib_map_sections after the loop
for (p = so->sections; p < so->sections_end; p++)
* Then just use here the VMS address from so->sections but one needs to find
it first:
struct target_section *p;
for (p = solib->sections; p < solib->sections_end; p++)
if (p->the_bfd_section == asect)
break;
use p->addr
> +
> + /* 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);
Remove the bfd_get_section_contents call completely,
use elf_tdata (so->abfd)->build_id , there it is already read in and parsed.
> +
> + if (build_id == NULL)
Here could be a comment - if it was intended so:
/* Even if gdbserver failed to find the build-id read it by
target_read_memory. */
> + {
> + build_idsz = size;
> + build_id = xmalloc (size);
> + make_cleanup (xfree, build_id);
If you start to store the build-id to so->build_id then the xfree is no longer
appropriate here.
> + if (target_read_memory (sect_lma, build_id, size) != 0)
> + {
> + build_id = NULL;
> + res = -1;
Return value -1 is not documented for this function; but see below.
> + }
> + }
> +
> + if (build_id != NULL)
> + res = size == build_idsz
> + && memcmp (build_id, data, size) == 0;
The line does not need wrapping, it is under 80 columns:
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;
When the variable is called 'res' then one expects it will be returned as is,
therefore 'return res;'.
> +}
> +
> +/* 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);
> +}
I do not see why there is this wrapper svr4_validate, you could just move
those two gdb_assert to svr4_validate_build_id and use directly
svr4_validate_build_id, it has no other caller anyway.
> +
> /* Implement the "open_symbol_file_object" target_so_ops method.
>
> If no open symbol file, attempt to locate and open the main symbol
> @@ -999,7 +1080,11 @@ 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;
> + size_t hex_build_id_len;
Sometimes you call it "build_idsz" and sometimes "build_id_len", unify it.
(I prefer the latter.)
>
> new_elem = XZALLOC (struct so_list);
> new_elem->lm_info = XZALLOC (struct lm_info);
> @@ -1010,6 +1095,21 @@ 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 && (hex_build_id_len = strlen (hex_build_id)) > 0)
Do not use assignment this way, make it a separate line, see GNU Coding
Standards:
Try to avoid assignments inside if-conditions
> + {
> + new_elem->build_id = xmalloc (hex_build_id_len / 2 + 1);
Why the '+ 1' here? NEW_ELEM->BUILD_ID is in binary form so there is no '\0'
terminator.
> + 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))
Check it the opposite way:
if (2 * new_elem->build_idsz != hex_build_id_len)
as otherwise odd length of the "build-id" attribute string will not be caught
as invalid.
> + {
> + warning (_("Gdbserver returned invalid hex encoded build_id '%s'"
gdbserver build-id
> + "(%zu/%zu)\n"),
I would omit this (%zu/%zu) part. Primarily currently %z is not allowed as it
is not compatible with some OSes, there is a plan to import %z printf support
in gdb/gnulib/ but so far there wasn't a need for it.
Besides that you should describe what the two numbers mean otherwise they are
mostly useless. And after all when you already print the XML string the
numbers do not add any more info to it.
> + 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;
I am not completely sure warning cannot throw, better to do these cleanups
before the warning call (moreover when %zu/%zu will no longer be printed).
> + }
> + }
>
> *list->tailp = new_elem;
> list->tailp = &new_elem->next;
> @@ -1044,6 +1144,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 },
There has to be be GDB_XML_EF_OPTIONAL.
> { NULL, GDB_XML_AF_NONE, NULL, NULL }
> };
>
> @@ -2458,4 +2559,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"
I do not see used it anywhere.
> +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id"
It is used only in solib-svr4.c so it should be in that file.
> +
> 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."),
Number of columns exceeds 80 characters.
And move it under 'for (p = so->sections; p < so->sections_end; p++)' with the
reasons described above.
> + 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)
Up to you but I would prefer "default_solib_validate", "solib_validate" name
seems as if it does some validation.
> +{
> + return 1; /* No validation. */
Formatting:
/* No validation. */
return 1;
> +}
> +
> 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..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
build-id
> + .note.gnu.build-id including note header.
It really should not contain the note header, it should be exactly 20 bytes
with the standard build-id in place.
I wanted to check it with gdbserver but gdbserver does not work for me due to
those errors like:
gdbserver: Error parsing {s,}maps file '/usr/lib64/libdl-2.17.so'^M
> 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
>
> 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"
Macros should use uppercased names.
> +
> +
> +/* 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
I do not see why this comment is here.
> +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
Use specific text, like:
untested "get_compiler_info failed."
> +}
> +
> +# First version of the object, to be loaded by ld
> +set srclibfilerun ${testfile}-lib.c
Please make empty lines before comments.
> +# 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}
Use [standard_output_file ...], not ${objdir}.
> +
> +# Second solib version is in current directory, '-libmod' version.
> +set binlibfiledirgdb ${objdir}/${subdir}
Likewise.
> +set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase}
> +
> +# Executeable
> +set srcfile ${testfile}.c
> +set executable ${testfile}
> +set objfile ${objdir}/${subdir}/${executable}.o
Likewise.
> +set binfile ${objdir}/${subdir}/${executable}
Likewise.
> +
> +send_user "Current WD: [eval pwd]\r\n"
Testfiles must not print messages during normal run. Use "verbose -log" if needed.
3 times more below.
> +
> +file mkdir "${binlibfiledirrun}"
> +
Initialize it by:
set exec_opts {}
as IIRC regex testcases have persistent variables during one runtest run.
> +if { ![istarget "*-*-nto-*"] } {
> + set exec_opts [list debug shlib_load]
> +}
> +
> +if { [prepare_for_testing $testfile.exp $executable $srcfile $exec_opts] != 0 } {
> + untested ${testfile}.exp
untested is not needed, prepare_for_testing complains on its own.
> + 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
Use specific message.
> + 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
use clean_restart
> +
> + send_gdb "set verbose 1\n"
Never (only in some exceptional cases) use send_gdb, it creates races wrt
syncing on end of the commands. Use gdb_test or gdb_test_no_output.
> + send_gdb "file \"${binlibfiledirrun}/${executable}\"\n"
Do not use "file" by hand, clean_restart does it.
> + 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"
Why is this command here? Could you put a comment there?
> + 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"
Do not use send_gdb and there is gdb_breakpoint function.
> + 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"
Use runto_main. And check its result code.
Currently gdbserver (in non-extended mode) is never tested as "run" will never
start gdbserver.
After I fixed it I get from gdbserver messages like:
gdbserver: Error parsing {s,}maps file '/home/jkratoch/redhat/gdb-qnx/gdb/testsuite/gdb.base/solib-mismatch'^M
> + gdb_expect {
> + -re "Starting program.*${gdb_prompt} $" {
> + }
> + default {
> + untested "${testfile}: Failed to hit breakpoint at ${bp_location}"
> + return -1
> + }
> + }
> +
> + send_gdb "sharedlibrary\n"
Use gdb_test.
> + 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}.*" \
^^
BTW leading .* is excessive, gdb_test regex does not have anchored its start.
> + "Symbols for ${solibfile} loaded: expected '${symsloaded}'"
Protect ${symsloaded} by [string_to_regexp $string] as user
may have regex-unsafe characters there.
> +
> + send_gdb "p/x foo\n"
Use gdb_test.
> + gdb_expect {
> + -re ".*${gdb_prompt} $" {
> +#Nothing, just drain the buffer
> + }
> + default {
> + untested "${testfile}: Failed 'info symbol foo'"
> + return -1
> + }
> + }
> +
> + send_gdb "detach\n"
I do not see a need for this command, remove it.
> + 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"
The testcase is not safe for gdbserver targets not sharing the filesystem with
the runtest machine. There are functions like gdb_download for it although
AFAIK many GDB testcases do not work well with such targets. I do not have
experience with it and/or such a gdbserver setup.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-03-28 20:56 ` Jan Kratochvil
@ 2013-04-02 17:25 ` Aleksandar Ristovski
2013-04-02 17:32 ` Aleksandar Ristovski
` (2 more replies)
0 siblings, 3 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-02 17:25 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 37789 bytes --]
New patch attached. Details inlined below.
On 13-03-28 02:37 PM, Jan Kratochvil wrote:
> On Fri, 22 Mar 2013 14:12:18 +0100, Aleksandar Ristovski wrote:
>> (depends on the gdbserver changes:
>> http://sourceware.org/ml/gdb-patches/2013-03/msg00838.html)
>>
>> ChangeLog:
>>
>>
>> * 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_validate_build_id): New function.
>> (svr4_validate): New function.
>> (library_list_start_library): Parse 'build-id' attribute.
>> (svr4_library_pattributes): Add 'build-id' attribute.
>> (_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'.
>>
>>
>>
>> Test ChangeLog:
>> * 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.
>>
>>
>> Thanks,
>>
>> Aleksandar
>>
>
>> diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
>> index 2ebe2fe..2e950b6 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;
>
> I do not see why this override should be done. There is above:
> mips_svr4_so_ops = svr4_so_ops;
>
> so unless you have a specific reason why the verification cannot work for MIPS
> - and such reason should be put in a comment there - just remove these two
> '+' linse.
[AR] Ok. Removed.
>
>
>> 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;
>
> Likewise.
[AR] Ok.
>
>
>> 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 b9a4be1..b588f86 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 ea2acd1..c5f84f3 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 f646cfb..06749d0 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 = solib_validate;
>>
>> memset (&dld_cache, 0, sizeof (dld_cache));
>> }
>> diff --git a/gdb/solib-som.c b/gdb/solib-som.c
>> index ff7fbaa..0d68aac 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 7be5232..94b9a36 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;
>
> In whis case the override of SVR4_SO_OPS.VALIDATE seems as a safe bet, Ulrich
> Weigand could test if it works with SPU but for the initial check-in I find it
> OK as you wrote it.
[AR]. Ok. Change stays, but solib_validate is renamed to
default_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..9dd9cab 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)
>
> Such change is OK although it needs to be checked in separately.
[AR] Ok, separated.
>
>
>> {
>> 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)
>
> If you are used to it then OK but for GDB one does not have to make 'const'
> even the variables themselves ('so'), that does not bring much benefits.
> This is everywhere in the patch.
[AR] I consider it good practice much the same as const-qualifying local
vars.
>
>
>> +{
>> + asection *asect;
>> + int res = 1;
>> + size_t size;
>
> There are multiple sizes around, please call it "asect_size" or somehow
> similar to see this "size" is for the section.
[AR] Ok.
>
>
>> + const CORE_ADDR l_addr = lm_addr_check (so, so->abfd);
>
> Move this variable to the inner block where it is used, its computation
> possibly would not be used.
[AR] ok.
>
>
>> +
>> + 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)
>
> Coding style for pointer comparison according to doc/gdbinte.texinfo:
> if (asect == NULL || !so->lm_info->l_addr_p)
>
> But that l_addr_p check is not needed, drop it, lm_addr_check cannot fail,
> l_addr_p is only internal field for lm_addr_check.
[AR] Ok.
>
>
>> + {
>> + 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;
>
> You never set so->build_id anywhere so it will be always NULL.
>
> But in fact I do not see why there exists so->build_id at all. It is only
> verified once when loading the library and then if it remains loaded one can
> pick the build_id from elf_tdata (so->abfd)->build_id which has been already
> verified as matching.
>
> So just drop so->build_id, it is a duplcate to elf_tdata (so->abfd)->build_id.
[AR] I believe it is clearer by now, we need so->build_id as so->abfd
may be closed due to mismatch.
>
>
>
>> + 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. */
>
> I do not understand this comment but as the code will change I prefer
> a removal of the comment or a new/different comment.
[AR] ok. Comment removed. It wanted to say that this is load address, as
if the shared object was link-edited with base 0 (i.e. this is after
applying displacement).
>
>
>> + const CORE_ADDR sect_lma = l_addr + bfd_section_vma (so->abfd, asect);
>
> "lma" is irrelevant here, it needs to be VMA as you do runtime
> target_read_memory for that address.
[AR] I read "lma" as load memory address, i.e. address where it is
actually loaded. This is to differentiate load address from virtual
address as set by the link-editor.
>
> I won't argue if the expression is right or wrong but it at least looks as
> a duplication of computation done for target_section->addr:
>
> * Move the 'ops->validate (se)' call in solib_map_sections after the loop
> for (p = so->sections; p < so->sections_end; p++)
>
> * Then just use here the VMS address from so->sections but one needs to find
> it first:
> struct target_section *p;
> for (p = solib->sections; p < solib->sections_end; p++)
> if (p->the_bfd_section == asect)
> break;
> use p->addr
>
>
>> +
>> + /* 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);
>
> Remove the bfd_get_section_contents call completely,
> use elf_tdata (so->abfd)->build_id , there it is already read in and parsed.
>
>
>> +
>> + if (build_id == NULL)
>
> Here could be a comment - if it was intended so:
>
> /* Even if gdbserver failed to find the build-id read it by
> target_read_memory. */
>
>
>> + {
>> + build_idsz = size;
>> + build_id = xmalloc (size);
>> + make_cleanup (xfree, build_id);
>
> If you start to store the build-id to so->build_id then the xfree is no longer
> appropriate here.
[AR]
>
>
>> + if (target_read_memory (sect_lma, build_id, size) != 0)
>> + {
>> + build_id = NULL;
>> + res = -1;
>
> Return value -1 is not documented for this function; but see below.
>
>
>> + }
>> + }
>> +
>> + if (build_id != NULL)
>> + res = size == build_idsz
>> + && memcmp (build_id, data, size) == 0;
>
> The line does not need wrapping, it is under 80 columns:
> 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;
>
> When the variable is called 'res' then one expects it will be returned as is,
> therefore 'return res;'.
>
>
>> +}
>> +
>> +/* 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);
>> +}
>
> I do not see why there is this wrapper svr4_validate, you could just move
> those two gdb_assert to svr4_validate_build_id and use directly
> svr4_validate_build_id, it has no other caller anyway.
>
>
>> +
>> /* Implement the "open_symbol_file_object" target_so_ops method.
>>
>> If no open symbol file, attempt to locate and open the main symbol
>> @@ -999,7 +1080,11 @@ 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;
>> + size_t hex_build_id_len;
>
> Sometimes you call it "build_idsz" and sometimes "build_id_len", unify it.
> (I prefer the latter.)
>
>
>>
>> new_elem = XZALLOC (struct so_list);
>> new_elem->lm_info = XZALLOC (struct lm_info);
>> @@ -1010,6 +1095,21 @@ 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 && (hex_build_id_len = strlen (hex_build_id)) > 0)
>
> Do not use assignment this way, make it a separate line, see GNU Coding
> Standards:
> Try to avoid assignments inside if-conditions
>
>
>> + {
>> + new_elem->build_id = xmalloc (hex_build_id_len / 2 + 1);
>
> Why the '+ 1' here? NEW_ELEM->BUILD_ID is in binary form so there is no '\0'
> terminator.
>
>
>> + 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))
>
> Check it the opposite way:
> if (2 * new_elem->build_idsz != hex_build_id_len)
>
> as otherwise odd length of the "build-id" attribute string will not be caught
> as invalid.
>
>
>> + {
>> + warning (_("Gdbserver returned invalid hex encoded build_id '%s'"
> gdbserver build-id
>
>> + "(%zu/%zu)\n"),
>
> I would omit this (%zu/%zu) part. Primarily currently %z is not allowed as it
> is not compatible with some OSes, there is a plan to import %z printf support
> in gdb/gnulib/ but so far there wasn't a need for it.
>
> Besides that you should describe what the two numbers mean otherwise they are
> mostly useless. And after all when you already print the XML string the
> numbers do not add any more info to it.
>
>
>> + 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;
>
> I am not completely sure warning cannot throw, better to do these cleanups
> before the warning call (moreover when %zu/%zu will no longer be printed).
>
>
>> + }
>> + }
>>
>> *list->tailp = new_elem;
>> list->tailp = &new_elem->next;
>> @@ -1044,6 +1144,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 },
>
> There has to be be GDB_XML_EF_OPTIONAL.
>
>
>> { NULL, GDB_XML_AF_NONE, NULL, NULL }
>> };
>>
>> @@ -2458,4 +2559,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"
>
> I do not see used it anywhere.
>
>
>> +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id"
>
> It is used only in solib-svr4.c so it should be in that file.
>
>
>> +
>> 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."),
>
> Number of columns exceeds 80 characters.
>
>
>
> And move it under 'for (p = so->sections; p < so->sections_end; p++)' with the
> reasons described above.
>
>
>> + 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)
>
> Up to you but I would prefer "default_solib_validate", "solib_validate" name
> seems as if it does some validation.
>
>
>> +{
>> + return 1; /* No validation. */
>
> Formatting:
> /* No validation. */
> return 1;
>
>
>> +}
>> +
>> 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..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
> build-id
>
>> + .note.gnu.build-id including note header.
>
> It really should not contain the note header, it should be exactly 20 bytes
> with the standard build-id in place.
>
> I wanted to check it with gdbserver but gdbserver does not work for me due to
> those errors like:
>
> gdbserver: Error parsing {s,}maps file '/usr/lib64/libdl-2.17.so'^M
>
>
>> 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
>>
>
>> 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"
>
> Macros should use uppercased names.
[AR] ok.
>
>
>> +
>> +
>> +/* 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
>
> I do not see why this comment is here.
[AR] copy-paste; removed
>
>
>> +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
>
> Use specific text, like:
> untested "get_compiler_info failed."
[AR] ok.
>
>> +}
>> +
>> +# First version of the object, to be loaded by ld
>> +set srclibfilerun ${testfile}-lib.c
>
> Please make empty lines before comments.
>
[AR] ok.
>
>> +# 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}
>
> Use [standard_output_file ...], not ${objdir}.
>
[AR] ok.
>
>> +
>> +# Second solib version is in current directory, '-libmod' version.
>> +set binlibfiledirgdb ${objdir}/${subdir}
>
> Likewise.
>
>
>> +set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase}
>> +
>> +# Executeable
>> +set srcfile ${testfile}.c
>> +set executable ${testfile}
>> +set objfile ${objdir}/${subdir}/${executable}.o
> Likewise.
>> +set binfile ${objdir}/${subdir}/${executable}
> Likewise.
>> +
>> +send_user "Current WD: [eval pwd]\r\n"
>
> Testfiles must not print messages during normal run. Use "verbose -log" if needed.
>
> 3 times more below.
[AR] Ok, informative message incorporated in the PASS/FAIL/UNTESTED entry.
>
>
>> +
>> +file mkdir "${binlibfiledirrun}"
>> +
> Initialize it by:
> set exec_opts {}
> as IIRC regex testcases have persistent variables during one runtest run.
>
>> +if { ![istarget "*-*-nto-*"] } {
>> + set exec_opts [list debug shlib_load]
>> +}
>> +
>> +if { [prepare_for_testing $testfile.exp $executable $srcfile $exec_opts] != 0 } {
>> + untested ${testfile}.exp
>
> untested is not needed, prepare_for_testing complains on its own.
[AR] ok.
>
>
>> + 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
>
> Use specific message.
>
[AR] ok.
>
>> + 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
>
> use clean_restart
>
>
>> +
>> + send_gdb "set verbose 1\n"
>
> Never (only in some exceptional cases) use send_gdb, it creates races wrt
> syncing on end of the commands. Use gdb_test or gdb_test_no_output.
[AR] I very much dislike using gdb_test unless I actually am doing a
test. Otherwise, we end up with testcases that tend to have 30-40 passes
but only 2-3 relevant. Thus, when these 2-3 relevant ones start to FAIL
it is easy to neglect that due to false cozy feeling that, well, *most*
are still passing.
>
>
>> + send_gdb "file \"${binlibfiledirrun}/${executable}\"\n"
>
> Do not use "file" by hand, clean_restart does it.
[AR] ok.
>
>
>> + 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"
>
> Why is this command here? Could you put a comment there?
[AR] so that we can have control over when is the output printed and
match it correctly. I added the comment.
>
>
>> + 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"
>
> Do not use send_gdb and there is gdb_breakpoint function.
[AR] I am not testing setting breakpoints. I do not want these to show
up as PASS-es. These passes are irrelevant. The assumption is that
breakpoints do work; there are other tests for breakponts.
>
>
>> + 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"
>
> Use runto_main. And check its result code.
[AR] The same. I am not testing run to main. I am testing this
particular feature. There are other tests that test runto_main.
>
> Currently gdbserver (in non-extended mode) is never tested as "run" will never
> start gdbserver.
>
> After I fixed it I get from gdbserver messages like:
>
> gdbserver: Error parsing {s,}maps file '/home/jkratoch/redhat/gdb-qnx/gdb/testsuite/gdb.base/solib-mismatch'^M
>
>
>
>> + gdb_expect {
>> + -re "Starting program.*${gdb_prompt} $" {
>> + }
>> + default {
>> + untested "${testfile}: Failed to hit breakpoint at ${bp_location}"
>> + return -1
>> + }
>> + }
>> +
>> + send_gdb "sharedlibrary\n"
>
> Use gdb_test.
[AR] the same. Irrelevant PASS-es. I do not want them.
>
>> + 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}.*" \
> ^^
> BTW leading .* is excessive, gdb_test regex does not have anchored its start.
[AR] ok.
>
>
>> + "Symbols for ${solibfile} loaded: expected '${symsloaded}'"
>
> Protect ${symsloaded} by [string_to_regexp $string] as user
> may have regex-unsafe characters there.
[AR] symsloaded is argument passed to solib_matching_test, and the test
is the only user. Ther eare no other users, and the string may contain
only 'Yes' or 'No'.
>
>
>> +
>> + send_gdb "p/x foo\n"
>
> Use gdb_test.
>
>
>> + gdb_expect {
>> + -re ".*${gdb_prompt} $" {
>> +#Nothing, just drain the buffer
>> + }
>> + default {
>> + untested "${testfile}: Failed 'info symbol foo'"
>> + return -1
>> + }
>> + }
>> +
>> + send_gdb "detach\n"
>
> I do not see a need for this command, remove it.
>
>
>> + 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"
>
>
> The testcase is not safe for gdbserver targets not sharing the filesystem with
> the runtest machine. There are functions like gdb_download for it although
> AFAIK many GDB testcases do not work well with such targets. I do not have
> experience with it and/or such a gdbserver setup.
>
>
> Thanks,
> Jan
>
Thanks,
Aleksandar
[-- Attachment #2: 0007-Validate-symbol-file-using-build-id.patch --]
[-- Type: text/x-patch, Size: 15423 bytes --]
From b5796c9a30c81c35b9849094344f86d60a16e2c2 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: 10565 bytes --]
From d2a051a24105cb0396ca4056235e933dffbdea67 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 | 165 ++++++++++++++++++++++++
4 files changed, 291 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..47316b7
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-mismatch.exp
@@ -0,0 +1,165 @@
+# 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"]
+
+ send_gdb "tbreak ${srcfile}:${bp_location}\n"
+ gdb_expect {
+ -re "Temporary breakpoint.*${gdb_prompt} $" {
+ }
+ default {
+ untested "${msg} - Failed to set temp. breakpoint at ${bp_location}"
+ return -1
+ }
+ }
+
+ 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}.*" \
+ "${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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-02 17:25 ` Aleksandar Ristovski
@ 2013-04-02 17:32 ` Aleksandar Ristovski
2013-04-02 17:45 ` Jan Kratochvil
2013-04-04 3:16 ` Jan Kratochvil
2 siblings, 0 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-02 17:32 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 37789 bytes --]
New patch attached. Details inlined below.
On 13-03-28 02:37 PM, Jan Kratochvil wrote:
> On Fri, 22 Mar 2013 14:12:18 +0100, Aleksandar Ristovski wrote:
>> (depends on the gdbserver changes:
>> http://sourceware.org/ml/gdb-patches/2013-03/msg00838.html)
>>
>> ChangeLog:
>>
>>
>> * 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_validate_build_id): New function.
>> (svr4_validate): New function.
>> (library_list_start_library): Parse 'build-id' attribute.
>> (svr4_library_pattributes): Add 'build-id' attribute.
>> (_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'.
>>
>>
>>
>> Test ChangeLog:
>> * 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.
>>
>>
>> Thanks,
>>
>> Aleksandar
>>
>
>> diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
>> index 2ebe2fe..2e950b6 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;
>
> I do not see why this override should be done. There is above:
> mips_svr4_so_ops = svr4_so_ops;
>
> so unless you have a specific reason why the verification cannot work for MIPS
> - and such reason should be put in a comment there - just remove these two
> '+' linse.
[AR] Ok. Removed.
>
>
>> 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;
>
> Likewise.
[AR] Ok.
>
>
>> 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 b9a4be1..b588f86 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 ea2acd1..c5f84f3 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 f646cfb..06749d0 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 = solib_validate;
>>
>> memset (&dld_cache, 0, sizeof (dld_cache));
>> }
>> diff --git a/gdb/solib-som.c b/gdb/solib-som.c
>> index ff7fbaa..0d68aac 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 7be5232..94b9a36 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;
>
> In whis case the override of SVR4_SO_OPS.VALIDATE seems as a safe bet, Ulrich
> Weigand could test if it works with SPU but for the initial check-in I find it
> OK as you wrote it.
[AR]. Ok. Change stays, but solib_validate is renamed to
default_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..9dd9cab 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)
>
> Such change is OK although it needs to be checked in separately.
[AR] Ok, separated.
>
>
>> {
>> 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)
>
> If you are used to it then OK but for GDB one does not have to make 'const'
> even the variables themselves ('so'), that does not bring much benefits.
> This is everywhere in the patch.
[AR] I consider it good practice much the same as const-qualifying local
vars.
>
>
>> +{
>> + asection *asect;
>> + int res = 1;
>> + size_t size;
>
> There are multiple sizes around, please call it "asect_size" or somehow
> similar to see this "size" is for the section.
[AR] Ok.
>
>
>> + const CORE_ADDR l_addr = lm_addr_check (so, so->abfd);
>
> Move this variable to the inner block where it is used, its computation
> possibly would not be used.
[AR] ok.
>
>
>> +
>> + 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)
>
> Coding style for pointer comparison according to doc/gdbinte.texinfo:
> if (asect == NULL || !so->lm_info->l_addr_p)
>
> But that l_addr_p check is not needed, drop it, lm_addr_check cannot fail,
> l_addr_p is only internal field for lm_addr_check.
[AR] Ok.
>
>
>> + {
>> + 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;
>
> You never set so->build_id anywhere so it will be always NULL.
>
> But in fact I do not see why there exists so->build_id at all. It is only
> verified once when loading the library and then if it remains loaded one can
> pick the build_id from elf_tdata (so->abfd)->build_id which has been already
> verified as matching.
>
> So just drop so->build_id, it is a duplcate to elf_tdata (so->abfd)->build_id.
[AR] I believe it is clearer by now, we need so->build_id as so->abfd
may be closed due to mismatch.
>
>
>
>> + 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. */
>
> I do not understand this comment but as the code will change I prefer
> a removal of the comment or a new/different comment.
[AR] ok. Comment removed. It wanted to say that this is load address, as
if the shared object was link-edited with base 0 (i.e. this is after
applying displacement).
>
>
>> + const CORE_ADDR sect_lma = l_addr + bfd_section_vma (so->abfd, asect);
>
> "lma" is irrelevant here, it needs to be VMA as you do runtime
> target_read_memory for that address.
[AR] I read "lma" as load memory address, i.e. address where it is
actually loaded. This is to differentiate load address from virtual
address as set by the link-editor.
>
> I won't argue if the expression is right or wrong but it at least looks as
> a duplication of computation done for target_section->addr:
>
> * Move the 'ops->validate (se)' call in solib_map_sections after the loop
> for (p = so->sections; p < so->sections_end; p++)
>
> * Then just use here the VMS address from so->sections but one needs to find
> it first:
> struct target_section *p;
> for (p = solib->sections; p < solib->sections_end; p++)
> if (p->the_bfd_section == asect)
> break;
> use p->addr
>
>
>> +
>> + /* 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);
>
> Remove the bfd_get_section_contents call completely,
> use elf_tdata (so->abfd)->build_id , there it is already read in and parsed.
>
>
>> +
>> + if (build_id == NULL)
>
> Here could be a comment - if it was intended so:
>
> /* Even if gdbserver failed to find the build-id read it by
> target_read_memory. */
>
>
>> + {
>> + build_idsz = size;
>> + build_id = xmalloc (size);
>> + make_cleanup (xfree, build_id);
>
> If you start to store the build-id to so->build_id then the xfree is no longer
> appropriate here.
[AR]
>
>
>> + if (target_read_memory (sect_lma, build_id, size) != 0)
>> + {
>> + build_id = NULL;
>> + res = -1;
>
> Return value -1 is not documented for this function; but see below.
>
>
>> + }
>> + }
>> +
>> + if (build_id != NULL)
>> + res = size == build_idsz
>> + && memcmp (build_id, data, size) == 0;
>
> The line does not need wrapping, it is under 80 columns:
> 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;
>
> When the variable is called 'res' then one expects it will be returned as is,
> therefore 'return res;'.
>
>
>> +}
>> +
>> +/* 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);
>> +}
>
> I do not see why there is this wrapper svr4_validate, you could just move
> those two gdb_assert to svr4_validate_build_id and use directly
> svr4_validate_build_id, it has no other caller anyway.
>
>
>> +
>> /* Implement the "open_symbol_file_object" target_so_ops method.
>>
>> If no open symbol file, attempt to locate and open the main symbol
>> @@ -999,7 +1080,11 @@ 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;
>> + size_t hex_build_id_len;
>
> Sometimes you call it "build_idsz" and sometimes "build_id_len", unify it.
> (I prefer the latter.)
>
>
>>
>> new_elem = XZALLOC (struct so_list);
>> new_elem->lm_info = XZALLOC (struct lm_info);
>> @@ -1010,6 +1095,21 @@ 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 && (hex_build_id_len = strlen (hex_build_id)) > 0)
>
> Do not use assignment this way, make it a separate line, see GNU Coding
> Standards:
> Try to avoid assignments inside if-conditions
>
>
>> + {
>> + new_elem->build_id = xmalloc (hex_build_id_len / 2 + 1);
>
> Why the '+ 1' here? NEW_ELEM->BUILD_ID is in binary form so there is no '\0'
> terminator.
>
>
>> + 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))
>
> Check it the opposite way:
> if (2 * new_elem->build_idsz != hex_build_id_len)
>
> as otherwise odd length of the "build-id" attribute string will not be caught
> as invalid.
>
>
>> + {
>> + warning (_("Gdbserver returned invalid hex encoded build_id '%s'"
> gdbserver build-id
>
>> + "(%zu/%zu)\n"),
>
> I would omit this (%zu/%zu) part. Primarily currently %z is not allowed as it
> is not compatible with some OSes, there is a plan to import %z printf support
> in gdb/gnulib/ but so far there wasn't a need for it.
>
> Besides that you should describe what the two numbers mean otherwise they are
> mostly useless. And after all when you already print the XML string the
> numbers do not add any more info to it.
>
>
>> + 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;
>
> I am not completely sure warning cannot throw, better to do these cleanups
> before the warning call (moreover when %zu/%zu will no longer be printed).
>
>
>> + }
>> + }
>>
>> *list->tailp = new_elem;
>> list->tailp = &new_elem->next;
>> @@ -1044,6 +1144,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 },
>
> There has to be be GDB_XML_EF_OPTIONAL.
>
>
>> { NULL, GDB_XML_AF_NONE, NULL, NULL }
>> };
>>
>> @@ -2458,4 +2559,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"
>
> I do not see used it anywhere.
>
>
>> +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id"
>
> It is used only in solib-svr4.c so it should be in that file.
>
>
>> +
>> 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."),
>
> Number of columns exceeds 80 characters.
>
>
>
> And move it under 'for (p = so->sections; p < so->sections_end; p++)' with the
> reasons described above.
>
>
>> + 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)
>
> Up to you but I would prefer "default_solib_validate", "solib_validate" name
> seems as if it does some validation.
>
>
>> +{
>> + return 1; /* No validation. */
>
> Formatting:
> /* No validation. */
> return 1;
>
>
>> +}
>> +
>> 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..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
> build-id
>
>> + .note.gnu.build-id including note header.
>
> It really should not contain the note header, it should be exactly 20 bytes
> with the standard build-id in place.
>
> I wanted to check it with gdbserver but gdbserver does not work for me due to
> those errors like:
>
> gdbserver: Error parsing {s,}maps file '/usr/lib64/libdl-2.17.so'^M
>
>
>> 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
>>
>
>> 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"
>
> Macros should use uppercased names.
[AR] ok.
>
>
>> +
>> +
>> +/* 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
>
> I do not see why this comment is here.
[AR] copy-paste; removed
>
>
>> +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
>
> Use specific text, like:
> untested "get_compiler_info failed."
[AR] ok.
>
>> +}
>> +
>> +# First version of the object, to be loaded by ld
>> +set srclibfilerun ${testfile}-lib.c
>
> Please make empty lines before comments.
>
[AR] ok.
>
>> +# 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}
>
> Use [standard_output_file ...], not ${objdir}.
>
[AR] ok.
>
>> +
>> +# Second solib version is in current directory, '-libmod' version.
>> +set binlibfiledirgdb ${objdir}/${subdir}
>
> Likewise.
>
>
>> +set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase}
>> +
>> +# Executeable
>> +set srcfile ${testfile}.c
>> +set executable ${testfile}
>> +set objfile ${objdir}/${subdir}/${executable}.o
> Likewise.
>> +set binfile ${objdir}/${subdir}/${executable}
> Likewise.
>> +
>> +send_user "Current WD: [eval pwd]\r\n"
>
> Testfiles must not print messages during normal run. Use "verbose -log" if needed.
>
> 3 times more below.
[AR] Ok, informative message incorporated in the PASS/FAIL/UNTESTED entry.
>
>
>> +
>> +file mkdir "${binlibfiledirrun}"
>> +
> Initialize it by:
> set exec_opts {}
> as IIRC regex testcases have persistent variables during one runtest run.
>
>> +if { ![istarget "*-*-nto-*"] } {
>> + set exec_opts [list debug shlib_load]
>> +}
>> +
>> +if { [prepare_for_testing $testfile.exp $executable $srcfile $exec_opts] != 0 } {
>> + untested ${testfile}.exp
>
> untested is not needed, prepare_for_testing complains on its own.
[AR] ok.
>
>
>> + 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
>
> Use specific message.
>
[AR] ok.
>
>> + 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
>
> use clean_restart
>
>
>> +
>> + send_gdb "set verbose 1\n"
>
> Never (only in some exceptional cases) use send_gdb, it creates races wrt
> syncing on end of the commands. Use gdb_test or gdb_test_no_output.
[AR] I very much dislike using gdb_test unless I actually am doing a
test. Otherwise, we end up with testcases that tend to have 30-40 passes
but only 2-3 relevant. Thus, when these 2-3 relevant ones start to FAIL
it is easy to neglect that due to false cozy feeling that, well, *most*
are still passing.
>
>
>> + send_gdb "file \"${binlibfiledirrun}/${executable}\"\n"
>
> Do not use "file" by hand, clean_restart does it.
[AR] ok.
>
>
>> + 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"
>
> Why is this command here? Could you put a comment there?
[AR] so that we can have control over when is the output printed and
match it correctly. I added the comment.
>
>
>> + 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"
>
> Do not use send_gdb and there is gdb_breakpoint function.
[AR] I am not testing setting breakpoints. I do not want these to show
up as PASS-es. These passes are irrelevant. The assumption is that
breakpoints do work; there are other tests for breakponts.
>
>
>> + 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"
>
> Use runto_main. And check its result code.
[AR] The same. I am not testing run to main. I am testing this
particular feature. There are other tests that test runto_main.
>
> Currently gdbserver (in non-extended mode) is never tested as "run" will never
> start gdbserver.
>
> After I fixed it I get from gdbserver messages like:
>
> gdbserver: Error parsing {s,}maps file '/home/jkratoch/redhat/gdb-qnx/gdb/testsuite/gdb.base/solib-mismatch'^M
>
>
>
>> + gdb_expect {
>> + -re "Starting program.*${gdb_prompt} $" {
>> + }
>> + default {
>> + untested "${testfile}: Failed to hit breakpoint at ${bp_location}"
>> + return -1
>> + }
>> + }
>> +
>> + send_gdb "sharedlibrary\n"
>
> Use gdb_test.
[AR] the same. Irrelevant PASS-es. I do not want them.
>
>> + 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}.*" \
> ^^
> BTW leading .* is excessive, gdb_test regex does not have anchored its start.
[AR] ok.
>
>
>> + "Symbols for ${solibfile} loaded: expected '${symsloaded}'"
>
> Protect ${symsloaded} by [string_to_regexp $string] as user
> may have regex-unsafe characters there.
[AR] symsloaded is argument passed to solib_matching_test, and the test
is the only user. Ther eare no other users, and the string may contain
only 'Yes' or 'No'.
>
>
>> +
>> + send_gdb "p/x foo\n"
>
> Use gdb_test.
>
>
>> + gdb_expect {
>> + -re ".*${gdb_prompt} $" {
>> +#Nothing, just drain the buffer
>> + }
>> + default {
>> + untested "${testfile}: Failed 'info symbol foo'"
>> + return -1
>> + }
>> + }
>> +
>> + send_gdb "detach\n"
>
> I do not see a need for this command, remove it.
>
>
>> + 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"
>
>
> The testcase is not safe for gdbserver targets not sharing the filesystem with
> the runtest machine. There are functions like gdb_download for it although
> AFAIK many GDB testcases do not work well with such targets. I do not have
> experience with it and/or such a gdbserver setup.
>
>
> Thanks,
> Jan
>
Thanks,
Aleksandar
[-- Attachment #2: 0007-Validate-symbol-file-using-build-id.patch --]
[-- Type: text/x-patch, Size: 15423 bytes --]
From b5796c9a30c81c35b9849094344f86d60a16e2c2 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: 10565 bytes --]
From d2a051a24105cb0396ca4056235e933dffbdea67 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 | 165 ++++++++++++++++++++++++
4 files changed, 291 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..47316b7
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-mismatch.exp
@@ -0,0 +1,165 @@
+# 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"]
+
+ send_gdb "tbreak ${srcfile}:${bp_location}\n"
+ gdb_expect {
+ -re "Temporary breakpoint.*${gdb_prompt} $" {
+ }
+ default {
+ untested "${msg} - Failed to set temp. breakpoint at ${bp_location}"
+ return -1
+ }
+ }
+
+ 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}.*" \
+ "${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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-02 17:25 ` Aleksandar Ristovski
2013-04-02 17:32 ` Aleksandar Ristovski
@ 2013-04-02 17:45 ` Jan Kratochvil
2013-04-02 18:02 ` Aleksandar Ristovski
2013-04-04 3:16 ` Jan Kratochvil
2 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-02 17:45 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
Hi Aleksandar,
just some obvious issues of the testsuite first:
On Tue, 02 Apr 2013 18:24:18 +0200, Aleksandar Ristovski wrote:
> >>+ send_gdb "set verbose 1\n"
> >
> >Never (only in some exceptional cases) use send_gdb, it creates races wrt
> >syncing on end of the commands. Use gdb_test or gdb_test_no_output.
>
> [AR] I very much dislike using gdb_test unless I actually am doing a
> test. Otherwise, we end up with testcases that tend to have 30-40
> passes but only 2-3 relevant. Thus, when these 2-3 relevant ones
> start to FAIL it is easy to neglect that due to false cozy feeling
> that, well, *most* are still passing.
* Even a single PASS->FAIL can be a serious GDB regression.
* There are still many racy testcases (with "random" results).
* Therefore comparing any PASS/FAIL counts is irrelevant, only diff matters.
Besides that send_gdb really does not work, it does not read the "(gdb) "
response will confuse the later first test which does wait for a response.
If you do not like trivial testcase names then just use:
gdb_test_no_output "command" ""
or
gdb_test "command" "response" ""
GDB testsuite handles testcase name "" by omitting it from the output.
> >>+ send_gdb "tbreak ${srcfile}:${bp_location}\n"
> >
> >Do not use send_gdb and there is gdb_breakpoint function.
>
> [AR] I am not testing setting breakpoints. I do not want these to
> show up as PASS-es. These passes are irrelevant. The assumption is
> that breakpoints do work; there are other tests for breakponts.
gdb_breakpoint does not produce any PASS message when it succeeds.
But it will FAIL if a problem occured.
> >>+ send_gdb "run\r\n"
> >
> >Use runto_main. And check its result code.
>
> [AR] The same. I am not testing run to main. I am testing this
> particular feature. There are other tests that test runto_main.
Again, successful runto_main does not produce any PASS message.
> >>+ gdb_test "info sharedlibrary ${solibfile}" \
> >>+ ".*From.*To.*Syms.*Read.*Shared.*\r\n.*${symsloaded}.*" \
> > ^^
> >BTW leading .* is excessive, gdb_test regex does not have anchored its start.
>
> [AR] ok.
>
> >
> >
> >>+ "Symbols for ${solibfile} loaded: expected '${symsloaded}'"
> >
> >Protect ${symsloaded} by [string_to_regexp $string] as user
> >may have regex-unsafe characters there.
>
> [AR] symsloaded is argument passed to solib_matching_test, and the
> test is the only user. Ther eare no other users, and the string may
> contain only 'Yes' or 'No'.
OK, I did not notice, I agree string_to_regexp is not needed there.
But when you expect only one shared library make the expectation explicit,
both for a single line and for ${binlibfilebase}.
gdb_test "info sharedlibrary ${solibfile}" \
"From\[^\r\n\]*To\[^\r\n\]*Syms\[^\r\n\]*Read\[^\r\n\]*Shared\[^\r\n\]*\r\n\[^\r\n\]*${symsloaded}\[^\r\n\]*[string_to_regexp ${binlibfilebase}]" \
(I did not test this regex.)
I can very well imagine GDB could print >= 2 lines or a line without
${binlibfilebase} there which could make false PASS.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-02 17:45 ` Jan Kratochvil
@ 2013-04-02 18:02 ` Aleksandar Ristovski
2013-04-03 18:52 ` Jan Kratochvil
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-02 18:02 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-04-02 12:53 PM, Jan Kratochvil wrote:
> Hi Aleksandar,
>
> just some obvious issues of the testsuite first:
>
>
> On Tue, 02 Apr 2013 18:24:18 +0200, Aleksandar Ristovski wrote:
>>>> + send_gdb "set verbose 1\n"
>>>
>>> Never (only in some exceptional cases) use send_gdb, it creates races wrt
>>> syncing on end of the commands. Use gdb_test or gdb_test_no_output.
>>
>> [AR] I very much dislike using gdb_test unless I actually am doing a
>> test. Otherwise, we end up with testcases that tend to have 30-40
>> passes but only 2-3 relevant. Thus, when these 2-3 relevant ones
>> start to FAIL it is easy to neglect that due to false cozy feeling
>> that, well, *most* are still passing.
>
> * Even a single PASS->FAIL can be a serious GDB regression.
> * There are still many racy testcases (with "random" results).
> * Therefore comparing any PASS/FAIL counts is irrelevant, only diff matters.
>
> Besides that send_gdb really does not work, it does not read the "(gdb) "
> response will confuse the later first test which does wait for a response.
[AR]
Ok, it's been a while since I looked at gdb.exp closely, and
'no-message' was added since. Changed the test as so:
@@ -93,15 +93,7 @@ proc solib_matching_test { solibfile symsloaded msg } {
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 "${msg} - Failed to set temp. breakpoint at ${bp_location}"
- return -1
- }
- }
+ gdb_breakpoint ${srcfile}:${bp_location} temporary no-message
gdb_run_cmd { ${binlibfiledirrun} }
gdb_expect {
>
> If you do not like trivial testcase names then just use:
> gdb_test_no_output "command" ""
> or
> gdb_test "command" "response" ""
> GDB testsuite handles testcase name "" by omitting it from the output.
>
>
>>>> + send_gdb "tbreak ${srcfile}:${bp_location}\n"
>>>
>>> Do not use send_gdb and there is gdb_breakpoint function.
>>
>> [AR] I am not testing setting breakpoints. I do not want these to
>> show up as PASS-es. These passes are irrelevant. The assumption is
>> that breakpoints do work; there are other tests for breakponts.
>
> gdb_breakpoint does not produce any PASS message when it succeeds.
> But it will FAIL if a problem occured.
>
>
>>>> + send_gdb "run\r\n"
>>>
>>> Use runto_main. And check its result code.
>>
>> [AR] The same. I am not testing run to main. I am testing this
>> particular feature. There are other tests that test runto_main.
>
> Again, successful runto_main does not produce any PASS message.
[AR]
It does produce PASS (see gdb.exp, lines 476-488), but this comment is
not relevant as test does not use 'run' any more, it uses gdb_run_cmd;
it does not need to stop at main, just run to the line it wants.
>
>
>>>> + gdb_test "info sharedlibrary ${solibfile}" \
>>>> + ".*From.*To.*Syms.*Read.*Shared.*\r\n.*${symsloaded}.*" \
>>> ^^
>>> BTW leading .* is excessive, gdb_test regex does not have anchored its start.
>>
>> [AR] ok.
>>
>>>
>>>
>>>> + "Symbols for ${solibfile} loaded: expected '${symsloaded}'"
>>>
>>> Protect ${symsloaded} by [string_to_regexp $string] as user
>>> may have regex-unsafe characters there.
>>
>> [AR] symsloaded is argument passed to solib_matching_test, and the
>> test is the only user. Ther eare no other users, and the string may
>> contain only 'Yes' or 'No'.
>
> OK, I did not notice, I agree string_to_regexp is not needed there.
>
> But when you expect only one shared library make the expectation explicit,
> both for a single line and for ${binlibfilebase}.
>
> gdb_test "info sharedlibrary ${solibfile}" \
> "From\[^\r\n\]*To\[^\r\n\]*Syms\[^\r\n\]*Read\[^\r\n\]*Shared\[^\r\n\]*\r\n\[^\r\n\]*${symsloaded}\[^\r\n\]*[string_to_regexp ${binlibfilebase}]" \
> (I did not test this regex.)
>
> I can very well imagine GDB could print >= 2 lines or a line without
> ${binlibfilebase} there which could make false PASS.
[AR] How can it print >= 2 lines? I will augument regex to explicitly
look for ${solibfile}
@@ -124,7 +124,7 @@ proc solib_matching_test { solibfile symsloaded msg } {
}
gdb_test "info sharedlibrary ${solibfile}" \
- "From.*To.*Syms.*Read.*Shared.*\r\n.*${symsloaded}.*" \
+ "From.*To.*Syms.*Read.*Shared.*\r\n.*${symsloaded}.*${solibfile}.*" \
"${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'"
return 0
}
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-02 18:02 ` Aleksandar Ristovski
@ 2013-04-03 18:52 ` Jan Kratochvil
2013-04-04 11:07 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-03 18:52 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Tue, 02 Apr 2013 19:18:09 +0200, Aleksandar Ristovski wrote:
> [AR]
> Ok, it's been a while since I looked at gdb.exp closely, and
> 'no-message' was added since. Changed the test as so:
>
> @@ -93,15 +93,7 @@ proc solib_matching_test { solibfile symsloaded msg } {
>
> 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 "${msg} - Failed to set temp. breakpoint at ${bp_location}"
> - return -1
> - }
> - }
> + gdb_breakpoint ${srcfile}:${bp_location} temporary no-message
"no-message" should not be used there, there should be just:
gdb_breakpoint ${srcfile}:${bp_location} temporary
Copy-pasting here the comment of gdb_break from lib/gdb.exp:
# Note: The handling of message vs no-message is messed up, but it's based
# on historical usage. By default this function does not print passes,
# only fails.
# no-message: turns off printing of fails (and passes, but they're already off)
# message: turns on printing of passes (and fails, but they're already on)
I have even verified now the behavior really fully corresponds to this comment.
You do not want to suppress FAIL if ${srcfile}:${bp_location} is not found.
> >Again, successful runto_main does not produce any PASS message.
>
>
> [AR]
> It does produce PASS (see gdb.exp, lines 476-488),
It does not, runto has the same parameters and behavior as gdb_breakpoint.
On those lines is:
if { $print_pass } {
pass $test_name
}
But $print_pass is true only if "message" parameter was specified, "message"
parameter should not be specified.
> but this comment is not relevant as test does not use 'run' any more, it
> uses gdb_run_cmd; it does not need to stop at main, just run to the line it
> wants.
There is now:
+ 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
+ }
+ }
Never use gdb_expect, there is gdb_test_multiple for such cases which
automatically handles various errors, that "default" case is not needed there.
But here even gdb_test_multiple is not needed, use just:
gdb_run_cmd { ${binlibfiledirrun} }
gdb_test "" "set breakpoint 1 here.*" ""
First empty parameter of gdb_test does not send anything, even no newline.
> >But when you expect only one shared library make the expectation explicit,
> >both for a single line and for ${binlibfilebase}.
> >
> > gdb_test "info sharedlibrary ${solibfile}" \
> > "From\[^\r\n\]*To\[^\r\n\]*Syms\[^\r\n\]*Read\[^\r\n\]*Shared\[^\r\n\]*\r\n\[^\r\n\]*${symsloaded}\[^\r\n\]*[string_to_regexp ${binlibfilebase}]" \
> > (I did not test this regex.)
> >
> >I can very well imagine GDB could print >= 2 lines or a line without
> >${binlibfilebase} there which could make false PASS.
>
> [AR] How can it print >= 2 lines?
For example when "set auto-solib-add off" starts to behave differently and for
example vDSO get still displayed (if they get displayed) etc.
> I will augument regex to explicitly look for ${solibfile}
This will not work as if there are >= 2 lines ${symsloaded} may match on one
line and ${solibfile} may match on a different line.
>
> @@ -124,7 +124,7 @@ proc solib_matching_test { solibfile symsloaded msg } {
> }
>
> gdb_test "info sharedlibrary ${solibfile}" \
> - "From.*To.*Syms.*Read.*Shared.*\r\n.*${symsloaded}.*" \
> + "From.*To.*Syms.*Read.*Shared.*\r\n.*${symsloaded}.*${solibfile}.*" \
> "${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'"
> return 0
> }
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-02 17:25 ` Aleksandar Ristovski
2013-04-02 17:32 ` Aleksandar Ristovski
2013-04-02 17:45 ` Jan Kratochvil
@ 2013-04-04 3:16 ` Jan Kratochvil
2 siblings, 0 replies; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-04 3:16 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Tue, 02 Apr 2013 18:24:18 +0200, Aleksandar Ristovski wrote:
> >>+ const CORE_ADDR sect_lma = l_addr + bfd_section_vma (so->abfd, asect);
> >
> >"lma" is irrelevant here, it needs to be VMA as you do runtime
> >target_read_memory for that address.
>
> [AR] I read "lma" as load memory address, i.e. address where it is
> actually loaded. This is to differentiate load address from virtual
> address as set by the link-editor.
It is no longer in the code but LMA was confusing, LMA is an established term
in bfd scope with a different meaning:
$ info '(ld)Output Section LMA'
This is not yet a full review.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-03 18:52 ` Jan Kratochvil
@ 2013-04-04 11:07 ` Aleksandar Ristovski
2013-04-04 13:30 ` Jan Kratochvil
0 siblings, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-04 11:07 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
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.
The chunk of code that is in svr4_relocate_section_addresses in the
latest version of the patch needs to go back to svr4_validate, and not
store build-id.
Ideally, however, build id would be read from target memory phdrs, not
from bfd.
Main complication, of course, is that due to missing load base for a
shared object, this becomes target os specific. On Neutrino, it is
straight forward, but on gnu it requires parsing smaps.
So, I'm thinking that linux-nat should be taught to return
TARGET_OBJECT_LIBRARIES_SVR4, and also augument gdbserver to return load
base.
i.e. gdbserver would return, in addition to what it already does, a
mandatory attribute "load_base".
If a native implementation does not support
TARGET_OBJECT_LIBRARIES_SVR4, build-id is not checked.
Thoughts?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-04 11:07 ` Aleksandar Ristovski
@ 2013-04-04 13:30 ` Jan Kratochvil
2013-04-04 17:15 ` Aleksandar Ristovski
0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-04 13:30 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
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 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.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-04 13:30 ` Jan Kratochvil
@ 2013-04-04 17:15 ` Aleksandar Ristovski
2013-04-04 18:11 ` Aleksandar Ristovski
` (3 more replies)
0 siblings, 4 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-04 17:15 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-04 17:15 ` Aleksandar Ristovski
@ 2013-04-04 18:11 ` Aleksandar Ristovski
2013-04-05 13:03 ` Jan Kratochvil
` (2 subsequent siblings)
3 siblings, 0 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-04 18:11 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-04 17:15 ` Aleksandar Ristovski
2013-04-04 18:11 ` Aleksandar Ristovski
@ 2013-04-05 13:03 ` Jan Kratochvil
2013-04-05 16:08 ` Aleksandar Ristovski
2013-04-08 18:54 ` Pedro Alves
2013-04-05 15:05 ` Aleksandar Ristovski
2013-04-07 5:54 ` Jan Kratochvil
3 siblings, 2 replies; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-05 13:03 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Thu, 04 Apr 2013 15:03:05 +0200, Aleksandar Ristovski wrote:
> The problem is, we could 'remember' build-id that is garbage.
Where/how?
In gdbserver mode gdbserver sends really the build-id of target library.
Therefore at GDB so_list->build_id - if set - is also always right (for the
target side). GDB then uses elf_tdata (so->abfd)->build_id for the comparison
which is also always right on the GDB side.
In solib-svr4 mode GDB uses target_read_memory for an address found from the
symbol file. This may read a garbage but that garbage is never stored
anywhere, it is only local variable in svr4_validate_build_id. It compares it
with elf_tdata (so->abfd)->build_id which is always right for the symbol file.
> 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).
I do not understand this paragraph after my reply above.
> 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;
I was talking about linux-nat to differentiate it from gdbserver. But in fact
the non-gdbserver (local) patchset part is in solib-svr4.c, not linux-nat.c.
Only that commonly when one uses the local part of solib-svr4.c one is using
linux-nat.c that time - but one could be using for example sparc-sol2-nat.c
instead.
As discussed before solib-svr4.c is not Linux-specific, therefore it does not
and cannot read /proc/PID/maps. Therefore it cannot find the ELF header
without getting a help from the symbol file (which will give the address
difference between ELF header and DYNAMIC segment which we know from l_ld).
At least I have never found a way how to reliably find the ELF header from
link_map entry without having an associated symbol file.
This is why gdbserver (using linux-low.c which IS Linux specific) situation is
very different from the non-gdbserver local (using solib-svr4.c which is
OS-independent) situation.
Sure one could make a Linux-specific local solib-*.c backend but the current
plan is to drop all (in reality just some) *-nat.c files in the favor of
always using gdbserver.
> in fact this could be the same code;
Really could not, see above. The local solib-svr4.c mode should not exist but
it unfortunately still needs to be kept live as gdbserver is not fully
feature-by-feature matching linux-nat.c:
http://sourceware.org/gdb/wiki/LocalRemoteFeatureParity
> 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.
Unfortunately could not.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-04 17:15 ` Aleksandar Ristovski
2013-04-04 18:11 ` Aleksandar Ristovski
2013-04-05 13:03 ` Jan Kratochvil
@ 2013-04-05 15:05 ` Aleksandar Ristovski
2013-04-07 10:24 ` Aleksandar Ristovski
2013-04-08 18:32 ` Jan Kratochvil
2013-04-07 5:54 ` Jan Kratochvil
3 siblings, 2 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-05 15:05 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches
[-- 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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-05 13:03 ` Jan Kratochvil
@ 2013-04-05 16:08 ` Aleksandar Ristovski
2013-04-07 6:06 ` Jan Kratochvil
2013-04-08 18:54 ` Pedro Alves
1 sibling, 1 reply; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-05 16:08 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-04-05 07:47 AM, Jan Kratochvil wrote:
> On Thu, 04 Apr 2013 15:03:05 +0200, Aleksandar Ristovski wrote:
>> The problem is, we could 'remember' build-id that is garbage.
>
> Where/how?
>
> In gdbserver mode gdbserver sends really the build-id of target library.
> Therefore at GDB so_list->build_id - if set - is also always right (for the
> target side). GDB then uses elf_tdata (so->abfd)->build_id for the comparison
> which is also always right on the GDB side.
Correct.
>
> In solib-svr4 mode GDB uses target_read_memory for an address found from the
> symbol file. This may read a garbage but that garbage is never stored
> anywhere, it is only local variable in svr4_validate_build_id. It compares it
> with elf_tdata (so->abfd)->build_id which is always right for the symbol file.
It is stored in the latest patch, in build-id.
>
>
>> 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).
>
> I do not understand this paragraph after my reply above.
See my comment above.
>
>
>> 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;
>
> I was talking about linux-nat to differentiate it from gdbserver. But in fact
> the non-gdbserver (local) patchset part is in solib-svr4.c, not linux-nat.c.
> Only that commonly when one uses the local part of solib-svr4.c one is using
> linux-nat.c that time - but one could be using for example sparc-sol2-nat.c
> instead.
What I am suggesting is that linux-nat (and any other *-nat) should
implement TARGET_OBJECT_LIBRARIES_SVR4.
>
> As discussed before solib-svr4.c is not Linux-specific, therefore it does not
> and cannot read /proc/PID/maps. Therefore it cannot find the ELF header
> without getting a help from the symbol file (which will give the address
> difference between ELF header and DYNAMIC segment which we know from l_ld).
> At least I have never found a way how to reliably find the ELF header from
> link_map entry without having an associated symbol file.
Exactly, see above.
>
> This is why gdbserver (using linux-low.c which IS Linux specific) situation is
> very different from the non-gdbserver local (using solib-svr4.c which is
> OS-independent) situation.
>
> Sure one could make a Linux-specific local solib-*.c backend but the current
> plan is to drop all (in reality just some) *-nat.c files in the favor of
> always using gdbserver.
>
>
>> in fact this could be the same code;
>
> Really could not, see above. The local solib-svr4.c mode should not exist but
> it unfortunately still needs to be kept live as gdbserver is not fully
> feature-by-feature matching linux-nat.c:
> http://sourceware.org/gdb/wiki/LocalRemoteFeatureParity
I don't think you are following me, but hopefully my comments above
clarify it.
>
>
>> 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.
>
> Unfortunately could not.
>
>
> Thanks,
> Jan
>
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-04 17:15 ` Aleksandar Ristovski
` (2 preceding siblings ...)
2013-04-05 15:05 ` Aleksandar Ristovski
@ 2013-04-07 5:54 ` Jan Kratochvil
3 siblings, 0 replies; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-07 5:54 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Thu, 04 Apr 2013 15:03:05 +0200, Aleksandar Ristovski wrote:
> The problem is, we could 'remember' build-id that is garbage.
[...]
On Fri, 05 Apr 2013 15:06:36 +0200, Aleksandar Ristovski wrote:
> It is stored in the latest patch, in build-id.
OK, true with the new patch.
The problem is there is:
xfree (so->build_id);
in free_so() but it should be in free_so_symbols instead. free_so_symbols is
called also from reload_shared_libraries_1 where so_list->abfd can change.
Then obviously one should also set so->build_id = NULL there.
I was thinking making the BUILD_ID data private so solib-svr4.c but that is
currently not possible, lm_info is private for solib-svr4.c but that has
lifetime of so_list, not the lifetime of so_list->abfd.
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-05 16:08 ` Aleksandar Ristovski
@ 2013-04-07 6:06 ` Jan Kratochvil
0 siblings, 0 replies; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-07 6:06 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches, Gary Benson
On Fri, 05 Apr 2013 15:06:36 +0200, Aleksandar Ristovski wrote:
> On 13-04-05 07:47 AM, Jan Kratochvil wrote:
> > I was talking about linux-nat to differentiate it from gdbserver. But in fact
> > the non-gdbserver (local) patchset part is in solib-svr4.c, not linux-nat.c.
> > Only that commonly when one uses the local part of solib-svr4.c one is using
> > linux-nat.c that time - but one could be using for example sparc-sol2-nat.c
> > instead.
>
> What I am suggesting is that linux-nat (and any other *-nat) should
> implement TARGET_OBJECT_LIBRARIES_SVR4.
That seems as a great idea, I somehow completely missed that. It should be
enough to implement it to linux-nat (by moving the gdbserver/linux-low.c
implementation to gdb/common/ ), other *-nat targets can implement later if
they want to.
Would you like to check in your patch as is or to rebase it on top of the
TARGET_OBJECT_LIBRARIES_SVR4-only implementation? I do not think too big part
of your patch is affected by it, though. The linux-nat
TARGET_OBJECT_LIBRARIES_SVR4 part should be done quickly I hope.
This may even unify more the Gary's patch, although he has already the
solib-svr4.c part complete.
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-05 15:05 ` Aleksandar Ristovski
@ 2013-04-07 10:24 ` Aleksandar Ristovski
2013-04-08 18:32 ` Jan Kratochvil
1 sibling, 0 replies; 47+ messages in thread
From: Aleksandar Ristovski @ 2013-04-07 10:24 UTC (permalink / raw)
To: gdb-patches; +Cc: Jan Kratochvil, gdb-patches
[-- 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
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-05 15:05 ` Aleksandar Ristovski
2013-04-07 10:24 ` Aleksandar Ristovski
@ 2013-04-08 18:32 ` Jan Kratochvil
1 sibling, 0 replies; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-08 18:32 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
Hi Aleksandar,
according to IRC you are going to send a new patchset so just replying with
a review what I have now.
On Fri, 05 Apr 2013 15:02:47 +0200, Aleksandar Ristovski wrote:
> @@ -2274,10 +2321,53 @@ static void
> svr4_relocate_section_addresses (struct so_list *so,
> struct target_section *sec)
> {
> + ULONGEST bfd_sect_size;
Move this variable to the inner block.
> +
> 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)
If you did negative conditional here with 'return;' the block below would
not get so right making it less readable. Not required, just suggested.
> + {
> + /* 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)
If you did negative conditional here with 'return;' the block below would
not get so right making it less readable. Not required, just suggested.
> + {
> + 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;
I would say this is a strict aliasing violation (char * -> type *).
Or why it is not?
> +
> + 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;
You use 4 above but here you use sizeof (note->namesz) (and descsz). Choose
one in both cases the same.
Also the GNU Coding Standards require parentheses on multi-line expressions
AFAIK to workaround Emacs bug, therefore:
build_id_offs = (sizeof (note->namesz) + sizeof (note->descsz)
+ sizeof (note->type) + namesz);
The note name is not verified here to be "GNU\0".
> + 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"
I already wrote in previous mail:
I do not see used it anywhere.
> +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id"
I already wrote in previous mail:
It is used only in solib-svr4.c so it should be in that file.
This happens multiple times with your mails. If you do not agree with it then
reply why.
> +
> struct objfile;
> struct target_so_ops;
>
[...]
> @@ -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. */
I already wrote in the last mail:
Formatting:
/* No validation. */
return 1;
Thanks,
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-05 13:03 ` Jan Kratochvil
2013-04-05 16:08 ` Aleksandar Ristovski
@ 2013-04-08 18:54 ` Pedro Alves
2013-04-09 1:15 ` Jan Kratochvil
1 sibling, 1 reply; 47+ messages in thread
From: Pedro Alves @ 2013-04-08 18:54 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Aleksandar Ristovski, gdb-patches
On 04/05/2013 12:47 PM, Jan Kratochvil wrote:
> Sure one could make a Linux-specific local solib-*.c backend but the current
> plan is to drop all (in reality just some) *-nat.c files in the favor of
> always using gdbserver.
Not for core files. We'll still fallback to solib-svr4.c for those.
Are core files being considered in all this?
--
Pedro Alves
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch] validate binary before use
2013-04-08 18:54 ` Pedro Alves
@ 2013-04-09 1:15 ` Jan Kratochvil
0 siblings, 0 replies; 47+ messages in thread
From: Jan Kratochvil @ 2013-04-09 1:15 UTC (permalink / raw)
To: Pedro Alves; +Cc: Aleksandar Ristovski, gdb-patches
On Mon, 08 Apr 2013 16:57:02 +0200, Pedro Alves wrote:
> On 04/05/2013 12:47 PM, Jan Kratochvil wrote:
> > Sure one could make a Linux-specific local solib-*.c backend but the current
> > plan is to drop all (in reality just some) *-nat.c files in the favor of
> > always using gdbserver.
>
> Not for core files. We'll still fallback to solib-svr4.c for those.
> Are core files being considered in all this?
I admit I did not think much about core files but:
Core files will work with the current solib-svr4.c code.
Linux core files have now NT_FILE extension with /proc/PID/maps content which
is also recognized by Tom's patch in FSF GDB HEAD so it could fully work with
core files. Just one has to compare filenames instead of inode there, inode
is not present in NT_FILE.
Jan
^ permalink raw reply [flat|nested] 47+ messages in thread
end of thread, other threads:[~2013-04-08 17:02 UTC | newest]
Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-12-21 20:21 [patch] validate binary before use Aleksandar Ristovski
2012-12-24 19:57 ` Aleksandar Ristovski
2012-12-25 7:37 ` Jan Kratochvil
2012-12-27 20:07 ` Aleksandar Ristovski
2012-12-27 20:59 ` Jan Kratochvil
2012-12-27 21:03 ` Aleksandar Ristovski
2012-12-27 21:13 ` Jan Kratochvil
2012-12-27 21:21 ` Aleksandar Ristovski
2013-01-29 16:15 ` Aleksandar Ristovski
2013-01-30 19:17 ` Jan Kratochvil
2013-01-31 14:23 ` Aleksandar Ristovski
2013-02-01 3:06 ` Jan Kratochvil
2013-02-01 14:31 ` Aleksandar Ristovski
2013-02-01 20:43 ` Jan Kratochvil
2013-02-01 21:32 ` Aleksandar Ristovski
2013-02-02 12:25 ` Jan Kratochvil
2013-02-21 21:00 ` Aleksandar Ristovski
2013-02-21 21:07 ` Jan Kratochvil
2013-01-31 6:35 ` Jan Kratochvil
2013-01-31 14:24 ` Aleksandar Ristovski
2013-02-22 15:09 ` Aleksandar Ristovski
2013-02-27 17:42 ` Aleksandar Ristovski
2013-02-27 18:14 ` Aleksandar Ristovski
2013-03-22 16:58 ` Aleksandar Ristovski
2013-03-22 14:45 ` Aleksandar Ristovski
2013-03-28 20:56 ` Jan Kratochvil
2013-04-02 17:25 ` Aleksandar Ristovski
2013-04-02 17:32 ` Aleksandar Ristovski
2013-04-02 17:45 ` Jan Kratochvil
2013-04-02 18:02 ` Aleksandar Ristovski
2013-04-03 18:52 ` Jan Kratochvil
2013-04-04 11:07 ` Aleksandar Ristovski
2013-04-04 13:30 ` Jan Kratochvil
2013-04-04 17:15 ` Aleksandar Ristovski
2013-04-04 18:11 ` Aleksandar Ristovski
2013-04-05 13:03 ` Jan Kratochvil
2013-04-05 16:08 ` Aleksandar Ristovski
2013-04-07 6:06 ` Jan Kratochvil
2013-04-08 18:54 ` Pedro Alves
2013-04-09 1:15 ` Jan Kratochvil
2013-04-05 15:05 ` Aleksandar Ristovski
2013-04-07 10:24 ` Aleksandar Ristovski
2013-04-08 18:32 ` Jan Kratochvil
2013-04-07 5:54 ` Jan Kratochvil
2013-04-04 3:16 ` Jan Kratochvil
2012-12-26 19:24 ` Poenitz Andre
2012-12-27 20:10 ` Aleksandar Ristovski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox