Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1566620

[PATCH 08/23] perf tools: Add disassembler for x86 using the XED library

From Arnaldo Carvalho de Melo <acme@kernel.org>
Newsgroups linux.kernel
Subject [PATCH 08/23] perf tools: Add disassembler for x86 using the XED library
Date 2017-01-25 15:00 +0100
Message-ID <t3whd-2sl-37@gated-at.bofh.it> (permalink)
References <t3whb-2sl-5@gated-at.bofh.it>
Organization linux.* mail to news gateway

Show all headers | View raw


From: Andi Kleen <ak@linux.intel.com>

Add a generic disassembler function for x86 using the XED library, and a
fallback function for architectures that don't implement one.  Other
architectures can implement their own disassembler functions.

The previous version of this patch used udis86, but was
rejected because udis86 was unmaintained and a runtime dependency.
Using the recently released xed avoids both of these problems:

- XED is well maintained, uptodate, and used by many Intel tools

- XED is linked statically so there is no runtime dependency.

The XED library can be downloaded from http://github.com/intelxed/xed

v2: Clean up includes.

Committer notes:

- Aligned struct member definitions;

- Added missing includes to dis.h

- Went back to the feature detection patch to make sure the xed
  path is added to CFLAGS so that this patch can actually build.

Disable -Werror=old-style-declaration for tools/perf/arch/x86/util/dis.o
due to xed header problems, for which we don't have control:

  $ gcc --version
  gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1)
  $ make XED=1
  XED_DIR=/home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64 O=/tmp/build/perf -C tools/perf

  CC       /tmp/build/perf/tests/openat-syscall.o
