Split vDSO range lookup to a gdbarch hook
authorPedro Alves <palves@redhat.com>
Fri, 10 Oct 2014 14:57:13 +0000 (15:57 +0100)
committerPedro Alves <palves@redhat.com>
Fri, 10 Oct 2014 14:57:13 +0000 (15:57 +0100)
We have a case in solib-svr4.c where we could reuse symfile-mem.c's
vDSO range lookup.  Since symfile-mem.c is not present in all
configurations solib-svr4.c is, move that lookup to a gdbarch hook.

This has the minor (good) side effect that we stop even trying the
target_auxv_search lookup against targets that don't have a concept of
a vDSO, in case symfile-mem.c happens to be linked in the build
(--enable-targets=all).

Tested on x86_64 Fedora 20.

gdb/
2014-10-10  Pedro Alves  <palves@redhat.com>

* arch-utils.c (default_vsyscall_range): New function.
* arch-utils.h (default_vsyscall_range): New declaration.
* gdbarch.sh (vsyscall_range): New hook.
* gdbarch.h, gdbarch.c: Regenerate.
* linux-tdep.c (linux_vsyscall_range): New function.
(linux_init_abi): Install linux_vsyscall_range as
vsyscall_range gdbarch hook.
* memrange.c (address_in_mem_range): New function.
* memrange.h (address_in_mem_range): New declaration.
* symfile-mem.c (find_vdso_size): Delete function.
(add_vsyscall_page): Use gdbarch_vsyscall_range.

gdb/ChangeLog
gdb/arch-utils.c
gdb/arch-utils.h
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/linux-tdep.c
gdb/memrange.c
gdb/memrange.h
gdb/symfile-mem.c

index 8d5b1ee..8923698 100644 (file)
@@ -1,5 +1,19 @@
 2014-10-10  Pedro Alves  <palves@redhat.com>
 
+       * arch-utils.c (default_vsyscall_range): New function.
+       * arch-utils.h (default_vsyscall_range): New declaration.
+       * gdbarch.sh (vsyscall_range): New hook.
+       * gdbarch.h, gdbarch.c: Regenerate.
+       * linux-tdep.c (linux_vsyscall_range): New function.
+       (linux_init_abi): Install linux_vsyscall_range as
+       vsyscall_range gdbarch hook.
+       * memrange.c (address_in_mem_range): New function.
+       * memrange.h (address_in_mem_range): New declaration.
+       * symfile-mem.c (find_vdso_size): Delete function.
+       (add_vsyscall_page): Use gdbarch_vsyscall_range.
+
+2014-10-10  Pedro Alves  <palves@redhat.com>
+
        * infrun.c (normal_stop): Fix typo in comment.
 
 2014-10-09  Sergio Durigan Junior  <sergiodj@redhat.com>
index 5ae9fb3..41cf828 100644 (file)
@@ -243,6 +243,14 @@ default_remote_register_number (struct gdbarch *gdbarch,
   return regno;
 }
 
+/* See arch-utils.h.  */
+
+int
+default_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
+{
+  return 0;
+}
+
 \f
 /* Functions to manipulate the endianness of the target.  */
 
index 46d1573..a609662 100644 (file)
@@ -174,4 +174,8 @@ extern int default_return_in_first_hidden_param_p (struct gdbarch *,
 extern int default_insn_is_call (struct gdbarch *, CORE_ADDR);
 extern int default_insn_is_ret (struct gdbarch *, CORE_ADDR);
 extern int default_insn_is_jump (struct gdbarch *, CORE_ADDR);
+
+/* Do-nothing version of vsyscall_range.  Returns false.  */
+
+extern int default_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range);
 #endif
index e96d651..2984358 100644 (file)
@@ -315,6 +315,7 @@ struct gdbarch
   gdbarch_insn_is_ret_ftype *insn_is_ret;
   gdbarch_insn_is_jump_ftype *insn_is_jump;
   gdbarch_auxv_parse_ftype *auxv_parse;
+  gdbarch_vsyscall_range_ftype *vsyscall_range;
 };
 
 /* Create a new ``struct gdbarch'' based on information provided by
@@ -407,6 +408,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->insn_is_call = default_insn_is_call;
   gdbarch->insn_is_ret = default_insn_is_ret;
   gdbarch->insn_is_jump = default_insn_is_jump;
+  gdbarch->vsyscall_range = default_vsyscall_range;
   /* gdbarch_alloc() */
 
   return gdbarch;
@@ -626,6 +628,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of insn_is_ret, invalid_p == 0 */
   /* Skip verify of insn_is_jump, invalid_p == 0 */
   /* Skip verify of auxv_parse, has predicate.  */
+  /* Skip verify of vsyscall_range, invalid_p == 0 */
   buf = ui_file_xstrdup (log, &length);
   make_cleanup (xfree, buf);
   if (length > 0)
@@ -1292,6 +1295,9 @@ 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,
@@ -4383,6 +4389,23 @@ set_gdbarch_auxv_parse (struct gdbarch *gdbarch,
   gdbarch->auxv_parse = auxv_parse;
 }
 
+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;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules.  */
index 6e84004..f5330c2 100644 (file)
@@ -59,6 +59,7 @@ struct axs_value;
 struct stap_parse_info;
 struct ravenscar_arch_ops;
 struct elf_internal_linux_prpsinfo;
