[PATCH v3 12/15] btrace: support 32-bit inferior on 64-bit host

Markus Metzger
2015-01-29T16:28:58Z

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.

CC: Jan Kratochvil <jan.kratochvil@redhat.com>

2015-01-29 Markus Metzger <markus.t.metzger@intel.com>

gdb/
* nat/linux-btrace.c: Include sys/utsname.h.
(linux_determine_ptr_bits): New.
(linux_enable_bts): Call linux_determine_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/gdbserver/linux-low.c | 2 +-
gdb/nat/linux-btrace.c | 29 ++++++++++++++++++++++++++++-
gdb/x86-linux-nat.c | 8 +++++---
3 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 62be7aa..6dca61e 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5931,7 +5931,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 3376a0f..c5c05a2 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -38,6 +38,7 @@
#include <sys/ptrace.h>
#include <sys/types.h>
#include <signal.h>
+#include <sys/utsname.h>

/* A branch trace record in perf_event. */
struct perf_event_bts
@@ -102,6 +103,32 @@ 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_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 +461,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_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 9d82be2..0bf564a 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -441,9 +441,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;
}

--
1.8.3.1