From 309a2c4e3be8a5dc55e76e766be2d2fb0f9cdec2 Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Sat, 10 Mar 2012 21:44:03 +0000 Subject: Revert "[llvm.py] Implement interface to enhanced disassembler" Chris Lattner says the edis interface is going away. It doesn't make sense to land something that will go away in the near future. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152508 91177308-0d34-0410-b5e6-96231b3b80d8 --- bindings/python/llvm/disassembler.py | 564 ------------------------ bindings/python/llvm/tests/test_disassembler.py | 62 --- 2 files changed, 626 deletions(-) delete mode 100644 bindings/python/llvm/disassembler.py delete mode 100644 bindings/python/llvm/tests/test_disassembler.py (limited to 'bindings/python') diff --git a/bindings/python/llvm/disassembler.py b/bindings/python/llvm/disassembler.py deleted file mode 100644 index d1fd789dba..0000000000 --- a/bindings/python/llvm/disassembler.py +++ /dev/null @@ -1,564 +0,0 @@ -#===- disassembler.py - Python LLVM Bindings -----------------*- python -*--===# -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -#===------------------------------------------------------------------------===# - -from abc import ABCMeta -from abc import abstractmethod - -from ctypes import CFUNCTYPE -from ctypes import POINTER -from ctypes import byref -from ctypes import c_char_p -from ctypes import c_int -from ctypes import c_ubyte -from ctypes import c_uint64 -from ctypes import c_uint -from ctypes import c_void_p -from ctypes import memmove - -from .common import CachedProperty -from .common import LLVMObject -from .common import c_object_p -from .common import get_library - -__all__ = [ - 'DisassemblerByteArraySource', - 'DisassemblerFileSource', - 'DisassemblerSource', - 'Disassembler', - 'Instruction', - 'Operand', - 'Token', -] - -callbacks = {} - -class DisassemblerSource: - """Abstract base class for disassembler input. - - This defines the interface to which inputs to the disassembler must - conform. - - Basically, the disassembler input is a read-only sequence of a finite - length. - """ - __metaclass__ = ABCMeta - - @abstractmethod - def __len__(self): - """Returns the number of bytes that are available for input.""" - pass - - @abstractmethod - def get_byte(self, address): - """Returns the byte at the specified address.""" - pass - - @abstractmethod - def start_address(self): - """Returns the address at which to start fetch bytes, as a long.""" - pass - -class DisassemblerByteArraySource(DisassemblerSource): - """A disassembler source for byte arrays.""" - - def __init__(self, b): - self._array = b - - def __len__(self): - return len(self._array) - - def get_byte(self, address): - return self._array[address] - - def start_address(self): - return 0 - -class DisassemblerFileSource(DisassemblerSource): - """A disassembler source for file segments. - - This allows you to feed in segments of a file into a Disassembler. - """ - - def __init__(self, filename, start_offset, length=None, end_offset=None, - start_address=None): - """Create a new source from a file. - - A source begins at a specified byte offset and can be defined in terms - of byte length of the end byte offset. - """ - if length is None and end_offset is None: - raise Exception('One of length or end_offset must be defined.') - - self._start_address = start_address - if self._start_address is None: - self._start_address = 0 - - count = length - if length is None: - count = end_offset - start_offset - - with open(filename, 'rb') as fh: - fh.seek(start_offset) - - # FIXME handle case where read bytes != requested - self._buf = fh.read(count) - - def __len__(self): - return len(self._buf) - - def get_byte(self, address): - return self._buf[address - self._start_address] - - def start_address(self): - return self._start_address - -class Disassembler(LLVMObject): - """Interface to LLVM's enhanced disassembler. - - The API is slightly different from the C API in that we tightly couple a - disassembler instance to an input source. This saves an extra level of - abstraction and makes the Python implementation easier. - """ - - SYNTAX_X86_INTEL = 0 - SYNTAX_X86_ATT = 1 - SYNTAX_ARM_UAL = 2 - - def __init__(self, triple, source, syntax=0): - """Create a new disassembler instance. - - Arguments: - - triple -- str target type (e.g. x86_64-apple-darwin10) - source -- DisassemblerSource instance to be fed into this disassembler. - syntax -- The assembly syntax to use. One of the SYNTAX_* class - constants. e.g. EnhancedDisassembler.SYNTAX_X86_INTEL - """ - assert isinstance(source, DisassemblerSource) - - ptr = c_object_p() - result = lib.EDGetDisassembler(byref(ptr), c_char_p(triple), - c_int(syntax)) - if result != 0: - raise Exception('Non-0 return code.') - - LLVMObject.__init__(self, ptr) - - self._source = source - - def get_instructions(self): - """Obtain the instructions from the input. - - This is a generator for Instruction instances. - - By default, this will return instructions for the entire source which - has been defined. It does this by querying the source's start_address() - method and continues to request instructions until len(source) is - exhausted. - """ - - # We currently obtain 1 instruction at a time because it is easiest. - - # This serves as our EDByteReaderCallback. It is a proxy between C and - # the Python DisassemblerSource. - def byte_reader(dest, address, arg): - try: - byte = self._source.get_byte(address) - memmove(dest, byte, 1) - - return 0 - except: - return -1 - - address = self._source.start_address() - end_address = address + len(self._source) - cb = callbacks['byte_reader'](byte_reader) - while address < end_address: - ptr = c_object_p() - - result = lib.EDCreateInsts(byref(ptr), c_uint(1), self, cb, - address, c_void_p(None)) - - if result != 1: - raise Exception('Error obtaining instruction at address %d' % - address) - - instruction = Instruction(ptr, self) - yield instruction - - address += instruction.byte_size - - -class Instruction(LLVMObject): - """Represents an individual instruction. - - Instruction instances are obtained from Disassembler.get_instructions(). - """ - def __init__(self, ptr, disassembler): - """Create a new instruction. - - Instructions are created from within this module. You should have no - need to call this from outside this module. - """ - assert isinstance(ptr, c_object_p) - assert isinstance(disassembler, Disassembler) - - LLVMObject.__init__(self, ptr, disposer=lib.EDReleaseInst) - self._disassembler = disassembler - - def __str__(self): - s = c_char_p(None) - result = lib.EDGetInstString(byref(s), self) - if result != 0: - raise Exception('Non-0 return code.') - - return s.value - - @CachedProperty - def byte_size(self): - result = lib.EDInstByteSize(self) - if result == -1: - raise Exception('Error code returned.') - - return result - - @CachedProperty - def id(self): - i = c_uint() - result = lib.EDInstID(byref(i), self) - if result != 0: - raise Exception('Non-0 return code.') - - return i.value - - @CachedProperty - def is_branch(self): - result = lib.EDInstIsBranch(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def is_move(self): - result = lib.EDInstIsMove(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def branch_target_id(self): - result = lib.EDBranchTargetID(self) - if result == -1: - raise Exception('Error code returned.') - - return result - - @CachedProperty - def move_source_id(self): - result = lib.EDMoveSourceID(self) - if result == -1: - raise Exception('Error code returned.') - - return result - - def get_tokens(self): - """Obtain the tokens in this instruction. - - This is a generator for Token instances. - """ - count = lib.EDNumTokens(self) - if count == -1: - raise Exception('Error code returned.') - - for i in range(0, count): - ptr = c_object_p() - result = lib.EDGetToken(byref(ptr), self, c_int(i)) - if result != 0: - raise Exception('Non-0 return code.') - - yield Token(ptr, self) - - def get_operands(self): - """Obtain the operands in this instruction. - - This is a generator for Operand instances. - """ - count = lib.EDNumOperands(self) - if count == -1: - raise Exception('Error code returned.') - - for i in range(0, count): - ptr = c_object_p() - result = lib.EDGetOperand(byref(ptr), self, c_int(i)) - if result != 0: - raise Exception('Non-0 return code.') - - yield Operand(ptr, self) - -class Token(LLVMObject): - def __init__(self, ptr, instruction): - assert isinstance(ptr, c_object_p) - assert isinstance(instruction, Instruction) - - LLVMObject.__init__(self, ptr) - - self._instruction = instruction - - def __str__(self): - s = c_char_p(None) - result = lib.EDGetTokenString(byref(s), self) - if result != 0: - raise Exception('Non-0 return code.') - - return s.value - - @CachedProperty - def operand_index(self): - result = lib.EDOperandIndexForToken(self) - if result == -1: - raise Exception('Error code returned.') - - return result - - @CachedProperty - def is_whitespace(self): - result = lib.EDTokenIsWhitespace(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def is_punctuation(self): - result = lib.EDTokenIsPunctuation(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def is_opcode(self): - result = lib.EDTokenIsOpcode(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def is_literal(self): - result = lib.EDTokenIsLiteral(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def is_register(self): - result = lib.EDTokenIsRegister(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def is_negative_literal(self): - result = lib.EDTokenIsNegativeLiteral(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def absolute_value(self): - value = c_uint64() - result = lib.EDLiteralTokenAbsoluteValue(byref(value), self) - if result != 0: - raise Exception('Non-0 return code.') - - return value - - @CachedProperty - def register_value(self): - value = c_uint() - result = lib.EDRegisterTokenValue(byref(value), self) - if result != 0: - raise Exception('Non-0 return code.') - - return value - -class Operand(LLVMObject): - """Represents an operand in an instruction. - - FIXME support register evaluation. - """ - def __init__(self, ptr, instruction): - assert isinstance(ptr, c_object_p) - assert isinstance(instruction, Instruction) - - LLVMObject.__init__(self, ptr) - - self._instruction = instruction - - @CachedProperty - def is_register(self): - result = lib.EDOperandIsRegister(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def is_immediate(self): - result = lib.EDOperandIsImmediate(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def is_memory(self): - result = lib.EDOperandIsMemory(self) - if result == -1: - raise Exception('Error code returned.') - - return result > 0 - - @CachedProperty - def register_value(self): - value = c_uint() - result = lib.EDRegisterOperandValue(byref(value), self) - if result != 0: - raise Exception('Non-0 return code.') - - return value - - @CachedProperty - def immediate_value(self): - value = c_uint64() - result = lib.EDImmediateOperandValue(byref(value), self) - if result != 0: - raise Exception('Non-0 return code.') - - return value - -def register_library(library): - library.EDGetDisassembler.argtypes = [POINTER(c_object_p), c_char_p, c_int] - library.EDGetDisassembler.restype = c_int - - library.EDGetRegisterName.argtypes = [POINTER(c_char_p), Disassembler, - c_uint] - library.EDGetRegisterName.restype = c_int - - library.EDRegisterIsStackPointer.argtypes = [Disassembler, c_uint] - library.EDRegisterIsStackPointer.restype = c_int - - library.EDRegisterIsProgramCounter.argtypes = [Disassembler, c_uint] - library.EDRegisterIsProgramCounter.restype = c_int - - library.EDCreateInsts.argtypes = [POINTER(c_object_p), c_uint, - Disassembler, callbacks['byte_reader'], c_uint64, c_void_p] - library.EDCreateInsts.restype = c_uint - - library.EDReleaseInst.argtypes = [Instruction] - - library.EDInstByteSize.argtypes = [Instruction] - library.EDInstByteSize.restype = c_int - - library.EDGetInstString.argtypes = [POINTER(c_char_p), Instruction] - library.EDGetInstString.restype = c_int - - library.EDInstID.argtypes = [POINTER(c_uint), Instruction] - library.EDInstID.restype = c_int - - library.EDInstIsBranch.argtypes = [Instruction] - library.EDInstIsBranch.restype = c_int - - library.EDInstIsMove.argtypes = [Instruction] - library.EDInstIsMove.restype = c_int - - library.EDBranchTargetID.argtypes = [Instruction] - library.EDBranchTargetID.restype = c_int - - library.EDMoveSourceID.argtypes = [Instruction] - library.EDMoveSourceID.restype = c_int - - library.EDMoveTargetID.argtypes = [Instruction] - library.EDMoveTargetID.restype = c_int - - library.EDNumTokens.argtypes = [Instruction] - library.EDNumTokens.restype = c_int - - library.EDGetToken.argtypes = [POINTER(c_object_p), Instruction, c_int] - library.EDGetToken.restype = c_int - - library.EDGetTokenString.argtypes = [POINTER(c_char_p), Token] - library.EDGetTokenString.restype = c_int - - library.EDOperandIndexForToken.argtypes = [Token] - library.EDOperandIndexForToken.restype = c_int - - library.EDTokenIsWhitespace.argtypes = [Token] - library.EDTokenIsWhitespace.restype = c_int - - library.EDTokenIsPunctuation.argtypes = [Token] - library.EDTokenIsPunctuation.restype = c_int - - library.EDTokenIsOpcode.argtypes = [Token] - library.EDTokenIsOpcode.restype = c_int - - library.EDTokenIsLiteral.argtypes = [Token] - library.EDTokenIsLiteral.restype = c_int - - library.EDTokenIsRegister.argtypes = [Token] - library.EDTokenIsRegister.restype = c_int - - library.EDTokenIsNegativeLiteral.argtypes = [Token] - library.EDTokenIsNegativeLiteral.restype = c_int - - library.EDLiteralTokenAbsoluteValue.argtypes = [POINTER(c_uint64), Token] - library.EDLiteralTokenAbsoluteValue.restype = c_int - - library.EDRegisterTokenValue.argtypes = [POINTER(c_uint), Token] - library.EDRegisterTokenValue.restype = c_int - - library.EDNumOperands.argtypes = [Instruction] - library.EDNumOperands.restype = c_int - - library.EDGetOperand.argtypes = [POINTER(c_object_p), Instruction, c_int] - library.EDGetOperand.restype = c_int - - library.EDOperandIsRegister.argtypes = [Operand] - library.EDOperandIsRegister.restype = c_int - - library.EDOperandIsImmediate.argtypes = [Operand] - library.EDOperandIsImmediate.restype = c_int - - library.EDOperandIsMemory.argtypes = [Operand] - library.EDOperandIsMemory.restype = c_int - - library.EDRegisterOperandValue.argtypes = [POINTER(c_uint), Operand] - library.EDRegisterOperandValue.restype = c_int - - library.EDImmediateOperandValue.argtypes = [POINTER(c_uint64), Operand] - library.EDImmediateOperandValue.restype = c_int - - library.EDEvaluateOperand.argtypes = [c_uint64, Operand, - callbacks['register_reader'], c_void_p] - library.EDEvaluateOperand.restype = c_int - -# Enhanced disassembler. -callbacks['byte_reader'] = CFUNCTYPE(c_int, POINTER(c_ubyte), c_uint64, - c_void_p) -callbacks['register_reader'] = CFUNCTYPE(c_int, POINTER(c_uint64), c_uint, - c_void_p) - -lib = get_library() -register_library(lib) diff --git a/bindings/python/llvm/tests/test_disassembler.py b/bindings/python/llvm/tests/test_disassembler.py deleted file mode 100644 index 6eb11a23dc..0000000000 --- a/bindings/python/llvm/tests/test_disassembler.py +++ /dev/null @@ -1,62 +0,0 @@ -from unittest import expectedFailure -from unittest import skip - -from .base import TestBase -from ..disassembler import DisassemblerByteArraySource -from ..disassembler import DisassemblerFileSource -from ..disassembler import Disassembler -from ..object import ObjectFile - -class TestDisassembler(TestBase): - def test_simple(self): - sequence = '\x67\xe3\x81' # jcxz -127 - triple = 'i686-apple-darwin9' - - source = DisassemblerByteArraySource(sequence) - - disassembler = Disassembler(triple, source) - instructions = list(disassembler.get_instructions()) - - self.assertEqual(len(instructions), 1) - - i = instructions[0] - self.assertEqual(str(i), '\tjcxz\t-127\n') - self.assertEqual(i.byte_size, 3) - self.assertEqual(i.id, 1032) - self.assertTrue(i.is_branch) - self.assertFalse(i.is_move) - self.assertEqual(i.branch_target_id, 0) - - tokens = list(i.get_tokens()) - self.assertEqual(len(tokens), 4) - token = tokens[0] - self.assertEqual(str(token), 'jcxz') - self.assertFalse(token.is_whitespace) - self.assertFalse(token.is_punctuation) - self.assertTrue(token.is_opcode) - self.assertFalse(token.is_literal) - self.assertFalse(token.is_register) - - self.assertTrue(tokens[1].is_whitespace) - - operands = list(i.get_operands()) - self.assertEqual(len(operands), 1) - - # TODO implement operand tests - - @skip('This test is horribly broken and probably not even correct.') - def test_read_instructions(self): - filename = self.get_test_binary() - o = ObjectFile(filename=filename) - - for symbol in o.get_symbols(): - address = symbol.address - offset = symbol.file_offset - size = symbol.size - - source = DisassemblerFileSource(filename, offset, length=size, - start_address=address) - - disassembler = Disassembler('x86-generic-gnu-linux', source) - for instruction in disassembler.get_instructions(): - print instruction -- cgit v1.2.3