Added functions to the C++ API, for the benefit of non-8-bit byte architectures.

New functions to give client applications to tools to discover target byte sizes
for addresses prior to ReadMemory. Also added GetPlatform and ReadMemory to the
SBTarget class, since they seemed to be useful utilities to have.

Each new API has had a test case added.

http://reviews.llvm.org/D5867

llvm-svn: 220372
This commit is contained in:
Matthew Gardiner 2014-10-22 07:22:56 +00:00
parent 0cf39569bf
commit c928de3e8e
14 changed files with 615 additions and 0 deletions

View File

@ -71,6 +71,18 @@ public:
SectionType
GetSectionType ();
//------------------------------------------------------------------
/// Return the size of a target's byte represented by this section
/// in numbers of host bytes. Note that certain architectures have
/// varying minimum addressable unit (i.e. byte) size for their
/// CODE or DATA buses.
///
/// @return
/// The number of host (8-bit) bytes needed to hold a target byte
//------------------------------------------------------------------
uint32_t
GetTargetByteSize ();
bool
operator == (const lldb::SBSection &rhs);

View File

@ -22,6 +22,8 @@
namespace lldb {
class SBPlatform;
class SBLaunchInfo
{
public:
@ -308,6 +310,18 @@ public:
lldb::SBProcess
GetProcess ();
//------------------------------------------------------------------
/// Return the platform object associated with the target.
///
/// After return, the platform object should be checked for
/// validity.
///
/// @return
/// A platform object.
//------------------------------------------------------------------
lldb::SBPlatform
GetPlatform ();
//------------------------------------------------------------------
/// Install any binaries that need to be installed.
///
@ -563,6 +577,26 @@ public:
const char *
GetTriple ();
//------------------------------------------------------------------
/// Architecture data byte width accessor
///
/// @return
/// The size in 8-bit (host) bytes of a minimum addressable
/// unit from the Architecture's data bus
//------------------------------------------------------------------
uint32_t
GetDataByteSize ();
//------------------------------------------------------------------
/// Architecture code byte width accessor
///
/// @return
/// The size in 8-bit (host) bytes of a minimum addressable
/// unit from the Architecture's code bus
//------------------------------------------------------------------
uint32_t
GetCodeByteSize ();
//------------------------------------------------------------------
/// Set the base load address for a module section.
///
@ -727,6 +761,17 @@ public:
void
Clear ();
//------------------------------------------------------------------
/// Resolve a current file address into a section offset address.
///
/// @param[in] file_addr
///
/// @return
/// An SBAddress which will be valid if...
//------------------------------------------------------------------
lldb::SBAddress
ResolveFileAddress (lldb::addr_t file_addr);
//------------------------------------------------------------------
/// Resolve a current load address into a section offset address.
///
@ -772,6 +817,31 @@ public:
ResolveSymbolContextForAddress (const SBAddress& addr,
uint32_t resolve_scope);
//------------------------------------------------------------------
/// Read target memory. If a target process is running then memory
/// is read from here. Otherwise the memory is read from the object
/// files. For a target whose bytes are sized as a multiple of host
/// bytes, the data read back will preserve the target's byte order.
///
/// @param[in] addr
/// A target address to read from.
///
/// @param[out] buf
/// The buffer to read memory into.
///
/// @param[in] size
/// The maximum number of host bytes to read in the buffer passed
/// into this call
///
/// @param[out] error
/// Error information is written here if the memory read fails.
///
/// @return
/// The amount of data read in host bytes.
//------------------------------------------------------------------
size_t
ReadMemory (const SBAddress addr, void *buf, size_t size, lldb::SBError &error);
lldb::SBBreakpoint
BreakpointCreateByLocation (const char *file, uint32_t line);

View File

@ -1133,6 +1133,9 @@ public:
Error
Install(ProcessLaunchInfo *launch_info);
bool
ResolveFileAddress (lldb::addr_t load_addr,
Address &so_addr);
bool
ResolveLoadAddress (lldb::addr_t load_addr,

View File

@ -90,6 +90,20 @@ public:
SectionType
GetSectionType ();
%feature("docstring", "
//------------------------------------------------------------------
/// Return the size of a target's byte represented by this section
/// in numbers of host bytes. Note that certain architectures have
/// varying minimum addressable unit (i.e. byte) size for their
/// CODE or DATA buses.
///
/// @return
/// The number of host (8-bit) bytes needed to hold a target byte
//------------------------------------------------------------------
") GetTargetByteSize;
uint32_t
GetTargetByteSize ();
bool
GetDescription (lldb::SBStream &description);
@ -127,6 +141,9 @@ public:
__swig_getmethods__["type"] = GetSectionType
if _newclass: type = property(GetSectionType, None, doc='''A read only property that returns an lldb enumeration value (see enumerations that start with "lldb.eSectionType") that represents the type of this section (code, data, etc.).''')
__swig_getmethods__["target_byte_size"] = GetTargetByteSize
if _newclass: target_byte_size = property(GetTargetByteSize, None, doc='''A read only property that returns the size of a target byte represented by this section as a number of host bytes.''')
%}
private:

View File

@ -282,6 +282,21 @@ public:
lldb::SBProcess
GetProcess ();
%feature("docstring", "
//------------------------------------------------------------------
/// Return the platform object associated with the target.
///
/// After return, the platform object should be checked for
/// validity.
///
/// @return
/// A platform object.
//------------------------------------------------------------------
") GetPlatform;
lldb::SBPlatform
GetPlatform ();
%feature("docstring", "
//------------------------------------------------------------------
/// Install any binaries that need to be installed.
@ -579,6 +594,30 @@ public:
const char *
GetTriple ();
%feature("docstring", "
//------------------------------------------------------------------
/// Architecture data byte width accessor
///
/// @return
/// The size in 8-bit (host) bytes of a minimum addressable
/// unit from the Architecture's data bus
//------------------------------------------------------------------
") GetDataByteSize;
uint32_t
GetDataByteSize ();
%feature("docstring", "
//------------------------------------------------------------------
/// Architecture code byte width accessor
///
/// @return
/// The size in 8-bit (host) bytes of a minimum addressable
/// unit from the Architecture's code bus
//------------------------------------------------------------------
") GetCodeByteSize;
uint32_t
GetCodeByteSize ();
lldb::SBError
SetSectionLoadAddress (lldb::SBSection section,
lldb::addr_t section_base_addr);
@ -676,6 +715,19 @@ public:
void
Clear ();
%feature("docstring", "
//------------------------------------------------------------------
/// Resolve a current file address into a section offset address.
///
/// @param[in] file_addr
///
/// @return
/// An SBAddress which will be valid if...
//------------------------------------------------------------------
") ResolveFileAddress;
lldb::SBAddress
ResolveFileAddress (lldb::addr_t file_addr);
lldb::SBAddress
ResolveLoadAddress (lldb::addr_t vm_addr);
@ -686,6 +738,33 @@ public:
ResolveSymbolContextForAddress (const SBAddress& addr,
uint32_t resolve_scope);
%feature("docstring", "
//------------------------------------------------------------------
/// Read target memory. If a target process is running then memory
/// is read from here. Otherwise the memory is read from the object
/// files. For a target whose bytes are sized as a multiple of host
/// bytes, the data read back will preserve the target's byte order.
///
/// @param[in] addr
/// A target address to read from.
///
/// @param[out] buf
/// The buffer to read memory into.
///
/// @param[in] size
/// The maximum number of host bytes to read in the buffer passed
/// into this call
///
/// @param[out] error
/// Error information is written here if the memory read fails.
///
/// @return
/// The amount of data read in host bytes.
//------------------------------------------------------------------
") ReadMemory;
size_t
ReadMemory (const SBAddress addr, void *buf, size_t size, lldb::SBError &error);
lldb::SBBreakpoint
BreakpointCreateByLocation (const char *file, uint32_t line);
@ -904,6 +983,15 @@ public:
__swig_getmethods__["triple"] = GetTriple
if _newclass: triple = property(GetTriple, None, doc='''A read only property that returns the target triple (arch-vendor-os) for this target as a string.''')
__swig_getmethods__["data_byte_size"] = GetDataByteSize
if _newclass: addr_size = property(GetDataByteSize, None, doc='''A read only property that returns the size in host bytes of a byte in the data address space for this target.''')
__swig_getmethods__["code_byte_size"] = GetCodeByteSize
if _newclass: addr_size = property(GetCodeByteSize, None, doc='''A read only property that returns the size in host bytes of a byte in the code address space for this target.''')
__swig_getmethods__["platform"] = GetPlatform
if _newclass: platform = property(GetPlatform, None, doc='''A read only property that returns the platform associated with with this target.''')
%}
};

View File

@ -250,6 +250,14 @@ SBSection::GetSectionType ()
return eSectionTypeInvalid;
}
uint32_t
SBSection::GetTargetByteSize ()
{
SectionSP section_sp (GetSP());
if (section_sp.get())
return section_sp->GetTargetByteSize();
return 0;
}
bool
SBSection::operator == (const SBSection &rhs)

View File

@ -587,6 +587,19 @@ SBTarget::GetProcess ()
return sb_process;
}
SBPlatform
SBTarget::GetPlatform ()
{
TargetSP target_sp(GetSP());
if (!target_sp)
return SBPlatform();
SBPlatform platform;
platform.m_opaque_sp = target_sp->GetPlatform();
return platform;
}
SBDebugger
SBTarget::GetDebugger () const
{
@ -1231,6 +1244,22 @@ SBTarget::ResolveLoadAddress (lldb::addr_t vm_addr)
return sb_addr;
}
lldb::SBAddress
SBTarget::ResolveFileAddress (lldb::addr_t file_addr)
{
lldb::SBAddress sb_addr;
Address &addr = sb_addr.ref();
TargetSP target_sp(GetSP());
if (target_sp)
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
if (target_sp->ResolveFileAddress (file_addr, addr))
return sb_addr;
}
addr.SetRawAddress(file_addr);
return sb_addr;
}
lldb::SBAddress
SBTarget::ResolvePastLoadAddress (uint32_t stop_id, lldb::addr_t vm_addr)
@ -1265,6 +1294,29 @@ SBTarget::ResolveSymbolContextForAddress (const SBAddress& addr,
return sc;
}
size_t
SBTarget::ReadMemory (const SBAddress addr,
void *buf,
size_t size,
lldb::SBError &error)
{
SBError sb_error;
size_t bytes_read = 0;
TargetSP target_sp(GetSP());
if (target_sp)
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
lldb_private::Address addr_priv(addr.GetFileAddress(), NULL);
lldb_private::Error err_priv;
bytes_read = target_sp->ReadMemory(addr_priv, false, buf, size, err_priv);
if(err_priv.Fail())
{
sb_error.SetError(err_priv.GetError(), err_priv.GetType());
}
}
return bytes_read;
}
SBBreakpoint
SBTarget::BreakpointCreateByLocation (const char *file,
@ -2060,6 +2112,28 @@ SBTarget::GetTriple ()
return NULL;
}
uint32_t
SBTarget::GetDataByteSize ()
{
TargetSP target_sp(GetSP());
if (target_sp)
{
return target_sp->GetArchitecture().GetDataByteSize() ;
}
return 0;
}
uint32_t
SBTarget::GetCodeByteSize ()
{
TargetSP target_sp(GetSP());
if (target_sp)
{
return target_sp->GetArchitecture().GetCodeByteSize() ;
}
return 0;
}
uint32_t
SBTarget::GetAddressByteSize()
{

View File

@ -2283,6 +2283,12 @@ Target::ResolveLoadAddress (addr_t load_addr, Address &so_addr, uint32_t stop_id
return m_section_load_history.ResolveLoadAddress(stop_id, load_addr, so_addr);
}
bool
Target::ResolveFileAddress (lldb::addr_t file_addr, Address &resolved_addr)
{
return m_images.ResolveFileAddress(file_addr, resolved_addr);
}
bool
Target::SetSectionLoadAddress (const SectionSP &section_sp, addr_t new_section_load_addr, bool warn_multiple)
{

View File

@ -137,6 +137,8 @@ VALID_SYMBOL = "Got a valid symbol"
VALID_TARGET = "Got a valid target"
VALID_PLATFORM = "Got a valid platform"
VALID_TYPE = "Got a valid type"
VALID_VARIABLE = "Got a valid variable"

View File

@ -0,0 +1,10 @@
LEVEL = ../../make
C_SOURCES := main.c
include $(LEVEL)/Makefile.rules
LEVEL = ../../make
C_SOURCES := main.c
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,120 @@
"""
Test SBSection APIs.
"""
import unittest2
from lldbtest import *
class SectionAPITestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
def test_get_target_byte_size_with_dsym(self):
d = {'EXE': 'a.out'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('a.out')
# find the .data section of the main module
data_section = self.find_data_section(target)
self.assertEquals(data_section.target_byte_size, 1)
@python_api_test
@dwarf_test
def test_get_target_byte_size_with_dwarf(self):
d = {'EXE': 'b.out'}
self.buildDwarf(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('b.out')
# find the .data section of the main module
data_section = self.find_data_section(target)
self.assertEquals(data_section.target_byte_size, 1)
def create_simple_target(self, fn):
exe = os.path.join(os.getcwd(), fn)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
return target
def find_data_section(self, target):
mod = target.GetModuleAtIndex(0)
data_section = None
for s in mod.sections:
if ".data" == s.name:
data_section = s
break
self.assertIsNotNone(data_section)
return data_section
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()
"""
Test SBSection APIs.
"""
import unittest2
from lldbtest import *
class SectionAPITestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
def test_get_target_byte_size_with_dsym(self):
d = {'EXE': 'a.out'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('a.out')
# find the .data section of the main module
data_section = self.find_data_section(target)
self.assertEquals(data_section.target_byte_size, 1)
@python_api_test
@dwarf_test
def test_get_target_byte_size_with_dwarf(self):
d = {'EXE': 'b.out'}
self.buildDwarf(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('b.out')
# find the .data section of the main module
data_section = self.find_data_section(target)
self.assertEquals(data_section.target_byte_size, 1)
def create_simple_target(self, fn):
exe = os.path.join(os.getcwd(), fn)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
return target
def find_data_section(self, target):
mod = target.GetModuleAtIndex(0)
data_section = None
for s in mod.sections:
if ".data" == s.name:
data_section = s
break
self.assertIsNotNone(data_section)
return data_section
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View File

@ -0,0 +1,56 @@
//===-- main.c --------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
#include <string.h>
// This simple program is to test the lldb Python API SBSection. It includes
// somes global data, and so the build process produces a DATA section, which
// the test code can use to query for the target byte size
char my_global_var_of_char_type = 'X';
int main (int argc, char const *argv[])
{
// this code just "does something" with the global so that it is not
// optimised away
if (argc > 1 && strlen(argv[1]))
{
my_global_var_of_char_type += argv[1][0];
}
return my_global_var_of_char_type;
}
//===-- main.c --------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
#include <string.h>
// This simple program is to test the lldb Python API SBSection. It includes
// somes global data, and so the build process produces a DATA section, which
// the test code can use to query for the target byte size
char my_global_var_of_char_type = 'X';
int main (int argc, char const *argv[])
{
// this code just "does something" with the global so that it is not
// optimised away
if (argc > 1 && strlen(argv[1]))
{
my_global_var_of_char_type += argv[1][0];
}
return my_global_var_of_char_type;
}

View File

@ -104,12 +104,160 @@ class TargetAPITestCase(TestBase):
self.buildDwarf()
self.resolve_symbol_context_with_address()
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
def test_get_platform_with_dsym(self):
d = {'EXE': 'a.out'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('a.out')
platform = target.platform
self.assertTrue(platform, VALID_PLATFORM)
@python_api_test
@dwarf_test
def test_get_platform_with_dwarf(self):
d = {'EXE': 'b.out'}
self.buildDwarf(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('b.out')
platform = target.platform
self.assertTrue(platform, VALID_PLATFORM)
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
def test_get_data_byte_size_with_dsym(self):
d = {'EXE': 'a.out'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('a.out')
self.assertEquals(target.data_byte_size, 1)
@python_api_test
@dwarf_test
def test_get_data_byte_size_with_dwarf(self):
d = {'EXE': 'b.out'}
self.buildDwarf(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('b.out')
self.assertEquals(target.data_byte_size, 1)
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
def test_get_code_byte_size_with_dsym(self):
d = {'EXE': 'a.out'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('a.out')
self.assertEquals(target.code_byte_size, 1)
@python_api_test
@dwarf_test
def test_get_code_byte_size_with_dwarf(self):
d = {'EXE': 'b.out'}
self.buildDwarf(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('b.out')
self.assertEquals(target.code_byte_size, 1)
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
def test_resolve_file_address_with_dsym(self):
d = {'EXE': 'a.out'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('a.out')
self.resolve_file_address(target)
@python_api_test
@dwarf_test
def test_resolve_file_address_with_dwarf(self):
d = {'EXE': 'b.out'}
self.buildDwarf(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('b.out')
self.resolve_file_address(target)
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
def test_read_memory_with_dsym(self):
d = {'EXE': 'a.out'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('a.out')
self.read_memory(target)
@python_api_test
@dwarf_test
def test_read_memory_with_dwarf(self):
d = {'EXE': 'b.out'}
self.buildDwarf(dictionary=d)
self.setTearDownCleanup(dictionary=d)
target = self.create_simple_target('b.out')
self.read_memory(target)
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to of function 'c'.
self.line1 = line_number('main.c', '// Find the line number for breakpoint 1 here.')
self.line2 = line_number('main.c', '// Find the line number for breakpoint 2 here.')
self.line_main = line_number("main.c", "// Set a break at entry to main.")
def read_memory(self, target):
breakpoint = target.BreakpointCreateByLocation("main.c", self.line_main)
self.assertTrue(breakpoint, VALID_BREAKPOINT)
# Launch the process, and do not stop at the entry point.
process = target.LaunchSimple (None, None, self.get_process_working_directory())
# find the file address in the .data section of the main
# module
data_section = self.find_data_section(target)
data_section_addr = data_section.file_addr
a = target.ResolveFileAddress(data_section_addr)
content = target.ReadMemory(a, 1, lldb.SBError())
self.assertEquals(len(content), 1)
def create_simple_target(self, fn):
exe = os.path.join(os.getcwd(), fn)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
return target
def resolve_file_address(self, target):
# find the file address in the .data section of the main
# module
data_section = self.find_data_section(target)
data_section_addr = data_section.file_addr
# resolve the above address, and compare the address produced
# by the resolution against the original address/section
res_file_addr = target.ResolveFileAddress(data_section_addr)
self.assertTrue(res_file_addr.IsValid())
self.assertEquals(data_section_addr, res_file_addr.file_addr)
data_section2 = res_file_addr.section
self.assertIsNotNone(data_section2)
self.assertEquals(data_section.name, data_section2.name)
def find_data_section(self, target):
mod = target.GetModuleAtIndex(0)
data_section = None
for s in mod.sections:
if ".data" == s.name:
data_section = s
break
self.assertIsNotNone(data_section)
return data_section
def find_global_variables(self, exe_name):
"""Exercise SBTaget.FindGlobalVariables() API."""

View File

@ -46,6 +46,7 @@ int c(int val)
int main (int argc, char const *argv[])
{
// Set a break at entry to main.
int A1 = a(1); // a(1) -> b(1) -> c(1)
printf("a(1) returns %d\n", A1);