paolosev updated this revision to Diff 239784.
paolosev added a comment.
I have verified the logic of the dynamic loader quite carefully, but there are
a couple of things to clarify.
A Wasm module is loaded at a 64 bit address, where the upper 32 bits are used
as module identifier. Let’s say that we have a module with Id==4, so it will be
loaded at address 0x00000004`00000000. Each section is loaded at its relative
file offset. Therefore if the code section starts at file offset 0x4d in the
Wasm module, we call:
Target::SetSectionLoadAddress(section_sp, 0x40000004d).
The module can also contain embedded DWARF sections, which will also be loaded
at their relative file offset in the same way. And since there cannot be
duplicated sections in a module, there is no overlapping, we can always convert
a load address back into a section.
However, there are two complications.
The first is that we need to call `Target::SetSectionLoadAddress()` twice, from
two different places. First we need to call `Target::SetSectionLoadAddress()`
in `ObjectFileWasm::SetLoadAddress()`, and then again in
`DynamicLoaderWasmDYLD::DidAttach()`. The reason for this seems to originate in
the sequence of function calls:
In `DynamicLoaderWasmDYLD::DidAttach()` we call
`ProcessGDBRemote::LoadModules()` to get list of loaded modules from the remote
(Wasm engine).
`ProcessGDBRemote::LoadModules()` calls, first:
- `DynamicLoaderWasmDYLD::LoadModuleAtAddress()` and from there:
1. `DynamicLoader::UpdateLoadedSections() -> ObjectFileWasm::SetLoadAddress()`
2. `Target::GetImages()::AppendIfNeeded(module) ->
ProcessGDBRemote::ModulesDidLoad() -> JITLoaderList::ModulesDidLoad() ->
Module::GetSymbolFile() -> SymbolFileDWARF::CalculateAbilities()`. Here we
initialize the symbols for the module, and set `m_did_load_symfile`, but for
this to work we need to have already set the load address for each section, in
the previous `ObjectFileWasm::SetLoadAddress()`.
then:
- `Target::SetExecutableModule() -> Target::ClearModules() ->
SectionLoadList::Clear()`
So, at the end of `LoadModules()` in `DynamicLoaderWasmDYLD::DidAttach()` the
SectionLoadList is empty, and we need to set it again by calling
`Target::.SetSectionLoadAddress()` again.
This works but the duplication is ugly; is there a way to improve this?
_
The second problem is that the Code Section needs to be initialized (in
`ObjectFileWasm::CreateSections()`) with `m_file_addr = m_file_offset = 0`, and
not with the actual file offset of the Code section in the Wasm file. If we set
`Section::m_file_addr` and `Section::m_file_offset` to the actual code offset,
the DWARF info does not work correctly.
I have some doubts regarding the DWARF data generated by Clang for a Wasm
target. Looking at an example, for a Wasm module that has the Code section at
offset 0x57, I see this DWARF data:
0x0000000b: DW_TAG_compile_unit
[…]
DW_AT_low_pc (0x0000000000000000)
DW_AT_ranges (0x00000000
[0x00000002, 0x0000000e)
[0x0000000f, 0x0000001a)
[0x0000001b, 0x00000099)
[0x0000009b, 0x0000011c))
The documentation <https://yurydelendik.github.io/webassembly-dwarf/#pc> says
that //“Wherever a code address is used in DWARF for WebAssembly, it must be
the offset of an instruction relative within the Code section of the
WebAssembly file.”//
But is this correct? Shouldn't maybe code addresses be offset-ed by the file
address of the Code section?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D72751/new/
https://reviews.llvm.org/D72751
Files:
lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestWasm.py
lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/test_wasm.yaml
lldb/source/API/SystemInitializerFull.cpp
lldb/source/Plugins/DynamicLoader/CMakeLists.txt
lldb/source/Plugins/DynamicLoader/wasm-DYLD/CMakeLists.txt
lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp
lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h
lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
lldb/tools/lldb-test/SystemInitializerTest.cpp
Index: lldb/tools/lldb-test/SystemInitializerTest.cpp
===================================================================
--- lldb/tools/lldb-test/SystemInitializerTest.cpp
+++ lldb/tools/lldb-test/SystemInitializerTest.cpp
@@ -37,6 +37,7 @@
#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
+#include "Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h"
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
#include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h"
@@ -246,6 +247,7 @@
DynamicLoaderMacOSXDYLD::Initialize();
DynamicLoaderMacOS::Initialize();
DynamicLoaderPOSIXDYLD::Initialize();
+ wasm::DynamicLoaderWasmDYLD::Initialize();
DynamicLoaderStatic::Initialize();
DynamicLoaderWindowsDYLD::Initialize();
@@ -329,6 +331,7 @@
DynamicLoaderMacOSXDYLD::Terminate();
DynamicLoaderMacOS::Terminate();
DynamicLoaderPOSIXDYLD::Terminate();
+ wasm::DynamicLoaderWasmDYLD::Terminate();
DynamicLoaderStatic::Terminate();
DynamicLoaderWindowsDYLD::Terminate();
Index: lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
===================================================================
--- lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
+++ lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
@@ -101,8 +101,7 @@
bool value_is_offset) override;
lldb_private::Address GetBaseAddress() override {
- return IsInMemory() ? Address(m_memory_addr + m_code_section_offset)
- : Address(m_code_section_offset);
+ return IsInMemory() ? Address(m_memory_addr) : Address(0);
}
/// \}
@@ -112,6 +111,8 @@
/// information for this module.
llvm::Optional<FileSpec> GetExternalDebugInfoFileSpec();
+ uint32_t GetCodeSectionOffset() const { return m_code_section_offset; }
+
private:
ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
lldb::offset_t data_offset, const FileSpec *file,
@@ -127,7 +128,7 @@
/// \}
/// Read a range of bytes from the Wasm module.
- DataExtractor ReadImageData(uint64_t offset, size_t size);
+ DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size);
typedef struct section_info {
lldb::offset_t offset;
Index: lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -355,12 +355,12 @@
return false;
const size_t num_sections = section_list->GetSize();
- size_t sect_idx = 0;
-
- for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
- if (target.GetSectionLoadList().SetSectionLoadAddress(
- section_sp, load_address | section_sp->GetFileAddress())) {
+ lldb::addr_t file_address = (section_sp->GetName() == "code")
+ ? GetCodeSectionOffset()
+ : section_sp->GetFileAddress();
+ if (target.SetSectionLoadAddress(section_sp, load_address | file_address)) {
++num_loaded_sections;
}
}
@@ -368,11 +368,11 @@
return num_loaded_sections > 0;
}
-DataExtractor ObjectFileWasm::ReadImageData(uint64_t offset, size_t size) {
+DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
DataExtractor data;
if (m_file) {
if (offset < GetByteSize()) {
- size = std::min(size, GetByteSize() - offset);
+ size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
auto buffer_sp = MapFileData(m_file, size, offset);
return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
}
Index: lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h
@@ -0,0 +1,52 @@
+//===-- DynamicLoaderWasmDYLD.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Plugins_DynamicLoaderWasmDYLD_h_
+#define liblldb_Plugins_DynamicLoaderWasmDYLD_h_
+
+#include "lldb/Target/DynamicLoader.h"
+
+namespace lldb_private {
+namespace wasm {
+
+class DynamicLoaderWasmDYLD : public DynamicLoader {
+public:
+ DynamicLoaderWasmDYLD(Process *process);
+
+ static void Initialize();
+ static void Terminate() {}
+
+ static ConstString GetPluginNameStatic();
+ static const char *GetPluginDescriptionStatic();
+
+ static DynamicLoader *CreateInstance(Process *process, bool force);
+
+ /// DynamicLoader
+ /// \{
+ lldb::ModuleSP LoadModuleAtAddress(const lldb_private::FileSpec &file,
+ lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr,
+ bool base_addr_is_offset) override;
+ void DidAttach() override;
+ void DidLaunch() override {}
+ Status CanLoadImage() override { return Status(); }
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) override;
+ /// \}
+
+ /// PluginInterface protocol.
+ /// \{
+ ConstString GetPluginName() override { return GetPluginNameStatic(); }
+ uint32_t GetPluginVersion() override { return 1; }
+ /// \}
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // liblldb_Plugins_DynamicLoaderWasmDYLD_h_
Index: lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp
@@ -0,0 +1,133 @@
+//===-- DynamicLoaderWasmDYLD.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DynamicLoaderWasmDYLD.h"
+
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+DynamicLoaderWasmDYLD::DynamicLoaderWasmDYLD(Process *process)
+ : DynamicLoader(process) {}
+
+void DynamicLoaderWasmDYLD::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+ConstString DynamicLoaderWasmDYLD::GetPluginNameStatic() {
+ static ConstString g_plugin_name("wasm-dyld");
+ return g_plugin_name;
+}
+
+const char *DynamicLoaderWasmDYLD::GetPluginDescriptionStatic() {
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in WebAssembly engines.";
+}
+
+DynamicLoader *DynamicLoaderWasmDYLD::CreateInstance(Process *process,
+ bool force) {
+ bool should_create = force;
+ if (!should_create) {
+ should_create =
+ (process->GetTarget().GetArchitecture().GetTriple().getArch() ==
+ llvm::Triple::wasm32);
+ }
+
+ if (should_create)
+ return new DynamicLoaderWasmDYLD(process);
+
+ return nullptr;
+}
+
+/// In WebAssembly, linear memory is disjointed from code space. The VM can load
+/// multiple instances of a module, which logically share the same code.
+/// Currently we only support wasm32, which uses a 32-bit address space for the
+/// code.
+/// We represent a code address in LLDB as a 64-bit address with the format:
+/// 63 32 31 0
+/// +---------------+---------------+
+/// + module_id | offset |
+/// +---------------+---------------+
+/// where the lower 32 bits represent a module offset (relative to the module
+/// start not to the beginning of the code section) and the higher 32 bits
+/// uniquely identify the module in the WebAssembly VM.
+/// This method should be called for each Wasm module loaded in the debuggee,
+/// with base_addr = 0x{module_id}|00000000 (for example 0x0000000100000000).
+ModuleSP DynamicLoaderWasmDYLD::LoadModuleAtAddress(const FileSpec &file,
+ addr_t link_map_addr,
+ addr_t base_addr,
+ bool base_addr_is_offset) {
+ if (ModuleSP module_sp = m_process->ReadModuleFromMemory(file, base_addr)) {
+ UpdateLoadedSections(module_sp, link_map_addr, base_addr, false);
+ m_process->GetTarget().GetImages().AppendIfNeeded(module_sp);
+ return module_sp;
+ }
+
+ return ModuleSP();
+}
+
+void DynamicLoaderWasmDYLD::DidAttach() {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ LLDB_LOGF(log, "DynamicLoaderWasmDYLD::%s()", __FUNCTION__);
+
+ // Ask the process for the list of loaded WebAssembly modules.
+ auto error = m_process->LoadModules();
+ LLDB_LOG_ERROR(log, std::move(error), "Couldn't load modules: {0}");
+
+ ModuleList loaded_module_list;
+ const ModuleList &module_list = m_process->GetTarget().GetImages();
+ const size_t num_modules = module_list.GetSize();
+ for (uint32_t idx = 0; idx < num_modules; ++idx) {
+ ModuleSP module_sp(module_list.GetModuleAtIndexUnlocked(idx));
+ if (!module_sp)
+ continue;
+
+ ObjectFileWasm *image_object_file =
+ llvm::dyn_cast_or_null<ObjectFileWasm>(module_sp->GetObjectFile());
+ if (!image_object_file)
+ continue;
+
+ lldb::addr_t image_load_address =
+ image_object_file->GetBaseAddress().GetOffset();
+
+ SectionList *section_list = image_object_file->GetSectionList();
+ if (!section_list)
+ continue;
+
+ // Fixes the section load address for each section.
+ const size_t num_sections = section_list->GetSize();
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
+ SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
+
+ // Code section load address is offsetted by the code section
+ // offset in the Wasm module.
+ lldb::addr_t file_addr = (section_sp->GetName() == "code")
+ ? image_object_file->GetCodeSectionOffset()
+ : section_sp->GetFileAddress();
+ lldb::addr_t load_addr = image_load_address | file_addr;
+ if (m_process->GetTarget().SetSectionLoadAddress(section_sp, load_addr))
+ loaded_module_list.AppendIfNeeded(module_sp);
+ }
+ }
+
+ m_process->GetTarget().ModulesDidLoad(loaded_module_list);
+}
+
+ThreadPlanSP DynamicLoaderWasmDYLD::GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) {
+ return ThreadPlanSP();
+}
Index: lldb/source/Plugins/DynamicLoader/wasm-DYLD/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/DynamicLoader/wasm-DYLD/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lldb_library(lldbPluginDynamicLoaderWasmDYLD PLUGIN
+ DynamicLoaderWasmDYLD.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbTarget
+ LINK_COMPONENTS
+ Support
+ )
Index: lldb/source/Plugins/DynamicLoader/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/DynamicLoader/CMakeLists.txt
+++ lldb/source/Plugins/DynamicLoader/CMakeLists.txt
@@ -4,3 +4,4 @@
add_subdirectory(Static)
add_subdirectory(Hexagon-DYLD)
add_subdirectory(Windows-DYLD)
+add_subdirectory(wasm-DYLD)
Index: lldb/source/API/SystemInitializerFull.cpp
===================================================================
--- lldb/source/API/SystemInitializerFull.cpp
+++ lldb/source/API/SystemInitializerFull.cpp
@@ -45,6 +45,7 @@
#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
+#include "Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h"
#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
#include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h"
@@ -284,6 +285,7 @@
DynamicLoaderMacOSXDYLD::Initialize();
DynamicLoaderMacOS::Initialize();
DynamicLoaderPOSIXDYLD::Initialize();
+ wasm::DynamicLoaderWasmDYLD::Initialize();
DynamicLoaderStatic::Initialize();
DynamicLoaderWindowsDYLD::Initialize();
@@ -377,6 +379,7 @@
DynamicLoaderMacOSXDYLD::Terminate();
DynamicLoaderMacOS::Terminate();
DynamicLoaderPOSIXDYLD::Terminate();
+ wasm::DynamicLoaderWasmDYLD::Terminate();
DynamicLoaderStatic::Terminate();
DynamicLoaderWindowsDYLD::Terminate();
Index: lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/test_wasm.yaml
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/test_wasm.yaml
@@ -0,0 +1,25 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals:
+ - Type: I32
+ Count: 6
+ Body: 238080808000210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B
+ - Type: CUSTOM
+ Name: .debug_info
+ Payload: 4C00
+ - Type: CUSTOM
+ Name: .debug_abbrev
+ Payload: 0111
+ - Type: CUSTOM
+ Name: .debug_line
+ Payload: 5100
+ - Type: CUSTOM
+ Name: .debug_str
+ Payload: 636CFF
+...
Index: lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestWasm.py
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestWasm.py
@@ -0,0 +1,124 @@
+import lldb
+import binascii
+import struct
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from gdbclientutils import *
+
+def format_register_value(val):
+ """
+ Encode each byte by two hex digits in little-endian order.
+ """
+ return ''.join(x.encode('hex') for x in struct.pack('<Q', val))
+
+class TestWasm(GDBRemoteTestBase):
+
+ def setUp(self):
+ super(TestWasm, self).setUp()
+ self._initial_platform = lldb.DBG.GetSelectedPlatform()
+
+ def tearDown(self):
+ lldb.DBG.SetSelectedPlatform(self._initial_platform)
+ super(TestWasm, self).tearDown()
+
+ def test_connect(self):
+
+ class MyResponder(MockGDBServerResponder):
+ load_address = 0x400000000
+ current_pc = 0x40000000a
+
+ def __init__(self, obj_path):
+ self._obj_path = obj_path
+ MockGDBServerResponder.__init__(self)
+
+ def respond(self, packet):
+ if packet == "qProcessInfo":
+ return self.qProcessInfo()
+ if packet[0:13] == "qRegisterInfo":
+ return self.qRegisterInfo(packet[13:])
+ return MockGDBServerResponder.respond(self, packet)
+
+ def qSupported(self, client_supported):
+ return "qXfer:libraries:read+;PacketSize=1000;vContSupported-"
+
+ def qHostInfo(self):
+ return ""
+
+ def QEnableErrorStrings(self):
+ return ""
+
+ def qfThreadInfo(self):
+ return "OK"
+
+ def qRegisterInfo(self, index):
+ if (index == 0):
+ return "name:pc;alt-name:pc;bitsize:64;offset:0;encoding:uint;format:hex;set:General Purpose Registers;gcc:16;dwarf:16;generic:pc;"
+ return "E45"
+
+ def qProcessInfo(self):
+ return "pid:1;ppid:1;uid:1;gid:1;euid:1;egid:1;name:%s;triple:%s;ptrsize:4" % (hex_encode_bytes("lldb"), hex_encode_bytes("wasm32-unknown-unknown-wasm"))
+
+ def haltReason(self):
+ return "T05thread-pcs:" + format(self.current_pc, 'x') + ";thread:1;"
+
+ def readRegister(self, register):
+ return format_register_value(self.current_pc)
+
+ def qXferRead(self, obj, annex, offset, length):
+ if obj == "libraries":
+ xml = '<library-list><library name=\"%s\"><section address=\"%d\"/></library></library-list>' % ("test_wasm", self.load_address)
+ return xml, False
+ else:
+ return None, False
+
+ def readMemory(self, addr, length):
+ result = ""
+ with open(self._obj_path, mode='rb') as file:
+ file_content = bytearray(file.read())
+ addr_from = addr - self.load_address
+ addr_to = addr_from + min(length, len(file_content) - addr_from)
+ for i in range(addr_from, addr_to):
+ result += format(file_content[i], '02x')
+ file.close()
+ return result
+
+ """Test connecting to a WebAssembly engine via GDB-remote"""
+
+ yaml_path = "test_wasm.yaml"
+ yaml_base, ext = os.path.splitext(yaml_path)
+ obj_path = self.getBuildArtifact(yaml_base)
+ self.yaml2obj(yaml_path, obj_path)
+
+ self.server.responder = MyResponder(obj_path)
+
+ target = self.dbg.CreateTarget("")
+ process = self.connect(target)
+ lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateStopped])
+
+ num_modules = target.GetNumModules()
+ self.assertEquals(1, num_modules)
+
+ module = target.GetModuleAtIndex(0)
+ num_sections = module.GetNumSections()
+ self.assertEquals(5, num_sections)
+
+ code_section = module.GetSectionAtIndex(0)
+ self.assertEquals("code", code_section.GetName())
+ self.assertEquals(0x40000000a, code_section.GetLoadAddress(target))
+
+ debug_info_section = module.GetSectionAtIndex(1)
+ self.assertEquals(".debug_info", debug_info_section.GetName())
+ self.assertEquals(0x400000050, debug_info_section.GetLoadAddress(target))
+
+ debug_abbrev_section = module.GetSectionAtIndex(2)
+ self.assertEquals(".debug_abbrev", debug_abbrev_section.GetName())
+ self.assertEquals(0x400000062, debug_abbrev_section.GetLoadAddress(target))
+
+ debug_line_section = module.GetSectionAtIndex(3)
+ self.assertEquals(".debug_line", debug_line_section.GetName())
+ self.assertEquals(0x400000072, debug_line_section.GetLoadAddress(target))
+
+ debug_str_section = module.GetSectionAtIndex(4)
+ self.assertEquals(".debug_str", debug_str_section.GetName())
+ self.assertEquals(0x400000081, debug_str_section.GetLoadAddress(target))
+
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits