[PATCH 02/12] perf, tools, script: Print insn/insnlen for non PT sample
From: Andi Kleen
Date: Mon Nov 27 2017 - 19:25:50 EST
From: Andi Kleen <ak@xxxxxxxxxxxxxxx>
Dumping insn/insnlen only works for PT samples where the PT decoder
fills in these fields. Add a fallback for other samples where we
grab the instructions manually and then call an architecture
specific function to determine the instruction length.
The architecture specific function is currently only implemented
for x86, and uses the standard Linux instruction decoder.
Signed-off-by: Andi Kleen <ak@xxxxxxxxxxxxxxx>
---
tools/perf/arch/x86/util/Build | 1 +
tools/perf/arch/x86/util/insnlen.c | 12 ++++++++++++
tools/perf/builtin-script.c | 13 +++++++++++++
tools/perf/util/Build | 1 +
tools/perf/util/insnlen.c | 10 ++++++++++
tools/perf/util/insnlen.h | 6 ++++++
6 files changed, 43 insertions(+)
create mode 100644 tools/perf/arch/x86/util/insnlen.c
create mode 100644 tools/perf/util/insnlen.c
create mode 100644 tools/perf/util/insnlen.h
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index f95e6f46ef0d..139f9f1a56f9 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -1,6 +1,7 @@
libperf-y += header.o
libperf-y += tsc.o
libperf-y += pmu.o
+libperf-y += insnlen.o
libperf-y += kvm-stat.o
libperf-y += perf_regs.o
libperf-y += group.o
diff --git a/tools/perf/arch/x86/util/insnlen.c b/tools/perf/arch/x86/util/insnlen.c
new file mode 100644
index 000000000000..8e2e50bd5201
--- /dev/null
+++ b/tools/perf/arch/x86/util/insnlen.c
@@ -0,0 +1,12 @@
+#include "intel-pt-decoder/insn.h"
+#include "intel-pt-decoder/inat.h"
+#include "insnlen.h"
+
+int arch_insn_len(char *insnbytes, int insnlen, int is64bit)
+{
+ struct insn insn;
+
+ insn_init(&insn, insnbytes, insnlen, is64bit);
+ insn_get_length(&insn);
+ return insn.length;
+}
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index ee7c7aaaae72..cae4b13fc715 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -20,6 +20,7 @@
#include "util/data.h"
#include "util/auxtrace.h"
#include "util/cpumap.h"
+#include "util/insnlen.h"
#include "util/thread_map.h"
#include "util/stat.h"
#include "util/string2.h"
@@ -1108,6 +1109,18 @@ static int perf_sample__fprintf_insn(struct perf_sample *sample,
{
int printed = 0;
+ if ((PRINT_FIELD(INSNLEN) || PRINT_FIELD(INSN)) && !sample->insn_len) {
+ u8 ibuf[64];
+ bool is64bit;
+ u8 cpumode;
+
+ if (grab_bb(ibuf, sample->ip, sample->ip + 16,
+ machine, thread, &is64bit, &cpumode, false) > 0) {
+ sample->insn_len = arch_insn_len((char *)ibuf, 16, is64bit);
+ memcpy(sample->insn, ibuf, sample->insn_len);
+ }
+ }
+
if (PRINT_FIELD(INSNLEN))
printed += fprintf(fp, " ilen: %d", sample->insn_len);
if (PRINT_FIELD(INSN)) {
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index a3de7916fe63..80c05329835a 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -14,6 +14,7 @@ libperf-y += kallsyms.o
libperf-y += levenshtein.o
libperf-y += llvm-utils.o
libperf-y += mmap.o
+libperf-y += insnlen.o
libperf-y += memswap.o
libperf-y += parse-events.o
libperf-y += perf_regs.o
diff --git a/tools/perf/util/insnlen.c b/tools/perf/util/insnlen.c
new file mode 100644
index 000000000000..6c126960a7e6
--- /dev/null
+++ b/tools/perf/util/insnlen.c
@@ -0,0 +1,10 @@
+#include "perf.h"
+#include "insnlen.h"
+
+/* Fallback for architectures not supporting this */
+__weak int arch_insn_len(char *buf __maybe_unused,
+ int len __maybe_unused,
+ int is64bit __maybe_unused)
+{
+ return 0;
+}
diff --git a/tools/perf/util/insnlen.h b/tools/perf/util/insnlen.h
new file mode 100644
index 000000000000..289877dff89d
--- /dev/null
+++ b/tools/perf/util/insnlen.h
@@ -0,0 +1,6 @@
+#ifndef INSNLEN_H
+#define INSNLEN_H 1
+
+int arch_insn_len(char *buf, int len, int is64bit);
+
+#endif
--
2.13.6