mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	Check should be for pointer being NULL, not what it points to. Also adds a test for this case. Reviewed By: indygreg Differential Revision: http://llvm-reviews.chandlerc.com/D1878 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194965 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			171 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #===- 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 ctypes import CFUNCTYPE
 | |
| from ctypes import POINTER
 | |
| from ctypes import addressof
 | |
| from ctypes import c_byte
 | |
| from ctypes import c_char_p
 | |
| from ctypes import c_int
 | |
| from ctypes import c_size_t
 | |
| from ctypes import c_ubyte
 | |
| from ctypes import c_uint64
 | |
| from ctypes import c_void_p
 | |
| from ctypes import cast
 | |
| 
 | |
| from .common import LLVMObject
 | |
| from .common import c_object_p
 | |
| from .common import get_library
 | |
| 
 | |
| __all__ = [
 | |
|     'Disassembler',
 | |
| ]
 | |
| 
 | |
| lib = get_library()
 | |
| callbacks = {}
 | |
| 
 | |
| # Constants for set_options
 | |
| Option_UseMarkup = 1
 | |
| 
 | |
| 
 | |
| 
 | |
| _initialized = False
 | |
| _targets = ['AArch64', 'ARM', 'Hexagon', 'MSP430', 'Mips', 'NVPTX', 'PowerPC', 'R600', 'Sparc', 'SystemZ', 'X86', 'XCore']
 | |
| def _ensure_initialized():
 | |
|     global _initialized
 | |
|     if not _initialized:
 | |
|         # Here one would want to call the functions
 | |
|         # LLVMInitializeAll{TargetInfo,TargetMC,Disassembler}s, but
 | |
|         # unfortunately they are only defined as static inline
 | |
|         # functions in the header files of llvm-c, so they don't exist
 | |
|         # as symbols in the shared library.
 | |
|         # So until that is fixed use this hack to initialize them all
 | |
|         for tgt in _targets:
 | |
|             for initializer in ("TargetInfo", "TargetMC", "Disassembler"):
 | |
|                 try:
 | |
|                     f = getattr(lib, "LLVMInitialize" + tgt + initializer)
 | |
|                 except AttributeError:
 | |
|                     continue
 | |
|                 f()
 | |
|         _initialized = True
 | |
| 
 | |
| 
 | |
| class Disassembler(LLVMObject):
 | |
|     """Represents a disassembler instance.
 | |
| 
 | |
|     Disassembler instances are tied to specific "triple," which must be defined
 | |
|     at creation time.
 | |
| 
 | |
|     Disassembler instances can disassemble instructions from multiple sources.
 | |
|     """
 | |
|     def __init__(self, triple):
 | |
|         """Create a new disassembler instance.
 | |
| 
 | |
|         The triple argument is the triple to create the disassembler for. This
 | |
|         is something like 'i386-apple-darwin9'.
 | |
|         """
 | |
| 
 | |
|         _ensure_initialized()
 | |
| 
 | |
|         ptr = lib.LLVMCreateDisasm(c_char_p(triple), c_void_p(None), c_int(0),
 | |
|                 callbacks['op_info'](0), callbacks['symbol_lookup'](0))
 | |
|         if not ptr:
 | |
|             raise Exception('Could not obtain disassembler for triple: %s' %
 | |
|                             triple)
 | |
| 
 | |
|         LLVMObject.__init__(self, ptr, disposer=lib.LLVMDisasmDispose)
 | |
| 
 | |
|     def get_instruction(self, source, pc=0):
 | |
|         """Obtain the next instruction from an input source.
 | |
| 
 | |
|         The input source should be a str or bytearray or something that
 | |
|         represents a sequence of bytes.
 | |
| 
 | |
|         This function will start reading bytes from the beginning of the
 | |
|         source.
 | |
| 
 | |
|         The pc argument specifies the address that the first byte is at.
 | |
| 
 | |
|         This returns a 2-tuple of:
 | |
| 
 | |
|           long number of bytes read. 0 if no instruction was read.
 | |
|           str representation of instruction. This will be the assembly that
 | |
|             represents the instruction.
 | |
|         """
 | |
|         buf = cast(c_char_p(source), POINTER(c_ubyte))
 | |
|         out_str = cast((c_byte * 255)(), c_char_p)
 | |
| 
 | |
|         result = lib.LLVMDisasmInstruction(self, buf, c_uint64(len(source)),
 | |
|                                            c_uint64(pc), out_str, 255)
 | |
| 
 | |
|         return (result, out_str.value)
 | |
| 
 | |
|     def get_instructions(self, source, pc=0):
 | |
|         """Obtain multiple instructions from an input source.
 | |
| 
 | |
|         This is like get_instruction() except it is a generator for all
 | |
|         instructions within the source. It starts at the beginning of the
 | |
|         source and reads instructions until no more can be read.
 | |
| 
 | |
|         This generator returns 3-tuple of:
 | |
| 
 | |
|           long address of instruction.
 | |
|           long size of instruction, in bytes.
 | |
|           str representation of instruction.
 | |
|         """
 | |
|         source_bytes = c_char_p(source)
 | |
|         out_str = cast((c_byte * 255)(), c_char_p)
 | |
| 
 | |
|         # This could probably be written cleaner. But, it does work.
 | |
|         buf = cast(source_bytes, POINTER(c_ubyte * len(source))).contents
 | |
|         offset = 0
 | |
|         address = pc
 | |
|         end_address = pc + len(source)
 | |
|         while address < end_address:
 | |
|             b = cast(addressof(buf) + offset, POINTER(c_ubyte))
 | |
|             result = lib.LLVMDisasmInstruction(self, b,
 | |
|                     c_uint64(len(source) - offset), c_uint64(address),
 | |
|                     out_str, 255)
 | |
| 
 | |
|             if result == 0:
 | |
|                 break
 | |
| 
 | |
|             yield (address, result, out_str.value)
 | |
| 
 | |
|             address += result
 | |
|             offset += result
 | |
| 
 | |
|     def set_options(self, options):
 | |
|         if not lib.LLVMSetDisasmOptions(self, options):
 | |
|             raise Exception('Unable to set all disassembler options in %i' % options)
 | |
| 
 | |
| 
 | |
| def register_library(library):
 | |
|     library.LLVMCreateDisasm.argtypes = [c_char_p, c_void_p, c_int,
 | |
|         callbacks['op_info'], callbacks['symbol_lookup']]
 | |
|     library.LLVMCreateDisasm.restype = c_object_p
 | |
| 
 | |
|     library.LLVMDisasmDispose.argtypes = [Disassembler]
 | |
| 
 | |
|     library.LLVMDisasmInstruction.argtypes = [Disassembler, POINTER(c_ubyte),
 | |
|             c_uint64, c_uint64, c_char_p, c_size_t]
 | |
|     library.LLVMDisasmInstruction.restype = c_size_t
 | |
| 
 | |
|     library.LLVMSetDisasmOptions.argtypes = [Disassembler, c_uint64]
 | |
|     library.LLVMSetDisasmOptions.restype = c_int
 | |
| 
 | |
| 
 | |
| callbacks['op_info'] = CFUNCTYPE(c_int, c_void_p, c_uint64, c_uint64, c_uint64,
 | |
|                                  c_int, c_void_p)
 | |
| callbacks['symbol_lookup'] = CFUNCTYPE(c_char_p, c_void_p, c_uint64,
 | |
|                                        POINTER(c_uint64), c_uint64,
 | |
|                                        POINTER(c_char_p))
 | |
| 
 | |
| register_library(lib)
 |