added functionality to llvm.mc.Instr to print itself

uses binding of printInst on MCInstPrinter for printing
instruction.

also fixed a bug in llvm.mc.Disassembler.decode: idx should
start at zero, and we should pass code.getBase() + idx to
getInstruction. idx must start at zero because the while loop
compares it against code.getExtent() which returns only the
length of bs.
This commit is contained in:
anthony cantor 2013-08-18 16:39:26 -06:00 • committed by Siu Kwan Lam
commit 8dbfc377ad
4 changed files with 50 additions and 18 deletions

View file

@ -5,7 +5,7 @@ if llvm.version < (3, 4):
from io import BytesIO from io import BytesIO
import contextlib import contextlib
from llvmpy import api from llvmpy import api, extra
from llvmpy.api.llvm import MCDisassembler from llvmpy.api.llvm import MCDisassembler
class Operand(object): class Operand(object):
@ -22,7 +22,7 @@ class Operand(object):
self.tm = target_machine self.tm = target_machine
def __repr__(self): def __str__(self):
s = "invalid" s = "invalid"
if self.op.isReg(): if self.op.isReg():
s = "reg(%s)" % (self.reg_name()) s = "reg(%s)" % (self.reg_name())
@ -37,6 +37,9 @@ class Operand(object):
return s return s
def __repr__(self):
return str(self)
def reg_name(self): def reg_name(self):
if self.op.isReg(): if self.op.isReg():
s = self.tm.reg_info.getName(self.op.getReg()) s = self.tm.reg_info.getName(self.op.getReg())
@ -61,10 +64,16 @@ class Instr(object):
self.tm = target_machine self.tm = target_machine
def __str__(self):
os = extra.make_raw_ostream_for_printing()
self.tm.inst_printer.printInst(self.mcinst, os, "")
return str(os.str())
def __repr__(self): def __repr__(self):
return repr(self.mcinst) return str(self)
def __len__(self): def __len__(self):
''' the number of operands '''
return int(self.mcinst.size()) return int(self.mcinst.size())
def operands(self): def operands(self):
@ -100,28 +109,29 @@ class Disassembler(object):
def bad_instr(self, mcinst): def bad_instr(self, mcinst):
return BadInstr(mcinst, self.tm) return BadInstr(mcinst, self.tm)
def decode(self, bs, addr): def decode(self, bs, base_addr):
''' '''
decodes some the bytes in @bs into instructions and yields decodes some the bytes in @bs into instructions and yields
each instructionas it is decoded. @addr is the base address each instructionas it is decoded. @base_addr is the base address
where the instruction bytes are from (not an offset into where the instruction bytes are from (not an offset into
@bs) @bs)
''' '''
code = api.llvm.StringRefMemoryObject.new(bs, addr) code = api.llvm.StringRefMemoryObject.new(bs, base_addr)
idx = code.getBase() idx = 0
align = self.mai.getMinInstAlignment() 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.mdasm.getInstruction(inst, code, idx) addr = code.getBase() + idx
status, size = self.mdasm.getInstruction(inst, code, addr)
if status == MCDisassembler.DecodeStatus.Fail: if status == MCDisassembler.DecodeStatus.Fail:
yield (idx, None) yield (addr, None)
elif status == MCDisassembler.DecodeStatus.SoftFail: elif status == MCDisassembler.DecodeStatus.SoftFail:
yield (idx, self.bad_instr(inst)) yield (addr, self.bad_instr(inst))
else: else:
yield (idx, self.instr(inst)) yield (addr, self.instr(inst))
if size < 1: if size < 1:
idx += (align - (idx % align)) idx += (align - (idx % align))

View file

@ -225,6 +225,19 @@ class TargetMachine(llvm.Wrapper):
return self._dasm return self._dasm
@property
def inst_printer(self):
if not getattr(self, '_mip', False):
self._mip = self.target.createMCInstPrinter(
self.asm_info.getAssemblerDialect(),
self.asm_info,
self.instr_info,
self.reg_info,
self.subtarget_info
)
return self._mip
def is_little_endian(self): def is_little_endian(self):
return self.asm_info.isLittleEndian() return self.asm_info.isLittleEndian()

View file

@ -2,6 +2,7 @@ from binding import *
from ..namespace import llvm from ..namespace import llvm
from ..Support.StringRefMemoryObject import MemoryObject from ..Support.StringRefMemoryObject import MemoryObject
from ..Support.raw_ostream import raw_ostream from ..Support.raw_ostream import raw_ostream
from src.ADT.StringRef import StringRef
MCSubtargetInfo = llvm.Class() MCSubtargetInfo = llvm.Class()
MCDisassembler = llvm.Class() MCDisassembler = llvm.Class()
@ -90,6 +91,12 @@ class MCInstrAnalysis:
class MCInstPrinter: class MCInstPrinter:
_include_ = "llvm/MC/MCInstPrinter.h" _include_ = "llvm/MC/MCInstPrinter.h"
printInst = Method(Void,
const(ptr(MCInst)), #MI
ref(raw_ostream), #OS
cast(str, StringRef) #Annot
)
@MCDisassembler @MCDisassembler
class MCDisassembler: class MCDisassembler:
_include_ = "llvm/MC/MCDisassembler.h" _include_ = "llvm/MC/MCDisassembler.h"

View file

@ -9,17 +9,19 @@ if llvm.version >= (3, 4):
llvm.target.initialize_all() llvm.target.initialize_all()
def print_instructions(dasm, bs): def print_instructions(dasm, bs):
for (offset, inst) in dasm.decode(bs, 0): print("print instructions")
for (addr, inst) in dasm.decode(bs, 0x4000):
if inst is None: if inst is None:
print("\t%r=>(bad): 0, []" % (offset)) print("\t0x%x => (bad)" % (addr))
else: else:
ops = ", ".join(map(lambda op: repr(op), inst.operands()))
if isinstance(inst, mc.BadInstr): if isinstance(inst, mc.BadInstr):
print("\t%r=>(bad)%r: %r" % (offset, inst, len(inst))) print("\t0x%x (bad) ops = %s" % (addr, ops))
else: else:
print("\t%r=>%r: %r" % (offset, inst, len(inst))) print("\t0x%x ops = %s" % (addr, ops))
for op in inst.operands(): for line in str(inst).split("\n"):
print("\t\t%s" % repr(op)) print("\t%s" % (line))
x86 = TargetMachine.x86() x86 = TargetMachine.x86()