diff --git a/llvm/mc/__init__.py b/llvm/mc/__init__.py index 16aeb03..07b503e 100644 --- a/llvm/mc/__init__.py +++ b/llvm/mc/__init__.py @@ -8,12 +8,20 @@ import contextlib from llvmpy import api from llvmpy.api.llvm import MCDisassembler -class Instr: - def __init__(self, mcinst): +class Instr(object): + + def __init__(self, mcinst, target_machine): + ''' + @mcinst: an MCInst object + @target_machine: an llvm.target.TargetMachine object + ''' + self.mcinst = mcinst if not self.mcinst: raise llvm.LLVMException("null MCInst argument") + self.tm = target_machine + def __repr__(self): return repr(self.mcinst) @@ -34,103 +42,45 @@ class Instr: class BadInstr(Instr): pass -class Disassembler: +class Disassembler(object): - def __init__(self, mcdisasm, mri, mai, mii, mia, mip): - self.mcdisasm = mcdisasm - if not self.mcdisasm: - raise llvm.LLVMException("null MCDisassembler argument") + def __init__(self, target_machine): + self.tm = target_machine - self.mri = mri - self.mai = mai - self.mii = mii - self.mia = mia - self.mip = mip + @property + def mdasm(self): + return self.tm.disassembler - def __repr__(self): - return repr(self.mcdisasm) + @property + def mai(self): + return self.tm.asm_info - @staticmethod - def new_from_target(target, triple, cpu, features): - def raise_on_false(name, obj): - if not obj: - raise llvm.LLVMException("Could not create %s" % name) + def instr(self, mcinst): + return Instr(mcinst, self) - sti = target.createMCSubtargetInfo(triple, cpu, features) - raise_on_false("subtarget info", sti) - mri = target.createMCRegInfo(triple) - raise_on_false("register info", mri) - mai = target.createMCAsmInfo(mri, triple) - raise_on_false("asm info", mai) - mii = target.createMCInstrInfo() - raise_on_false("instr info", mii) - mia = target.createMCInstrAnalysis(mii) - raise_on_false("instr analysis", mia) - mip = target.createMCInstPrinter(mai.getAssemblerDialect(), - mai, mii, mri, sti) - - return Disassembler(target.createMCDisassembler(sti), - mri, mai, mii, mia, mip) - - @staticmethod - def new_from_triple(triple='', cpu='', features=''): - if not triple: - triple = api.llvm.sys.getDefaultTargetTriple() - print repr(triple) - - with contextlib.closing(BytesIO()) as error: - target = api.llvm.TargetRegistry.lookupTarget(triple, error) - if not target: - raise llvm.LLVMException(error.read()) - if not target.hasMCDisassembler(): - raise llvm.LLVMException(target, "No disassembler provided for %s." % triple) - - return Disassembler.new_from_target(target, triple, cpu, features) - - @staticmethod - def new_from_name(name, cpu='', features=''): - name = name.strip() - for target in api.llvm.TargetRegistry.targetsList(): - if name == target.getName(): - return Disassembler.new_from_target(target, name, cpu, features) - - raise llvm.LLVMException("failed to find target with name %s" % name) - - @staticmethod - def x86(): - return Disassembler.new_from_name('x86') - - @staticmethod - def x86_64(): - return Disassembler.new_from_name('x86-64') - - @staticmethod - def arm(): - return Disassembler.new_from_name('arm') - - @staticmethod - def thumb(): - return Disassembler.new_from_name('thumb') + def bad_instr(self, mcinst): + return BadInstr(mcinst, self) #decode some bytes into instructions. yields each instruction #as it is decoded. def decode(self, bs): code = api.llvm.StringRefMemoryObject.new(bs, 0) idx = code.getBase() + align = self.mai.getMinInstAlignment() while(idx < code.getExtent()): inst = api.llvm.MCInst.new() - status, size = self.mcdisasm.getInstruction(inst, code, idx) + status, size = self.mdasm.getInstruction(inst, code, idx) if status == MCDisassembler.DecodeStatus.Fail: yield (idx, None) elif status == MCDisassembler.DecodeStatus.SoftFail: - yield (idx, BadInstr(inst)) + yield (idx, self.bad_instr(inst)) else: - yield (idx, Instr(inst)) + yield (idx, self.instr(inst)) - if size <= 1: - idx += 1 + if size < 1: + idx += (align - (idx % align)) else: idx += size diff --git a/llvm/target.py b/llvm/target.py index fe014f8..7cfdbd6 100644 --- a/llvm/target.py +++ b/llvm/target.py @@ -187,3 +187,44 @@ class TargetMachine(llvm.Wrapper): def feature_string(self): return self._ptr.getTargetFeatureString() + @property + def target(self): + return self._ptr.getTarget() + + if llvm.version >= (3, 4): + @property + def reg_info(self): + if not getattr(self, '_mri', False): + self._mri = self.target.createMCRegInfo(self.triple) + + return self._mri + + @property + def subtarget_info(self): + return self._ptr.getSubtargetImpl() + + @property + def asm_info(self): + return self._ptr.getMCAsmInfo() + + @property + def instr_info(self): + return self._ptr.getInstrInfo() + + @property + def instr_analysis(self): + if not getattr(self, '_mia', False): + self._mia = self.target.getMCInstrAnalysis(self.instr_info) + + return self._mia + + @property + def disassembler(self): + if not getattr(self, '_dasm', False): + self._dasm = self.target.createMCDisassembler(self.subtarget_info) + + return self._dasm + + def is_little_endian(self): + return self.asm_info.isLittleEndian() + diff --git a/llvmpy/src/MC/__init__.py b/llvmpy/src/MC/__init__.py index 6bcca5f..a7512c4 100644 --- a/llvmpy/src/MC/__init__.py +++ b/llvmpy/src/MC/__init__.py @@ -14,10 +14,17 @@ MCInstrInfo = llvm.Class() MCInstrAnalysis = llvm.Class() MCInstPrinter = llvm.Class() +TargetSubtargetInfo = llvm.Class(MCSubtargetInfo) +TargetInstrInfo = llvm.Class(MCInstrInfo) + @MCSubtargetInfo class MCSubtargetInfo: pass +@TargetSubtargetInfo +class TargetSubtargetInfo: + _include_ = 'llvm/Target/TargetSubtargetInfo.h' + @MCExpr class MCExpr: _include_ = "llvm/MC/MCExpr.h" @@ -65,6 +72,10 @@ class MCRegisterInfo: class MCInstrInfo: _include_ = "llvm/MC/MCInstrInfo.h" +@TargetInstrInfo +class TargetInstrInfo: + _include_ = 'llvm/Target/TargetInstrInfo.h' + @MCInstrAnalysis class MCInstrAnalysis: _include_ = "llvm/MC/MCInstrAnalysis.h" diff --git a/llvmpy/src/Target/TargetMachine.py b/llvmpy/src/Target/TargetMachine.py index 84c0d5d..764f8d0 100644 --- a/llvmpy/src/Target/TargetMachine.py +++ b/llvmpy/src/Target/TargetMachine.py @@ -8,6 +8,8 @@ from src.ADT.StringRef import StringRef from src.Support.CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc from src.GlobalValue import GlobalValue from src.DataLayout import DataLayout +if LLVM_VERSION >= (3, 4): + from src.MC import MCAsmInfo, TargetInstrInfo, TargetSubtargetInfo if LLVM_VERSION < (3, 3): from src.TargetTransformInfo import (ScalarTargetTransformInfo, @@ -55,4 +57,10 @@ class TargetMachine: cast(bool, Bool) ).require_only(3) + if LLVM_VERSION >= (3, 4): + getSubtargetImpl = Method(const(ptr(TargetSubtargetInfo))) + + getMCAsmInfo = Method(const(ptr(MCAsmInfo))) + + getInstrInfo = Method(const(ptr(TargetInstrInfo))) diff --git a/test/example-disassemble.py b/test/example-disassemble.py index 439652a..71a2ec6 100644 --- a/test/example-disassemble.py +++ b/test/example-disassemble.py @@ -2,11 +2,11 @@ import llvm if llvm.version >= (3, 4): + from llvm.target import TargetMachine from llvm import mc from llvm.mc import Disassembler - from llvmpy import api - llvm.initialize_all_target_components() + llvm.target.initialize_all() def op_str(op): s = [] @@ -37,7 +37,7 @@ if llvm.version >= (3, 4): if inst is None: print("\t%r=>(bad): 0, []" % (offset)) else: - if isinstance(inst, mc.BadInstr): + if isinstance(inst, mc.BadInstr): print("\t%r=>(bad)%r: %r" % (offset, inst, len(inst))) else: print("\t%r=>%r: %r" % (offset, inst, len(inst))) @@ -46,11 +46,16 @@ if llvm.version >= (3, 4): print("\t\t%s" % op_str(op)) - print("x86:") - print_instructions(Disassembler.x86(), "\x01\xc3\xc3\xcc\x90") - print("x86-64:") - print_instructions(Disassembler.x86_64(), "\x55\x48\x89\xe8") - print("arm:") + x86 = TargetMachine.x86() + print("x86: LE=%s" % x86.is_little_endian()) + print_instructions(Disassembler(x86), "\x01\xc3\xc3\xcc\x90") + + x86_64 = TargetMachine.x86_64() + print("x86-64: LE=%s" % x86_64.is_little_endian()) + print_instructions(Disassembler(x86_64), "\x55\x48\x89\xe8") + + arm = TargetMachine.arm() + print("arm: LE=%s" % arm.is_little_endian()) code = [ "\xe9\x2d\x48\x00", "\xea\x00\x00\x06", @@ -58,4 +63,4 @@ if llvm.version >= (3, 4): "\xe2\x8d\xb0\x04", "\xe5\x0b\x00\x20" ] - print_instructions(Disassembler.arm(), "".join(map(lambda s: s[::-1], code))) + print_instructions(Disassembler(arm), "".join(map(lambda s: s[::-1], code)))