#!/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