From 43f7330fda58d0b5880520998629b3b8ad89baff Mon Sep 17 00:00:00 2001 From: anthony cantor Date: Mon, 2 Sep 2013 23:55:51 -0600 Subject: [PATCH] llvm.mc.Disassembler.decode now yields the byte sequence which generated the instruction added custom method to extra.h to return a PyBytes object from the bytes read from MemoryObject.readBytes. also moved the generic methods from StringRefMemoryObject up to MemoryObject --- llvm/mc/__init__.py | 38 ++++++++++++++------- llvmpy/include/llvm_binding/extra.h | 31 +++++++++++++++++ llvmpy/src/Support/StringRefMemoryObject.py | 21 +++++++++--- test/example-disassemble.py | 5 +-- test/testall.py | 2 +- 5 files changed, 78 insertions(+), 19 deletions(-) diff --git a/llvm/mc/__init__.py b/llvm/mc/__init__.py index 63e8d65..f165d5d 100644 --- a/llvm/mc/__init__.py +++ b/llvm/mc/__init__.py @@ -126,9 +126,11 @@ class Disassembler(object): def decode(self, bs, base_addr): ''' decodes some the bytes in @bs into instructions and yields - each instructionas it is decoded. @base_addr is the base address + each instruction as it is decoded. @base_addr is the base address where the instruction bytes are from (not an offset into - @bs) + @bs). yields instructions in the form of (addr, data, inst) where + addr is an integer, data is a bytearray and inst is an instance of + llvm.mc.Instr ''' if not isinstance(bs, bytes): @@ -146,15 +148,27 @@ class Disassembler(object): addr = code.getBase() + idx status, size = self.mdasm.getInstruction(inst, code, addr) - if status == MCDisassembler.DecodeStatus.Fail: - yield (addr, None) - elif status == MCDisassembler.DecodeStatus.SoftFail: - yield (addr, self.bad_instr(inst)) - else: - yield (addr, self.instr(inst)) - if size < 1: - idx += (align - (idx % align)) - else: - idx += size + size = (align - (idx % align)) + amt_left = code.getExtent() - idx + if amt_left >= size: + data = code.readBytes(addr, size) + elif amt_left < 1: + break + else: + data = code.readBytes(addr, amt_left) + + if sys.version_info.major < 3: + data = bytearray(map(lambda b: ord(b), data)) + else: + data = bytearray(data) + + if status == MCDisassembler.DecodeStatus.Fail: + yield (addr, data, None) + elif status == MCDisassembler.DecodeStatus.SoftFail: + yield (addr, data, self.bad_instr(inst)) + else: + yield (addr, data, self.instr(inst)) + + idx += size diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index a6ad89b..b2b6f11 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -955,6 +955,36 @@ PyObject* TargetRegistry_targets_list() "llvm::Target", "llvm::Target"); } +static +PyObject* MemoryObject_readBytes(const llvm::MemoryObject *mobj, + uint64_t addr, + uint64_t size + ) +{ + int status; + uint8_t *bytes; + PyObject* po; + + if(size < 1) + goto fail; + + bytes = new uint8_t[size]; + if(bytes == NULL) + goto fail; + + status = mobj->readBytes(addr, size, bytes); + if(status != 0) { + delete bytes; + goto fail; + } + + po = PyBytes_FromStringAndSize((const char *) bytes, size); + delete bytes; + + return po; +fail: + Py_RETURN_NONE; +} #if LLVM_VERSION_MAJOR >= 3 and LLVM_VERSION_MINOR >= 4 static @@ -972,6 +1002,7 @@ PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm, llvm::nulls(), llvm::nulls()); return Py_BuildValue("(i,i)", int(status), size); } + #endif /* llvm >= 3.4 */ static diff --git a/llvmpy/src/Support/StringRefMemoryObject.py b/llvmpy/src/Support/StringRefMemoryObject.py index 583ef5f..fa3883d 100644 --- a/llvmpy/src/Support/StringRefMemoryObject.py +++ b/llvmpy/src/Support/StringRefMemoryObject.py @@ -8,7 +8,23 @@ if LLVM_VERSION >= (3, 4): @MemoryObject class MemoryObject: - pass + _include_ = "llvm/Support/MemoryObject.h" + + getBase = Method(cast(Uint64, int)) + getExtent = Method(cast(Uint64, int)) + + readBytes = CustomMethod('MemoryObject_readBytes', + PyObjectPtr, + cast(int, Uint64), #address + cast(int, Uint64) #size + ) + @CustomPythonMethod + def readAll(self): + result = self.readBytes(self.getBase(), self.getExtent()) + if not result: + raise Exception("expected readBytes to be successful!") + return result + if LLVM_VERSION >= (3, 4): @StringRefMemoryObject @@ -16,6 +32,3 @@ if LLVM_VERSION >= (3, 4): _include_ = "llvm/Support/StringRefMemoryObject.h" new = Constructor(cast(bytes, StringRef), cast(int, Uint64)) - - getBase = Method(cast(Uint64, int)) - getExtent = Method(cast(Uint64, int)) diff --git a/test/example-disassemble.py b/test/example-disassemble.py index 0958842..862036f 100644 --- a/test/example-disassemble.py +++ b/test/example-disassemble.py @@ -10,7 +10,8 @@ if llvm.version >= (3, 4): def print_instructions(dasm, bs): print("print instructions") - for (addr, inst) in dasm.decode(bs, 0x4000): + for (addr, data, inst) in dasm.decode(bs, 0x4000): + if inst is None: print("\t0x%x => (bad)" % (addr)) else: @@ -22,7 +23,7 @@ if llvm.version >= (3, 4): print("\t\tflags = 0x%x, tsflags = 0x%x" % (inst.flags, inst.ts_flags)) for line in str(inst).split("\n"): - print("\t%s" % (line)) + print("\t\t%-24s %s" % ("".join(map(lambda b: "%02x" % b, data))+":", line.strip())) x86 = TargetMachine.x86() diff --git a/test/testall.py b/test/testall.py index 25d319c..7710391 100644 --- a/test/testall.py +++ b/test/testall.py @@ -659,7 +659,7 @@ def do_llvm_mc(): tm = TargetMachine.x86() dasm = mc.Disassembler(tm) - for (offset, instr) in dasm.decode("c3", 0): + for (offset, data, instr) in dasm.decode("c3", 0): pass def main():