moved the MC data type access to TargetMachine

Disassembler now simply needs a TargetMachine object
and it will be able to access all the descriptor objects
it needs for disassembly through the target machine.
This commit is contained in:
anthony cantor 2013-08-17 20:21:51 -06:00 • committed by Siu Kwan Lam
commit cbf4a61a17
5 changed files with 103 additions and 88 deletions

View file

@ -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

View file

@ -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()

View file

@ -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"

View file

@ -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)))

View file

@ -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)))