From 13ace07792fa75aa276e2d7c3cb03cec117d63a4 Mon Sep 17 00:00:00 2001 From: Markus Metzger Date: Mon, 21 Nov 2016 14:27:57 +0100 Subject: [PATCH] btrace: support decoder events Newer versions of libipt support instruction flow decoder events instead of indicating those events with flags in struct pt_insn. Add support for them in GDB. gdb/ * btrace.c (handle_pt_insn_events): New. (ftrace_add_pt): Call handle_pt_insn_events. Rename ERRCODE into STATUS. Split into this and ... (handle_pt_insn_event_flags): ... this. --- gdb/ChangeLog | 7 +++ gdb/btrace.c | 155 ++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 121 insertions(+), 41 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ac2394f..158670d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,12 @@ 2017-05-31 Markus Metzger + * btrace.c (handle_pt_insn_events): New. + (ftrace_add_pt): Call handle_pt_insn_events. Rename ERRCODE into + STATUS. Split into this and ... + (handle_pt_insn_event_flags): ... this. + +2017-05-31 Markus Metzger + * configure.ac: Check for pt_insn_event, struct pt_insn.enabled, and struct pt_insn.resynced. * configure: Regenerated. diff --git a/gdb/btrace.c b/gdb/btrace.c index 34572b0..10224c5 100644 --- a/gdb/btrace.c +++ b/gdb/btrace.c @@ -1187,6 +1187,103 @@ pt_btrace_insn (const struct pt_insn &insn) pt_btrace_insn_flags (insn)}; } +/* Handle instruction decode events (libipt-v2). */ + +static int +handle_pt_insn_events (struct btrace_thread_info *btinfo, + struct pt_insn_decoder *decoder, + std::vector &gaps, int status) +{ +#if defined (HAVE_PT_INSN_EVENT) + while (status & pts_event_pending) + { + struct btrace_function *bfun; + struct pt_event event; + uint64_t offset; + + status = pt_insn_event (decoder, &event, sizeof (event)); + if (status < 0) + break; + + switch (event.type) + { + default: + break; + + case ptev_enabled: + if (event.variant.enabled.resumed == 0 && !btinfo->functions.empty ()) + { + bfun = ftrace_new_gap (btinfo, BDE_PT_DISABLED, gaps); + + pt_insn_get_offset (decoder, &offset); + + warning (_("Non-contiguous trace at instruction %u (offset = 0x%" + PRIx64 ")."), bfun->insn_offset - 1, offset); + } + + break; + + case ptev_overflow: + bfun = ftrace_new_gap (btinfo, BDE_PT_OVERFLOW, gaps); + + pt_insn_get_offset (decoder, &offset); + + warning (_("Overflow at instruction %u (offset = 0x%" PRIx64 ")."), + bfun->insn_offset - 1, offset); + + break; + } + } +#endif /* defined (HAVE_PT_INSN_EVENT) */ + + return status; +} + +/* Handle events indicated by flags in INSN (libipt-v1). */ + +static void +handle_pt_insn_event_flags (struct btrace_thread_info *btinfo, + struct pt_insn_decoder *decoder, + const struct pt_insn &insn, + std::vector &gaps) +{ +#if defined (HAVE_STRUCT_PT_INSN_ENABLED) + /* Tracing is disabled and re-enabled each time we enter the kernel. Most + times, we continue from the same instruction we stopped before. This is + indicated via the RESUMED instruction flag. The ENABLED instruction flag + means that we continued from some other instruction. Indicate this as a + trace gap except when tracing just started. */ + if (insn.enabled && !btinfo->functions.empty ()) + { + struct btrace_function *bfun; + uint64_t offset; + + bfun = ftrace_new_gap (btinfo, BDE_PT_DISABLED, gaps); + + pt_insn_get_offset (decoder, &offset); + + warning (_("Non-contiguous trace at instruction %u (offset = 0x%" PRIx64 + ", pc = 0x%" PRIx64 ")."), bfun->insn_offset - 1, offset, + insn.ip); + } +#endif /* defined (HAVE_STRUCT_PT_INSN_ENABLED) */ + +#if defined (HAVE_STRUCT_PT_INSN_RESYNCED) + /* Indicate trace overflows. */ + if (insn.resynced) + { + struct btrace_function *bfun; + uint64_t offset; + + bfun = ftrace_new_gap (btinfo, BDE_PT_OVERFLOW, gaps); + + pt_insn_get_offset (decoder, &offset); + + warning (_("Overflow at instruction %u (offset = 0x%" PRIx64 ", pc = 0x%" + PRIx64 ")."), bfun->insn_offset - 1, offset, insn.ip); + } +#endif /* defined (HAVE_STRUCT_PT_INSN_RESYNCED) */ +} /* Add function branch trace to BTINFO using DECODER. */ @@ -1198,58 +1295,34 @@ ftrace_add_pt (struct btrace_thread_info *btinfo, { struct btrace_function *bfun; uint64_t offset; - int errcode; + int status; for (;;) { struct pt_insn insn; - errcode = pt_insn_sync_forward (decoder); - if (errcode < 0) + status = pt_insn_sync_forward (decoder); + if (status < 0) { - if (errcode != -pte_eos) + if (status != -pte_eos) warning (_("Failed to synchronize onto the Intel Processor " - "Trace stream: %s."), pt_errstr (pt_errcode (errcode))); + "Trace stream: %s."), pt_errstr (pt_errcode (status))); break; } for (;;) { - errcode = pt_insn_next (decoder, &insn, sizeof(insn)); - if (errcode < 0) + /* Handle events from the previous iteration or synchronization. */ + status = handle_pt_insn_events (btinfo, decoder, gaps, status); + if (status < 0) break; - /* Look for gaps in the trace - unless we're at the beginning. */ - if (!btinfo->functions.empty ()) - { - /* Tracing is disabled and re-enabled each time we enter the - kernel. Most times, we continue from the same instruction we - stopped before. This is indicated via the RESUMED instruction - flag. The ENABLED instruction flag means that we continued - from some other instruction. Indicate this as a trace gap. */ - if (insn.enabled) - { - bfun = ftrace_new_gap (btinfo, BDE_PT_DISABLED, gaps); - - pt_insn_get_offset (decoder, &offset); - - warning (_("Non-contiguous trace at instruction %u (offset " - "= 0x%" PRIx64 ", pc = 0x%" PRIx64 ")."), - bfun->insn_offset - 1, offset, insn.ip); - } - } - - /* Indicate trace overflows. */ - if (insn.resynced) - { - bfun = ftrace_new_gap (btinfo, BDE_PT_OVERFLOW, gaps); - - pt_insn_get_offset (decoder, &offset); + status = pt_insn_next (decoder, &insn, sizeof(insn)); + if (status < 0) + break; - warning (_("Overflow at instruction %u (offset = 0x%" PRIx64 - ", pc = 0x%" PRIx64 ")."), bfun->insn_offset - 1, - offset, insn.ip); - } + /* Handle events indicated by flags in INSN. */ + handle_pt_insn_event_flags (btinfo, decoder, insn, gaps); bfun = ftrace_update_function (btinfo, insn.ip); @@ -1260,17 +1333,17 @@ ftrace_add_pt (struct btrace_thread_info *btinfo, ftrace_update_insns (bfun, &btinsn); } - if (errcode == -pte_eos) + if (status == -pte_eos) break; /* Indicate the gap in the trace. */ - bfun = ftrace_new_gap (btinfo, errcode, gaps); + bfun = ftrace_new_gap (btinfo, status, gaps); pt_insn_get_offset (decoder, &offset); warning (_("Decode error (%d) at instruction %u (offset = 0x%" PRIx64 - ", pc = 0x%" PRIx64 "): %s."), errcode, bfun->insn_offset - 1, - offset, insn.ip, pt_errstr (pt_errcode (errcode))); + ", pc = 0x%" PRIx64 "): %s."), status, bfun->insn_offset - 1, + offset, insn.ip, pt_errstr (pt_errcode (status))); } } -- 2.7.4