108 lines
3.3 KiB
Python
108 lines
3.3 KiB
Python
#!/usr/bin/env python
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
# libxed.py: Python wrapper for libxed.so
|
|
# Copyright (c) 2014-2021, Intel Corporation.
|
|
|
|
# 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
|
|
#
|
|
|
|
import sys
|
|
|
|
from ctypes import CDLL, Structure, create_string_buffer, addressof, sizeof, \
|
|
c_void_p, c_bool, c_byte, c_char, c_int, c_uint, c_longlong, c_ulonglong
|
|
|
|
# XED Disassembler
|
|
|
|
class xed_state_t(Structure):
|
|
|
|
_fields_ = [
|
|
("mode", c_int),
|
|
("width", c_int)
|
|
]
|
|
|
|
class XEDInstruction():
|
|
|
|
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 = xed_state_t()
|
|
self.statep = addressof(self.state)
|
|
# Buffer for disassembled instruction text
|
|
self.buffer = create_string_buffer(256)
|
|
self.bufferp = addressof(self.buffer)
|
|
|
|
class LibXED():
|
|
|
|
def __init__(self):
|
|
try:
|
|
self.libxed = CDLL("libxed.so")
|
|
except:
|
|
self.libxed = None
|
|
if not self.libxed:
|
|
self.libxed = CDLL("/usr/local/lib/libxed.so")
|
|
|
|
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_tables_init()
|
|
|
|
def Instruction(self):
|
|
return XEDInstruction(self)
|
|
|
|
def SetMode(self, inst, 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 DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip):
|
|
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, ""
|
|
if sys.version_info[0] == 2:
|
|
result = inst.buffer.value
|
|
else:
|
|
result = inst.buffer.value.decode()
|
|
# Return instruction length and the disassembled instruction text
|
|
# For now, assume the length is in byte 166
|
|
return inst.xedd[166], result
|