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
import contextlib
from llvmpy import api
from llvmpy import api, extra
from llvmpy.api.llvm import MCDisassembler
class Operand(object):
@ -22,7 +22,7 @@ class Operand(object):
self.tm = target_machine
def __repr__(self):
def __str__(self):
s = "invalid"
if self.op.isReg():
s = "reg(%s)" % (self.reg_name())
@ -37,6 +37,9 @@ class Operand(object):
return s
def __repr__(self):
return str(self)
def reg_name(self):
if self.op.isReg():
s = self.tm.reg_info.getName(self.op.getReg())
@ -61,10 +64,16 @@ class Instr(object):
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):
return repr(self.mcinst)
return str(self)
def __len__(self):
''' the number of operands '''
return int(self.mcinst.size())
def operands(self):
@ -100,28 +109,29 @@ class Disassembler(object):
def bad_instr(self, mcinst):
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
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
@bs)
'''
code = api.llvm.StringRefMemoryObject.new(bs, addr)
idx = code.getBase()
code = api.llvm.StringRefMemoryObject.new(bs, base_addr)
idx = 0
align = self.mai.getMinInstAlignment()
while(idx < code.getExtent()):
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:
yield (idx, None)
yield (addr, None)
elif status == MCDisassembler.DecodeStatus.SoftFail:
yield (idx, self.bad_instr(inst))
yield (addr, self.bad_instr(inst))
else:
yield (idx, self.instr(inst))
yield (addr, self.instr(inst))
if size < 1:
idx += (align - (idx % align))

View file

@ -225,6 +225,19 @@ class TargetMachine(llvm.Wrapper):
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):
return self.asm_info.isLittleEndian()

View file

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

View file

@ -9,17 +9,19 @@ if llvm.version >= (3, 4):
llvm.target.initialize_all()
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:
print("\t%r=>(bad): 0, []" % (offset))
print("\t0x%x => (bad)" % (addr))
else:
ops = ", ".join(map(lambda op: repr(op), inst.operands()))
if isinstance(inst, mc.BadInstr):
print("\t%r=>(bad)%r: %r" % (offset, inst, len(inst)))
print("\t0x%x (bad) ops = %s" % (addr, ops))
else:
print("\t%r=>%r: %r" % (offset, inst, len(inst)))
for op in inst.operands():
print("\t\t%s" % repr(op))
print("\t0x%x ops = %s" % (addr, ops))
for line in str(inst).split("\n"):
print("\t%s" % (line))
x86 = TargetMachine.x86()