In file included from /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-inst.h:41:0,
                 from /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-decoded-inst.h:28,
                 from /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-decode.h:24,
                 from /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-interface.h:40,
                 from arch/x86/util/dis.c:3:
  /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-iform-map.h:74:1: error: ‘inline’ is not at beginning of declaration [-Werror=old-style-declaration]
   xed_iclass_enum_t XED_INLINE xed_iform_to_iclass(xed_iform_enum_t iform) {
   ^~~~~~~~~~~~~~~~~
  In file included from /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-interface.h:43:0,
                   from arch/x86/util/dis.c:3:

Ditto for -Werror=switch-enum:

  In file included from /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-interface.h:43:0,
                   from arch/x86/util/dis.c:8:
  /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-state.h: In function ‘xed_state_get_address_width’:
  /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-state.h:144:5: error: enumeration value ‘XED_MACHINE_MODE_INVALID’ not handled in switch [-Werror=switch-enum]
       switch(xed_state_get_machine_mode(p)) {
       ^~~~~~
  /home/acme/git/xed/kits/xed-install-base-2017-01-23-lin-x86-64/include/xed/xed-state.h:144:5: error: enumeration value ‘XED_MACHINE_MODE_LAST’ not handled in switch [-Werror=switch-enum]
  cc1: all warnings being treated as errors
  mv: cannot stat '/tmp/build/perf/arch/x86/util/.dis.o.tmp': No such file or directory
  /home/acme/git/linux/tools/build/Makefile.build:91: recipe for target '/tmp/build/perf/arch/x86/util/dis.o' failed

Now we have the static xed library linked with perf:

  $ nm /tmp/build/perf/perf | grep "T xed" | head
  0000000000682761 T xed3_decode_operands
  0000000000682700 T xed3_dynamic_decode_part2
  0000000000742002 T xed3_get_generic_operand
  0000000000742ca4 T xed3_set_generic_operand
  000000000068380e T xed3_static_decode
  000000000064a6d0 T xed_attribute
  000000000064a6ca T xed_attribute_max
  00000000007409ab T xed_chip_enum_t2str
  00000000007409d8 T xed_chip_enum_t_last
  000000000074c8a7 T xed_dec_lu_ASZ_NONTERM_EASZ_MAP_MOD3_REXW_RM4_VEXVALID_VEX_PREFIX_VL
  $

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/20170119014150.19218-4-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/arch/x86/util/Build |  3 ++
 tools/perf/arch/x86/util/dis.c | 86 ++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/Build          |  1 +
 tools/perf/util/dis.c          | 15 ++++++++
 tools/perf/util/dis.h          | 23 +++++++++++
 5 files changed, 128 insertions(+)
 create mode 100644 tools/perf/arch/x86/util/dis.c
 create mode 100644 tools/perf/util/dis.c
 create mode 100644 tools/perf/util/dis.h

diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index f95e6f46ef0d..fd1dfd7c6321 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -14,3 +14,6 @@ libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 libperf-$(CONFIG_AUXTRACE) += auxtrace.o
 libperf-$(CONFIG_AUXTRACE) += intel-pt.o
 libperf-$(CONFIG_AUXTRACE) += intel-bts.o
+libperf-$(CONFIG_XED) += dis.o
+
+CFLAGS_dis.o += -Wno-old-style-declaration -Wno-switch-enum
diff --git a/tools/perf/arch/x86/util/dis.c b/tools/perf/arch/x86/util/dis.c
new file mode 100644
index 000000000000..39703512fe17
--- /dev/null
+++ b/tools/perf/arch/x86/util/dis.c
@@ -0,0 +1,86 @@
+/* Disassembler using the XED library */
+#include "perf.h"
+#include "util/session.h"
+#include "util/symbol.h"
+#include "util/thread.h"
+#include "util/dis.h"
+
+#include <xed/xed-interface.h>
+#include <xed/xed-decode.h>
+#include <xed/xed-decoded-inst-api.h>
+
+static int dis_resolve(xed_uint64_t addr, char *buf, xed_uint32_t buflen,
+		xed_uint64_t *off, void *data)
+{
+	struct perf_dis *x = data;
+	struct addr_location al;
+
+	memset(&al, 0, sizeof(struct addr_location));
+
+	thread__find_addr_map(x->thread, x->cpumode, MAP__FUNCTION, addr, &al);
+	if (!al.map)
+		thread__find_addr_map(x->thread, x->cpumode, MAP__VARIABLE,
+					addr, &al);
+	al.cpu = x->cpu;
+	al.sym = NULL;
+
+	if (al.map)
+		al.sym = map__find_symbol(al.map, al.addr);
+
+	if (!al.sym)
+		return 0;
+
+	if (al.addr < al.sym->end)
+		*off = al.addr - al.sym->start;
+	else
+		*off = al.addr - al.map->start - al.sym->start;
+	snprintf(buf, buflen, "%s", al.sym->name);
+	return 1;
+}
+
+/* x must be set up earlier */
+char *disas_inst(struct perf_dis *x, uint64_t ip, u8 *inbuf, int inlen,
+		 int *lenp)
+{
+	xed_decoded_inst_t inst;
+	xed_print_info_t info;
+	xed_error_enum_t err;
+	static bool init;
+
+	if (!init) {
+		xed_tables_init();
+		init = true;
+	}
+
+	if (lenp)
+		*lenp = 0;
+
+	xed_init_print_info(&info);
+	info.syntax = XED_SYNTAX_ATT;
+	info.disassembly_callback = dis_resolve;
+	info.context = x;
+
+	xed_decoded_inst_zero(&inst);
+	if (x->is64bit)
+		xed_decoded_inst_set_mode(&inst, XED_MACHINE_MODE_LONG_64,
+				XED_ADDRESS_WIDTH_64b);
+	else
+		xed_decoded_inst_set_mode(&inst, XED_MACHINE_MODE_LEGACY_32,
+				XED_ADDRESS_WIDTH_32b);
+
+	err = xed_decode(&inst, (uint8_t *)inbuf, inlen);
+	if (err != XED_ERROR_NONE) {
+		snprintf(x->out, sizeof(x->out), "err: %s for %d bytes",
+				xed_error_enum_t2str(err), inlen);
+		return x->out;
+	}
+	if (lenp)
+		*lenp = xed_decoded_inst_get_length(&inst);
+	info.p = &inst;
+	info.buf = x->out;
+	info.blen = sizeof(x->out);
+	info.runtime_address = ip;
+	if (!xed_format_generic(&info))
+		strcpy(x->out, "err: cannot format");
+	return x->out;
+}
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5da376bc1afc..cdaeb4764fee 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -88,6 +88,7 @@ libperf-y += mem-events.o
 libperf-y += vsprintf.o
 libperf-y += drv_configs.o
 libperf-y += time-utils.o
+libperf-y += dis.o
 
 libperf-$(CONFIG_LIBBPF) += bpf-loader.o
 libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
diff --git a/tools/perf/util/dis.c b/tools/perf/util/dis.c
new file mode 100644
index 000000000000..61cf96fbcd1b
--- /dev/null
+++ b/tools/perf/util/dis.c
@@ -0,0 +1,15 @@
+#include "perf.h"
+#include "dis.h"
+#include "util.h"
+
+/* Fallback for architectures with no disassembler */
+
+__weak char *disas_inst(struct perf_dis *x, uint64_t ip __maybe_unused,
+			u8 *inbuf __maybe_unused, int inlen __maybe_unused,
+			int *lenp)
+{
+	if (lenp)
+		*lenp = 0;
+	strcpy(x->out, "?");
+	return x->out;
+}
diff --git a/tools/perf/util/dis.h b/tools/perf/util/dis.h
new file mode 100644
index 000000000000..79ff8d915d3b
--- /dev/null
+++ b/tools/perf/util/dis.h
@@ -0,0 +1,23 @@
+#ifndef DIS_H
+#define DIS_H 1
+
+#include <stdbool.h>
+#include <linux/types.h>
+
+struct thread;
+
+#define MAXINSN 15
+
+struct perf_dis {
+	/* Initialized by callers: */
+	struct thread *thread;
+	u8	      cpumode;
+	int	      cpu;
+	bool	      is64bit;
+	/* Temporary */
+	char	      out[256];
+};
+
+char *disas_inst(struct perf_dis *x, uint64_t ip, u8 *inbuf, int inlen, int *lenp);
+
+#endif
-- 
2.9.3

Back to linux.kernel | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

[GIT PULL 00/23] perf/core improvements and fixes Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 19/23] perf tools: Propagate perf_config() errors Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 15/23] tools lib bpf: Define prog_type fns with macro Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 10/23] perf script: Add "brstackasm" output for branch stacks Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 11/23] perf probe: Fix wrong register name for arm64 Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 09/23] perf script: Add support for printing assembler Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 18/23] perf scripting perl: Do not die() when not founding event for a type Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 21/23] perf util: Add more debug message on failure path Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 08/23] perf tools: Add disassembler for x86 using the XED library Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 14/23] tools lib bpf: Fix map offsets in relocation Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 02/23] perf hists browser: Put hist_entry folding logic into single function Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 22/23] perf ftrace: Introduce new 'ftrace' tool Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 01/23] perf unwind: Fix looking up dwarf unwind stack info Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 13/23] perf probe: Delete an unnecessary assignment in try_to_find_absolute_address() Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 23/23] perf ftrace: Make 'function_graph' be the default tracer Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 04/23] perf c2c report: Display Total records column in offset view Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100
  [PATCH 06/23] perf tools: Add probing for the XED disassembler library Arnaldo Carvalho de Melo <acme@kernel.org> - 2017-01-25 15:00 +0100

csiph-web