1 #===- disassembler.py - Python LLVM Bindings -----------------*- python -*--===#
3 # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 # See https://llvm.org/LICENSE.txt for license information.
5 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 #===------------------------------------------------------------------------===#
9 from ctypes
import CFUNCTYPE
10 from ctypes
import POINTER
11 from ctypes
import addressof
12 from ctypes
import c_byte
13 from ctypes
import c_char_p
14 from ctypes
import c_int
15 from ctypes
import c_size_t
16 from ctypes
import c_ubyte
17 from ctypes
import c_uint64
18 from ctypes
import c_void_p
19 from ctypes
import cast
21 from .common
import LLVMObject
22 from .common
import c_object_p
23 from .common
import get_library
32 # Constants for set_options
38 _targets
= ['AArch64', 'ARM', 'Hexagon', 'MSP430', 'Mips', 'NVPTX', 'PowerPC', 'R600', 'Sparc', 'SystemZ', 'X86', 'XCore']
39 def _ensure_initialized():
42 # Here one would want to call the functions
43 # LLVMInitializeAll{TargetInfo,TargetMC,Disassembler}s, but
44 # unfortunately they are only defined as static inline
45 # functions in the header files of llvm-c, so they don't exist
46 # as symbols in the shared library.
47 # So until that is fixed use this hack to initialize them all
49 for initializer
in ("TargetInfo", "TargetMC", "Disassembler"):
51 f
= getattr(lib
, "LLVMInitialize" + tgt
+ initializer
)
52 except AttributeError:
58 class Disassembler(LLVMObject
):
59 """Represents a disassembler instance.
61 Disassembler instances are tied to specific "triple," which must be defined
64 Disassembler instances can disassemble instructions from multiple sources.
66 def __init__(self
, triple
):
67 """Create a new disassembler instance.
69 The triple argument is the triple to create the disassembler for. This
70 is something like 'i386-apple-darwin9'.
75 ptr
= lib
.LLVMCreateDisasm(c_char_p(triple
), c_void_p(None), c_int(0),
76 callbacks
['op_info'](0), callbacks
['symbol_lookup'](0))
78 raise Exception('Could not obtain disassembler for triple: %s' %
81 LLVMObject
.__init
__(self
, ptr
, disposer
=lib
.LLVMDisasmDispose
)
83 def get_instruction(self
, source
, pc
=0):
84 """Obtain the next instruction from an input source.
86 The input source should be a str or bytearray or something that
87 represents a sequence of bytes.
89 This function will start reading bytes from the beginning of the
92 The pc argument specifies the address that the first byte is at.
94 This returns a 2-tuple of:
96 long number of bytes read. 0 if no instruction was read.
97 str representation of instruction. This will be the assembly that
98 represents the instruction.
100 buf
= cast(c_char_p(source
), POINTER(c_ubyte
))
101 out_str
= cast((c_byte
* 255)(), c_char_p
)
103 result
= lib
.LLVMDisasmInstruction(self
, buf
, c_uint64(len(source
)),
104 c_uint64(pc
), out_str
, 255)
106 return (result
, out_str
.value
)
108 def get_instructions(self
, source
, pc
=0):
109 """Obtain multiple instructions from an input source.
111 This is like get_instruction() except it is a generator for all
112 instructions within the source. It starts at the beginning of the
113 source and reads instructions until no more can be read.
115 This generator returns 3-tuple of:
117 long address of instruction.
118 long size of instruction, in bytes.
119 str representation of instruction.
121 source_bytes
= c_char_p(source
)
122 out_str
= cast((c_byte
* 255)(), c_char_p
)
124 # This could probably be written cleaner. But, it does work.
125 buf
= cast(source_bytes
, POINTER(c_ubyte
* len(source
))).contents
128 end_address
= pc
+ len(source
)
129 while address
< end_address
:
130 b
= cast(addressof(buf
) + offset
, POINTER(c_ubyte
))
131 result
= lib
.LLVMDisasmInstruction(self
, b
,
132 c_uint64(len(source
) - offset
), c_uint64(address
),
138 yield (address
, result
, out_str
.value
)
143 def set_options(self
, options
):
144 if not lib
.LLVMSetDisasmOptions(self
, options
):
145 raise Exception('Unable to set all disassembler options in %i' % options
)
148 def register_library(library
):
149 library
.LLVMCreateDisasm
.argtypes
= [c_char_p
, c_void_p
, c_int
,
150 callbacks
['op_info'], callbacks
['symbol_lookup']]
151 library
.LLVMCreateDisasm
.restype
= c_object_p
153 library
.LLVMDisasmDispose
.argtypes
= [Disassembler
]
155 library
.LLVMDisasmInstruction
.argtypes
= [Disassembler
, POINTER(c_ubyte
),
156 c_uint64
, c_uint64
, c_char_p
, c_size_t
]
157 library
.LLVMDisasmInstruction
.restype
= c_size_t
159 library
.LLVMSetDisasmOptions
.argtypes
= [Disassembler
, c_uint64
]
160 library
.LLVMSetDisasmOptions
.restype
= c_int
163 callbacks
['op_info'] = CFUNCTYPE(c_int
, c_void_p
, c_uint64
, c_uint64
, c_uint64
,
165 callbacks
['symbol_lookup'] = CFUNCTYPE(c_char_p
, c_void_p
, c_uint64
,
166 POINTER(c_uint64
), c_uint64
,
169 register_library(lib
)