paolosev updated this revision to Diff 236237.
paolosev marked 8 inline comments as done.
paolosev added a comment.
Addressed more review comments:
- removed code to manage "external_debug_info" sections; logic for this will be
implemented in the symbol vendor code.
- modified test code, from unittests to be Shell "lit" tests.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D71575/new/
https://reviews.llvm.org/D71575
Files:
lldb/include/lldb/Utility/ArchSpec.h
lldb/source/API/SystemInitializerFull.cpp
lldb/source/Plugins/ObjectFile/CMakeLists.txt
lldb/source/Plugins/ObjectFile/wasm/CMakeLists.txt
lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
lldb/source/Utility/ArchSpec.cpp
lldb/test/Shell/ObjectFile/wasm/basic.yaml
lldb/test/Shell/ObjectFile/wasm/debug-sections.yaml
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
@@ -56,6 +56,7 @@
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
#include "Plugins/Platform/Android/PlatformAndroid.h"
#include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h"
#include "Plugins/Platform/Linux/PlatformLinux.h"
@@ -152,6 +153,7 @@
ObjectFileELF::Initialize();
ObjectFileMachO::Initialize();
ObjectFilePECOFF::Initialize();
+ wasm::ObjectFileWasm::Initialize();
ScriptInterpreterNone::Initialize();
@@ -345,6 +347,7 @@
ObjectFileELF::Terminate();
ObjectFileMachO::Terminate();
ObjectFilePECOFF::Terminate();
+ wasm::ObjectFileWasm::Terminate();
// Now shutdown the common parts, in reverse order.
SystemInitializerCommon::Terminate();
Index: lldb/test/Shell/ObjectFile/wasm/debug-sections.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/wasm/debug-sections.yaml
@@ -0,0 +1,109 @@
+# RUN: yaml2obj %s > %t
+# RUN: lldb-test object-file %t | FileCheck %s
+
+# CHECK: Plugin name: wasm
+# CHECK: Architecture: wasm32-unknown-unknown-wasm
+# CHECK: UUID:
+# CHECK: Executable: true
+# CHECK: Stripped: true
+# CHECK: Type: executable
+# CHECK: Strata: user
+# CHECK: Base VM address: 0x40
+
+# CHECK: Name: code
+# CHECK: Type: code
+# CHECK: VM address: 0x0
+# CHECK: VM size: 56
+
+# CHECK: Name: .debug_info
+# CHECK: Type: dwarf-info
+# CHECK: VM address: 0x87
+# CHECK: VM size: 80
+
+# CHECK: Name: .debug_abbrev
+# CHECK: Type: dwarf-abbrev
+# CHECK: VM address: 0xe7
+# CHECK: VM size: 67
+
+# CHECK: Name: .debug_line
+# CHECK: Type: dwarf-line
+# CHECK: VM address: 0x138
+# CHECK: VM size: 85
+
+# CHECK: Name: .debug_str
+# CHECK: Type: dwarf-str
+# CHECK: VM address: 0x19b
+# CHECK: VM size: 167
+
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: TYPE
+ Signatures:
+ - Index: 0
+ ParamTypes:
+ - I32
+ ReturnTypes:
+ - I32
+ - Type: FUNCTION
+ FunctionTypes: [ 0 ]
+ - Type: TABLE
+ Tables:
+ - ElemType: FUNCREF
+ Limits:
+ Flags: [ HAS_MAX ]
+ Initial: 0x00000001
+ Maximum: 0x00000001
+ - Type: MEMORY
+ Memories:
+ - Initial: 0x00000002
+ - Type: GLOBAL
+ Globals:
+ - Index: 0
+ Type: I32
+ Mutable: true
+ InitExpr:
+ Opcode: I32_CONST
+ Value: 66560
+ - Type: EXPORT
+ Exports:
+ - Name: memory
+ Kind: MEMORY
+ Index: 0
+ - Name: square
+ Kind: FUNCTION
+ Index: 0
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals:
+ - Type: I32
+ Count: 6
+ Body: 238080808000210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B
+ - Type: CUSTOM
+ Name: .debug_info
+ Payload: 4C0000000400000000000401000000000C005D00000000000000750000000200000036000000020200000036000000960000000101480000000302230CA100000001014800000000049D000000050400
+ - Type: CUSTOM
+ Name: .debug_abbrev
+ Payload: 011101250E1305030E10171B0E110112060000022E0111011206030E3A0B3B0B271949133F1900000305000218030E3A0B3B0B49130000042400030E3E0B0B0B000000
+ - Type: CUSTOM
+ Name: .debug_line
+ Payload: 5100000004002F000000010101FB0E0D000101010100000001000001673A5C746573745C73717561726500007371756172652E6300010000000005020200000001050C0A08BB051406740512740505740204000101
+ - Type: CUSTOM
+ Name: .debug_str
+ Payload: 636C616E672076657273696F6E2031302E302E302028473A2F4C4C564D31302F6C6C766D2D70726F6A6563742F636C616E6720393338313731623361643737336433366133313362336366626164633730623234323565636133662900673A5C746573745C7371756172655C7371756172652E6300473A5C4C4C564D31305C6C6C766D2D70726F6A6563745C64656275675F7836340073717561726500696E740076616C756500
+ - Type: CUSTOM
+ Name: name
+ FunctionNames:
+ - Index: 0
+ Name: square
+ - Type: CUSTOM
+ Name: producers
+ Languages:
+ - Name: C99
+ Version: ''
+ Tools:
+ - Name: clang
+ Version: '10.0.0'
+...
Index: lldb/test/Shell/ObjectFile/wasm/basic.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/wasm/basic.yaml
@@ -0,0 +1,79 @@
+# RUN: yaml2obj %s > %t
+# RUN: lldb-test object-file %t | FileCheck %s
+
+# CHECK: Plugin name: wasm
+# CHECK: Architecture: wasm32-unknown-unknown-wasm
+# CHECK: UUID:
+# CHECK: Executable: true
+# CHECK: Stripped: true
+# CHECK: Type: executable
+# CHECK: Strata: user
+# CHECK: Base VM address: 0x40
+
+# CHECK: Name: code
+# CHECK: Type: code
+# CHECK: VM address: 0x0
+# CHECK: VM size: 56
+
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: TYPE
+ Signatures:
+ - Index: 0
+ ParamTypes:
+ - I32
+ ReturnTypes:
+ - I32
+ - Type: FUNCTION
+ FunctionTypes: [ 0 ]
+ - Type: TABLE
+ Tables:
+ - ElemType: FUNCREF
+ Limits:
+ Flags: [ HAS_MAX ]
+ Initial: 0x00000001
+ Maximum: 0x00000001
+ - Type: MEMORY
+ Memories:
+ - Initial: 0x00000002
+ - Type: GLOBAL
+ Globals:
+ - Index: 0
+ Type: I32
+ Mutable: true
+ InitExpr:
+ Opcode: I32_CONST
+ Value: 66560
+ - Type: EXPORT
+ Exports:
+ - Name: memory
+ Kind: MEMORY
+ Index: 0
+ - Name: square
+ Kind: FUNCTION
+ Index: 0
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals:
+ - Type: I32
+ Count: 6
+ Body: 238080808000210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B
+ - Type: CUSTOM
+ Name: name
+ FunctionNames:
+ - Index: 0
+ Name: square
+ - Type: CUSTOM
+ Name: producers
+ Languages:
+ - Name: C99
+ Version: ''
+ Tools:
+ - Name: clang
+ Version: '10.0.0'
+ - Type: CUSTOM
+ Name: external_debug_info
+ Payload: 0F7371756172655F73796D2E7761736D
Index: lldb/source/Utility/ArchSpec.cpp
===================================================================
--- lldb/source/Utility/ArchSpec.cpp
+++ lldb/source/Utility/ArchSpec.cpp
@@ -104,9 +104,9 @@
{eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64,
ArchSpec::eCore_arm_armv8, "armv8"},
{eByteOrderLittle, 4, 2, 4, llvm::Triple::arm,
- ArchSpec::eCore_arm_armv8l, "armv8l"},
+ ArchSpec::eCore_arm_armv8l, "armv8l"},
{eByteOrderLittle, 4, 4, 4, llvm::Triple::aarch64_32,
- ArchSpec::eCore_arm_arm64_32, "arm64_32"},
+ ArchSpec::eCore_arm_arm64_32, "arm64_32"},
{eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64,
ArchSpec::eCore_arm_aarch64, "aarch64"},
@@ -220,8 +220,11 @@
ArchSpec::eCore_uknownMach32, "unknown-mach-32"},
{eByteOrderLittle, 8, 4, 4, llvm::Triple::UnknownArch,
ArchSpec::eCore_uknownMach64, "unknown-mach-64"},
- {eByteOrderLittle, 4, 2, 4, llvm::Triple::arc, ArchSpec::eCore_arc, "arc"}
-};
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arc, ArchSpec::eCore_arc, "arc"},
+
+ {eByteOrderLittle, 4, 1, 4, llvm::Triple::wasm32, ArchSpec::eCore_wasm32,
+ "wasm32"}
+ };
// Ensure that we have an entry in the g_core_definitions for each core. If you
// comment out an entry above, you will need to comment out the corresponding
Index: lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
@@ -0,0 +1,137 @@
+//===-- ObjectFileWasm.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 LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H
+#define LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/ArchSpec.h"
+
+namespace lldb_private {
+namespace wasm {
+
+/// Generic Wasm object file reader.
+///
+/// This class provides a generic wasm32 reader plugin implementing the
+/// ObjectFile protocol.
+class ObjectFileWasm : public ObjectFile {
+public:
+ static void Initialize();
+ static void Terminate();
+
+ static ConstString GetPluginNameStatic();
+ static const char *GetPluginDescriptionStatic() {
+ return "WebAssembly object file reader.";
+ }
+
+ static ObjectFile *
+ CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset, const FileSpec *file,
+ lldb::offset_t file_offset, lldb::offset_t length);
+
+ static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP &data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
+ static size_t GetModuleSpecifications(const FileSpec &file,
+ lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ ModuleSpecList &specs);
+
+ /// PluginInterface protocol.
+ /// \{
+ ConstString GetPluginName() override { return GetPluginNameStatic(); }
+ uint32_t GetPluginVersion() override { return 1; }
+ /// \}
+
+ /// ObjectFile Protocol.
+ /// \{
+ bool ParseHeader() override;
+
+ lldb::ByteOrder GetByteOrder() const override {
+ return m_arch.GetByteOrder();
+ }
+
+ bool IsExecutable() const override { return true; }
+
+ uint32_t GetAddressByteSize() const override {
+ return m_arch.GetAddressByteSize();
+ }
+
+ AddressClass GetAddressClass(lldb::addr_t file_addr) override {
+ return AddressClass::eInvalid;
+ }
+
+ Symtab *GetSymtab() override;
+
+ bool IsStripped() override { return true; }
+
+ void CreateSections(SectionList &unified_section_list) override;
+
+ void Dump(Stream *s) override;
+
+ ArchSpec GetArchitecture() override { return m_arch; }
+
+ UUID GetUUID() override { return m_uuid; }
+
+ uint32_t GetDependentModules(FileSpecList &files) override { return 0; }
+
+ Type CalculateType() override { return eTypeExecutable; }
+
+ Strata CalculateStrata() override { return eStrataUser; }
+
+ bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value,
+ bool value_is_offset) override;
+
+ lldb_private::Address GetBaseAddress() override {
+ return Address(m_memory_addr + m_code_section_offset);
+ }
+ /// \}
+
+private:
+ ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset, const FileSpec *file,
+ lldb::offset_t offset, lldb::offset_t length);
+ ObjectFileWasm(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP &header_data_sp,
+ const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);
+
+ /// Wasm section decoding routines.
+ /// \{
+ bool DecodeNextSection(lldb::offset_t *offset_ptr);
+ bool DecodeSections(lldb::addr_t load_address);
+ /// \}
+
+ /// Read a range of bytes from the Wasm module.
+ DataExtractor ReadImageData(uint64_t offset, size_t size);
+
+ typedef struct section_info {
+ lldb::offset_t offset;
+ uint32_t size;
+ uint32_t id;
+ ConstString name;
+ } section_info_t;
+
+ /// Wasm section header dump routines.
+ /// \{
+ void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info_t &sh);
+ void DumpSectionHeaders(llvm::raw_ostream &ostream);
+ /// \}
+
+ std::vector<section_info_t> m_sect_infos;
+ ArchSpec m_arch;
+ UUID m_uuid;
+ uint32_t m_code_section_offset;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+#endif // LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H
Index: lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -0,0 +1,433 @@
+//===-- ObjectFileWasm.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 "ObjectFileWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Format.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+static const uint32_t kWasmHeaderSize =
+ sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion);
+
+/// Checks whether the data buffer starts with a valid Wasm module header.
+static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
+ if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize)
+ return false;
+
+ if (llvm::identify_magic(toStringRef(data_sp->GetData())) !=
+ llvm::file_magic::wasm_object)
+ return false;
+
+ uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic);
+
+ uint32_t version = llvm::support::endian::read32le(Ptr);
+ return version == llvm::wasm::WasmVersion;
+}
+
+/// Reads a LEB128 variable-length unsigned integer, limited to 7 bits.
+static llvm::Optional<uint8_t> GetVaruint7(DataExtractor §ion_header_data,
+ lldb::offset_t *offset_ptr) {
+ lldb::offset_t initial_offset = *offset_ptr;
+ uint64_t value = section_header_data.GetULEB128(offset_ptr);
+ if (*offset_ptr == initial_offset || value > 127)
+ return llvm::None;
+ return static_cast<uint8_t>(value);
+}
+
+/// Reads a LEB128 variable-length unsigned integer, limited to 32 bits.
+static llvm::Optional<uint32_t> GetVaruint32(DataExtractor §ion_header_data,
+ lldb::offset_t *offset_ptr) {
+ lldb::offset_t initial_offset = *offset_ptr;
+ uint64_t value = section_header_data.GetULEB128(offset_ptr);
+ if (*offset_ptr == initial_offset || value > uint64_t(1) << 32)
+ return llvm::None;
+ return static_cast<uint32_t>(value);
+}
+
+void ObjectFileWasm::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ CreateMemoryInstance, GetModuleSpecifications);
+}
+
+void ObjectFileWasm::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+ConstString ObjectFileWasm::GetPluginNameStatic() {
+ static ConstString g_name("wasm");
+ return g_name;
+}
+
+ObjectFile *
+ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp,
+ offset_t data_offset, const FileSpec *file,
+ offset_t file_offset, offset_t length) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
+
+ if (!data_sp) {
+ data_sp = MapFileData(*file, length, file_offset);
+ if (!data_sp) {
+ LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s",
+ file->GetPath().c_str());
+ return nullptr;
+ }
+ data_offset = 0;
+ }
+
+ assert(data_sp);
+ if (!ValidateModuleHeader(data_sp)) {
+ LLDB_LOGF(log,
+ "Failed to create ObjectFileWasm instance: invalid Wasm header");
+ return nullptr;
+ }
+
+ // Update the data to contain the entire file if it doesn't contain it
+ // already.
+ if (data_sp->GetByteSize() < length) {
+ data_sp = MapFileData(*file, length, file_offset);
+ if (!data_sp) {
+ LLDB_LOGF(log,
+ "Failed to create ObjectFileWasm instance: cannot read file %",
+ file->GetPath().c_str());
+ return nullptr;
+ }
+ data_offset = 0;
+ }
+
+ std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm(
+ module_sp, data_sp, data_offset, file, file_offset, length));
+ ArchSpec spec = objfile_up->GetArchitecture();
+ if (spec && objfile_up->SetModulesArchitecture(spec)) {
+ LLDB_LOGF(log,
+ "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s",
+ static_cast<void *>(objfile_up.get()),
+ static_cast<void *>(objfile_up->GetModule().get()),
+ objfile_up->GetModule()->GetSpecificationDescription().c_str(),
+ file ? file->GetPath().c_str() : "<NULL>");
+ return objfile_up.release();
+ }
+
+ LLDB_LOGF(log, "Failed to create ObjectFileWasm instance");
+ return nullptr;
+}
+
+ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp,
+ DataBufferSP &data_sp,
+ const ProcessSP &process_sp,
+ addr_t header_addr) {
+ if (!ValidateModuleHeader(data_sp))
+ return nullptr;
+
+ std::unique_ptr<ObjectFileWasm> objfile_up(
+ new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr));
+ ArchSpec spec = objfile_up->GetArchitecture();
+ if (spec && objfile_up->SetModulesArchitecture(spec))
+ return objfile_up.release();
+ return nullptr;
+}
+
+bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
+ // Buffer sufficient to read a section header and find the pointer to the next
+ // section.
+ const uint32_t kBufferSize = 1024;
+ DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize);
+
+ lldb::offset_t offset = 0;
+
+ // Each section consists of:
+ // - a one-byte section id,
+ // - the u32 size of the contents, in bytes,
+ // - the actual contents.
+ llvm::Optional<uint8_t> section_id =
+ GetVaruint7(section_header_data, &offset);
+ if (!section_id)
+ return false;
+
+ llvm::Optional<uint32_t> payload_len =
+ GetVaruint32(section_header_data, &offset);
+ if (!payload_len)
+ return false;
+
+ if (*section_id == 0) {
+ // Custom sections have the id 0. Their contents consist of a name
+ // identifying the custom section, followed by an uninterpreted sequence
+ // of bytes.
+ // The name is encoded as a vector of UTF-8 codes.
+ // Vectors are encoded with their u32 length followed by the element
+ // sequence.
+ lldb::offset_t prev_offset = offset;
+ llvm::Optional<uint32_t> name_len =
+ GetVaruint32(section_header_data, &offset);
+ if (!name_len)
+ return false;
+ uint32_t name_len_uleb_size = offset - prev_offset;
+
+ const uint8_t *name_bytes = section_header_data.PeekData(offset, *name_len);
+ // If a custom section has a name longer than the allocated buffer or longer
+ // than the data left in the image, ignore this section.
+ if (!name_bytes)
+ return false;
+
+ llvm::StringRef sect_name(reinterpret_cast<const char *>(name_bytes),
+ *name_len);
+ offset += *name_len;
+
+ uint32_t section_length = *payload_len - *name_len - name_len_uleb_size;
+ m_sect_infos.push_back(section_info{*offset_ptr + offset, section_length,
+ *section_id, ConstString(sect_name)});
+ offset += section_length;
+ } else if (*section_id <= llvm::wasm::WASM_SEC_EVENT) {
+ m_sect_infos.push_back(section_info{*offset_ptr + offset, *payload_len,
+ *section_id, ConstString()});
+ offset += *payload_len;
+ } else {
+ // Invalid section id.
+ return false;
+ }
+ *offset_ptr += offset;
+ return true;
+}
+
+bool ObjectFileWasm::DecodeSections(lldb::addr_t load_address) {
+ lldb::offset_t offset = load_address + kWasmHeaderSize;
+ while (DecodeNextSection(&offset))
+ ;
+ return true;
+}
+
+size_t ObjectFileWasm::GetModuleSpecifications(
+ const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
+ offset_t file_offset, offset_t length, ModuleSpecList &specs) {
+ if (!ValidateModuleHeader(data_sp)) {
+ return 0;
+ }
+
+ ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm"));
+ specs.Append(spec);
+ return 1;
+}
+
+ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp,
+ offset_t data_offset, const FileSpec *file,
+ offset_t offset, offset_t length)
+ : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
+ m_arch("wasm32-unknown-unknown-wasm"), m_code_section_offset(0) {
+ m_data.SetAddressByteSize(4);
+}
+
+ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP &header_data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr)
+ : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
+ m_arch("wasm32-unknown-unknown-wasm"), m_code_section_offset(0) {}
+
+bool ObjectFileWasm::ParseHeader() {
+ // We already parsed the header during initialization.
+ return true;
+}
+
+Symtab *ObjectFileWasm::GetSymtab() { return nullptr; }
+
+void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
+ if (m_sections_up)
+ return;
+
+ m_sections_up = std::make_unique<SectionList>();
+
+ if (m_sect_infos.empty()) {
+ DecodeSections(0);
+ }
+
+ for (const section_info §_info : m_sect_infos) {
+ SectionType section_type = eSectionTypeOther;
+ ConstString section_name;
+ addr_t file_addr = 0;
+ offset_t file_offset = 0;
+
+ if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
+ section_type = eSectionTypeCode;
+ section_name = ConstString("code");
+ m_code_section_offset = sect_info.offset & 0xffffffff;
+ } else {
+ section_type =
+ llvm::StringSwitch<SectionType>(sect_info.name.GetStringRef())
+ .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev)
+ .Case(".debug_addr", eSectionTypeDWARFDebugAddr)
+ .Case(".debug_aranges", eSectionTypeDWARFDebugAranges)
+ .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex)
+ .Case(".debug_frame", eSectionTypeDWARFDebugFrame)
+ .Case(".debug_info", eSectionTypeDWARFDebugInfo)
+ .Case(".debug_line", eSectionTypeDWARFDebugLine)
+ .Case(".debug_line_str", eSectionTypeDWARFDebugLineStr)
+ .Case(".debug_loc", eSectionTypeDWARFDebugLoc)
+ .Case(".debug_loclists", eSectionTypeDWARFDebugLocLists)
+ .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo)
+ .Case(".debug_macro", eSectionTypeDWARFDebugMacro)
+ .Case(".debug_names", eSectionTypeDWARFDebugNames)
+ .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames)
+ .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes)
+ .Case(".debug_ranges", eSectionTypeDWARFDebugRanges)
+ .Case(".debug_rnglists", eSectionTypeDWARFDebugRngLists)
+ .Case(".debug_str", eSectionTypeDWARFDebugStr)
+ .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets)
+ .Case(".debug_types", eSectionTypeDWARFDebugTypes)
+ .Default(eSectionTypeOther);
+ if (section_type == eSectionTypeOther)
+ continue;
+ section_name = sect_info.name;
+ file_addr = sect_info.offset & 0xffffffff;
+ file_offset = file_addr;
+ }
+
+ SectionSP section_sp(
+ new Section(GetModule(), // Module to which this section belongs.
+ this, // ObjectFile to which this section belongs and
+ // should read section data from.
+ section_type, // Section ID.
+ section_name, // Section name.
+ section_type, // Section type.
+ file_addr, // VM address.
+ sect_info.size, // VM size in bytes of this section.
+ file_offset, // Offset of this section in the file.
+ sect_info.size, // Size of the section as found in the file.
+ 0, // Alignment of the section
+ 0, // Flags for this section.
+ 1)); // Number of host bytes per target byte
+ m_sections_up->AddSection(section_sp);
+ unified_section_list.AddSection(section_sp);
+ }
+}
+
+bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
+ bool value_is_offset) {
+ /// In WebAssembly, linear memory is disjointed from code space. The VM can
+ /// load multiple instances of a module, which logically share the same code.
+ /// We represent a wasm32 code address with 64-bits, like:
+ /// 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.
+ /// In other words, we assume that each WebAssembly module is loaded by the
+ /// engine at a 64-bit address that starts at the boundary of 4GB pages, like
+ /// 0x0000000400000000 for module_id == 4.
+ /// These 64-bit addresses will be used to request code ranges for a specific
+ /// module from the WebAssembly engine.
+ ModuleSP module_sp = GetModule();
+ if (!module_sp)
+ return false;
+
+ DecodeSections(load_address);
+
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ 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) {
+ SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
+ if (target.GetSectionLoadList().SetSectionLoadAddress(
+ section_sp, load_address | section_sp->GetFileAddress())) {
+ ++num_loaded_sections;
+ }
+ }
+
+ return num_loaded_sections > 0;
+}
+
+DataExtractor ObjectFileWasm::ReadImageData(uint64_t offset, size_t size) {
+ DataExtractor data;
+ if (m_file) {
+ if (offset < GetByteSize()) {
+ size = std::min(size, GetByteSize() - offset);
+ auto buffer_sp = MapFileData(m_file, size, offset);
+ return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
+ }
+ } else {
+ ProcessSP process_sp(m_process_wp.lock());
+ if (process_sp) {
+ auto data_up = std::make_unique<DataBufferHeap>(size, 0);
+ Status readmem_error;
+ size_t bytes_read = process_sp->ReadMemory(
+ offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
+ if (bytes_read > 0) {
+ DataBufferSP buffer_sp(data_up.release());
+ data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
+ }
+ }
+ }
+ return data;
+}
+
+void ObjectFileWasm::Dump(Stream *s) {
+ ModuleSP module_sp(GetModule());
+ if (!module_sp)
+ return;
+
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+
+ llvm::raw_ostream &ostream = s->AsRawOstream();
+ ostream << static_cast<void *>(this) << ": ";
+ s->Indent();
+ ostream << "ObjectFileWasm, file = '";
+ m_file.Dump(ostream);
+ ostream << "', arch = ";
+ ostream << GetArchitecture().GetArchitectureName() << "\n";
+
+ SectionList *sections = GetSectionList();
+ if (sections) {
+ sections->Dump(s, nullptr, true, UINT32_MAX);
+ }
+ ostream << "\n";
+ DumpSectionHeaders(ostream);
+ ostream << "\n";
+}
+
+void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
+ const section_info_t &sh) {
+ ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
+ << llvm::format_hex(sh.offset, 10) << " "
+ << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
+ << "\n";
+}
+
+void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) {
+ ostream << "Section Headers\n";
+ ostream << "IDX name addr size id\n";
+ ostream << "==== ---------------- ---------- ---------- ------\n";
+
+ uint32_t idx = 0;
+ for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end();
+ ++pos, ++idx) {
+ ostream << "[" << llvm::format_decimal(idx, 2) << "] ";
+ ObjectFileWasm::DumpSectionHeader(ostream, *pos);
+ }
+}
Index: lldb/source/Plugins/ObjectFile/wasm/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectFile/wasm/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_lldb_library(lldbPluginObjectFileWasm PLUGIN
+ ObjectFileWasm.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbHost
+ lldbSymbol
+ lldbUtility
+ LINK_COMPONENTS
+ Support
+ )
Index: lldb/source/Plugins/ObjectFile/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ObjectFile/CMakeLists.txt
+++ lldb/source/Plugins/ObjectFile/CMakeLists.txt
@@ -3,3 +3,4 @@
add_subdirectory(Mach-O)
add_subdirectory(PECOFF)
add_subdirectory(JIT)
+add_subdirectory(wasm)
\ No newline at end of file
Index: lldb/source/API/SystemInitializerFull.cpp
===================================================================
--- lldb/source/API/SystemInitializerFull.cpp
+++ lldb/source/API/SystemInitializerFull.cpp
@@ -69,6 +69,7 @@
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
#include "Plugins/OperatingSystem/Python/OperatingSystemPython.h"
#include "Plugins/Platform/Android/PlatformAndroid.h"
#include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h"
@@ -173,6 +174,7 @@
ObjectFileELF::Initialize();
ObjectFileMachO::Initialize();
ObjectFilePECOFF::Initialize();
+ wasm::ObjectFileWasm::Initialize();
ObjectContainerBSDArchive::Initialize();
ObjectContainerUniversalMachO::Initialize();
@@ -396,6 +398,7 @@
ObjectFileELF::Terminate();
ObjectFileMachO::Terminate();
ObjectFilePECOFF::Terminate();
+ wasm::ObjectFileWasm::Terminate();
ObjectContainerBSDArchive::Terminate();
ObjectContainerUniversalMachO::Terminate();
Index: lldb/include/lldb/Utility/ArchSpec.h
===================================================================
--- lldb/include/lldb/Utility/ArchSpec.h
+++ lldb/include/lldb/Utility/ArchSpec.h
@@ -188,6 +188,8 @@
eCore_arc, // little endian ARC
+ eCore_wasm32,
+
kNumCores,
kCore_invalid,
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits