This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: warning: Could not load shared library symbols for linux-vdso.so.1.


On 08/12/2016 11:28 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> Is there an easy way to check whether we're in the vdso prelinked
>> situation just from doing some address comparisions?  I feel like that
>> should be possible, but I didn't think it through.  It is is indeed
>> possible, we could alwayy skip the /proc/pid/maps parsing entirely
>> even against live processes, on modern kernels.
> 
> I don't know either.  However, looks vDSO prelink is done only on x86
> and was already removed from kernel in 2014, as far as I can see.  The
> base address of vDSO in kernel is VDSO_PRELINK, which is hard-coded.  I
> am not sure we can rely on this hard-coded constant.

I tried to come up with some clean way to detect this, and failed.

This made me have second thoughts on the approach, since there's a remote
chance that we'll hide the wrong DSO, on older kernels.

I think I found an alternative fix.  

The idea is simply to read the vDSO bfd out of memory anyway even
when we weren't able to find its size from the mappings.  When 
elf_bfd_from_remote_memory is passed '0' for size, it figures
out the size of the elf in memory from the elf structure.  If we use
that as another source for the vdso address range, then
svr4_current_sos doesn't have to change at all.

Now, in order to do this, we need to move the add_vsyscall_page
call earlier, before svr4_current_dsos is ever called, in order
to read the vdso bfd out of memory before we ever first need to
filter out the vdso.  The cleanest I could do with the current
gdbarch_vsyscall_range-based design was to do the add_vsyscall_page
call from within gdbarch_vsyscall_range.  But that looks very ugly
to me, for reading symbols from a quite innocent looking gdbarch hook.

So I bit the bullet and made a custom Linux-specific
struct solib_ops that inherits svr4_so_ops, and overrides a couple
methods for vDSO awareness.  I think the end result is clearer
and probably more extensible if/when we decide to do the work necessary
to be able to show the vdso in "info sharedlibrary", without causing
could-not-find-file warnings.

I'm attaching two patches; the first implements the new solib_ops
instance, and then the second uses the vDSO's bfd size, fixing the
bug.

Passes testing on x86_64 Fedora 23 here, as well as the new test.

Let me know what you think.

Pedro Alves

>From f830ed7d1b3289c2a7d9da4fd92dd667ff3bb3f2 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Fri, 19 Aug 2016 01:11:16 +0100
Subject: [PATCH 1/2] Introduce linux_solib_ops

Add a custom solib_ops for Linux-based targets that extends
solib-svr4.c and then adds vDSO awareness to a couple solib_ops
methods.  This replaces the current scheme of including a bit of
vDSO-awareness in solib-svr4.c directly, but hidden (though not very
well) behind the gdbarch_vsyscall_range gdbarch hook.

The idea is to read the vDSO out of memory before current_sos() is
ever called, and the scheme doesn't allow that in a clean way.

This change allows centralizing all vDSO handling in linux-tdep.c, and
completely getting rid of that gdbarch hook.
symfile-mem.c:add_vsyscall_page could move to linux-tdep.c too, but I
have not done that yet.  I'd like to do that though in the future, and
also do a global s/vsyscall/vDSO/g throughout, since we're really
handling the vDSO, not the old vsyscall.  All the vsyscall references
are probably making all this code quite confusing to newcomers, I bet.
---
 gdb/gdbarch.c         |  23 ------
 gdb/gdbarch.h         |   9 ---
 gdb/gdbarch.sh        |   6 --
 gdb/linux-tdep.c      | 134 +++++++++++++++++++++++++++++++++--
 gdb/linux-tdep.h      |   4 ++
 gdb/mips-linux-tdep.c |   2 +-
 gdb/ppc-linux-tdep.c  |   2 +-
 gdb/solib-spu.c       |  18 ++---
 gdb/solib-svr4.c      | 190 +++++++++++++++-----------------------------------
 gdb/solib-svr4.h      |  21 ++++++
 gdb/solib.c           |   2 +-
 gdb/solib.h           |   4 ++
 gdb/symfile-mem.c     |  38 ++++------
 gdb/symfile-mem.h     |  30 ++++++++
 14 files changed, 269 insertions(+), 214 deletions(-)
 create mode 100644 gdb/symfile-mem.h

diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index af7359e..a07029e 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -330,7 +330,6 @@ struct gdbarch
   gdbarch_insn_is_jump_ftype *insn_is_jump;
   gdbarch_auxv_parse_ftype *auxv_parse;
   gdbarch_print_auxv_entry_ftype *print_auxv_entry;
-  gdbarch_vsyscall_range_ftype *vsyscall_range;
   gdbarch_infcall_mmap_ftype *infcall_mmap;
   gdbarch_infcall_munmap_ftype *infcall_munmap;
   gdbarch_gcc_target_options_ftype *gcc_target_options;
@@ -435,7 +434,6 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->insn_is_ret = default_insn_is_ret;
   gdbarch->insn_is_jump = default_insn_is_jump;
   gdbarch->print_auxv_entry = default_print_auxv_entry;
-  gdbarch->vsyscall_range = default_vsyscall_range;
   gdbarch->infcall_mmap = default_infcall_mmap;
   gdbarch->infcall_munmap = default_infcall_munmap;
   gdbarch->gcc_target_options = default_gcc_target_options;
@@ -682,7 +680,6 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of insn_is_jump, invalid_p == 0 */
   /* Skip verify of auxv_parse, has predicate.  */
   /* Skip verify of print_auxv_entry, invalid_p == 0 */
-  /* Skip verify of vsyscall_range, invalid_p == 0 */
   /* Skip verify of infcall_mmap, invalid_p == 0 */
   /* Skip verify of infcall_munmap, invalid_p == 0 */
   /* Skip verify of gcc_target_options, invalid_p == 0 */
@@ -1423,9 +1420,6 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: virtual_frame_pointer = <%s>\n",
                       host_address_to_string (gdbarch->virtual_frame_pointer));
   fprintf_unfiltered (file,
-                      "gdbarch_dump: vsyscall_range = <%s>\n",
-                      host_address_to_string (gdbarch->vsyscall_range));
-  fprintf_unfiltered (file,
                       "gdbarch_dump: vtable_function_descriptors = %s\n",
                       plongest (gdbarch->vtable_function_descriptors));
   fprintf_unfiltered (file,
@@ -4793,23 +4787,6 @@ set_gdbarch_print_auxv_entry (struct gdbarch *gdbarch,
   gdbarch->print_auxv_entry = print_auxv_entry;
 }
 
-int
-gdbarch_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
-{
-  gdb_assert (gdbarch != NULL);
-  gdb_assert (gdbarch->vsyscall_range != NULL);
-  if (gdbarch_debug >= 2)
-    fprintf_unfiltered (gdb_stdlog, "gdbarch_vsyscall_range called\n");
-  return gdbarch->vsyscall_range (gdbarch, range);
-}
-
-void
-set_gdbarch_vsyscall_range (struct gdbarch *gdbarch,
-                            gdbarch_vsyscall_range_ftype vsyscall_range)
-{
-  gdbarch->vsyscall_range = vsyscall_range;
-}
-
 CORE_ADDR
 gdbarch_infcall_mmap (struct gdbarch *gdbarch, CORE_ADDR size, unsigned prot)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index bc0f692..8c7a37b 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1471,15 +1471,6 @@ typedef void (gdbarch_print_auxv_entry_ftype) (struct gdbarch *gdbarch, struct u
 extern void gdbarch_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file, CORE_ADDR type, CORE_ADDR val);
 extern void set_gdbarch_print_auxv_entry (struct gdbarch *gdbarch, gdbarch_print_auxv_entry_ftype *print_auxv_entry);
 
-/* Find the address range of the current inferior's vsyscall/vDSO, and
-   write it to *RANGE.  If the vsyscall's length can't be determined, a
-   range with zero length is returned.  Returns true if the vsyscall is
-   found, false otherwise. */
-
-typedef int (gdbarch_vsyscall_range_ftype) (struct gdbarch *gdbarch, struct mem_range *range);
-extern int gdbarch_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range);
-extern void set_gdbarch_vsyscall_range (struct gdbarch *gdbarch, gdbarch_vsyscall_range_ftype *vsyscall_range);
-
 /* Allocate SIZE bytes of PROT protected page aligned memory in inferior.
    PROT has GDB_MMAP_PROT_* bitmask format.
    Throw an error if it is not possible.  Returned address is always valid. */
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index d8e0eeb..8f5a893 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1114,12 +1114,6 @@ M:int:auxv_parse:gdb_byte **readptr, gdb_byte *endptr, CORE_ADDR *typep, CORE_AD
 # to FILE.
 m:void:print_auxv_entry:struct ui_file *file, CORE_ADDR type, CORE_ADDR val:file, type, val::default_print_auxv_entry::0
 
-# Find the address range of the current inferior's vsyscall/vDSO, and
-# write it to *RANGE.  If the vsyscall's length can't be determined, a
-# range with zero length is returned.  Returns true if the vsyscall is
-# found, false otherwise.
-m:int:vsyscall_range:struct mem_range *range:range::default_vsyscall_range::0
-
 # Allocate SIZE bytes of PROT protected page aligned memory in inferior.
 # PROT has GDB_MMAP_PROT_* bitmask format.
 # Throw an error if it is not possible.  Returned address is always valid.
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index ab110b0..91931eb 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -38,9 +38,17 @@
 #include "gdbcmd.h"
 #include "gdb_regex.h"
 #include "common/enum-flags.h"
+#include "solib.h"
+#include "solist.h"
+#include "solib-svr4.h"
+#include "symfile-mem.h"
 
 #include <ctype.h>
 
+/* Shared library operations for Linux.  This inherits svr4, and adds
+   support for the vDSO.  */
+struct target_so_ops linux_so_ops;
+
 /* This enum represents the values that the user can choose when
    informing the Linux kernel about which memory mappings will be
    dumped in a corefile.  They are described in the file
@@ -2343,11 +2351,15 @@ linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
   return 0;
 }
 
-/* Implementation of the "vsyscall_range" gdbarch hook.  Handles
-   caching, and defers the real work to linux_vsyscall_range_raw.  */
+/* Find the address range of the current inferior's vDSO.  If the
+   vDSO's length can't be determined, a range with zero length is
+   recorded.  Returns true if the vDSO is found, false otherwise.
+
+   Handles caching in struct linux_info, and defers the real work to
+   linux_vsyscall_range_raw.  */
 
 static int
-linux_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
+linux_vsyscall_range (struct gdbarch *gdbarch)
 {
   struct linux_info *info = get_linux_inferior_data ();
 
@@ -2361,9 +2373,8 @@ linux_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
 
   if (info->vsyscall_range_p < 0)
     return 0;
-
-  *range = info->vsyscall_range;
-  return 1;
+  else
+    return 1;
 }
 
 /* Symbols for linux_infcall_mmap's ARG_FLAGS; their Linux MAP_* system
@@ -2484,6 +2495,107 @@ show_use_coredump_filter (struct ui_file *file, int from_tty,
 			    " corefiles is %s.\n"), value);
 }
 
+/* Implement the "create_inferior_hook" target_so_ops method.  */
+
+static void
+linux_solib_create_inferior_hook (int from_tty)
+{
+  struct linux_info *info = get_linux_inferior_data ();
+
+  if (linux_vsyscall_range (target_gdbarch ()))
+    {
+      /* Add the vDSO symbols.  We need to do this before calling the
+	 svr4 version, because that refreshes the DSO list.  In some
+	 cases, such as when debugging core dumps, the information
+	 necessary for identifying the vDSO in order to filter it out
+	 can only be found by reading the vDSO out of memory.
+
+	 Note we don't pass SYMFILE_VERBOSE (i.e., pass FROM_TTY==0),
+	 because the action of loading the vDSO was not triggered by
+	 the user, even if the user typed "run" at the TTY.  */
+      add_vsyscall_page (&info->vsyscall_range, SYMFILE_DEFER_BP_RESET);
+    }
+
+  svr4_so_ops.solib_create_inferior_hook (from_tty);
+}
+
+/* Implement the "current_sos" target_so_ops method.  */
+
+static struct so_list *
+linux_current_sos (void)
+{
+  struct so_list *so_head = svr4_so_ops.current_sos ();
+  struct linux_info *info = get_linux_inferior_data ();
+
+  /* Filter out the vDSO module, if present.  Its symbol file would
+     not be found on disk.  The vDSO/vsyscall's OBJFILE is instead
+     managed by symfile-mem.c:add_vsyscall_page.  */
+  if (linux_vsyscall_range (target_gdbarch ())
+      && info->vsyscall_range.length != 0)
+    {
+      struct so_list **sop;
+
+      sop = &so_head;
+      while (*sop != NULL)
+	{
+	  struct so_list *so = *sop;
+	  struct svr4_lm_info *lm_info = (struct svr4_lm_info *) so->lm_info;
+
+	  /* We can't simply match the vDSO by starting address alone,
+	     because lm_info->l_addr_inferior (and also l_addr) do not
+	     necessarily represent the real starting address of the
+	     ELF if the vDSO's ELF itself is "prelinked".  The l_ld
+	     field (the ".dynamic" section of the shared object)
+	     always points at the absolute/resolved address though.
+	     So check whether that address is inside the vDSO's
+	     mapping instead.
+
+	     E.g., on Linux 3.16 (x86_64) the vDSO is a regular
+	     0-based ELF, and we see:
+
+	      (gdb) info auxv
+	      33  AT_SYSINFO_EHDR  System-supplied DSO's ELF header 0x7ffff7ffb000
+	      (gdb)  p/x *_r_debug.r_map.l_next
+	      $1 = {l_addr = 0x7ffff7ffb000, ..., l_ld = 0x7ffff7ffb318, ...}
+
+	     And on Linux 2.6.32 (x86_64) we see:
+
+	      (gdb) info auxv
+	      33  AT_SYSINFO_EHDR  System-supplied DSO's ELF header 0x7ffff7ffe000
+	      (gdb) p/x *_r_debug.r_map.l_next
+	      $5 = {l_addr = 0x7ffff88fe000, ..., l_ld = 0x7ffff7ffe580, ... }
+
+	     Dumping that vDSO shows:
+
+	      (gdb) info proc mappings
+	      0x7ffff7ffe000  0x7ffff7fff000  0x1000  0  [vdso]
+	      (gdb) dump memory vdso.bin 0x7ffff7ffe000 0x7ffff7fff000
+	      # readelf -Wa vdso.bin
+	      [...]
+		Entry point address: 0xffffffffff700700
+	      [...]
+	      Section Headers:
+		[Nr] Name     Type    Address	       Off    Size
+		[ 0]	      NULL    0000000000000000 000000 000000
+		[ 1] .hash    HASH    ffffffffff700120 000120 000038
+		[ 2] .dynsym  DYNSYM  ffffffffff700158 000158 0000d8
+	      [...]
+		[ 9] .dynamic DYNAMIC ffffffffff700580 000580 0000f0
+	  */
+	  if (address_in_mem_range (lm_info->l_ld, &info->vsyscall_range))
+	    {
+	      *sop = so->next;
+	      free_so (so);
+	      break;
+	    }
+
+	  sop = &so->next;
+	}
+    }
+
+  return so_head;
+}
+
 /* To be called from the various GDB_OSABI_LINUX handlers for the
    various GNU/Linux architectures and machine types.  */
 
