[rfc]: Framework for looking up multiply defined global symbols in shared libraries

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[rfc]: Framework for looking up multiply defined global symbols in shared libraries

Markus Deuling
Hi,



this patch introduces a framework for looking up multiply defined global symbols

from shared libraries. Solib handler like eg. solib-svr4.c can now install a callback

to implement a libray-specific routine for looking up global symbols.



As an example I implemented a special lookup routine for ELF shared libraries

linked with -Bsymbolic. While the focus is within such a library, the global

symbol lookup shall first search for the symbol within this libray and then

go through the main executable if not found.



The patch also includes a testcase for this new feature. The testsuite

showed no regressions.



I would appreciate your comment on this patch. Would this be ok for mainline?
Thanks in advance.


ChangeLog:
        * cp-namespace.c (lookup_symbol_file): Add block
        to call for lookup_symbol_global.
        * Makefile.in (solist_h): Update dependencies.
        (solib.o): Likewise.
        (symtab.o): Likewise.
        * solib.c: New include "symtab.h".
        (solib_global_lookup): New function.
        * solib-svr4.c (has_SYMBOLIC): New function.
        (elf_lookup_lib_symbol): New function.
        (_initialize_svr4_solib): Add elf_lookup_lib_symbol
        to svr4_so_ops.
        * solist.h: New include "symtab.h".
        (target_so_ops): New member lookup_lib_global_symbol.
        (solib_global_lookup): Declare.
        * symtab.c: New include "solist.h".
        (lookup_objfile_from_block): New function.
        (lookup_global_symbol_from_objfile): New function.
        (basic_lookup_symbol_nonlocal): Add block to call
        for lookup_symbol_global.
        (lookup_symbol_global): Change lookup order. First
        call solib_global_lookup then lookup global symbol
        in both symtab and psymtab.
        * symtab.h (lookup_symbol_global): Add block to
        declaration.
        (lookup_objfile_from_block): Declare.
        (lookup_global_symbol_from_objfile): Declare.
        * gdb.base/libmd.c: New file for testcase.
        * gdb.base/libmd.h: Likewise.
        * gdb.base/solib_symbol.c: Likewise.
        * gdb.base/solib_symbol.exp: New testcase for
        multiply defined global symbol lookup.


--
Markus Deuling
GNU Toolchain for Linux on Cell BE
[hidden email]


diff -urN src/gdb/cp-namespace.c dev/gdb/cp-namespace.c
--- src/gdb/cp-namespace.c 2007-01-09 18:58:50.000000000 +0100
+++ dev/gdb/cp-namespace.c 2007-04-26 07:18:49.000000000 +0200
@@ -491,7 +491,7 @@
     }
   else
     {
-      sym = lookup_symbol_global (name, linkage_name, domain, symtab);
+      sym = lookup_symbol_global (name, linkage_name, block, domain, symtab);
     }
 
   if (sym != NULL)
diff -urN src/gdb/Makefile.in dev/gdb/Makefile.in
--- src/gdb/Makefile.in 2007-04-26 06:53:55.000000000 +0200
+++ dev/gdb/Makefile.in 2007-04-26 07:18:50.000000000 +0200
@@ -797,7 +797,7 @@
 solib_pa64_h = solib-pa64.h
 solib_som_h = solib-som.h
 solib_svr4_h = solib-svr4.h
-solist_h = solist.h
+solist_h = solist.h $(symtab_h)
 source_h = source.h
 sparc64_tdep_h = sparc64-tdep.h $(sparc_tdep_h)
 sparc_nat_h = sparc-nat.h
@@ -2574,7 +2574,7 @@
  $(objfiles_h) $(exceptions_h) $(gdbcore_h) $(command_h) $(target_h) \
  $(frame_h) $(gdb_regex_h) $(inferior_h) $(environ_h) $(language_h) \
  $(gdbcmd_h) $(completer_h) $(filenames_h) $(exec_h) $(solist_h) \
- $(observer_h) $(readline_h)
+ $(observer_h) $(readline_h) $(symtab_h)
 solib-frv.o: solib-frv.c $(defs_h) $(gdb_string_h) $(inferior_h) \
  $(gdbcore_h) $(solist_h) $(frv_tdep_h) $(objfiles_h) $(symtab_h) \
  $(language_h) $(command_h) $(gdbcmd_h) $(elf_frv_h) $(solib_h)
@@ -2721,7 +2721,8 @@
  $(language_h) $(demangle_h) $(inferior_h) $(linespec_h) $(source_h) \
  $(filenames_h) $(objc_lang_h) $(ada_lang_h) $(hashtab_h) \
  $(gdb_obstack_h) $(block_h) $(dictionary_h) $(gdb_string_h) \
- $(gdb_stat_h) $(cp_abi_h) $(observer_h) $(gdb_assert_h)
+ $(gdb_stat_h) $(cp_abi_h) $(observer_h) $(gdb_assert_h) \
+ $(solist_h)
 target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \
  $(symtab_h) $(inferior_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
  $(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \
diff -urN src/gdb/solib.c dev/gdb/solib.c
--- src/gdb/solib.c 2007-01-09 18:58:58.000000000 +0100
+++ dev/gdb/solib.c 2007-04-26 07:18:50.000000000 +0200
@@ -45,6 +45,7 @@
 #include "solist.h"
 #include "observer.h"
 #include "readline/readline.h"
+#include "symtab.h"
 
 /* Architecture-specific operations.  */
 
@@ -945,6 +946,32 @@
 }
 
 
+/* Handler for library-specific lookup of global symbol
+   NAME in BLOCK.  Detect objfile corresponding to BLOCK
+   and call the library-specific handler if it is installed
+   for the current target.  */
+
+struct symbol *
+solib_global_lookup (const struct block *block,
+     const char *name,
+     const char *linkage_name,
+     const domain_enum domain,
+     struct symtab **symtab)
+{
+  struct objfile *objfile;
+
+  objfile = lookup_objfile_from_block (block);
+  if (objfile == NULL)
+    return NULL;
+
+  if (current_target_so_ops->lookup_lib_global_symbol != NULL)
+    return current_target_so_ops->lookup_lib_global_symbol (objfile,
+ name, linkage_name, domain, symtab);
+
+  return NULL;
+}
+
+
 extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */
 
 void
diff -urN src/gdb/solib-svr4.c dev/gdb/solib-svr4.c
--- src/gdb/solib-svr4.c 2007-04-16 13:51:29.000000000 +0200
+++ dev/gdb/solib-svr4.c 2007-04-26 07:18:50.000000000 +0200
@@ -378,6 +378,72 @@
 
  */
 
+/* Scan OBFD for a SYMBOLIC flag
+   in the .dynamic section. If it is set then
+   OBFD is a dso with a special rule for symbol
+   lookup. The lookup then starts in the dso before
+   searching in the executable.  */
+static int
+has_SYMBOLIC (bfd *obfd)
+{
+  CORE_ADDR dyn_ptr = 0;
+  int sect_size, arch_size;
+  gdb_byte *buf, *bufstart, *bufend, *p;
+  asection *sect;
+
+  if (obfd == NULL)
+    return -1;
+  arch_size = bfd_get_arch_size (obfd);
+  if (arch_size == -1)
+    return -1;
+
+  /* Retrieve information about .dynamic section.  */
+  sect = bfd_get_section_by_name (obfd, ".dynamic");
+  if (!sect)
+    return -1;
+
+  /* Read the .dynamic section.  */
+  sect_size = bfd_section_size (obfd, sect);
+  buf = alloca (sect_size);
+  if (!bfd_get_section_contents (obfd, sect,
+ buf, 0, sect_size))
+    return -1;
+
+  if (arch_size == 32)
+    { /* 32-bit elf */
+      for (bufend = buf + sect_size;
+   buf < bufend;
+   buf += sizeof (Elf32_External_Dyn))
+ {
+  Elf32_External_Dyn *x_dynp = (Elf32_External_Dyn *) buf;
+  long dyn_tag;
+  dyn_tag = extract_unsigned_integer ((gdb_byte *) x_dynp->d_tag, 4);
+  if (dyn_tag == DT_NULL)
+    break;
+  else if (dyn_tag == DT_SYMBOLIC)
+    return 1;
+ }
+    }
+  else
+    { /* 64-bit elf */
+      for (bufend = buf + sect_size;
+   buf < bufend;
+   buf += sizeof (Elf64_External_Dyn))
+ {
+  Elf64_External_Dyn *x_dynp = (Elf64_External_Dyn *) buf;
+  long dyn_tag;
+
+  dyn_tag = extract_unsigned_integer ((gdb_byte *) x_dynp->d_tag, 8);
+  if (dyn_tag == DT_NULL)
+    break;
+  else if (dyn_tag == DT_SYMBOLIC)
+    return 1;
+ }
+    }
+
+  return 0;
+}
+
 static CORE_ADDR
 elf_locate_base (void)
 {
@@ -1558,6 +1624,24 @@
 
 static struct target_so_ops svr4_so_ops;
 
+/* Lookup global symbol for ELF dso's linked with -Bsymbolic.
+   Those dso's have a different rule for symbol lookup. The lookup
+   begins here in the dso, not in the main executable.  */
+
+static struct symbol *
+elf_lookup_lib_symbol (struct objfile *objfile,
+       const char *name,
+       const char *linkage_name,
+       const domain_enum domain, struct symtab **symtab)
+{
+  if (objfile->obfd == NULL
+     || has_SYMBOLIC (objfile->obfd) != 1)
+    return NULL;
+
+  return  lookup_global_symbol_from_objfile
+ (objfile, name, linkage_name, domain, symtab);
+}
+
 extern initialize_file_ftype _initialize_svr4_solib; /* -Wmissing-prototypes */
 
 void
@@ -1573,6 +1657,7 @@
   svr4_so_ops.current_sos = svr4_current_sos;
   svr4_so_ops.open_symbol_file_object = open_symbol_file_object;
   svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code;
+  svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
 
   /* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops. */
   current_target_so_ops = &svr4_so_ops;
diff -urN src/gdb/solist.h dev/gdb/solist.h
--- src/gdb/solist.h 2007-01-09 18:58:58.000000000 +0100
+++ dev/gdb/solist.h 2007-04-26 07:18:50.000000000 +0200
@@ -23,6 +23,7 @@
 #define SOLIST_H
 
 #define SO_NAME_MAX_PATH_SIZE 512 /* FIXME: Should be dynamic */
+#include "symtab.h"
 
 /* Forward declaration for target specific link map information.  This
    struct is opaque to all but the target specific file.  */
@@ -103,7 +104,14 @@
        Convenience function for remote debuggers finding host libs.  */
     int (*find_and_open_solib) (char *soname,
         unsigned o_flags, char **temp_pathname);
-    
+
+    /* Hook for looking up global symbols in a library-specific way.  */
+    struct symbol * (*lookup_lib_global_symbol) (struct objfile *objfile,
+ const char *name,
+ const char *linkage_name,
+ const domain_enum domain,
+ struct symtab **symtab);
+
   };
 
 /* Free the memory associated with a (so_list *).  */
@@ -125,4 +133,13 @@
 #define TARGET_SO_IN_DYNSYM_RESOLVE_CODE \
   (current_target_so_ops->in_dynsym_resolve_code)
 
+/* Handler for library-specific global symbol lookup
+   in solib.c.  */
+struct symbol *
+solib_global_lookup (const struct block *block,
+     const char *name,
+     const char *linkage_name,
+     const domain_enum domain,
+     struct symtab **symtab);
+
 #endif
diff -urN src/gdb/symtab.c dev/gdb/symtab.c
--- src/gdb/symtab.c 2007-04-18 13:12:57.000000000 +0200
+++ dev/gdb/symtab.c 2007-04-26 07:18:50.000000000 +0200
@@ -57,6 +57,7 @@
 #include "cp-abi.h"
 #include "observer.h"
 #include "gdb_assert.h"
+#include "solist.h"
 
 /* Prototypes for local functions */
 
@@ -1265,6 +1266,44 @@
   return NULL;
 }
 
