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 import api
from llvmpy.api.llvm import MCDisassembler from llvmpy.api.llvm import MCDisassembler
class Instr: class Instr(object):
def __init__(self, mcinst):
def __init__(self, mcinst, target_machine):
'''
@mcinst: an MCInst object
@target_machine: an llvm.target.TargetMachine object
'''
self.mcinst = mcinst self.mcinst = mcinst
if not self.mcinst: if not self.mcinst:
raise llvm.LLVMException("null MCInst argument") raise llvm.LLVMException("null MCInst argument")
self.tm = target_machine
def __repr__(self): def __repr__(self):
return repr(self.mcinst) return repr(self.mcinst)
@ -34,103 +42,45 @@ class Instr:
class BadInstr(Instr): class BadInstr(Instr):
pass pass
class Disassembler: class Disassembler(object):
def __init__(self, mcdisasm, mri, mai, mii, mia, mip): def __init__(self, target_machine):
self.mcdisasm = mcdisasm self.tm = target_machine
if not self.mcdisasm:
raise llvm.LLVMException("null MCDisassembler argument")
self.mri = mri @property
self.mai = mai def mdasm(self):
self.mii = mii return self.tm.disassembler
self.mia = mia
self.mip = mip
def __repr__(self): @property
return repr(self.mcdisasm) def mai(self):
return self.tm.asm_info
@staticmethod def instr(self, mcinst):
def new_from_target(target, triple, cpu, features): return Instr(mcinst, self)
def raise_on_false(name, obj):
if not obj:
raise llvm.LLVMException("Could not create %s" % name)
sti = target.createMCSubtargetInfo(triple, cpu, features) def bad_instr(self, mcinst):
raise_on_false("subtarget info", sti) return BadInstr(mcinst, self)
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')
#decode some bytes into instructions. yields each instruction #decode some bytes into instructions. yields each instruction
#as it is decoded. #as it is decoded.
def decode(self, bs): def decode(self, bs):
code = api.llvm.StringRefMemoryObject.new(bs, 0) code = api.llvm.StringRefMemoryObject.new(bs, 0)
idx = code.getBase() idx = code.getBase()
align = self.mai.getMinInstAlignment()
while(idx < code.getExtent()): while(idx < code.getExtent()):
inst = api.llvm.MCInst.new() 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: if status == MCDisassembler.DecodeStatus.Fail:
yield (idx, None) yield (idx, None)
elif status == MCDisassembler.DecodeStatus.SoftFail: elif status == MCDisassembler.DecodeStatus.SoftFail:
yield (idx, BadInstr(inst)) yield (idx, self.bad_instr(inst))
else: else:
yield (idx, Instr(inst)) yield (idx, self.instr(inst))
if size <= 1: if size < 1:
idx += 1 idx += (align - (idx % align))
else: else:
idx += size idx += size

View file

@ -187,3 +187,44 @@ class TargetMachine(llvm.Wrapper):
def feature_string(self): def feature_string(self):
return self._ptr.getTargetFeatureString() 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() MCInstrAnalysis = llvm.Class()
MCInstPrinter = llvm.Class() MCInstPrinter = llvm.Class()
TargetSubtargetInfo = llvm.Class(MCSubtargetInfo)
TargetInstrInfo = llvm.Class(MCInstrInfo)
@MCSubtargetInfo @MCSubtargetInfo
class MCSubtargetInfo: class MCSubtargetInfo:
pass pass
@TargetSubtargetInfo
class TargetSubtargetInfo:
_include_ = 'llvm/Target/TargetSubtargetInfo.h'
@MCExpr @MCExpr
class MCExpr: class MCExpr:
_include_ = "llvm/MC/MCExpr.h" _include_ = "llvm/MC/MCExpr.h"
@ -65,6 +72,10 @@ class MCRegisterInfo:
class MCInstrInfo: class MCInstrInfo:
_include_ = "llvm/MC/MCInstrInfo.h" _include_ = "llvm/MC/MCInstrInfo.h"
@TargetInstrInfo
class TargetInstrInfo:
_include_ = 'llvm/Target/TargetInstrInfo.h'
@MCInstrAnalysis @MCInstrAnalysis
class MCInstrAnalysis: class MCInstrAnalysis:
_include_ = "llvm/MC/MCInstrAnalysis.h" _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.Support.CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc
from src.GlobalValue import GlobalValue from src.GlobalValue import GlobalValue
from src.DataLayout import DataLayout from src.DataLayout import DataLayout
if LLVM_VERSION >= (3, 4):
from src.MC import MCAsmInfo, TargetInstrInfo, TargetSubtargetInfo
if LLVM_VERSION < (3, 3): if LLVM_VERSION < (3, 3):
from src.TargetTransformInfo import (ScalarTargetTransformInfo, from src.TargetTransformInfo import (ScalarTargetTransformInfo,
@ -55,4 +57,10 @@ class TargetMachine:
cast(bool, Bool) cast(bool, Bool)
).require_only(3) ).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): if llvm.version >= (3, 4):
from llvm.target import TargetMachine
from llvm import mc from llvm import mc
from llvm.mc import Disassembler from llvm.mc import Disassembler
from llvmpy import api
llvm.initialize_all_target_components() llvm.target.initialize_all()
def op_str(op): def op_str(op):
s = [] s = []
@ -37,7 +37,7 @@ if llvm.version >= (3, 4):
if inst is None: if inst is None:
print("\t%r=>(bad): 0, []" % (offset)) print("\t%r=>(bad): 0, []" % (offset))
else: else:
if isinstance(inst, mc.BadInstr): if isinstance(inst, mc.BadInstr):
print("\t%r=>(bad)%r: %r" % (offset, inst, len(inst))) print("\t%r=>(bad)%r: %r" % (offset, inst, len(inst)))
else: else:
print("\t%r=>%r: %r" % (offset, inst, len(inst))) 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("\t\t%s" % op_str(op))
print("x86:") x86 = TargetMachine.x86()
print_instructions(Disassembler.x86(), "\x01\xc3\xc3\xcc\x90") print("x86: LE=%s" % x86.is_little_endian())
print("x86-64:") print_instructions(Disassembler(x86), "\x01\xc3\xc3\xcc\x90")
print_instructions(Disassembler.x86_64(), "\x55\x48\x89\xe8")
print("arm:") 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 = [ code = [
"\xe9\x2d\x48\x00", "\xe9\x2d\x48\x00",
"\xea\x00\x00\x06", "\xea\x00\x00\x06",
@ -58,4 +63,4 @@ if llvm.version >= (3, 4):
"\xe2\x8d\xb0\x04", "\xe2\x8d\xb0\x04",
"\xe5\x0b\x00\x20" "\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)))