This revision was automatically updated to reflect the committed changes.
Closed by commit rG4bafceced6a7: [LLDB] Add ObjectFileWasm plugin for 
WebAssembly debugging (authored by paolosev, committed by dschuff).

Changed prior to commit:
  https://reviews.llvm.org/D71575?vs=238168&id=238391#toc

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/embedded-debug-sections.yaml
  lldb/test/Shell/ObjectFile/wasm/stripped-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/stripped-debug-sections.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/wasm/stripped-debug-sections.yaml
@@ -0,0 +1,54 @@
+# 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: 0x0
+
+# CHECK: Name: .debug_info
+# CHECK: Type: dwarf-info
+# CHECK: VM address: 0x0
+# CHECK: VM size: 0
+# CHECK: File size: 2
+
+# CHECK: Name: .debug_abbrev
+# CHECK: Type: dwarf-abbrev
+# CHECK: VM address: 0x0
+# CHECK: VM size: 0
+# CHECK: File size: 2
+
+# CHECK: Name: .debug_line
+# CHECK: Type: dwarf-line
+# CHECK: VM address: 0x0
+# CHECK: VM size: 0
+# CHECK: File size: 2
+
+# CHECK: Name: .debug_str
+# CHECK: Type: dwarf-str
+# CHECK: VM address: 0x0
+# CHECK: VM size: 0
+# CHECK: File size: 3
+
+--- !WASM
+FileHeader:
+  Version:         0x00000001
+Sections:
+
+  - 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/test/Shell/ObjectFile/wasm/embedded-debug-sections.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/wasm/embedded-debug-sections.yaml
@@ -0,0 +1,67 @@
+# 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: 0xa
+
+# CHECK: Name: code
+# CHECK: Type: code
+# CHECK: VM address: 0x0
+# CHECK: VM size: 56
+# CHECK: File size: 56
+
+# CHECK: Name: .debug_info
+# CHECK: Type: dwarf-info
+# CHECK: VM address: 0x0
+# CHECK: VM size: 0
+# CHECK: File size: 2
+
+# CHECK: Name: .debug_abbrev
+# CHECK: Type: dwarf-abbrev
+# CHECK: VM address: 0x0
+# CHECK: VM size: 0
+# CHECK: File size: 2
+
+# CHECK: Name: .debug_line
+# CHECK: Type: dwarf-line
+# CHECK: VM address: 0x0
+# CHECK: VM size: 0
+# CHECK: File size: 2
+
+# CHECK: Name: .debug_str
+# CHECK: Type: dwarf-str
+# CHECK: VM address: 0x0
+# CHECK: VM size: 0
+# CHECK: File size: 3
+
+--- !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/test/Shell/ObjectFile/wasm/basic.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/wasm/basic.yaml
@@ -0,0 +1,30 @@
+# 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: 0xa
+
+# CHECK: Name: code
+# CHECK: Type: code
+# CHECK: VM address: 0x0
+# CHECK: VM size: 56
+# CHECK: File size: 56
+
+--- !WASM
+FileHeader:
+  Version:         0x00000001
+Sections:
+  - Type:            CODE
+    Functions:
+      - Index:           0
+        Locals:
+          - Type:            I32
+            Count:           6
+        Body:            238080808000210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B
+
Index: lldb/source/Utility/ArchSpec.cpp
===================================================================
--- lldb/source/Utility/ArchSpec.cpp
+++ lldb/source/Utility/ArchSpec.cpp
@@ -100,9 +100,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"},
 
@@ -216,7 +216,10 @@
      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
Index: lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
@@ -0,0 +1,138 @@
+//===-- 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 IsInMemory() ? Address(m_memory_addr + m_code_section_offset)
+                        : Address(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();
+  /// \}
+
+  /// 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,435 @@
+//===-- 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/SmallVector.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;
+}
+
+static llvm::Optional<ConstString>
+GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
+  // A Wasm string is encoded as a vector of UTF-8 codes.
+  // Vectors are encoded with their u32 length followed by the element
+  // sequence.
+  uint64_t len = data.getULEB128(c);
+  if (!c) {
+    consumeError(c.takeError());
+    return llvm::None;
+  }
+
+  if (len >= (uint64_t(1) << 32)) {
+    return llvm::None;
+  }
+
+  llvm::SmallVector<uint8_t, 32> str_storage;
+  data.getU8(c, str_storage, len);
+  if (!c) {
+    consumeError(c.takeError());
+    return llvm::None;
+  }
+
+  llvm::StringRef str = toStringRef(makeArrayRef(str_storage));
+  return ConstString(str);
+}
+
+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 %s",
+                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);
+
+  llvm::DataExtractor data = section_header_data.GetAsLLVM();
+  llvm::DataExtractor::Cursor c(0);
+
+  // Each section consists of:
+  // - a one-byte section id,
+  // - the u32 size of the contents, in bytes,
+  // - the actual contents.
+  uint8_t section_id = data.getU8(c);
+  uint64_t payload_len = data.getULEB128(c);
+  if (!c)
+    return !llvm::errorToBool(c.takeError());
+
+  if (payload_len >= (uint64_t(1) << 32))
+    return false;
+
+  if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
+    lldb::offset_t prev_offset = c.tell();
+    llvm::Optional<ConstString> sect_name = GetWasmString(data, c);
+    if (!sect_name)
+      return false;
+
+    if (payload_len < c.tell() - prev_offset)
+      return false;
+
+    uint32_t section_length = payload_len - (c.tell() - prev_offset);
+    m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length,
+                                        section_id, *sect_name});
+    *offset_ptr += (c.tell() + section_length);
+  } else if (section_id <= llvm::wasm::WASM_SEC_EVENT) {
+    m_sect_infos.push_back(section_info{*offset_ptr + c.tell(),
+                                        static_cast<uint32_t>(payload_len),
+                                        section_id, ConstString()});
+    *offset_ptr += (c.tell() + payload_len);
+  } else {
+    // Invalid section id.
+    return false;
+  }
+  return true;
+}
+
+bool ObjectFileWasm::DecodeSections() {
+  lldb::offset_t offset = kWasmHeaderSize;
+  if (IsInMemory()) {
+    offset += m_memory_addr;
+  }
+
+  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();
+  }
+
+  for (const section_info &sect_info : m_sect_infos) {
+    SectionType section_type = eSectionTypeOther;
+    ConstString section_name;
+    offset_t file_offset = 0;
+    addr_t vm_addr = 0;
+    size_t vm_size = 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;
+      vm_size = sect_info.size;
+    } 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_offset = sect_info.offset & 0xffffffff;
+      if (IsInMemory()) {
+        vm_addr = sect_info.offset & 0xffffffff;
+        vm_size = sect_info.size;
+      }
+    }
+
+    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.
+                    vm_addr,        // VM address.
+                    vm_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();
+
+  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());
+      }
+    }
+  }
+
+  data.SetByteOrder(GetByteOrder());
+  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
@@ -73,6 +73,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"
@@ -177,6 +178,7 @@
   ObjectFileELF::Initialize();
   ObjectFileMachO::Initialize();
   ObjectFilePECOFF::Initialize();
+  wasm::ObjectFileWasm::Initialize();
 
   ObjectContainerBSDArchive::Initialize();
   ObjectContainerUniversalMachO::Initialize();
@@ -404,6 +406,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
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to