+/* Look up objfile to BLOCK.  */
+
+struct objfile *
+lookup_objfile_from_block (const struct block *block)
+{
+  struct objfile *obj = NULL;
+  struct blockvector *bv;
+  struct block *b;
+  struct symtab *s;
+  struct partial_symtab *ps;
+
+  if (block == NULL)
+    return NULL;
+
+  /* Go through SYMTABS.  */
+  ALL_SYMTABS (obj, s)
+  {
+    bv = BLOCKVECTOR (s);
+    b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+    if (BLOCK_START (b) <= BLOCK_START (block)
+ && BLOCK_END (b) > BLOCK_START (block))
+      return obj;
+  }
+
+  /* Go through PSYMTABS.  */
+  ALL_PSYMTABS (obj, ps)
+  {
+    s = PSYMTAB_TO_SYMTAB (ps);
+    bv = BLOCKVECTOR (s);
+    b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+    if (BLOCK_START (b) <= BLOCK_START (block)
+ && BLOCK_END (b) > BLOCK_START (block))
+      return obj;
+  }
+
+  return NULL;
+}
+
 /* Look up a symbol in a block; if found, locate its symtab, fixup the
    symbol, and set block_found appropriately.  */
 
@@ -1306,6 +1345,57 @@
   return NULL;
 }
 
