Index: include/lldb/API/SBSection.h =================================================================== --- include/lldb/API/SBSection.h +++ include/lldb/API/SBSection.h @@ -71,6 +71,18 @@ 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); Index: include/lldb/API/SBTarget.h =================================================================== --- include/lldb/API/SBTarget.h +++ include/lldb/API/SBTarget.h @@ -22,6 +22,8 @@ namespace lldb { +class SBPlatform; + class SBLaunchInfo { public: @@ -309,6 +311,18 @@ 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. /// /// This function does nothing when debugging on the host system. @@ -564,6 +578,26 @@ 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. /// /// @param[in] section @@ -728,6 +762,17 @@ 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. /// /// @param[in] vm_addr @@ -772,6 +817,31 @@ 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); Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -1133,6 +1133,9 @@ Error Install(ProcessLaunchInfo *launch_info); + bool + ResolveFileAddress (lldb::addr_t load_addr, + Address &so_addr); bool ResolveLoadAddress (lldb::addr_t load_addr, Index: scripts/Python/interface/SBSection.i =================================================================== --- scripts/Python/interface/SBSection.i +++ scripts/Python/interface/SBSection.i @@ -90,6 +90,20 @@ 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 @@ __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: Index: scripts/Python/interface/SBTarget.i =================================================================== --- scripts/Python/interface/SBTarget.i +++ scripts/Python/interface/SBTarget.i @@ -282,6 +282,21 @@ 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 @@ 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 @@ 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 @@ 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 @@ __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.''') %} }; Index: source/API/SBSection.cpp =================================================================== --- source/API/SBSection.cpp +++ source/API/SBSection.cpp @@ -250,6 +250,14 @@ 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) Index: source/API/SBTarget.cpp =================================================================== --- source/API/SBTarget.cpp +++ source/API/SBTarget.cpp @@ -587,6 +587,19 @@ 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 @@ 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 @@ 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, @@ -2061,6 +2113,28 @@ } 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() { TargetSP target_sp(GetSP()); Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -2284,6 +2284,12 @@ } bool +Target::ResolveFileAddress (lldb::addr_t file_addr, Address &resolved_addr) +{ + return m_images.ResolveFileAddress(file_addr, resolved_addr); +} + +bool Target::SetSectionLoadAddress (const SectionSP §ion_sp, addr_t new_section_load_addr, bool warn_multiple) { const addr_t old_section_load_addr = m_section_load_history.GetSectionLoadAddress (SectionLoadHistory::eStopIDNow, section_sp); Index: test/lldbtest.py =================================================================== --- test/lldbtest.py +++ test/lldbtest.py @@ -137,6 +137,8 @@ VALID_TARGET = "Got a valid target" +VALID_PLATFORM = "Got a valid platform" + VALID_TYPE = "Got a valid type" VALID_VARIABLE = "Got a valid variable" Index: test/python_api/section/Makefile =================================================================== --- test/python_api/section/Makefile +++ test/python_api/section/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules Index: test/python_api/section/TestSectionAPI.py =================================================================== --- test/python_api/section/TestSectionAPI.py +++ test/python_api/section/TestSectionAPI.py @@ -0,0 +1,60 @@ +""" +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() Index: test/python_api/section/main.c =================================================================== --- test/python_api/section/main.c +++ test/python_api/section/main.c @@ -0,0 +1,28 @@ +//===-- 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 +#include + +// 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; +} Index: test/python_api/target/TestTargetAPI.py =================================================================== --- test/python_api/target/TestTargetAPI.py +++ test/python_api/target/TestTargetAPI.py @@ -104,12 +104,160 @@ 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.""" Index: test/python_api/target/main.c =================================================================== --- test/python_api/target/main.c +++ test/python_api/target/main.c @@ -46,6 +46,7 @@ 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);