Split vDSO range lookup to a gdbarch hook

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.
This commit is contained in:
Pedro Alves
2014-10-10 15:57:13 +01:00
parent 31cc0b807b
commit 3437254d7b
10 changed files with 120 additions and 26 deletions

View File

@ -1,3 +1,17 @@
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> 2014-10-10 Pedro Alves <palves@redhat.com>
* infrun.c (normal_stop): Fix typo in comment. * infrun.c (normal_stop): Fix typo in comment.

View File

@ -243,6 +243,14 @@ default_remote_register_number (struct gdbarch *gdbarch,
return regno; return regno;
} }
/* See arch-utils.h. */
int
default_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
{
return 0;
}
/* Functions to manipulate the endianness of the target. */ /* Functions to manipulate the endianness of the target. */

View 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_call (struct gdbarch *, CORE_ADDR);
extern int default_insn_is_ret (struct gdbarch *, CORE_ADDR); extern int default_insn_is_ret (struct gdbarch *, CORE_ADDR);
extern int default_insn_is_jump (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 #endif

View File

@ -315,6 +315,7 @@ struct gdbarch
gdbarch_insn_is_ret_ftype *insn_is_ret; gdbarch_insn_is_ret_ftype *insn_is_ret;
gdbarch_insn_is_jump_ftype *insn_is_jump; gdbarch_insn_is_jump_ftype *insn_is_jump;
gdbarch_auxv_parse_ftype *auxv_parse; gdbarch_auxv_parse_ftype *auxv_parse;
gdbarch_vsyscall_range_ftype *vsyscall_range;
}; };
/* Create a new ``struct gdbarch'' based on information provided by /* 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_call = default_insn_is_call;
gdbarch->insn_is_ret = default_insn_is_ret; gdbarch->insn_is_ret = default_insn_is_ret;
gdbarch->insn_is_jump = default_insn_is_jump; gdbarch->insn_is_jump = default_insn_is_jump;
gdbarch->vsyscall_range = default_vsyscall_range;
/* gdbarch_alloc() */ /* gdbarch_alloc() */
return gdbarch; 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_ret, invalid_p == 0 */
/* Skip verify of insn_is_jump, invalid_p == 0 */ /* Skip verify of insn_is_jump, invalid_p == 0 */
/* Skip verify of auxv_parse, has predicate. */ /* Skip verify of auxv_parse, has predicate. */
/* Skip verify of vsyscall_range, invalid_p == 0 */
buf = ui_file_xstrdup (log, &length); buf = ui_file_xstrdup (log, &length);
make_cleanup (xfree, buf); make_cleanup (xfree, buf);
if (length > 0) if (length > 0)
@ -1291,6 +1294,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file, fprintf_unfiltered (file,
"gdbarch_dump: virtual_frame_pointer = <%s>\n", "gdbarch_dump: virtual_frame_pointer = <%s>\n",
host_address_to_string (gdbarch->virtual_frame_pointer)); 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, fprintf_unfiltered (file,
"gdbarch_dump: vtable_function_descriptors = %s\n", "gdbarch_dump: vtable_function_descriptors = %s\n",
plongest (gdbarch->vtable_function_descriptors)); plongest (gdbarch->vtable_function_descriptors));
@ -4383,6 +4389,23 @@ set_gdbarch_auxv_parse (struct gdbarch *gdbarch,
gdbarch->auxv_parse = auxv_parse; 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 /* Keep a registry of per-architecture data-pointers required by GDB
modules. */ modules. */

View File

@ -59,6 +59,7 @@ struct axs_value;
struct stap_parse_info; struct stap_parse_info;
struct ravenscar_arch_ops; struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo; struct elf_internal_linux_prpsinfo;
struct mem_range;
/* The architecture associated with the inferior through the /* The architecture associated with the inferior through the
connection to the target. 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 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); 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. */ /* Definition for an unknown syscall, used basically in error-cases. */
#define UNKNOWN_SYSCALL (-1) #define UNKNOWN_SYSCALL (-1)

View File

@ -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 there is insufficient buffer for a whole entry.
# Return 1 if an entry was read into *TYPEP and *VALP. # 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 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 EOF
} }
@ -1149,6 +1155,7 @@ struct axs_value;
struct stap_parse_info; struct stap_parse_info;
struct ravenscar_arch_ops; struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo; struct elf_internal_linux_prpsinfo;
struct mem_range;
/* The architecture associated with the inferior through the /* The architecture associated with the inferior through the
connection to the target. connection to the target.

View File

@ -1796,6 +1796,40 @@ linux_gdb_signal_to_target (struct gdbarch *gdbarch,
return -1; 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 /* To be called from the various GDB_OSABI_LINUX handlers for the
various GNU/Linux architectures and machine types. */ 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); linux_gdb_signal_from_target);
set_gdbarch_gdb_signal_to_target (gdbarch, set_gdbarch_gdb_signal_to_target (gdbarch,
linux_gdb_signal_to_target); linux_gdb_signal_to_target);
set_gdbarch_vsyscall_range (gdbarch, linux_vsyscall_range);
} }
/* Provide a prototype to silence -Wmissing-prototypes. */ /* Provide a prototype to silence -Wmissing-prototypes. */

View File

@ -31,6 +31,15 @@ mem_ranges_overlap (CORE_ADDR start1, int len1,
return (l < h); 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 /* qsort comparison function, that compares mem_ranges. Ranges are
sorted in ascending START order. */ sorted in ascending START order. */

View File

@ -43,6 +43,11 @@ DEF_VEC_O(mem_range_s);
extern int mem_ranges_overlap (CORE_ADDR start1, int len1, extern int mem_ranges_overlap (CORE_ADDR start1, int len1,
CORE_ADDR start2, int len2); 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 /* Sort ranges by start address, then coalesce contiguous or
overlapping ranges. */ overlapping ranges. */

View File

@ -187,33 +187,15 @@ symbol_file_add_from_memory_wrapper (struct ui_out *uiout, void *data)
return 0; 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. /* Try to add the symbols for the vsyscall page, if there is one.
This function is called via the inferior_created observer. */ This function is called via the inferior_created observer. */
static void static void
add_vsyscall_page (struct target_ops *target, int from_tty) 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 if (gdbarch_vsyscall_range (target_gdbarch (), &vsyscall_range))
&& sysinfo_ehdr != (CORE_ADDR) 0)
{ {
struct bfd *bfd; struct bfd *bfd;
struct symbol_file_add_from_memory_args args; struct symbol_file_add_from_memory_args args;
@ -236,14 +218,11 @@ add_vsyscall_page (struct target_ops *target, int from_tty)
return; return;
} }
args.bfd = bfd; args.bfd = bfd;
args.sysinfo_ehdr = sysinfo_ehdr; args.sysinfo_ehdr = vsyscall_range.start;
args.size = 0; args.size = vsyscall_range.length;
if (gdbarch_find_memory_regions_p (target_gdbarch ()))
(void) gdbarch_find_memory_regions (target_gdbarch (),
find_vdso_size, &args);
args.name = xstrprintf ("system-supplied DSO at %s", 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 /* Pass zero for FROM_TTY, because the action of loading the
vsyscall DSO was not triggered by the user, even if the user vsyscall DSO was not triggered by the user, even if the user
typed "run" at the TTY. */ typed "run" at the TTY. */