+/* Check all global symbols in OBJFILE in symtabs and
+   psymtabs.  */
+
+struct symbol *
+lookup_global_symbol_from_objfile (struct objfile *objfile,
+   const char *name,
+   const char *linkage_name,
+   const domain_enum domain,
+   struct symtab **symtab)
+{
+  struct symbol *sym;
+  struct blockvector *bv;
+  const struct block *block;
+  struct symtab *s;
+  struct partial_symtab *ps;
+
+  /* Go through symtabs.  */
+  ALL_OBJFILE_SYMTABS (objfile, s)
+  {
+    bv = BLOCKVECTOR (s);
+    block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+    sym = lookup_block_symbol (block, name, linkage_name, domain);
+    if (sym)
+      {
+ block_found = block;
+ if (symtab != NULL)
+  *symtab = s;
+ return fixup_symbol_section (sym, objfile);
+      }
+  }
+
+  /* Now go through psymtabs.  */
+  ALL_OBJFILE_PSYMTABS (objfile, ps)
+  {
+    if (!ps->readin
+ && lookup_partial_symbol (ps, name, linkage_name,
+  1, domain))
+      {
+ s = PSYMTAB_TO_SYMTAB (ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ sym = lookup_block_symbol (block, name, linkage_name, domain);
+ if (symtab != NULL)
+  *symtab = s;
+ return fixup_symbol_section (sym, objfile);
+      }
+  }
+
+  return NULL;
+}
+
 /* Check to see if the symbol is defined in one of the symtabs.
    BLOCK_INDEX should be either GLOBAL_BLOCK or STATIC_BLOCK,
    depending on whether or not we want to search global symbols or
@@ -1571,7 +1661,7 @@
   if (sym != NULL)
     return sym;
 
-  return lookup_symbol_global (name, linkage_name, domain, symtab);
+  return lookup_symbol_global (name, linkage_name, block, domain, symtab);
 }
 
 /* Lookup a symbol in the static block associated to BLOCK, if there
@@ -1599,18 +1689,28 @@
 struct symbol *
 lookup_symbol_global (const char *name,
       const char *linkage_name,
+      const struct block *block,
       const domain_enum domain,
       struct symtab **symtab)
 {
   struct symbol *sym;
+  struct objfile *objfile;
 
-  sym = lookup_symbol_aux_symtabs (GLOBAL_BLOCK, name, linkage_name,
-   domain, symtab);
+  /* Call library-specific lookup procedure.  */
+  sym = solib_global_lookup (block, name, linkage_name, domain, symtab);
   if (sym != NULL)
     return sym;
 
-  return lookup_symbol_aux_psymtabs (GLOBAL_BLOCK, name, linkage_name,
-     domain, symtab);
+  /* Lookup global symbol in all objfiles in symtab and psymtab.  */
+  ALL_OBJFILES (objfile)
+  {
+    sym = lookup_global_symbol_from_objfile (objfile, name, linkage_name,
+     domain, symtab);
+    if (sym != NULL)
+      return sym;
+  }
+
+  return NULL;
 }
 
 /* Look, in partial_symtab PST, for symbol whose natural name is NAME.
diff -urN src/gdb/symtab.h dev/gdb/symtab.h
--- src/gdb/symtab.h 2007-03-28 05:42:54.000000000 +0200
+++ dev/gdb/symtab.h 2007-04-26 07:18:50.000000000 +0200
@@ -1050,6 +1050,7 @@
 
 extern struct symbol *lookup_symbol_global (const char *name,
     const char *linkage_name,
+    const struct block *block,
     const domain_enum domain,
     struct symtab **symtab);
 
@@ -1403,4 +1404,17 @@
    Defined in symtab.c, used in hppa-tdep.c. */
 extern int deprecated_hp_som_som_object_present;
 
+/* Lookup objfile to a block.  */
+extern struct objfile *
+lookup_objfile_from_block (const struct block *block);
+
+/* Check global symbols in objfile.  */
+struct symbol *
+lookup_global_symbol_from_objfile (struct objfile *objfile,
+   const char *name,
+   const char *linkage_name,
+   const domain_enum domain,
+   struct symtab **symtab);
+
+
 #endif /* !defined(SYMTAB_H) */