@@ -2501,10 +2613,18 @@ linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 				      linux_gdb_signal_from_target);
   set_gdbarch_gdb_signal_to_target (gdbarch,
 				    linux_gdb_signal_to_target);
-  set_gdbarch_vsyscall_range (gdbarch, linux_vsyscall_range);
   set_gdbarch_infcall_mmap (gdbarch, linux_infcall_mmap);
   set_gdbarch_infcall_munmap (gdbarch, linux_infcall_munmap);
   set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+
+  /* Inherit svr4 and override a few functions.  */
+  if (linux_so_ops.current_sos == NULL)
+    {
+      linux_so_ops = svr4_so_ops;
+      linux_so_ops.current_sos = linux_current_sos;
+      linux_so_ops.solib_create_inferior_hook = linux_solib_create_inferior_hook;
+  }
+  set_solib_ops (gdbarch, &linux_so_ops);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
index 2da7de4..da08097 100644
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -22,6 +22,10 @@
 
 #include "bfd.h"
 
+struct target_so_ops;
+
+extern struct target_so_ops linux_so_ops;
+
 struct regcache;
 
 /* Enum used to define the extra fields of the siginfo type used by an
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 8dc0566..78eb856 100644
--- a/gdb/mips-linux-tdep.c
+++ b/gdb/mips-linux-tdep.c
@@ -1716,7 +1716,7 @@ mips_linux_init_abi (struct gdbarch_info info,
      dependency on solib-svr4.c's _initialize routine.  */
   if (mips_svr4_so_ops.in_dynsym_resolve_code == NULL)
     {
-      mips_svr4_so_ops = svr4_so_ops;
+      mips_svr4_so_ops = linux_so_ops;
       mips_svr4_so_ops.in_dynsym_resolve_code
 	= mips_linux_in_dynsym_resolve_code;
     }
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index cde4f2e..e50a83a 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -1704,7 +1704,7 @@ ppc_linux_init_abi (struct gdbarch_info info,
 
       if (powerpc_so_ops.in_dynsym_resolve_code == NULL)
 	{
-	  powerpc_so_ops = svr4_so_ops;
+	  powerpc_so_ops = linux_so_ops;
 	  /* Override dynamic resolve function.  */
 	  powerpc_so_ops.in_dynsym_resolve_code =
 	    powerpc_linux_in_dynsym_resolve_code;
diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
index fa2977e..6952f32 100644
--- a/gdb/solib-spu.c
+++ b/gdb/solib-spu.c
@@ -34,7 +34,7 @@
 #include "breakpoint.h"
 #include "gdbthread.h"
 #include "gdb_bfd.h"
-
+#include "linux-tdep.h"
 #include "spu-tdep.h"
 
 /* Highest SPE id (file handle) the inferior may have.  */
@@ -164,7 +164,7 @@ spu_current_sos (void)
   int i, size;
 
   /* First, retrieve the SVR4 shared library list.  */
-  head = svr4_so_ops.current_sos ();
+  head = linux_so_ops.current_sos ();
 
   /* Append our libraries to the end of the list.  */
   for (link_ptr = &head; *link_ptr; link_ptr = &(*link_ptr)->next)
@@ -238,7 +238,7 @@ static void
 spu_free_so (struct so_list *so)
 {
   if (so->so_original_name[0] != '@')
-    svr4_so_ops.free_so (so);
+    linux_so_ops.free_so (so);
 }
 
 /* Relocate section addresses.  */
@@ -247,7 +247,7 @@ spu_relocate_section_addresses (struct so_list *so,
 				struct target_section *sec)
 {
   if (so->so_original_name[0] != '@')
-    svr4_so_ops.relocate_section_addresses (so, sec);
+    linux_so_ops.relocate_section_addresses (so, sec);
   else
     {
       unsigned long long addr;
@@ -355,7 +355,7 @@ spu_bfd_open (char *pathname)
 
   /* Handle regular SVR4 libraries.  */
   if (!original_name)
-    return svr4_so_ops.bfd_open (pathname);
+    return linux_so_ops.bfd_open (pathname);
 
   /* Decode object ID.  */
   if (sscanf (original_name, "@0x%llx <%d>", &addr, &fd) != 2)
@@ -399,8 +399,8 @@ spu_lookup_lib_symbol (struct objfile *objfile,
   if (bfd_get_arch (objfile->obfd) == bfd_arch_spu)
     return lookup_global_symbol_from_objfile (objfile, name, domain);
 
-  if (svr4_so_ops.lookup_lib_global_symbol != NULL)
-    return svr4_so_ops.lookup_lib_global_symbol (objfile, name, domain);
+  if (linux_so_ops.lookup_lib_global_symbol != NULL)
+    return linux_so_ops.lookup_lib_global_symbol (objfile, name, domain);
   return (struct block_symbol) {NULL, NULL};
 }
 
@@ -495,7 +495,7 @@ spu_solib_create_inferior_hook (int from_tty)
     }
 
   /* Call SVR4 hook -- this will re-insert the SVR4 solib breakpoints.  */
-  svr4_so_ops.solib_create_inferior_hook (from_tty);
+  linux_so_ops.solib_create_inferior_hook (from_tty);
 
   /* If the inferior is statically linked against libspe, we need to install
      our own solib breakpoint right now.  Otherwise, it will be installed by
@@ -514,7 +514,7 @@ set_spu_solib_ops (struct gdbarch *gdbarch)
      dependency on solib-svr4.c's _initialize routine.  */
   if (spu_so_ops.current_sos == NULL)
     {
-      spu_so_ops = svr4_so_ops;
+      spu_so_ops = linux_so_ops;
       spu_so_ops.solib_create_inferior_hook = spu_solib_create_inferior_hook;
       spu_so_ops.relocate_section_addresses = spu_relocate_section_addresses;
       spu_so_ops.free_so = spu_free_so;
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index fe36d45..d578683 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -51,27 +51,6 @@ static int svr4_have_link_map_offsets (void);
 static void svr4_relocate_main_executable (void);
 static void svr4_free_library_list (void *p_list);
 
-/* Link map info to include in an allocated so_list entry.  */
-
-struct lm_info
-  {
-    /* Amount by which addresses in the binary should be relocated to
-       match the inferior.  The direct inferior value is L_ADDR_INFERIOR.
-       When prelinking is involved and the prelink base address changes,
-       we may need a different offset - the recomputed offset is in L_ADDR.
-       It is commonly the same value.  It is cached as we want to warn about
-       the difference and compute it only once.  L_ADDR is valid
-       iff L_ADDR_P.  */
-    CORE_ADDR l_addr, l_addr_inferior;
-    unsigned int l_addr_p : 1;
-
-    /* The target location of lm.  */
-    CORE_ADDR lm_addr;
-
-    /* Values read in from inferior's fields of the same name.  */
-    CORE_ADDR l_ld, l_next, l_prev, l_name;
-  };
-
 /* On SVR4 systems, a list of symbols in the dynamic linker where
    GDB can try to place a breakpoint to monitor shared library
    events.
@@ -189,12 +168,12 @@ svr4_same (struct so_list *gdb, struct so_list *inferior)
   return (svr4_same_1 (gdb->so_original_name, inferior->so_original_name));
 }
 
-static struct lm_info *
+static struct svr4_lm_info *
 lm_info_read (CORE_ADDR lm_addr)
 {
   struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
   gdb_byte *lm;
-  struct lm_info *lm_info;
+  struct svr4_lm_info *lm_info;
   struct cleanup *back_to;
 
   lm = (gdb_byte *) xmalloc (lmo->link_map_size);
@@ -210,7 +189,7 @@ lm_info_read (CORE_ADDR lm_addr)
     {
       struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
 
-      lm_info = XCNEW (struct lm_info);
+      lm_info = XCNEW (struct svr4_lm_info);
       lm_info->lm_addr = lm_addr;
 
       lm_info->l_addr_inferior = extract_typed_address (&lm[lmo->l_addr_offset],
@@ -237,20 +216,28 @@ has_lm_dynamic_from_link_map (void)
   return lmo->l_ld_offset >= 0;
 }
 
+static struct svr4_lm_info *
+svr4_lm_info (const struct so_list *so)
+{
+  return (struct svr4_lm_info *) so->lm_info;
+}
+
 static CORE_ADDR
 lm_addr_check (const struct so_list *so, bfd *abfd)
 {
-  if (!so->lm_info->l_addr_p)
+  struct svr4_lm_info *lm_info = svr4_lm_info (so);
+
+  if (!lm_info->l_addr_p)
     {
       struct bfd_section *dyninfo_sect;
       CORE_ADDR l_addr, l_dynaddr, dynaddr;
 
-      l_addr = so->lm_info->l_addr_inferior;
+      l_addr = lm_info->l_addr_inferior;
 
       if (! abfd || ! has_lm_dynamic_from_link_map ())
 	goto set_addr;
 
-      l_dynaddr = so->lm_info->l_ld;
+      l_dynaddr = lm_info->l_ld;
 
       dyninfo_sect = bfd_get_section_by_name (abfd, ".dynamic");
       if (dyninfo_sect == NULL)
@@ -333,11 +320,11 @@ lm_addr_check (const struct so_list *so, bfd *abfd)
 	}
 
     set_addr:
-      so->lm_info->l_addr = l_addr;
-      so->lm_info->l_addr_p = 1;
+      lm_info->l_addr = l_addr;
+      lm_info->l_addr_p = 1;
     }
 
-  return so->lm_info->l_addr;
+  return lm_info->l_addr;
 }
 
 /* Per pspace SVR4 specific data.  */
@@ -978,6 +965,7 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
   struct svr4_info *info;
   CORE_ADDR ldsomap;
   struct so_list *newobj;
+  struct svr4_lm_info *lm_info;
   struct cleanup *old_chain;
   CORE_ADDR name_lm;
 
@@ -994,9 +982,10 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
 
   newobj = XCNEW (struct so_list);
   old_chain = make_cleanup (xfree, newobj);
-  newobj->lm_info = lm_info_read (ldsomap);
+  lm_info = lm_info_read (ldsomap);
+  newobj->lm_info = (struct lm_info *) lm_info;
   make_cleanup (xfree, newobj->lm_info);
-  name_lm = newobj->lm_info ? newobj->lm_info->l_name : 0;
+  name_lm = lm_info ? lm_info->l_name : 0;
   do_cleanups (old_chain);
 
   return (name_lm >= vaddr && name_lm < vaddr + size);
@@ -1102,8 +1091,10 @@ svr4_free_so (struct so_list *so)
 static void
 svr4_clear_so (struct so_list *so)
 {
-  if (so->lm_info != NULL)
-    so->lm_info->l_addr_p = 0;
+  struct svr4_lm_info *lm_info = svr4_lm_info (so);
+
+  if (lm_info != NULL)
+    lm_info->l_addr_p = 0;
 }
 
 /* Free so_list built so far (called via cleanup).  */
@@ -1133,12 +1124,14 @@ svr4_copy_library_list (struct so_list *src)
   while (src != NULL)
     {
       struct so_list *newobj;
+      struct svr4_lm_info *lm_info;
 
       newobj = XNEW (struct so_list);
       memcpy (newobj, src, sizeof (struct so_list));
 
-      newobj->lm_info = XNEW (struct lm_info);
-      memcpy (newobj->lm_info, src->lm_info, sizeof (struct lm_info));
+      lm_info = XNEW (struct svr4_lm_info);
+      newobj->lm_info = (struct lm_info *) lm_info;
+      memcpy (newobj->lm_info, src->lm_info, sizeof (struct svr4_lm_info));
 
       newobj->next = NULL;
       *link = newobj;
@@ -1172,12 +1165,14 @@ library_list_start_library (struct gdb_xml_parser *parser,
   ULONGEST *l_ldp
     = (ULONGEST *) xml_find_attribute (attributes, "l_ld")->value;
   struct so_list *new_elem;
+  struct svr4_lm_info *lm_info;
 
   new_elem = XCNEW (struct so_list);
-  new_elem->lm_info = XCNEW (struct lm_info);
-  new_elem->lm_info->lm_addr = *lmp;
-  new_elem->lm_info->l_addr_inferior = *l_addrp;
-  new_elem->lm_info->l_ld = *l_ldp;
+  lm_info = XCNEW (struct svr4_lm_info);
+  lm_info->lm_addr = *lmp;
+  lm_info->l_addr_inferior = *l_addrp;
+  lm_info->l_ld = *l_ldp;
+  new_elem->lm_info = (struct lm_info *) lm_info;
 
   strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1);
   new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0;
@@ -1323,17 +1318,19 @@ svr4_default_sos (void)
 {
   struct svr4_info *info = get_svr4_info ();
   struct so_list *newobj;
+  struct svr4_lm_info *lm_info;
 
   if (!info->debug_loader_offset_p)
     return NULL;
 
   newobj = XCNEW (struct so_list);
 
-  newobj->lm_info = XCNEW (struct lm_info);
+  lm_info = XCNEW (struct svr4_lm_info);
+  newobj->lm_info = (struct lm_info *) lm_info;
 
   /* Nothing will ever check the other fields if we set l_addr_p.  */
-  newobj->lm_info->l_addr = info->debug_loader_offset;
-  newobj->lm_info->l_addr_p = 1;
+  lm_info->l_addr = info->debug_loader_offset;
+  lm_info->l_addr_p = 1;
 
   strncpy (newobj->so_name, info->debug_loader_name, SO_NAME_MAX_PATH_SIZE - 1);
   newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
@@ -1363,24 +1360,26 @@ svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
       struct cleanup *old_chain;
       int errcode;
       char *buffer;
+      struct svr4_lm_info *lm_info;
 
       newobj = XCNEW (struct so_list);
       old_chain = make_cleanup_free_so (newobj);
 
-      newobj->lm_info = lm_info_read (lm);
-      if (newobj->lm_info == NULL)
+      lm_info = lm_info_read (lm);
+      if (lm_info == NULL)
 	{
 	  do_cleanups (old_chain);
 	  return 0;
 	}
 
-      next_lm = newobj->lm_info->l_next;
+      newobj->lm_info = (struct lm_info *) lm_info;
+      next_lm = lm_info->l_next;
 
-      if (newobj->lm_info->l_prev != prev_lm)
+      if (lm_info->l_prev != prev_lm)
 	{
 	  warning (_("Corrupted shared library list: %s != %s"),
 		   paddress (target_gdbarch (), prev_lm),
-		   paddress (target_gdbarch (), newobj->lm_info->l_prev));
+		   paddress (target_gdbarch (), lm_info->l_prev));
 	  do_cleanups (old_chain);
 	  return 0;
 	}
@@ -1390,18 +1389,18 @@ svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
          SVR4, it has no name.  For others (Solaris 2.3 for example), it
          does have a name, so we can no longer use a missing name to
          decide when to ignore it.  */
-      if (ignore_first && newobj->lm_info->l_prev == 0)
+      if (ignore_first && lm_info->l_prev == 0)
 	{
 	  struct svr4_info *info = get_svr4_info ();
 
-	  first_l_name = newobj->lm_info->l_name;
-	  info->main_lm_addr = newobj->lm_info->lm_addr;
+	  first_l_name = lm_info->l_name;
+	  info->main_lm_addr = lm_info->lm_addr;
 	  do_cleanups (old_chain);
 	  continue;
 	}
 
       /* Extract this shared object's name.  */
-      target_read_string (newobj->lm_info->l_name, &buffer,
+      target_read_string (lm_info->l_name, &buffer,
 			  SO_NAME_MAX_PATH_SIZE - 1, &errcode);
       if (errcode != 0)
 	{
@@ -1409,7 +1408,7 @@ svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
 	     inferior executable, then this is not a normal shared
 	     object, but (most likely) a vDSO.  In this case, silently
 	     skip it; otherwise emit a warning. */
-	  if (first_l_name == 0 || newobj->lm_info->l_name != first_l_name)
+	  if (first_l_name == 0 || lm_info->l_name != first_l_name)
 	    warning (_("Can't read pathname for load map: %s."),
 		     safe_strerror (errcode));
 	  do_cleanups (old_chain);
@@ -1515,7 +1514,7 @@ svr4_current_sos_direct (struct svr4_info *info)
    method.  */
 
 static struct so_list *
-svr4_current_sos_1 (void)
+svr4_current_sos (void)
 {
   struct svr4_info *info = get_svr4_info ();
 
@@ -1528,82 +1527,6 @@ svr4_current_sos_1 (void)
   return svr4_current_sos_direct (info);
 }
 
-/* Implement the "current_sos" target_so_ops method.  */
-
-static struct so_list *
-svr4_current_sos (void)
-{
-  struct so_list *so_head = svr4_current_sos_1 ();
-  struct mem_range vsyscall_range;
-
-  /* Filter out the vDSO module, if present.  Its symbol file would
-     not be found on disk.  The vDSO/vsyscall's OBJFILE is instead
-     managed by symfile-mem.c:add_vsyscall_page.  */
-  if (gdbarch_vsyscall_range (target_gdbarch (), &vsyscall_range)
-      && vsyscall_range.length != 0)
-    {
-      struct so_list **sop;
-
-      sop = &so_head;
-      while (*sop != NULL)
-	{
-	  struct so_list *so = *sop;
-
-	  /* We can't simply match the vDSO by starting address alone,
-	     because lm_info->l_addr_inferior (and also l_addr) do not
-	     necessarily represent the real starting address of the
-	     ELF if the vDSO's ELF itself is "prelinked".  The l_ld
-	     field (the ".dynamic" section of the shared object)
-	     always points at the absolute/resolved address though.
-	     So check whether that address is inside the vDSO's
-	     mapping instead.
-
-	     E.g., on Linux 3.16 (x86_64) the vDSO is a regular
-	     0-based ELF, and we see:
-
-	      (gdb) info auxv
-	      33  AT_SYSINFO_EHDR  System-supplied DSO's ELF header 0x7ffff7ffb000
-	      (gdb)  p/x *_r_debug.r_map.l_next
-	      $1 = {l_addr = 0x7ffff7ffb000, ..., l_ld = 0x7ffff7ffb318, ...}
-
-	     And on Linux 2.6.32 (x86_64) we see:
-
-	      (gdb) info auxv
-	      33  AT_SYSINFO_EHDR  System-supplied DSO's ELF header 0x7ffff7ffe000
-	      (gdb) p/x *_r_debug.r_map.l_next
-	      $5 = {l_addr = 0x7ffff88fe000, ..., l_ld = 0x7ffff7ffe580, ... }
-
-	     Dumping that vDSO shows:
-
-	      (gdb) info proc mappings
-	      0x7ffff7ffe000  0x7ffff7fff000  0x1000  0  [vdso]
-	      (gdb) dump memory vdso.bin 0x7ffff7ffe000 0x7ffff7fff000
-	      # readelf -Wa vdso.bin
-	      [...]
-		Entry point address: 0xffffffffff700700
-	      [...]
-	      Section Headers:
-		[Nr] Name     Type    Address	       Off    Size
-		[ 0]	      NULL    0000000000000000 000000 000000
-		[ 1] .hash    HASH    ffffffffff700120 000120 000038
-		[ 2] .dynsym  DYNSYM  ffffffffff700158 000158 0000d8
-	      [...]
-		[ 9] .dynamic DYNAMIC ffffffffff700580 000580 0000f0
-	  */
-	  if (address_in_mem_range (so->lm_info->l_ld, &vsyscall_range))
-	    {
-	      *sop = so->next;
-	      free_so (so);
-	      break;
-	    }
-
-	  sop = &so->next;
-	}
-    }
-
-  return so_head;
-}
-
 /* Get the address of the link_map for a given OBJFILE.  */
 
 CORE_ADDR
@@ -1624,7 +1547,7 @@ svr4_fetch_objfile_link_map (struct objfile *objfile)
      of shared libraries.  */
   for (so = master_so_list (); so; so = so->next)
     if (so->objfile == objfile)
-      return so->lm_info->lm_addr;
+      return svr4_lm_info (so)->lm_addr;
 
   /* Not found!  */
   return 0;
@@ -1856,7 +1779,7 @@ solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
   /* Walk to the end of the list.  */
   for (tail = info->solib_list; tail->next != NULL; tail = tail->next)
     /* Nothing.  */;
-  prev_lm = tail->lm_info->lm_addr;
+  prev_lm = svr4_lm_info (tail)->lm_addr;
 
   /* Read the new objects.  */
   if (info->using_xfer)
@@ -3187,7 +3110,8 @@ set_solib_svr4_fetch_link_map_offsets (struct gdbarch *gdbarch,
 
   ops->fetch_link_map_offsets = flmo;
 
-  set_solib_ops (gdbarch, &svr4_so_ops);
+  if (solib_ops (gdbarch) == NULL)
+    set_solib_ops (gdbarch, &svr4_so_ops);
 }
 
 /* Fetch a link_map_offsets structure using the architecture-specific
diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h
index d541136..87650d1 100644
--- a/gdb/solib-svr4.h
+++ b/gdb/solib-svr4.h
@@ -63,6 +63,27 @@ struct link_map_offsets
     int l_name_offset;
   };
 
+/* Link map info to include in an allocated so_list entry.  */
+
+struct svr4_lm_info
+  {
+    /* Amount by which addresses in the binary should be relocated to
+       match the inferior.  The direct inferior value is L_ADDR_INFERIOR.
+       When prelinking is involved and the prelink base address changes,
+       we may need a different offset - the recomputed offset is in L_ADDR.
+       It is commonly the same value.  It is cached as we want to warn about
+       the difference and compute it only once.  L_ADDR is valid
+       iff L_ADDR_P.  */
+    CORE_ADDR l_addr, l_addr_inferior;
+    unsigned int l_addr_p : 1;
+
+    /* The target location of lm.  */
+    CORE_ADDR lm_addr;
+
+    /* Values read in from inferior's fields of the same name.  */
+    CORE_ADDR l_ld, l_next, l_prev, l_name;
+  };
+
 /* set_solib_svr4_fetch_link_map_offsets() is intended to be called by
    a <arch>_gdbarch_init() function.  It is used to establish an
    architecture specific link_map_offsets fetcher for the architecture
diff --git a/gdb/solib.c b/gdb/solib.c
index 2235505..84ed485 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -62,7 +62,7 @@ solib_init (struct obstack *obstack)
   return ops;
 }
 
-static const struct target_so_ops *
+const struct target_so_ops *
 solib_ops (struct gdbarch *gdbarch)
 {
   const struct target_so_ops **ops
diff --git a/gdb/solib.h b/gdb/solib.h
index 00fd6cb..d594ea2 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -68,6 +68,10 @@ extern int in_solib_dynsym_resolve_code (CORE_ADDR);
 
 extern void no_shared_libraries (char *ignored, int from_tty);
 
+/* Get the solib operations for GDBARCH.  */
+
+const struct target_so_ops *solib_ops (struct gdbarch *gdbarch);
+
 /* Set the solib operations for GDBARCH to NEW_OPS.  */
 
 extern void set_solib_ops (struct gdbarch *gdbarch,
diff --git a/gdb/symfile-mem.c b/gdb/symfile-mem.c
index 79739a6..00d20a2 100644
--- a/gdb/symfile-mem.c
+++ b/gdb/symfile-mem.c
@@ -82,7 +82,7 @@ target_read_memory_bfd (bfd_vma memaddr, bfd_byte *myaddr, bfd_size_type len)
    which will be attached to the BFD.  */
 static struct objfile *
 symbol_file_add_from_memory (struct bfd *templ, CORE_ADDR addr,
-			     size_t size, char *name, int from_tty)
+			     size_t size, char *name, int add_flags)
 {
   struct objfile *objf;
   struct bfd *nbfd;
@@ -127,8 +127,7 @@ symbol_file_add_from_memory (struct bfd *templ, CORE_ADDR addr,
   sai->num_sections = i;
 
   objf = symbol_file_add_from_bfd (nbfd, bfd_get_filename (nbfd),
-				   from_tty ? SYMFILE_VERBOSE : 0,
-                                   sai, OBJF_SHARED, NULL);
+				   add_flags, sai, OBJF_SHARED, NULL);
 
   add_target_sections_of_objfile (objf);
 
@@ -145,6 +144,7 @@ add_symbol_file_from_memory_command (char *args, int from_tty)
 {
   CORE_ADDR addr;
   struct bfd *templ;
+  int add_flags = from_tty ? SYMFILE_VERBOSE : 0;
 
   if (args == NULL)
     error (_("add-symbol-file-from-memory requires an expression argument"));
@@ -160,7 +160,7 @@ add_symbol_file_from_memory_command (char *args, int from_tty)
     error (_("Must use symbol-file or exec-file "
 	     "before add-symbol-file-from-memory."));
 
-  symbol_file_add_from_memory (templ, addr, 0, NULL, from_tty);
+  symbol_file_add_from_memory (templ, addr, 0, NULL, add_flags);
 }
 
 /* Arguments for symbol_file_add_from_memory_wrapper.  */
@@ -171,7 +171,7 @@ struct symbol_file_add_from_memory_args
   CORE_ADDR sysinfo_ehdr;
   size_t size;
   char *name;
-  int from_tty;
+  int add_flags;
 };
 
 /* Wrapper function for symbol_file_add_from_memory, for
@@ -184,19 +184,15 @@ symbol_file_add_from_memory_wrapper (struct ui_out *uiout, void *data)
     = (struct symbol_file_add_from_memory_args *) data;
 
   symbol_file_add_from_memory (args->bfd, args->sysinfo_ehdr, args->size,
-			       args->name, args->from_tty);
+			       args->name, args->add_flags);
   return 0;
 }
 
-/* Try to add the symbols for the vsyscall page, if there is one.
-   This function is called via the inferior_created observer.  */
+/* See symfile-mem.h.  */
 
-static void
-add_vsyscall_page (struct target_ops *target, int from_tty)
+void
+add_vsyscall_page (struct mem_range *vsyscall_range, int add_flags)
 {
-  struct mem_range vsyscall_range;
-
-  if (gdbarch_vsyscall_range (target_gdbarch (), &vsyscall_range))
     {
       struct bfd *bfd;
       struct symbol_file_add_from_memory_args args;
@@ -218,15 +214,13 @@ add_vsyscall_page (struct target_ops *target, int from_tty)
 	  return;
 	}
       args.bfd = bfd;
-      args.sysinfo_ehdr = vsyscall_range.start;
-      args.size = vsyscall_range.length;
+      args.sysinfo_ehdr = vsyscall_range->start;
+      args.size = vsyscall_range->length;
 
       args.name = xstrprintf ("system-supplied DSO at %s",
-			      paddress (target_gdbarch (), vsyscall_range.start));
-      /* Pass zero for FROM_TTY, because the action of loading the
-	 vsyscall DSO was not triggered by the user, even if the user
-	 typed "run" at the TTY.  */
-      args.from_tty = 0;
+			      paddress (target_gdbarch (),
+					vsyscall_range->start));
+      args.add_flags = add_flags;
       catch_exceptions (current_uiout, symbol_file_add_from_memory_wrapper,
 			&args, RETURN_MASK_ALL);
     }
@@ -247,8 +241,4 @@ _initialize_symfile_mem (void)
 	     "Give an expression for the address "
 	     "of the file's shared object file header."),
            &cmdlist);
-
-  /* Want to know of each new inferior so that its vsyscall info can
-     be extracted.  */
-  observer_attach_inferior_created (add_vsyscall_page);
 }
diff --git a/gdb/symfile-mem.h b/gdb/symfile-mem.h
new file mode 100644
index 0000000..df0e879
--- /dev/null
+++ b/gdb/symfile-mem.h
@@ -0,0 +1,30 @@
+/* Definitions for reading symbol files from memory into GDB.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#if !defined (SYMFILE_MEM_H)
+#define SYMFILE_MEM_H
+
+struct mem_range;
+
+/* Try to add the symbols for the vsyscall page, if there is one.  */
+
+extern void add_vsyscall_page (struct mem_range *vsyscall_range,
+			       int add_flags);
+
+#endif /* !defined(SYMFILE_MEM_H) */
-- 
2.5.5

>From 17811ce925279d3a64eb04541591cb5c567ef3cc Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 18 Aug 2016 23:00:52 +0100
Subject: [PATCH 2/2] Make vDSO detection work with core files

- Make gdb.base/vdso-warning.exp test loading a core.  With
  LD_DEBUG=unused, we see the warning on systems with local glibc
  patches as well (Fedora/RHEL).

- When debugging a core, we can't find the size of the vDSO from the
  mappings, because they're nowhere to be found.  However, we can
  still read the vDSO out of memory when we don't know its size.  BFD
  will figure it out from the ELF structure.  In fact, this is what we
  always used to do before 5979d6b69b20 ("Handle VDSO section headers
  past end of page").

  So the fix is to read the vDSO out of memory before we ever fetch
  the current list of DSOs, and extract the vDSO size out of the size
  of the bfd read in.
---
 gdb/linux-tdep.c                        | 27 +++++++-----
 gdb/symfile-mem.c                       | 24 ++++++++++-
 gdb/testsuite/gdb.base/vdso-warning.exp | 76 ++++++++++++++++++++++-----------
 3 files changed, 90 insertions(+), 37 deletions(-)

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 91931eb..7d1d547 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -193,7 +193,7 @@ static const struct inferior_data *linux_inferior_data;
    transfering data from a remote target to the local host.  */
 struct linux_info
 {
-  /* Cache of the inferior's vsyscall/vDSO mapping range.  Only valid
+  /* Cache of the inferior's vsyscall/vDSO address range.  Only valid
      if VSYSCALL_RANGE_P is positive.  This is cached because getting
      at this info requires an auxv lookup (which is itself cached),
      and looking through the inferior's mappings (which change
@@ -2286,7 +2286,8 @@ linux_gdb_signal_to_target (struct gdbarch *gdbarch,
 }
 
 /* Helper for linux_vsyscall_range that does the real work of finding
-   the vsyscall's address range.  */
+   the vsyscall's address range based on auxv info and page
+   mappings.  */
 
 static int
 linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
@@ -2295,16 +2296,21 @@ linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
   long pid;
   char *data;
 
-  /* Can't access /proc if debugging a core file.  */
-  if (!target_has_execution)
+  if (target_auxv_search (&current_target, AT_SYSINFO_EHDR, &range->start) <= 0)
     return 0;
 
+  /* Alright, we know the starting address.  Let's see if we can find
+     the end address.  */
+  range->length = 0;
+
+  /* Can't access /proc if debugging a core file, and NT_FILE notes
+     don't include the vDSO mapping.  */
+  if (!target_has_execution)
+    return 1;
+
   /* We need to know the real target PID to access /proc.  */
   if (current_inferior ()->fake_pid_p)
-    return 0;
-
-  if (target_auxv_search (&current_target, AT_SYSINFO_EHDR, &range->start) <= 0)
-    return 0;
+    return 1;
 
   pid = current_inferior ()->pid;
 
@@ -2338,8 +2344,7 @@ linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
 		p++;
 	      endaddr = strtoulst (p, &p, 16);
 	      range->length = endaddr - addr;
-	      do_cleanups (cleanup);
-	      return 1;
+	      break;
 	    }
 	}
 
@@ -2348,7 +2353,7 @@ linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
   else
     warning (_("unable to open /proc file '%s'"), filename);
 
-  return 0;
+  return 1;
 }
 
 /* Find the address range of the current inferior's vDSO.  If the
diff --git a/gdb/symfile-mem.c b/gdb/symfile-mem.c
index 00d20a2..e172404 100644
--- a/gdb/symfile-mem.c
+++ b/gdb/symfile-mem.c
@@ -167,11 +167,15 @@ add_symbol_file_from_memory_command (char *args, int from_tty)
 
 struct symbol_file_add_from_memory_args
 {
+  /* Inputs.  */
   struct bfd *bfd;
   CORE_ADDR sysinfo_ehdr;
   size_t size;
   char *name;
   int add_flags;
+
+  /* Outputs.  */
+  struct objfile *objf_added;
 };
 
 /* Wrapper function for symbol_file_add_from_memory, for
@@ -183,8 +187,10 @@ symbol_file_add_from_memory_wrapper (struct ui_out *uiout, void *data)
   struct symbol_file_add_from_memory_args *args
     = (struct symbol_file_add_from_memory_args *) data;
 
-  symbol_file_add_from_memory (args->bfd, args->sysinfo_ehdr, args->size,
-			       args->name, args->add_flags);
+  args->objf_added = symbol_file_add_from_memory (args->bfd,
+						  args->sysinfo_ehdr,
+						  args->size, args->name,
+						  args->add_flags);
   return 0;
 }
 
@@ -196,6 +202,7 @@ add_vsyscall_page (struct mem_range *vsyscall_range, int add_flags)
     {
       struct bfd *bfd;
       struct symbol_file_add_from_memory_args args;
+      struct stat statbuf;
 
       if (core_bfd != NULL)
 	bfd = core_bfd;
@@ -223,6 +230,19 @@ add_vsyscall_page (struct mem_range *vsyscall_range, int add_flags)
       args.add_flags = add_flags;
       catch_exceptions (current_uiout, symbol_file_add_from_memory_wrapper,
 			&args, RETURN_MASK_ALL);
+
+      /* If we couldn't find the size of the vDSO from the mappings,
+	 then set it from the size of the bfd that we just read
+	 in.  */
+      if (vsyscall_range->length == 0)
+	{
+	  if (bfd_stat (args.objf_added->obfd, &statbuf) < 0)
+	    {
+	      internal_error (__FILE__, __LINE__,
+			      _("bfd_stat on memfile bfd failed"));
+	    }
+	  vsyscall_range->length = statbuf.st_size;
+	}
     }
 }
 
