summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2014-01-17 14:40:02 +0100
committerMarkus Metzger <markus.t.metzger@intel.com>2015-02-09 09:33:59 +0100
commitaadf7753fd4cc3d9eb1cd0c089fd7a483b58f59e (patch)
treec2ecfeb8490e4595b14c2a3ae89c6a094b51f3ab
parent043c35779713a14e0916a1b3e31e006cd1270ee4 (diff)
downloadbinutils-gdb-aadf7753fd4cc3d9eb1cd0c089fd7a483b58f59e.tar.gz
btrace, linux: add perf event buffer abstraction
Collect perf event buffer related fields from btrace_target_info into a new struct perf_event_buffer. Update functions that operated on the buffer to take a struct perf_event_buffer pointer rather than a btrace_target_info pointer. 2015-02-09 Markus Metzger <markus.t.metzger@intel.com> * nat/linux-btrace.h (perf_event_buffer): New. (btrace_target_info) <buffer, size, data_head>: Replace with ... <bts>: ... this. * nat/linux-btrace.c (perf_event_header, perf_event_mmap_size) (perf_event_buffer_size, perf_event_buffer_begin) (perf_event_buffer_end, linux_btrace_has_changed): Removed. Updated users. (perf_event_new_data): New.
-rw-r--r--gdb/ChangeLog11
-rw-r--r--gdb/nat/linux-btrace.c113
-rw-r--r--gdb/nat/linux-btrace.h34
3 files changed, 74 insertions, 84 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 255daa1cf8a..5989460e7bd 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,16 @@
2015-02-09 Markus Metzger <markus.t.metzger@intel.com>
+ * nat/linux-btrace.h (perf_event_buffer): New.
+ (btrace_target_info) <buffer, size, data_head>: Replace with ...
+ <bts>: ... this.
+ * nat/linux-btrace.c (perf_event_header, perf_event_mmap_size)
+ (perf_event_buffer_size, perf_event_buffer_begin)
+ (perf_event_buffer_end, linux_btrace_has_changed): Removed.
+ Updated users.
+ (perf_event_new_data): New.
+
+2015-02-09 Markus Metzger <markus.t.metzger@intel.com>
+
* btrace.c (btrace_enable): Pass BTRACE_FORMAT_BTS.
* record-btrace.c (record_btrace_open): Remove call to
target_supports_btrace.
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 08eb49b31c8..5b2266104b8 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -59,45 +59,12 @@ struct perf_event_sample
struct perf_event_bts bts;
};
-/* Get the perf_event header. */
+/* Return non-zero if there is new data in PEVENT; zero otherwise. */
-static inline volatile struct perf_event_mmap_page *
-perf_event_header (struct btrace_target_info* tinfo)
-{
- return tinfo->buffer;
-}
-
-/* Get the size of the perf_event mmap buffer. */
-
-static inline size_t
-perf_event_mmap_size (const struct btrace_target_info *tinfo)
-{
- /* The branch trace buffer is preceded by a configuration page. */
- return (tinfo->size + 1) * PAGE_SIZE;
-}
-
-/* Get the size of the perf_event buffer. */
-
-static inline size_t
-perf_event_buffer_size (struct btrace_target_info* tinfo)
-{
- return tinfo->size * PAGE_SIZE;
-}
-
-/* Get the start address of the perf_event buffer. */
-
-static inline const uint8_t *
-perf_event_buffer_begin (struct btrace_target_info* tinfo)
-{
- return ((const uint8_t *) tinfo->buffer) + PAGE_SIZE;
-}
-
-/* Get the end address of the perf_event buffer. */
-
-static inline const uint8_t *
-perf_event_buffer_end (struct btrace_target_info* tinfo)
+static int
+perf_event_new_data (const struct perf_event_buffer *pev)
{
- return perf_event_buffer_begin (tinfo) + perf_event_buffer_size (tinfo);
+ return *pev->data_head != pev->last_head;
}
/* Check whether an address is in the kernel. */
@@ -162,11 +129,12 @@ perf_event_sample_ok (const struct perf_event_sample *sample)
static VEC (btrace_block_s) *
perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
- const uint8_t *end, const uint8_t *start, size_t size)
+ const uint8_t *end, const uint8_t *start,
+ unsigned long long size)
{
VEC (btrace_block_s) *btrace = NULL;
struct perf_event_sample sample;
- size_t read = 0;
+ unsigned long long read = 0;
struct btrace_block block = { 0, 0 };
struct regcache *regcache;
@@ -432,6 +400,7 @@ linux_supports_btrace (struct target_ops *ops, enum btrace_format format)
struct btrace_target_info *
linux_enable_btrace (ptid_t ptid)
{
+ struct perf_event_mmap_page *header;
struct btrace_target_info *tinfo;
int pid, pg;
@@ -467,15 +436,24 @@ linux_enable_btrace (ptid_t ptid)
for (pg = 4; pg >= 0; --pg)
{
/* The number of pages we request needs to be a power of two. */
- tinfo->size = 1 << pg;
- tinfo->buffer = mmap (NULL, perf_event_mmap_size (tinfo),
- PROT_READ, MAP_SHARED, tinfo->file, 0);
- if (tinfo->buffer == MAP_FAILED)
- continue;
-
- return tinfo;
+ header = mmap (NULL, ((1 << pg) + 1) * PAGE_SIZE, PROT_READ, MAP_SHARED,
+ tinfo->file, 0);
+ if (header != MAP_FAILED)
+ break;
}
+ if (header == MAP_FAILED)
+ goto err_file;
+
+ tinfo->header = header;
+ tinfo->bts.mem = ((const uint8_t *) header) + PAGE_SIZE;
+ tinfo->bts.size = (1 << pg) * PAGE_SIZE;
+ tinfo->bts.data_head = &header->data_head;
+ tinfo->bts.last_head = 0;
+
+ return tinfo;
+
+ err_file:
/* We were not able to allocate any buffer. */
close (tinfo->file);
@@ -489,29 +467,13 @@ linux_enable_btrace (ptid_t ptid)
enum btrace_error
linux_disable_btrace (struct btrace_target_info *tinfo)
{
- int errcode;
-
- errno = 0;
- errcode = munmap (tinfo->buffer, perf_event_mmap_size (tinfo));
- if (errcode != 0)
- return BTRACE_ERR_UNKNOWN;
-
+ munmap((void *) tinfo->header, tinfo->bts.size + PAGE_SIZE);
close (tinfo->file);
xfree (tinfo);
return BTRACE_ERR_NONE;
}
-/* Check whether the branch trace has changed. */
-
-static int
-linux_btrace_has_changed (struct btrace_target_info *tinfo)
-{
- volatile struct perf_event_mmap_page *header = perf_event_header (tinfo);
-
- return header->data_head != tinfo->data_head;
-}
-
/* Read branch trace data in BTS format for the thread given by TINFO into
BTRACE using the TYPE reading method. */
@@ -520,24 +482,25 @@ linux_read_bts (struct btrace_data_bts *btrace,
struct btrace_target_info *tinfo,
enum btrace_read_type type)
{
- volatile struct perf_event_mmap_page *header;
+ struct perf_event_buffer *pevent;
const uint8_t *begin, *end, *start;
- unsigned long data_head, data_tail, retries = 5;
- size_t buffer_size, size;
+ unsigned long long data_head, data_tail, buffer_size, size;
+ unsigned int retries = 5;
+
+ pevent = &tinfo->bts;
/* For delta reads, we return at least the partial last block containing
the current PC. */
- if (type == BTRACE_READ_NEW && !linux_btrace_has_changed (tinfo))
+ if (type == BTRACE_READ_NEW && !perf_event_new_data (pevent))
return BTRACE_ERR_NONE;
- header = perf_event_header (tinfo);
- buffer_size = perf_event_buffer_size (tinfo);
- data_tail = tinfo->data_head;
+ buffer_size = pevent->size;
+ data_tail = pevent->last_head;
/* We may need to retry reading the trace. See below. */
while (retries--)
{
- data_head = header->data_head;
+ data_head = *pevent->data_head;
/* Delete any leftover trace from the previous iteration. */
VEC_free (btrace_block_s, btrace->blocks);
@@ -569,13 +532,13 @@ linux_read_bts (struct btrace_data_bts *btrace,
}
/* Data_head keeps growing; the buffer itself is circular. */
- begin = perf_event_buffer_begin (tinfo);
+ begin = pevent->mem;
start = begin + data_head % buffer_size;
if (data_head <= buffer_size)
end = start;
else
- end = perf_event_buffer_end (tinfo);
+ end = begin + pevent->size;
btrace->blocks = perf_event_read_bts (tinfo, begin, end, start, size);
@@ -584,11 +547,11 @@ linux_read_bts (struct btrace_data_bts *btrace,
kernel might be writing the last branch trace records.
Let's check whether the data head moved while we read the trace. */
- if (data_head == header->data_head)
+ if (data_head == *pevent->data_head)
break;
}
- tinfo->data_head = data_head;
+ pevent->last_head = data_head;
/* Prune the incomplete last block (i.e. the first one of inferior execution)
if we're not doing a delta read. There is no way of filling in its zeroed
diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h
index 24e06e86cd5..602a57134e1 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -32,6 +32,24 @@
struct target_ops;
+#if HAVE_LINUX_PERF_EVENT_H
+/* A Linux perf event buffer. */
+struct perf_event_buffer
+{
+ /* The mapped memory. */
+ const uint8_t *mem;
+
+ /* The size of the mapped memory in bytes. */
+ unsigned long long size;
+
+ /* A pointer to the data_head field for this buffer. */
+ volatile unsigned long long *data_head;
+
+ /* The data_head value from the last read. */
+ unsigned long long last_head;
+};
+#endif /* HAVE_LINUX_PERF_EVENT_H */
+
/* Branch trace target information per thread. */
struct btrace_target_info
{
@@ -42,16 +60,14 @@ struct btrace_target_info
/* The ptid of this thread. */
ptid_t ptid;
- /* The mmap configuration mapping the branch trace perf_event buffer.
-
- file .. the file descriptor
- buffer .. the mmapped memory buffer
- size .. the buffer's size in pages without the configuration page
- data_head .. the data head from the last read */
+ /* The perf event file. */
int file;
- void *buffer;
- size_t size;
- unsigned long data_head;
+
+ /* The perf event configuration page. */
+ volatile struct perf_event_mmap_page *header;
+
+ /* The BTS perf event buffer. */
+ struct perf_event_buffer bts;
#endif /* HAVE_LINUX_PERF_EVENT_H */
/* The size of a pointer in bits for this thread.