From d68e53f47932eb7c374df9b90faed7aca2eed9d7 Mon Sep 17 00:00:00 2001 From: Markus Metzger Date: Thu, 29 Jan 2015 10:43:05 +0100 Subject: [PATCH] btrace: support 32-bit inferior on 64-bit host The heuristic for filtering out kernel addressess in BTS trace checks the most significant bit in each address. This works fine for 32-bit and 64-bit mode. For 32-bit compatibility mode, i.e. a 32-bit inferior running on 64-bit host, we need to check bit 63 (or any bit bigger than 31), not bit 31. Use the machine field in struct utsname provided by a uname call to determine whether we are running on a 64-bit host. Thanks to Jan Kratochvil for reporting the issue. gdb/ * nat/linux-btrace.c: Include sys/utsname.h. (linux_determine_kernel_ptr_bits): New. (linux_enable_bts): Call linux_determine_kernel_ptr_bits. * x86-linux-nat.c (x86_linux_enable_btrace): Do not overwrite non-zero ptr_bits. gdbserver/ * linux-low.c (linux_low_enable_btrace): Do not overwrite non-zero ptr_bits. --- gdb/ChangeLog | 8 ++++++++ gdb/gdbserver/ChangeLog | 5 +++++ gdb/gdbserver/linux-low.c | 2 +- gdb/nat/linux-btrace.c | 28 +++++++++++++++++++++++++++- gdb/x86-linux-nat.c | 8 +++++--- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3e9fa55e957..1db98ff9f67 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2015-03-03 Markus Metzger + + * nat/linux-btrace.c: Include sys/utsname.h. + (linux_determine_kernel_ptr_bits): New. + (linux_enable_bts): Call linux_determine_kernel_ptr_bits. + * x86-linux-nat.c (x86_linux_enable_btrace): Do not overwrite non-zero + ptr_bits. + 2015-03-03 Markus Metzger * btrace.c (ftrace_update_function): Treat return as tailcall for diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 456985386c8..208601d1d6b 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,8 @@ +2015-03-03 Markus Metzger + + * linux-low.c (linux_low_enable_btrace): Do not overwrite non-zero + ptr_bits. + 2015-03-02 Andreas Arnez * Makefile.in (s390-vx-linux64.c, s390-tevx-linux64.c) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index a278c9a7a0c..452d0fceceb 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -5956,7 +5956,7 @@ linux_low_enable_btrace (ptid_t ptid, const struct btrace_config *conf) tinfo = linux_enable_btrace (ptid, conf); - if (tinfo != NULL) + if (tinfo != NULL && tinfo->ptr_bits == 0) { struct thread_info *thread = find_thread_ptid (ptid); struct regcache *regcache = get_thread_regcache (thread, 0); diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c index 3093a5cf8c7..e7aff5e4ad3 100644 --- a/gdb/nat/linux-btrace.c +++ b/gdb/nat/linux-btrace.c @@ -38,6 +38,7 @@ #include #include #include +#include /* A branch trace record in perf_event. */ struct perf_event_bts @@ -102,6 +103,31 @@ perf_event_new_data (const struct perf_event_buffer *pev) return *pev->data_head != pev->last_head; } +/* Try to determine the size of a pointer in bits for the OS. + + This is the same as the size of a pointer for the inferior process + except when a 32-bit inferior is running on a 64-bit OS. */ + +static int +linux_determine_kernel_ptr_bits (void) +{ + struct utsname utsn; + int errcode; + + memset (&utsn, 0, sizeof (utsn)); + + errcode = uname (&utsn); + if (errcode < 0) + return 0; + + /* We only need to handle the 64-bit host case, here. For 32-bit host, + the pointer size can be filled in later based on the inferior. */ + if (strcmp (utsn.machine, "x86_64") == 0) + return 64; + + return 0; +} + /* Check whether an address is in the kernel. */ static inline int @@ -434,7 +460,7 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf) tinfo = xzalloc (sizeof (*tinfo)); tinfo->ptid = ptid; - tinfo->ptr_bits = 0; + tinfo->ptr_bits = linux_determine_kernel_ptr_bits (); tinfo->conf.format = BTRACE_FORMAT_BTS; bts = &tinfo->variant.bts; diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c index c58c01a2bb7..7f038f01b56 100644 --- a/gdb/x86-linux-nat.c +++ b/gdb/x86-linux-nat.c @@ -450,9 +450,11 @@ x86_linux_enable_btrace (struct target_ops *self, ptid_t ptid, target_pid_to_str (ptid), safe_strerror (errno)); /* Fill in the size of a pointer in bits. */ - gdbarch = target_thread_architecture (ptid); - tinfo->ptr_bits = gdbarch_ptr_bit (gdbarch); - + if (tinfo->ptr_bits == 0) + { + gdbarch = target_thread_architecture (ptid); + tinfo->ptr_bits = gdbarch_ptr_bit (gdbarch); + } return tinfo; } -- 2.30.2