diff --git a/gdb/testsuite/gdb.base/vdso-warning.exp b/gdb/testsuite/gdb.base/vdso-warning.exp
index af2b2b0..aeb85a2 100644
--- a/gdb/testsuite/gdb.base/vdso-warning.exp
+++ b/gdb/testsuite/gdb.base/vdso-warning.exp
@@ -13,42 +13,70 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+# Test that on Linux, we don't warn about not finding the vDSO.  E.g.:
+#
+#   warning: Could not load shared library symbols for linux-vdso.so.1.
+
 standard_testfile
 
 if { [prepare_for_testing "failed to prepare" ${testfile} $srcfile] } {
     return -1
 }
 
-gdb_breakpoint "main"
+with_test_prefix "setup" {
+    gdb_breakpoint "main"
 
-# At least some versions of Fedora/RHEL glibc have local patches that
-# hide the vDSO.  This lines re-exposes it.  See PR libc/13097,
-# comment 2.  There's no support for passing environment variables in
-# the remote protocol, but that's OK -- if we're testing against a
-# glibc that doesn't list the vDSO without this, the test should still
-# pass.
-gdb_test_no_output "set environment LD_DEBUG=unused"
+    # At least some versions of Fedora/RHEL glibc have local patches that
+    # hide the vDSO.  This lines re-exposes it.  See PR libc/13097,
+    # comment 2.  There's no support for passing environment variables in
+    # the remote protocol, but that's OK -- if we're testing against a
+    # glibc that doesn't list the vDSO without this, the test should still
+    # pass.
+    gdb_test_no_output "set environment LD_DEBUG=unused"
+}
 
