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:
parent
82d9c787f3
commit
8dbfc377ad
4 changed files with 50 additions and 18 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue