From: Changbin Du <changbin.du@huawei.com>
To: Arnaldo Carvalho de Melo <acme@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@kernel.org>, Namhyung Kim <namhyung@kernel.org>,
<linux-kernel@vger.kernel.org>,
<linux-perf-users@vger.kernel.org>,
Hui Wang <hw.huiwang@huawei.com>, <changbin.du@gmail.com>,
Changbin Du <changbin.du@huawei.com>
Subject: [PATCH 2/3] perf: script: use capstone disasm engine to show disassembly instructions
Date: Fri, 9 Sep 2022 16:48:20 +0800 [thread overview]
Message-ID: <20220909084821.7894-3-changbin.du@huawei.com> (raw)
In-Reply-To: <20220909084821.7894-1-changbin.du@huawei.com>
Currently, the instructions of samples are shown as raw hex strings
which are hard to read. x86 has a special option '--xed' to disassemble
the hex string via intel XED.
Here we use capstone as our disassembly engine to do that. We select
libcapstone because capstone can provide more insn details.
The improvements compared to xed:
* support arm, arm64, x86-32, x86_64 (more could be supported),
xed only for x86_64.
* immediate address operands are shown as symbol+offs.
Before:
$ sudo perf script --insn-trace
perf 17423 [000] 423271.557970005: 7f2d95f16217 __GI___ioctl+0x7 (/lib/x86_64-linux-gnu/libc-2.27.so) insn: 48 3d 01 f0 ff ff
perf 17423 [000] 423271.557970005: 7f2d95f1621d __GI___ioctl+0xd (/lib/x86_64-linux-gnu/libc-2.27.so) insn: 73 01
perf 17423 [000] 423271.557970338: 7f2d95f1621f __GI___ioctl+0xf (/lib/x86_64-linux-gnu/libc-2.27.so) insn: c3
perf 17423 [000] 423271.557970338: 5593ad3346d7 perf_evsel__enable_cpu+0x97 (/work/linux/tools/perf/perf) insn: 85 c0
perf 17423 [000] 423271.557970338: 5593ad3346d9 perf_evsel__enable_cpu+0x99 (/work/linux/tools/perf/perf) insn: 75 12
perf 17423 [000] 423271.557970338: 5593ad3346db perf_evsel__enable_cpu+0x9b (/work/linux/tools/perf/perf) insn: 49 8b 84 24 a8 00 00 00
perf 17423 [000] 423271.557970338: 5593ad3346e3 perf_evsel__enable_cpu+0xa3 (/work/linux/tools/perf/perf) insn: 48 8b 50 20
After:
$ sudo perf script --insn-trace
perf 17423 [000] 423271.557970005: 7f2d95f16217 __GI___ioctl+0x7 (/lib/x86_64-linux-gnu/libc-2.27.so) insn: cmpq $-0xfff, %rax
perf 17423 [000] 423271.557970005: 7f2d95f1621d __GI___ioctl+0xd (/lib/x86_64-linux-gnu/libc-2.27.so) insn: jae __GI___ioctl+0x10
perf 17423 [000] 423271.557970338: 7f2d95f1621f __GI___ioctl+0xf (/lib/x86_64-linux-gnu/libc-2.27.so) insn: retq
perf 17423 [000] 423271.557970338: 5593ad3346d7 perf_evsel__enable_cpu+0x97 (/work/linux/tools/perf/perf) insn: testl %eax, %eax
perf 17423 [000] 423271.557970338: 5593ad3346d9 perf_evsel__enable_cpu+0x99 (/work/linux/tools/perf/perf) insn: jne perf_evsel__enable_cpu+0xad
perf 17423 [000] 423271.557970338: 5593ad3346db perf_evsel__enable_cpu+0x9b (/work/linux/tools/perf/perf) insn: movq 0xa8(%r12), %rax
perf 17423 [000] 423271.557970338: 5593ad3346e3 perf_evsel__enable_cpu+0xa3 (/work/linux/tools/perf/perf) insn: movq 0x20(%rax), %rdx
perf 17423 [000] 423271.557970338: 5593ad3346e7 perf_evsel__enable_cpu+0xa7 (/work/linux/tools/perf/perf) insn: cmpl %edx, %ebx
perf 17423 [000] 423271.557970338: 5593ad3346e9 perf_evsel__enable_cpu+0xa9 (/work/linux/tools/perf/perf) insn: jl perf_evsel__enable_cpu+0x60
perf 17423 [000] 423271.557970338: 5593ad3346eb perf_evsel__enable_cpu+0xab (/work/linux/tools/perf/perf) insn: xorl %eax, %eax
Signed-off-by: Changbin Du <changbin.du@huawei.com>
---
tools/perf/builtin-script.c | 8 +--
tools/perf/util/Build | 1 +
tools/perf/util/print_insn.c | 126 +++++++++++++++++++++++++++++++++++
tools/perf/util/print_insn.h | 13 ++++
4 files changed, 143 insertions(+), 5 deletions(-)
create mode 100644 tools/perf/util/print_insn.c
create mode 100644 tools/perf/util/print_insn.h
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 13580a9c50b8..2c7b4631f1d7 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -34,6 +34,7 @@
#include "util/event.h"
#include "ui/ui.h"
#include "print_binary.h"
+#include "print_insn.h"
#include "archinsn.h"
#include <linux/bitmap.h>
#include <linux/kernel.h>
@@ -1482,11 +1483,8 @@ static int perf_sample__fprintf_insn(struct perf_sample *sample,
if (PRINT_FIELD(INSNLEN))
printed += fprintf(fp, " ilen: %d", sample->insn_len);
if (PRINT_FIELD(INSN) && sample->insn_len) {
- int i;
-
- printed += fprintf(fp, " insn:");
- for (i = 0; i < sample->insn_len; i++)
- printed += fprintf(fp, " %02x", (unsigned char)sample->insn[i]);
+ printed += fprintf(fp, " insn: ");
+ printed += sample__fprintf_insn(sample, thread, machine, fp);
}
if (PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN))
printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp);
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 9dfae1bda9cc..b92680f27704 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -31,6 +31,7 @@ perf-y += tracepoint.o
perf-y += perf_regs.o
perf-y += path.o
perf-y += print_binary.o
+perf-y += print_insn.o
perf-y += rlimit.o
perf-y += argv_split.o
perf-y += rbtree.o
diff --git a/tools/perf/util/print_insn.c b/tools/perf/util/print_insn.c
new file mode 100644
index 000000000000..5229aa01d3b9
--- /dev/null
+++ b/tools/perf/util/print_insn.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Instruction binary disassembler based on capstone.
+ *
+ * Author(s): Changbin Du <changbin.du@huawei.com>
+ */
+#include "print_insn.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "util/debug.h"
+#include "util/thread.h"
+#include "util/symbol.h"
+#include "machine.h"
+
+#ifdef HAVE_LIBCAPSTONE_SUPPORT
+#include <capstone/capstone.h>
+#endif
+
+size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp)
+{
+ int printed = 0;
+
+ for (int i = 0; i < sample->insn_len; i++)
+ printed += fprintf(fp, "%02x ", (unsigned char)sample->insn[i]);
+ return printed;
+}
+
+#ifdef HAVE_LIBCAPSTONE_SUPPORT
+static csh cs_handle;
+static bool cs_supported;
+static bool cs_inited;
+
+static void cs_init(struct machine *machine)
+{
+ cs_arch arch;
+ cs_mode mode;
+
+ cs_inited = true;
+
+ if (machine__is(machine, "x86_64")) {
+ arch = CS_ARCH_X86;
+ mode = CS_MODE_64;
+ } else if (machine__normalized_is(machine, "x86")) {
+ arch = CS_ARCH_X86;
+ mode = CS_MODE_32;
+ } else if (machine__normalized_is(machine, "arm64")) {
+ arch = CS_ARCH_ARM64;
+ mode = CS_MODE_ARM;
+ } else if (machine__normalized_is(machine, "arm")) {
+ arch = CS_ARCH_ARM;
+ mode = CS_MODE_ARM + CS_MODE_V8;
+ } else {
+ return;
+ }
+
+ if (cs_open(arch, mode, &cs_handle) != CS_ERR_OK) {
+ pr_err("cs_open failed\n");
+ return;
+ }
+
+ cs_option(cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
+ if (machine__normalized_is(machine, "x86"))
+ cs_option(cs_handle, CS_OPT_DETAIL, CS_OPT_ON);
+
+ cs_supported = true;
+}
+
+static size_t print_insn_x86(struct perf_sample *sample, struct thread *thread,
+ cs_insn *insn, FILE *fp)
+{
+ cs_x86_op *op = NULL;
+ struct addr_location al;
+ size_t printed = 0;
+
+ if (insn->detail && insn->detail->x86.op_count == 1) {
+ op = &insn->detail->x86.operands[0];
+ al.filtered = 0;
+
+ if (op->type == X86_OP_IMM &&
+ thread__find_symbol(thread, sample->cpumode, op->imm, &al)) {
+ printed += fprintf(fp, "%s ", insn[0].mnemonic);
+ printed += symbol__fprintf_symname_offs(al.sym, &al, fp);
+ return printed;
+ }
+ }
+
+ printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
+ return printed;
+}
+
+size_t sample__fprintf_insn(struct perf_sample *sample, struct thread *thread,
+ struct machine *machine, FILE *fp)
+{
+ cs_insn *insn;
+ size_t count;
+ size_t printed = 0;
+
+ if (!cs_inited)
+ cs_init(machine);
+ if (!cs_supported) {
+ /* fallback */
+ return sample__fprintf_insn_raw(sample, fp);
+ }
+
+ count = cs_disasm(cs_handle, (uint8_t *)sample->insn, sample->insn_len,
+ sample->ip, 1, &insn);
+ if (count > 0) {
+ if (machine__normalized_is(machine, "x86"))
+ printed += print_insn_x86(sample, thread, &insn[0], fp);
+ else
+ printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
+ cs_free(insn, count);
+ } else {
+ printed += fprintf(fp, "illegal instruction");
+ }
+
+ return printed;
+}
+#else
+size_t sample__fprintf_insn(struct perf_sample *sample, struct thread *thread __maybe_unused,
+ struct machine *machine __maybe_unused, FILE *fp)
+{
+ return sample__fprintf_insn_raw(sample, fp);
+}
+#endif
diff --git a/tools/perf/util/print_insn.h b/tools/perf/util/print_insn.h
new file mode 100644
index 000000000000..f2c2b8764eae
--- /dev/null
+++ b/tools/perf/util/print_insn.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef PERF_PRINT_ISNS_H
+#define PERF_PRINT_ISNS_H
+
+#include <stddef.h>
+#include <stdio.h>
+#include "event.h"
+
+size_t sample__fprintf_insn(struct perf_sample *sample, struct thread *thread,
+ struct machine *machine, FILE *fp);
+size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp);
+
+#endif /* PERF_PRINT_ISNS_H */
--
2.17.1
next prev parent reply other threads:[~2022-09-09 8:57 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-09 8:48 [PATCH 0/3] perf: script: use capstone to show disassembly instructions for samples Changbin Du
2022-09-09 8:48 ` [PATCH 1/3] perf: build: introduce the libcapstone Changbin Du
2022-09-09 8:48 ` Changbin Du [this message]
2022-09-09 8:48 ` [PATCH 3/3] perf: script: Deprecate the '--xed' option Changbin Du
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220909084821.7894-3-changbin.du@huawei.com \
--to=changbin.du@huawei.com \
--cc=acme@kernel.org \
--cc=alexander.shishkin@linux.intel.com \
--cc=changbin.du@gmail.com \
--cc=hw.huiwang@huawei.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).