summaryrefslogtreecommitdiff
path: root/tools/perf/python/libxed.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/python/libxed.py')
-rwxr-xr-xtools/perf/python/libxed.py123
1 files changed, 123 insertions, 0 deletions
diff --git a/tools/perf/python/libxed.py b/tools/perf/python/libxed.py
new file mode 100755
index 000000000000..900bd3e0184b
--- /dev/null
+++ b/tools/perf/python/libxed.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+"""
+Python wrapper for libxed.so
+Ported from tools/perf/scripts/python/libxed.py
+"""
+from __future__ import annotations
+
+from ctypes import CDLL, Structure, create_string_buffer, addressof, sizeof, \
+ c_void_p, c_byte, c_int, c_uint, c_ulonglong
+
+# To use Intel XED, libxed.so must be present. To build and install
+# libxed.so:
+# git clone https://github.com/intelxed/mbuild.git mbuild
+# git clone https://github.com/intelxed/xed
+# cd xed
+# ./mfile.py --share
+# sudo ./mfile.py --prefix=/usr/local install
+# sudo ldconfig
+#
+
+
+class XedStateT(Structure):
+ """xed_state_t structure."""
+ _fields_ = [
+ ("mode", c_int),
+ ("width", c_int)
+ ]
+
+
+class XEDInstruction():
+ """Represents a decoded instruction."""
+
+ def __init__(self, libxed):
+ # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion
+ xedd_t = c_byte * 512
+ self.xedd = xedd_t()
+ self.xedp = addressof(self.xedd)
+ libxed.xed_decoded_inst_zero(self.xedp)
+ self.state = XedStateT()
+ self.statep = addressof(self.state)
+ # Buffer for disassembled instruction text
+ self.buffer = create_string_buffer(256)
+ self.bufferp = addressof(self.buffer)
+
+
+class LibXED():
+ """Wrapper for libxed.so."""
+
+ def __init__(self):
+ try:
+ self.libxed = CDLL("libxed.so")
+ except OSError:
+ self.libxed = None
+ if not self.libxed:
+ try:
+ self.libxed = CDLL("/usr/local/lib/libxed.so")
+ except OSError:
+ self.libxed = None
+
+ if not self.libxed:
+ raise ImportError("libxed.so not found. Please install Intel XED.")
+
+ self.xed_tables_init = self.libxed.xed_tables_init
+ self.xed_tables_init.restype = None
+ self.xed_tables_init.argtypes = []
+
+ self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero
+ self.xed_decoded_inst_zero.restype = None
+ self.xed_decoded_inst_zero.argtypes = [c_void_p]
+
+ self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode
+ self.xed_operand_values_set_mode.restype = None
+ self.xed_operand_values_set_mode.argtypes = [c_void_p, c_void_p]
+
+ self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode
+ self.xed_decoded_inst_zero_keep_mode.restype = None
+ self.xed_decoded_inst_zero_keep_mode.argtypes = [c_void_p]
+
+ self.xed_decode = self.libxed.xed_decode
+ self.xed_decode.restype = c_int
+ self.xed_decode.argtypes = [c_void_p, c_void_p, c_uint]
+
+ self.xed_format_context = self.libxed.xed_format_context
+ self.xed_format_context.restype = c_uint
+ self.xed_format_context.argtypes = [
+ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p
+ ]
+
+ self.xed_decoded_inst_get_length = self.libxed.xed_decoded_inst_get_length
+ self.xed_decoded_inst_get_length.restype = c_uint
+ self.xed_decoded_inst_get_length.argtypes = [c_void_p]
+
+ self.xed_tables_init()
+
+ def instruction(self):
+ """Create a new XEDInstruction."""
+ return XEDInstruction(self)
+
+ def set_mode(self, inst, mode):
+ """Set 32-bit or 64-bit mode."""
+ if mode:
+ inst.state.mode = 4 # 32-bit
+ inst.state.width = 4 # 4 bytes
+ else:
+ inst.state.mode = 1 # 64-bit
+ inst.state.width = 8 # 8 bytes
+ self.xed_operand_values_set_mode(inst.xedp, inst.statep)
+
+ def disassemble_one(self, inst, bytes_ptr, bytes_cnt, ip):
+ """Disassemble one instruction."""
+ self.xed_decoded_inst_zero_keep_mode(inst.xedp)
+ err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt)
+ if err:
+ return 0, ""
+ # Use AT&T mode (2), alternative is Intel (3)
+ ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0)
+ if not ok:
+ return 0, ""
+
+ result = inst.buffer.value.decode('utf-8')
+ # Return instruction length and the disassembled instruction text
+ return self.xed_decoded_inst_get_length(inst.xedp), result