[Lldb-commits] [lldb] 9b3254d - [LLDB] Add SymbolVendorWasm plugin for WebAssembly debugging

Derek Schuff via lldb-commits lldb-commits at lists.llvm.org
Thu Jan 16 09:36:56 PST 2020


Author: Paolo Severini
Date: 2020-01-16T09:36:17-08:00
New Revision: 9b3254dbf9f6624c772db7cfa7a3c29a0b94be8e

URL: https://github.com/llvm/llvm-project/commit/9b3254dbf9f6624c772db7cfa7a3c29a0b94be8e
DIFF: https://github.com/llvm/llvm-project/commit/9b3254dbf9f6624c772db7cfa7a3c29a0b94be8e.diff

LOG: [LLDB] Add SymbolVendorWasm plugin for WebAssembly debugging

Add plugin class SymbolVendorWasm, with the logic to manage debug symbols
for Wasm modules.

Reviewers: clayborg, labath, aprantl, sbc100, teemperor

Reviewed By: labath

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D72650

Added: 
    lldb/source/Plugins/SymbolVendor/wasm/CMakeLists.txt
    lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp
    lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h
    lldb/test/Shell/ObjectFile/wasm/unified-debug-sections.yaml

Modified: 
    lldb/source/API/SystemInitializerFull.cpp
    lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
    lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
    lldb/source/Plugins/SymbolVendor/CMakeLists.txt
    lldb/tools/lldb-test/SystemInitializerTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp
index 2c567974891c..2bc53af91d00 100644
--- a/lldb/source/API/SystemInitializerFull.cpp
+++ b/lldb/source/API/SystemInitializerFull.cpp
@@ -95,6 +95,7 @@
 #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
 #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
 #include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "Plugins/SymbolVendor/wasm/SymbolVendorWasm.h"
 #include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h"
 #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
 #include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
