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