+struct mem_range;
 
 /* The architecture associated with the inferior through the
    connection to the target.
@@ -1320,6 +1321,15 @@ typedef int (gdbarch_auxv_parse_ftype) (struct gdbarch *gdbarch, gdb_byte **read
 extern int gdbarch_auxv_parse (struct gdbarch *gdbarch, gdb_byte **readptr, gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp);
 extern void set_gdbarch_auxv_parse (struct gdbarch *gdbarch, gdbarch_auxv_parse_ftype *auxv_parse);
 
+/* 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);
+
 /* Definition for an unknown syscall, used basically in error-cases.  */
 #define UNKNOWN_SYSCALL (-1)
 
index c785887..5442799 100755 (executable)
@@ -1030,6 +1030,12 @@ m:int:insn_is_jump:CORE_ADDR addr:addr::default_insn_is_jump::0
 # Return -1 if there is insufficient buffer for a whole entry.
 # Return 1 if an entry was read into *TYPEP and *VALP.
 M:int:auxv_parse:gdb_byte **readptr, gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp:readptr, endptr, typep, valp
+
+# 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
 EOF
 }
 
@@ -1149,6 +1155,7 @@ struct axs_value;
 struct stap_parse_info;
 struct ravenscar_arch_ops;
 struct elf_internal_linux_prpsinfo;
+struct mem_range;
 
 /* The architecture associated with the inferior through the
    connection to the target.
index 7a76670..2ffd992 100644 (file)
@@ -1796,6 +1796,40 @@ linux_gdb_signal_to_target (struct gdbarch *gdbarch,
   return -1;
 }
 
+/* Rummage through mappings to find a mapping's size.  */
+
+static int
+find_mapping_size (CORE_ADDR vaddr, unsigned long size,
+                  int read, int write, int exec, int modified,
+                  void *data)
+{
+  struct mem_range *range = data;
+
+  if (vaddr == range->start)
+    {
+      range->length = size;
+      return 1;
+    }
+  return 0;
+}
+
+/* Implementation of the "vsyscall_range" gdbarch hook.  */
+
+static int
+linux_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
+{
+  if (target_auxv_search (&current_target, AT_SYSINFO_EHDR, &range->start) <= 0)
+    return 0;
+
+  /* This is installed by linux_init_abi below, so should always be
+     available.  */
+  gdb_assert (gdbarch_find_memory_regions_p (target_gdbarch ()));
+
+  range->length = 0;
+  gdbarch_find_memory_regions (gdbarch, find_mapping_size, range);
+  return 1;
+}
+
 /* To be called from the various GDB_OSABI_LINUX handlers for the
    various GNU/Linux architectures and machine types.  */
 
@@ -1813,6 +1847,7 @@ 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);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
index 2895ff2..485550b 100644 (file)
@@ -31,6 +31,15 @@ mem_ranges_overlap (CORE_ADDR start1, int len1,
   return (l < h);
 }
 
+/* See memrange.h.  */
+
+int
+address_in_mem_range (CORE_ADDR address, const struct mem_range *r)
+{
+  return (r->start <= address
+         && (address - r->start) < r->length);
+}
+
 /* qsort comparison function, that compares mem_ranges.  Ranges are
    sorted in ascending START order.  */
 
index 8c25d0a..2591789 100644 (file)
@@ -43,6 +43,11 @@ DEF_VEC_O(mem_range_s);
 extern int mem_ranges_overlap (CORE_ADDR start1, int len1,
                               CORE_ADDR start2, int len2);
 
+/* Returns true if ADDR is in RANGE.  */
+
+extern int address_in_mem_range (CORE_ADDR addr,
+                                const struct mem_range *range);
+
 /* Sort ranges by start address, then coalesce contiguous or
    overlapping ranges.  */
 
index b6986b0..eea97fd 100644 (file)
@@ -187,33 +187,15 @@ symbol_file_add_from_memory_wrapper (struct ui_out *uiout, void *data)
   return 0;
 }
 
-/* Rummage through mappings to find the vsyscall page size.  */
-
-static int
-find_vdso_size (CORE_ADDR vaddr, unsigned long size,
-               int read, int write, int exec, int modified,
-               void *data)
-{
-  struct symbol_file_add_from_memory_args *args = data;
-
-  if (vaddr == args->sysinfo_ehdr)
-    {
-      args->size = size;
-      return 1;
-    }
-  return 0;
-}
-
 /* Try to add the symbols for the vsyscall page, if there is one.
    This function is called via the inferior_created observer.  */
 
 static void
 add_vsyscall_page (struct target_ops *target, int from_tty)
 {
-  CORE_ADDR sysinfo_ehdr;
+  struct mem_range vsyscall_range;
 
-  if (target_auxv_search (target, AT_SYSINFO_EHDR, &sysinfo_ehdr) > 0
-      && sysinfo_ehdr != (CORE_ADDR) 0)
+  if (gdbarch_vsyscall_range (target_gdbarch (), &vsyscall_range))
     {
       struct bfd *bfd;
       struct symbol_file_add_from_memory_args args;
@@ -236,14 +218,11 @@ add_vsyscall_page (struct target_ops *target, int from_tty)
          return;
        }
       args.bfd = bfd;
-      args.sysinfo_ehdr = sysinfo_ehdr;
-      args.size = 0;
-      if (gdbarch_find_memory_regions_p (target_gdbarch ()))
-       (void) gdbarch_find_memory_regions (target_gdbarch (),
-                                           find_vdso_size, &args);
+      args.sysinfo_ehdr = vsyscall_range.start;
+      args.size = vsyscall_range.length;
 
       args.name = xstrprintf ("system-supplied DSO at %s",
-                             paddress (target_gdbarch (), sysinfo_ehdr));
+                             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.  */