implemented binding for MCDisassembler.getInstruction
also added new llvm.mc module to act as higher level python access to the MC section of LLVM (added Instr and Disassembler classes).
This commit is contained in:
parent
ba03b226c8
commit
818c9289fc
5 changed files with 176 additions and 13 deletions
|
|
@ -3,24 +3,112 @@ import contextlib
|
|||
|
||||
import llvm
|
||||
from llvmpy import api
|
||||
from llvmpy.api.llvm import MCDisassembler
|
||||
|
||||
class Disassembler(llvm.Wrapper):
|
||||
class Instr:
|
||||
def __init__(self, mcinst):
|
||||
self.mcinst = mcinst
|
||||
if not self.mcinst:
|
||||
raise llvm.LLVMException("null MCInst argument")
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.mcinst)
|
||||
|
||||
def __len__(self):
|
||||
return int(self.mcinst.size())
|
||||
|
||||
def operands(self):
|
||||
amt = self.mcinst.getNumOperands()
|
||||
if amt < 1:
|
||||
return []
|
||||
|
||||
l = []
|
||||
for i in range(0, amt):
|
||||
l.append(self.mcinst.getOperand(i))
|
||||
|
||||
return l
|
||||
|
||||
class BadInstr(Instr):
|
||||
pass
|
||||
|
||||
class Disassembler:
|
||||
|
||||
def __init__(self, mcdisasm):
|
||||
self.mcdisasm = mcdisasm
|
||||
if not self.mcdisasm:
|
||||
raise llvm.LLVMException("null MCDisassembler argument")
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.mcdisasm)
|
||||
|
||||
@staticmethod
|
||||
def new(triple='', cpu='', features=''):
|
||||
def new_from_target(target, subtargetinfo):
|
||||
return Disassembler(target.createMCDisassembler(subtargetinfo))
|
||||
|
||||
@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)
|
||||
raise llvm.LLVMException(error.read())
|
||||
if not target.hasMCDisassembler():
|
||||
raise llvm.LLVMException(target, "No disassembler provided for %s." % triple)
|
||||
|
||||
sti = target.createMCSubtargetInfo(triple, cpu, features)
|
||||
if not sti:
|
||||
raise llvm.LLVMException("Could not create sub target info")
|
||||
sti = target.createMCSubtargetInfo(triple, cpu, features)
|
||||
if not sti:
|
||||
raise llvm.LLVMException("Could not create sub target info")
|
||||
|
||||
return target.createMCDisassembler(sti)
|
||||
return Disassembler.new_from_target(target)
|
||||
|
||||
@staticmethod
|
||||
def new_from_name(name):
|
||||
name = name.strip()
|
||||
for target in api.llvm.TargetRegistry.targetsList():
|
||||
if name == target.getName():
|
||||
sti = target.createMCSubtargetInfo(name, '', '')
|
||||
return Disassembler.new_from_target(target, sti)
|
||||
|
||||
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
|
||||
#as it is decoded.
|
||||
def decode(self, bs):
|
||||
code = api.llvm.BytesMemoryObject.new(bs)
|
||||
idx = code.getBase()
|
||||
|
||||
while(idx < code.getExtent()):
|
||||
inst = api.llvm.MCInst.new()
|
||||
status, size = self.mcdisasm.getInstruction(inst, code, idx)
|
||||
|
||||
if status == MCDisassembler.DecodeStatus.Fail:
|
||||
yield (idx, None)
|
||||
elif status == MCDisassembler.DecodeStatus.SoftFail:
|
||||
yield (idx, BadInstr(inst))
|
||||
else:
|
||||
yield (idx, Instr(inst))
|
||||
|
||||
if size <= 1:
|
||||
idx += 1
|
||||
else:
|
||||
idx += size
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#include <llvm/PassRegistry.h>
|
||||
#include <llvm/Support/Host.h>
|
||||
#include <llvm/Support/MemoryObject.h>
|
||||
|
||||
#include <llvm/MC/MCDisassembler.h>
|
||||
#include <llvm/ExecutionEngine/MCJIT.h> // to make MCJIT working
|
||||
|
||||
#include "auto_pyobject.h"
|
||||
|
|
@ -976,6 +976,22 @@ PyObject* TargetRegistry_targets_list()
|
|||
"llvm::Target", "llvm::Target");
|
||||
}
|
||||
|
||||
static
|
||||
PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm,
|
||||
llvm::MCInst &instr,
|
||||
const llvm::MemoryObject ®ion,
|
||||
uint64_t address
|
||||
)
|
||||
{
|
||||
uint64_t size;
|
||||
llvm::MCDisassembler::DecodeStatus status;
|
||||
|
||||
size = 0;
|
||||
status = disasm->getInstruction(instr, size, region, address,
|
||||
llvm::nulls(), llvm::nulls());
|
||||
return Py_BuildValue("(i,i)", int(status), size);
|
||||
}
|
||||
|
||||
static
|
||||
PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,14 +1,42 @@
|
|||
from binding import *
|
||||
from ..namespace import llvm
|
||||
from ..BytesMemoryObject import MemoryObject
|
||||
from ..Support.raw_ostream import raw_ostream
|
||||
|
||||
MCSubtargetInfo = llvm.Class()
|
||||
MCDisassembler = llvm.Class()
|
||||
MCInst = llvm.Class()
|
||||
MCOperand = llvm.Class()
|
||||
|
||||
@MCSubtargetInfo
|
||||
class MCSubtargetInfo:
|
||||
pass
|
||||
|
||||
@MCOperand
|
||||
class MCOperand:
|
||||
pass
|
||||
|
||||
@MCInst
|
||||
class MCInst:
|
||||
_include_ = "llvm/MC/MCInst.h"
|
||||
new = Constructor()
|
||||
|
||||
size = Method(cast(Size_t, int))
|
||||
getNumOperands = Method(cast(Unsigned, int))
|
||||
|
||||
getOperand = Method(const(ref(MCOperand)), cast(int, Unsigned))
|
||||
|
||||
@MCDisassembler
|
||||
class MCDisassembler:
|
||||
pass
|
||||
_include_ = "llvm/MC/MCDisassembler.h"
|
||||
|
||||
DecodeStatus = Enum('Fail', 'SoftFail', 'Success')
|
||||
|
||||
getInstruction = CustomMethod('MCDisassembler_getInstruction',
|
||||
PyObjectPtr,
|
||||
ref(MCInst),
|
||||
ref(MemoryObject),
|
||||
cast(int, Uint64)
|
||||
|
||||
|
||||
)
|
||||
|
|
@ -46,10 +46,10 @@ class Target:
|
|||
).require_only(4)
|
||||
|
||||
createMCSubtargetInfo = Method(ptr(MCSubtargetInfo),
|
||||
cast(str, StringRef), #triple
|
||||
cast(str, StringRef), #cpu
|
||||
cast(str, StringRef) #features
|
||||
)
|
||||
cast(str, StringRef), #triple
|
||||
cast(str, StringRef), #cpu
|
||||
cast(str, StringRef) #features
|
||||
)
|
||||
|
||||
createMCDisassembler = Method(ptr(MCDisassembler), ref(MCSubtargetInfo))
|
||||
|
||||
|
|
|
|||
31
test/example-disassemble.py
Normal file
31
test/example-disassemble.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import llvm
|
||||
|
||||
from llvm import mc
|
||||
from llvm.mc import Disassembler
|
||||
from llvmpy import api
|
||||
|
||||
llvm.initialize_all_target_components()
|
||||
|
||||
|
||||
def print_instructions(dasm, bs):
|
||||
for (offset, inst) in dasm.decode(bs):
|
||||
if inst is None:
|
||||
print("\t%r=>(bad): 0, []" % (offset))
|
||||
elif isinstance(inst, mc.BadInstr):
|
||||
print("\t%r=>(bad)%r: %r, %r" % (offset, inst, len(inst), inst.operands()))
|
||||
else:
|
||||
print("\t%r=>%r: %r, %r" % (offset, inst, len(inst), inst.operands()))
|
||||
|
||||
|
||||
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:")
|
||||
#code = "\xe9\x2d\x40\x08\xe5\x9f\x00\x0c\xe5\x9f\x10\x0c" + \
|
||||
# "\xe5\x9f\x20\x0c\xe5\x9f\x30\x0c\xeb\xff\xff\xf6"
|
||||
#print_instructions(Disassembler.arm(), code)
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue