1*2b87386cSAdrian Hunter#!/usr/bin/env python
2*2b87386cSAdrian Hunter# SPDX-License-Identifier: GPL-2.0
3*2b87386cSAdrian Hunter# libxed.py: Python wrapper for libxed.so
4*2b87386cSAdrian Hunter# Copyright (c) 2014-2021, Intel Corporation.
5*2b87386cSAdrian Hunter
6*2b87386cSAdrian Hunter# To use Intel XED, libxed.so must be present. To build and install
7*2b87386cSAdrian Hunter# libxed.so:
8*2b87386cSAdrian Hunter#            git clone https://github.com/intelxed/mbuild.git mbuild
9*2b87386cSAdrian Hunter#            git clone https://github.com/intelxed/xed
10*2b87386cSAdrian Hunter#            cd xed
11*2b87386cSAdrian Hunter#            ./mfile.py --share
12*2b87386cSAdrian Hunter#            sudo ./mfile.py --prefix=/usr/local install
13*2b87386cSAdrian Hunter#            sudo ldconfig
14*2b87386cSAdrian Hunter#
15*2b87386cSAdrian Hunter
16*2b87386cSAdrian Hunterimport sys
17*2b87386cSAdrian Hunter
18*2b87386cSAdrian Hunterfrom ctypes import CDLL, Structure, create_string_buffer, addressof, sizeof, \
19*2b87386cSAdrian Hunter		   c_void_p, c_bool, c_byte, c_char, c_int, c_uint, c_longlong, c_ulonglong
20*2b87386cSAdrian Hunter
21*2b87386cSAdrian Hunter# XED Disassembler
22*2b87386cSAdrian Hunter
23*2b87386cSAdrian Hunterclass xed_state_t(Structure):
24*2b87386cSAdrian Hunter
25*2b87386cSAdrian Hunter	_fields_ = [
26*2b87386cSAdrian Hunter		("mode", c_int),
27*2b87386cSAdrian Hunter		("width", c_int)
28*2b87386cSAdrian Hunter	]
29*2b87386cSAdrian Hunter
30*2b87386cSAdrian Hunterclass XEDInstruction():
31*2b87386cSAdrian Hunter
32*2b87386cSAdrian Hunter	def __init__(self, libxed):
33*2b87386cSAdrian Hunter		# Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion
34*2b87386cSAdrian Hunter		xedd_t = c_byte * 512
35*2b87386cSAdrian Hunter		self.xedd = xedd_t()
36*2b87386cSAdrian Hunter		self.xedp = addressof(self.xedd)
37*2b87386cSAdrian Hunter		libxed.xed_decoded_inst_zero(self.xedp)
38*2b87386cSAdrian Hunter		self.state = xed_state_t()
39*2b87386cSAdrian Hunter		self.statep = addressof(self.state)
40*2b87386cSAdrian Hunter		# Buffer for disassembled instruction text
41*2b87386cSAdrian Hunter		self.buffer = create_string_buffer(256)
42*2b87386cSAdrian Hunter		self.bufferp = addressof(self.buffer)
43*2b87386cSAdrian Hunter
44*2b87386cSAdrian Hunterclass LibXED():
45*2b87386cSAdrian Hunter
46*2b87386cSAdrian Hunter	def __init__(self):
47*2b87386cSAdrian Hunter		try:
48*2b87386cSAdrian Hunter			self.libxed = CDLL("libxed.so")
49*2b87386cSAdrian Hunter		except:
50*2b87386cSAdrian Hunter			self.libxed = None
51*2b87386cSAdrian Hunter		if not self.libxed:
52*2b87386cSAdrian Hunter			self.libxed = CDLL("/usr/local/lib/libxed.so")
53*2b87386cSAdrian Hunter
54*2b87386cSAdrian Hunter		self.xed_tables_init = self.libxed.xed_tables_init
55*2b87386cSAdrian Hunter		self.xed_tables_init.restype = None
56*2b87386cSAdrian Hunter		self.xed_tables_init.argtypes = []
57*2b87386cSAdrian Hunter
58*2b87386cSAdrian Hunter		self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero
59*2b87386cSAdrian Hunter		self.xed_decoded_inst_zero.restype = None
60*2b87386cSAdrian Hunter		self.xed_decoded_inst_zero.argtypes = [ c_void_p ]
61*2b87386cSAdrian Hunter
62*2b87386cSAdrian Hunter		self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode
63*2b87386cSAdrian Hunter		self.xed_operand_values_set_mode.restype = None
64*2b87386cSAdrian Hunter		self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ]
65*2b87386cSAdrian Hunter
66*2b87386cSAdrian Hunter		self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode
67*2b87386cSAdrian Hunter		self.xed_decoded_inst_zero_keep_mode.restype = None
68*2b87386cSAdrian Hunter		self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ]
69*2b87386cSAdrian Hunter
70*2b87386cSAdrian Hunter		self.xed_decode = self.libxed.xed_decode
71*2b87386cSAdrian Hunter		self.xed_decode.restype = c_int
72*2b87386cSAdrian Hunter		self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ]
73*2b87386cSAdrian Hunter
74*2b87386cSAdrian Hunter		self.xed_format_context = self.libxed.xed_format_context
75*2b87386cSAdrian Hunter		self.xed_format_context.restype = c_uint
76*2b87386cSAdrian Hunter		self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ]
77*2b87386cSAdrian Hunter
78*2b87386cSAdrian Hunter		self.xed_tables_init()
79*2b87386cSAdrian Hunter
80*2b87386cSAdrian Hunter	def Instruction(self):
81*2b87386cSAdrian Hunter		return XEDInstruction(self)
82*2b87386cSAdrian Hunter
83*2b87386cSAdrian Hunter	def SetMode(self, inst, mode):
84*2b87386cSAdrian Hunter		if mode:
85*2b87386cSAdrian Hunter			inst.state.mode = 4 # 32-bit
86*2b87386cSAdrian Hunter			inst.state.width = 4 # 4 bytes
87*2b87386cSAdrian Hunter		else:
88*2b87386cSAdrian Hunter			inst.state.mode = 1 # 64-bit
89*2b87386cSAdrian Hunter			inst.state.width = 8 # 8 bytes
90*2b87386cSAdrian Hunter		self.xed_operand_values_set_mode(inst.xedp, inst.statep)
91*2b87386cSAdrian Hunter
92*2b87386cSAdrian Hunter	def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip):
93*2b87386cSAdrian Hunter		self.xed_decoded_inst_zero_keep_mode(inst.xedp)
94*2b87386cSAdrian Hunter		err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt)
95*2b87386cSAdrian Hunter		if err:
96*2b87386cSAdrian Hunter			return 0, ""
97*2b87386cSAdrian Hunter		# Use AT&T mode (2), alternative is Intel (3)
98*2b87386cSAdrian Hunter		ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0)
99*2b87386cSAdrian Hunter		if not ok:
100*2b87386cSAdrian Hunter			return 0, ""
101*2b87386cSAdrian Hunter		if sys.version_info[0] == 2:
102*2b87386cSAdrian Hunter			result = inst.buffer.value
103*2b87386cSAdrian Hunter		else:
104*2b87386cSAdrian Hunter			result = inst.buffer.value.decode()
105*2b87386cSAdrian Hunter		# Return instruction length and the disassembled instruction text
106*2b87386cSAdrian Hunter		# For now, assume the length is in byte 166
107*2b87386cSAdrian Hunter		return inst.xedd[166], result
108