@@ -242,6 +243,7 @@ llvm::Error SystemInitializerFull::Initialize() {
   SymbolFileDWARF::Initialize();
   SymbolFilePDB::Initialize();
   SymbolFileSymtab::Initialize();
+  wasm::SymbolVendorWasm::Initialize();
   UnwindAssemblyInstEmulation::Initialize();
   UnwindAssembly_x86::Initialize();
 
@@ -334,6 +336,7 @@ void SystemInitializerFull::Terminate() {
   ThreadSanitizerRuntime::Terminate();
   UndefinedBehaviorSanitizerRuntime::Terminate();
   MainThreadCheckerRuntime::Terminate();
+  wasm::SymbolVendorWasm::Terminate();
   SymbolVendorELF::Terminate();
   breakpad::SymbolFileBreakpad::Terminate();
   SymbolFileDWARF::Terminate();

diff  --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index 2c918a8f9db3..bd4c3597b066 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -72,6 +72,8 @@ GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
   return ConstString(str);
 }
 
+char ObjectFileWasm::ID;
+
 void ObjectFileWasm::Initialize() {
   PluginManager::RegisterPlugin(GetPluginNameStatic(),
                                 GetPluginDescriptionStatic(), CreateInstance,
@@ -177,6 +179,9 @@ bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
     return false;
 
   if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
+    // Custom sections have the id 0. Their contents consist of a name
+    // identifying the custom section, followed by an uninterpreted sequence
+    // of bytes.
     lldb::offset_t prev_offset = c.tell();
     llvm::Optional<ConstString> sect_name = GetWasmString(data, c);
     if (!sect_name)
@@ -389,6 +394,24 @@ DataExtractor ObjectFileWasm::ReadImageData(uint64_t offset, size_t size) {
   return data;
 }
 
+llvm::Optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() {
+  static ConstString g_sect_name_external_debug_info("external_debug_info");
+
+  for (const section_info &sect_info : m_sect_infos) {
+    if (g_sect_name_external_debug_info == sect_info.name) {
+      const uint32_t kBufferSize = 1024;
+      DataExtractor section_header_data =
+          ReadImageData(sect_info.offset, kBufferSize);
+      llvm::DataExtractor data = section_header_data.GetAsLLVM();
+      llvm::DataExtractor::Cursor c(0);
+      llvm::Optional<ConstString> symbols_url = GetWasmString(data, c);
+      if (symbols_url)
+        return FileSpec(symbols_url->GetStringRef());
+    }
+  }
+  return llvm::None;
+}
+
 void ObjectFileWasm::Dump(Stream *s) {
   ModuleSP module_sp(GetModule());
   if (!module_sp)

diff  --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
index 986f7f9f1679..65d237e20450 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
@@ -52,6 +52,15 @@ class ObjectFileWasm : public ObjectFile {
   uint32_t GetPluginVersion() override { return 1; }
   /// \}
 
+  /// LLVM RTTI support
+  /// \{
+  static char ID;
+  bool isA(const void *ClassID) const override {
+    return ClassID == &ID || ObjectFile::isA(ClassID);
+  }
+  static bool classof(const ObjectFile *obj) { return obj->isA(&ID); }
+  /// \}
+
   /// ObjectFile Protocol.
   /// \{
   bool ParseHeader() override;
@@ -97,6 +106,12 @@ class ObjectFileWasm : public ObjectFile {
   }
   /// \}
 
+  /// A Wasm module that has external DWARF debug information should contain a
+  /// custom section named "external_debug_info", whose payload is an UTF-8
+  /// encoded string that points to a Wasm module that contains the debug
+  /// information for this module.
+  llvm::Optional<FileSpec> GetExternalDebugInfoFileSpec();
+
 private:
   ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
                  lldb::offset_t data_offset, const FileSpec *file,

diff  --git a/lldb/source/Plugins/SymbolVendor/CMakeLists.txt b/lldb/source/Plugins/SymbolVendor/CMakeLists.txt
index 94862d588727..695b9a019ae7 100644
--- a/lldb/source/Plugins/SymbolVendor/CMakeLists.txt
+++ b/lldb/source/Plugins/SymbolVendor/CMakeLists.txt
@@ -3,3 +3,4 @@ if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
 endif()
 
 add_subdirectory(ELF)
+add_subdirectory(wasm)

diff  --git a/lldb/source/Plugins/SymbolVendor/wasm/CMakeLists.txt b/lldb/source/Plugins/SymbolVendor/wasm/CMakeLists.txt
new file mode 100644
index 000000000000..49f6012c7bca
--- /dev/null
+++ b/lldb/source/Plugins/SymbolVendor/wasm/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lldb_library(lldbPluginSymbolVendorWasm PLUGIN
+  SymbolVendorWasm.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbHost
+    lldbSymbol
+    lldbPluginObjectFileWasm
+  )

diff  --git a/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp
new file mode 100644
index 000000000000..bd59bd5cf358
--- /dev/null
+++ b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp
@@ -0,0 +1,145 @@
+//===-- SymbolVendorWasm.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 "SymbolVendorWasm.h"
+
+#include <string.h>
+
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/LocateSymbolFile.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+// SymbolVendorWasm constructor
+SymbolVendorWasm::SymbolVendorWasm(const lldb::ModuleSP &module_sp)
+    : SymbolVendor(module_sp) {}
+
+void SymbolVendorWasm::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void SymbolVendorWasm::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString SymbolVendorWasm::GetPluginNameStatic() {
+  static ConstString g_name("WASM");
+  return g_name;
+}
+
+const char *SymbolVendorWasm::GetPluginDescriptionStatic() {
+  return "Symbol vendor for WASM that looks for dwo files that match "
+         "executables.";
+}
+
+// CreateInstance
+//
+// Platforms can register a callback to use when creating symbol vendors to
+// allow for complex debug information file setups, and to also allow for
+// finding separate debug information files.
+SymbolVendor *
+SymbolVendorWasm::CreateInstance(const lldb::ModuleSP &module_sp,
+                                 lldb_private::Stream *feedback_strm) {
+  if (!module_sp)
+    return nullptr;
+
+  ObjectFileWasm *obj_file =
+      llvm::dyn_cast_or_null<ObjectFileWasm>(module_sp->GetObjectFile());
+  if (!obj_file)
+    return nullptr;
+
+  // If the main object file already contains debug info, then we are done.
+  if (obj_file->GetSectionList()->FindSectionByType(
+          lldb::eSectionTypeDWARFDebugInfo, true))
+    return nullptr;
+
+  static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+  Timer scoped_timer(func_cat, "SymbolVendorWasm::CreateInstance (module = %s)",
+                     module_sp->GetFileSpec().GetPath().c_str());
+
+  ModuleSpec module_spec;
+  module_spec.GetFileSpec() = obj_file->GetFileSpec();
+  FileSystem::Instance().Resolve(module_spec.GetFileSpec());
+  module_spec.GetUUID() = obj_file->GetUUID();
+
+  // A Wasm module may have a custom section named "external_debug_info" whose
+  // content is the absolute or relative path of the Wasm module that contains
+  // debug symbols for this module.
+  llvm::Optional<FileSpec> symbol_file_spec =
+      obj_file->GetExternalDebugInfoFileSpec();
+  if (!symbol_file_spec)
+    return nullptr;
+  module_spec.GetSymbolFileSpec() = *symbol_file_spec;
+
+  FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
+  FileSpec sym_fspec =
+      Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+  if (!sym_fspec)
+    return nullptr;
+
+  DataBufferSP sym_file_data_sp;
+  lldb::offset_t sym_file_data_offset = 0;
+  ObjectFileSP sym_objfile_sp = ObjectFile::FindPlugin(
+      module_sp, &sym_fspec, 0, FileSystem::Instance().GetByteSize(sym_fspec),
+      sym_file_data_sp, sym_file_data_offset);
+  if (!sym_objfile_sp)
+    return nullptr;
+
+  // This objfile is for debugging purposes.
+  sym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo);
+
+  SymbolVendorWasm *symbol_vendor = new SymbolVendorWasm(module_sp);
+
+  // Get the module unified section list and add our debug sections to
+  // that.
+  SectionList *module_section_list = module_sp->GetSectionList();
+  SectionList *objfile_section_list = sym_objfile_sp->GetSectionList();
+
+  static const SectionType g_sections[] = {
+      eSectionTypeDWARFDebugAbbrev,   eSectionTypeDWARFDebugAddr,
+      eSectionTypeDWARFDebugAranges,  eSectionTypeDWARFDebugCuIndex,
+      eSectionTypeDWARFDebugFrame,    eSectionTypeDWARFDebugInfo,
+      eSectionTypeDWARFDebugLine,     eSectionTypeDWARFDebugLineStr,
+      eSectionTypeDWARFDebugLoc,      eSectionTypeDWARFDebugLocLists,
+      eSectionTypeDWARFDebugMacInfo,  eSectionTypeDWARFDebugMacro,
+      eSectionTypeDWARFDebugPubNames, eSectionTypeDWARFDebugPubTypes,
+      eSectionTypeDWARFDebugRanges,   eSectionTypeDWARFDebugRngLists,
+      eSectionTypeDWARFDebugStr,      eSectionTypeDWARFDebugStrOffsets,
+      eSectionTypeDWARFDebugTypes};
+  for (SectionType section_type : g_sections) {
+    if (SectionSP section_sp =
+            objfile_section_list->FindSectionByType(section_type, true)) {
+      if (SectionSP module_section_sp =
+              module_section_list->FindSectionByType(section_type, true))
+        module_section_list->ReplaceSection(module_section_sp->GetID(),
+                                            section_sp);
+      else
+        module_section_list->AddSection(section_sp);
+    }
+  }
+
+  symbol_vendor->AddSymbolFileRepresentation(sym_objfile_sp);
+  return symbol_vendor;
+}
+
+// PluginInterface protocol
+ConstString SymbolVendorWasm::GetPluginName() { return GetPluginNameStatic(); }
+
+uint32_t SymbolVendorWasm::GetPluginVersion() { return 1; }

diff  --git a/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h
new file mode 100644
index 000000000000..7a688ab41301
--- /dev/null
+++ b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h
@@ -0,0 +1,44 @@
+//===-- SymbolVendorWasm.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_SymbolVendorWasm_h_
+#define liblldb_SymbolVendorWasm_h_
+
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+namespace wasm {
+
+class SymbolVendorWasm : public lldb_private::SymbolVendor {
+public:
+  SymbolVendorWasm(const lldb::ModuleSP &module_sp);
+
+  static void Initialize();
+  static void Terminate();
+  static lldb_private::ConstString GetPluginNameStatic();
+  static const char *GetPluginDescriptionStatic();
+
+  static lldb_private::SymbolVendor *
+  CreateInstance(const lldb::ModuleSP &module_sp,
+                 lldb_private::Stream *feedback_strm);
+
+  /// PluginInterface protocol.
+  /// \{
+  lldb_private::ConstString GetPluginName() override;
+  uint32_t GetPluginVersion() override;
+  /// \}
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(SymbolVendorWasm);
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // liblldb_SymbolVendorWasm_h_

diff  --git a/lldb/test/Shell/ObjectFile/wasm/unified-debug-sections.yaml b/lldb/test/Shell/ObjectFile/wasm/unified-debug-sections.yaml
new file mode 100644
index 000000000000..d72080f40224
--- /dev/null
+++ b/lldb/test/Shell/ObjectFile/wasm/unified-debug-sections.yaml
@@ -0,0 +1,85 @@
+# RUN: yaml2obj -docnum=1 %s > test.wasm
+# RUN: yaml2obj -docnum=2 %s > test_sym.wasm
+# RUN: lldb-test object-file test.wasm | FileCheck %s
+
+# This test checks that SymbolVendorWasm correctly loads DWARF debug sections
+# that have been stripped out into a separated Wasm module. The original Wasm
+# module contains a "external_debug_info" custom section with the absolute or
+# relative path of the debug module.
+
+# 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:            external_debug_info
+    Payload:         0D746573745F73796D2E7761736D  # test_sym.wasm
+
+...
+
+
+--- !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
+
+...

diff  --git a/lldb/tools/lldb-test/SystemInitializerTest.cpp b/lldb/tools/lldb-test/SystemInitializerTest.cpp
index ab8a92e8955f..db0a9d464146 100644
--- a/lldb/tools/lldb-test/SystemInitializerTest.cpp
+++ b/lldb/tools/lldb-test/SystemInitializerTest.cpp
@@ -76,6 +76,7 @@
 #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
 #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
 #include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "Plugins/SymbolVendor/wasm/SymbolVendorWasm.h"
 #include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h"
 #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
 #include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
@@ -201,6 +202,7 @@ llvm::Error SystemInitializerTest::Initialize() {
   SymbolFileDWARF::Initialize();
   SymbolFilePDB::Initialize();
   SymbolFileSymtab::Initialize();
+  wasm::SymbolVendorWasm::Initialize();
   UnwindAssemblyInstEmulation::Initialize();
   UnwindAssembly_x86::Initialize();
   EmulateInstructionARM64::Initialize();
@@ -288,6 +290,7 @@ void SystemInitializerTest::Terminate() {
   SymbolFileDWARF::Terminate();
   SymbolFilePDB::Terminate();
   SymbolFileSymtab::Terminate();
+  wasm::SymbolVendorWasm::Terminate();
   UnwindAssembly_x86::Terminate();
   UnwindAssemblyInstEmulation::Terminate();
   EmulateInstructionARM64::Terminate();


        


More information about the lldb-commits mailing list