diff -urN src/gdb/testsuite/gdb.base/libmd.c dev/gdb/testsuite/gdb.base/libmd.c
--- src/gdb/testsuite/gdb.base/libmd.c 1970-01-01 01:00:00.000000000 +0100
+++ dev/gdb/testsuite/gdb.base/libmd.c 2007-04-26 07:18:50.000000000 +0200
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include "libmd.h"
+
+void foo2 ();
+
+void
+foo ()
+{
+  printf ("foo in lib\n");
+  return;
+}
+
+void
+foo2()
+{
+  printf ("foo2 in lib\n");
+  return;
+}
diff -urN src/gdb/testsuite/gdb.base/libmd.h dev/gdb/testsuite/gdb.base/libmd.h
--- src/gdb/testsuite/gdb.base/libmd.h 1970-01-01 01:00:00.000000000 +0100
+++ dev/gdb/testsuite/gdb.base/libmd.h 2007-04-26 07:18:50.000000000 +0200
@@ -0,0 +1 @@
+extern void foo();
diff -urN src/gdb/testsuite/gdb.base/solib_symbol.c dev/gdb/testsuite/gdb.base/solib_symbol.c
--- src/gdb/testsuite/gdb.base/solib_symbol.c 1970-01-01 01:00:00.000000000 +0100
+++ dev/gdb/testsuite/gdb.base/solib_symbol.c 2007-04-26 07:18:50.000000000 +0200
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include "libmd.h"
+
+extern void foo();
+void foo3();
+void foo2();
+
+int main ()
+{
+  printf ("in main\n");
+  foo ();
+  foo3 ();
+  return 0;
+}
+
+void foo3()
+{
+  printf ("foo3 in main\n");
+  return;
+}
+
+void foo2()
+{
+  printf ("foo2 in main\n");
+  return;
+}
+
diff -urN src/gdb/testsuite/gdb.base/solib_symbol.exp dev/gdb/testsuite/gdb.base/solib_symbol.exp
--- src/gdb/testsuite/gdb.base/solib_symbol.exp 1970-01-01 01:00:00.000000000 +0100
+++ dev/gdb/testsuite/gdb.base/solib_symbol.exp 2007-04-26 07:18:50.000000000 +0200
@@ -0,0 +1,110 @@
+# Copyright 2007 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Contributed by Markus Deuling <[hidden email]>.
+#
+
+set prms_id 0
+set bug_id 0
+set timeout 5
+
+if { [istarget "spu-*"] } then {
+  unsupported "Skipping shared libraries testcase."
+  return -1
+}
+
+# Library file.
+set libfile "libmd"
+set srcfile_lib ${libfile}.c
+set binfile_lib ${objdir}/${subdir}/${libfile}.so
+# Binary file.
+set testfile "solib_symbol"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+# Build a solib with -Bsymbolic.
+set compile_flags {debug}
+set compile_flags "$compile_flags additional_flags=-fPIC"
+set compile_flags "$compile_flags additional_flags=-Wl,-Bsymbolic"
+set compile_flags "$compile_flags additional_flags=-shared"
+set sources ${srcdir}/${subdir}/${srcfile_lib}
+if { [gdb_compile $sources ${binfile_lib} executable $compile_flags] != "" } {
+  return -1
+}
+
+# Build binary.
+set compile_flags {debug}
+set compile_flags "$compile_flags additional_flags=-L${objdir}/${subdir}/"
+set compile_flags "$compile_flags additional_flags=-Wl,-rpath=${objdir}/${subdir}/"
+set compile_flags "$compile_flags additional_flags=-lmd"
+set sources ${srcdir}/${subdir}/${srcfile}
+if { [gdb_compile $sources ${binfile} executable $compile_flags] != "" } {
+  return -1
+}
+
+if [get_compiler_info ${binfile}] {
+  return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] then {
+  fail "Can't run to main"
+  return 0
+}
+
+# Set a breakpoint in the binary.
+gdb_test "br foo2" \
+ "Breakpoint.*file.*${srcdir}/${subdir}/${srcfile}.*" \
+ "foo2 in main"
+
+# Delete all breakpoints.
+send_gdb "delete breakpoints\n"
+gdb_expect {
+  -re "Delete.*all.*breakpoints.*\(y or n\).*" {
+    send_gdb "y\n"
+    gdb_expect {
+      -re "$gdb_prompt.*" { pass "Delete all breakpoints" }
+      timeout             { fail "Delete all breakpoints (timeout)" }
+    }
+  }
+  -re "$gdb_prompt"       { fail "Delete all breakpoints" }
+  timeout                 { fail "Delete all breakpoints (timeout)" }
+}
+
+
+# Break in the library.
+gdb_test "br foo" \
+ "" \
+ "foo in libmd"
+
+gdb_test "continue" \
+ "Continuing.*" \
+ "continue"
+
+# This symbol is now looked up in the ELF library.
+gdb_test "br foo2" \
+ "Breakpoint.*file.*${srcdir}/${subdir}/${srcfile_lib}.*" \
+ "foo2 in mdlib"
+
+
+gdb_exit
+
+return 0
+
+