-gdb_run_cmd
+proc test_no_vdso {command} {
+    global srcfile
+    global gdb_prompt
 
-set test "stop without warning"
-gdb_test_multiple "" $test {
-    -re "Could not load shared library symbols .*\r\n$gdb_prompt $" {
-	fail $test
+    set message "startup"
+    gdb_test_multiple "$command" $message {
+	-re "Could not load shared library symbols .*\r\n$gdb_prompt $" {
+	    fail $message
+	}
+	-re "main \\(\\) at .*$srcfile.*\r\n$gdb_prompt $" {
+	    pass $message
+	}
     }
-    -re "\r\nBreakpoint \[0-9\]+, main .*\r\n$gdb_prompt $" {
-	pass $test
+
+    # Extra testing in case the warning changes and we miss updating
+    # the above.
+    set test "no vdso without symbols is listed"
+    gdb_test_multiple "info shared" $test {
+	-re "No\[^\r\n\]+linux-(vdso|gate).*$gdb_prompt $" {
+	    fail $test
+	}
+	-re "$gdb_prompt $" {
+	    pass $test
+	}
     }
 }
 
-# Extra testing in case the warning changes and we miss updating the
-# above.
-set test "no vdso without symbols is listed"
-gdb_test_multiple "info shared" $test {
-    -re "No\[^\r\n\]+linux-(vdso|gate).*$gdb_prompt $" {
-	fail $test
-    }
-    -re "$gdb_prompt $" {
-	pass $test
+# First, try a live process.
+with_test_prefix "run" {
+    gdb_run_cmd
+    test_no_vdso ""
+}
+
+# Now, dump a core, and reload it.
+with_test_prefix "core" {
+    set corefile [standard_output_file $testfile.core]
+    set core_supported [gdb_gcore_cmd "$corefile" "save a corefile"]
+    if {!$core_supported} {
+	return -1
     }
+
+    clean_restart ${testfile}
+
+    test_no_vdso "core-file $corefile"
 }
-- 
2.5.5


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]