I have added a function to SBTarget that allows

clients to disassemble a series of raw bytes as
demonstrated by a new testcase.

In the future, this API will also allow clients
to provide a callback that adds comments for
addresses in the disassembly.

I also modified the SWIG harness to ensure that
Python ByteArrays work as well as strings as
sources of raw data.

llvm-svn: 146611
This commit is contained in:
Sean Callanan 2011-12-14 23:49:37 +00:00
parent 75d7d5e988
commit 50952e9571
8 changed files with 149 additions and 16 deletions

View File

@ -58,6 +58,7 @@ public:
protected:
friend class SBFunction;
friend class SBSymbol;
friend class SBTarget;
void
SetDisassembler (const lldb::DisassemblerSP &opaque_sp);

View File

@ -494,6 +494,12 @@ public:
SBSourceManager
GetSourceManager();
lldb::SBInstructionList
GetInstructions (lldb::SBAddress base_addr, const void *buf, size_t size);
lldb::SBInstructionList
GetInstructions (lldb::addr_t base_addr, const void *buf, size_t size);
#ifndef SWIG
bool

View File

@ -261,6 +261,13 @@ public:
const char *plugin_name,
const ExecutionContext &exe_ctx,
const AddressRange &disasm_range);
static lldb::DisassemblerSP
DisassembleBytes (const ArchSpec &arch,
const char *plugin_name,
const Address &start,
const void *bytes,
size_t length);
static bool
Disassemble (Debugger &debugger,

View File

@ -470,7 +470,10 @@ public:
lldb::SBBroadcaster
GetBroadcaster () const;
lldb::SBInstructionList
GetInstructions (lldb::SBAddress base_addr, const void *buf, size_t size);
bool
GetDescription (lldb::SBStream &description, lldb::DescriptionLevel description_level);
};

View File

@ -69,30 +69,48 @@
// typemap for an outgoing buffer
// See also SBEvent::SBEvent(uint32_t event, const char *cstr, uint32_t cstr_len).
%typemap(in) (const char *cstr, uint32_t cstr_len) {
if (!PyString_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expecting a string");
return NULL;
if (PyString_Check($input)) {
$1 = (char *) PyString_AsString($input);
$2 = PyString_Size($input);
}
else if(PyByteArray_Check($input)) {
$1 = (char *) PyByteArray_AsString($input);
$2 = PyByteArray_Size($input);
}
else {
PyErr_SetString(PyExc_ValueError, "Expecting a string");
return NULL;
}
$1 = (char *) PyString_AsString($input);
$2 = PyString_Size($input);
}
// Ditto for SBProcess::PutSTDIN(const char *src, size_t src_len).
%typemap(in) (const char *src, size_t src_len) {
if (!PyString_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expecting a string");
return NULL;
if (PyString_Check($input)) {
$1 = (char *) PyString_AsString($input);
$2 = PyString_Size($input);
}
else if(PyByteArray_Check($input)) {
$1 = (char *) PyByteArray_AsString($input);
$2 = PyByteArray_Size($input);
}
else {
PyErr_SetString(PyExc_ValueError, "Expecting a string");
return NULL;
}
$1 = (char *) PyString_AsString($input);
$2 = PyString_Size($input);
}
// And SBProcess::WriteMemory.
%typemap(in) (const void *buf, size_t size) {
if (!PyString_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expecting a string");
return NULL;
if (PyString_Check($input)) {
$1 = (void *) PyString_AsString($input);
$2 = PyString_Size($input);
}
else if(PyByteArray_Check($input)) {
$1 = (void *) PyByteArray_AsString($input);
$2 = PyByteArray_Size($input);
}
else {
PyErr_SetString(PyExc_ValueError, "Expecting a string");
return NULL;
}
$1 = (void *) PyString_AsString($input);
$2 = PyString_Size($input);
}
// typemap for an incoming buffer

View File

@ -1285,6 +1285,33 @@ SBTarget::GetSourceManager()
return source_manager;
}
lldb::SBInstructionList
SBTarget::GetInstructions (lldb::SBAddress base_addr, const void *buf, size_t size)
{
SBInstructionList sb_instructions;
if (m_opaque_sp)
{
Address addr;
if (base_addr.get())
addr = *base_addr.get();
sb_instructions.SetDisassembler (Disassembler::DisassembleBytes (m_opaque_sp->GetArchitecture(),
NULL,
addr,
buf,
size));
}
return sb_instructions;
}
lldb::SBInstructionList
SBTarget::GetInstructions (lldb::addr_t base_addr, const void *buf, size_t size)
{
return GetInstructions (ResolveLoadAddress(base_addr), buf, size);
}
SBError
SBTarget::SetSectionLoadAddress (lldb::SBSection section,

View File

@ -230,6 +230,37 @@ Disassembler::DisassembleRange
return disasm_sp;
}
lldb::DisassemblerSP
Disassembler::DisassembleBytes
(
const ArchSpec &arch,
const char *plugin_name,
const Address &start,
const void *bytes,
size_t length
)
{
lldb::DisassemblerSP disasm_sp;
if (bytes)
{
disasm_sp.reset(Disassembler::FindPlugin(arch, plugin_name));
if (disasm_sp)
{
DataExtractor data(bytes, length, arch.GetByteOrder(), arch.GetAddressByteSize());
(void)disasm_sp->DecodeInstructions (start,
data,
0,
UINT32_MAX,
false);
}
}
return disasm_sp;
}
bool
Disassembler::Disassemble

View File

@ -0,0 +1,40 @@
"""
Use lldb Python API to disassemble raw machine code bytes
"""
import os, time
import re
import unittest2
import lldb, lldbutil
from lldbtest import *
class DisassembleRawDataTestCase(TestBase):
mydir = os.path.join("api", "disassemble-raw-data")
@python_api_test
def test_disassemble_raw_data(self):
"""Test disassembling raw bytes with the API."""
self.disassemble_raw_data()
def disassemble_raw_data(self):
"""Test disassembling raw bytes with the API."""
# Create a target from the debugger.
target = self.dbg.CreateTargetWithFileAndTargetTriple ("", "x86_64-apple-darwin")
self.assertTrue(target, VALID_TARGET)
raw_bytes = bytearray([0x48, 0x89, 0xe5])
insts = target.GetInstructions(lldb.SBAddress(), raw_bytes)
inst = insts.GetInstructionAtIndex(0)
self.assertTrue (inst.GetMnemonic(target) == "movq")
self.assertTrue (inst.GetOperands(target) == '%' + "rsp, " + '%' + "rbp")
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()