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 . */ >> + >> + >> +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 . */ >> + >> + >> +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 . */ >> + >> + >> +#include >> +#include >> +#include >> +#include >> + >> +#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 . */ >> + >> +# 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