1//===-- SymbolVendorWasm.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SymbolVendorWasm.h"
10
11#include <cstring>
12#include <optional>
13
14#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
15#include "lldb/Core/Module.h"
16#include "lldb/Core/ModuleSpec.h"
17#include "lldb/Core/PluginManager.h"
18#include "lldb/Core/Section.h"
19#include "lldb/Host/Host.h"
20#include "lldb/Symbol/ObjectFile.h"
21#include "lldb/Target/Target.h"
22#include "lldb/Utility/StreamString.h"
23#include "lldb/Utility/Timer.h"
24
25using namespace lldb;
26using namespace lldb_private;
27using namespace lldb_private::wasm;
28
29LLDB_PLUGIN_DEFINE(SymbolVendorWasm)
30
31// SymbolVendorWasm constructor
32SymbolVendorWasm::SymbolVendorWasm(const lldb::ModuleSP &module_sp)
33    : SymbolVendor(module_sp) {}
34
35void SymbolVendorWasm::Initialize() {
36  PluginManager::RegisterPlugin(GetPluginNameStatic(),
37                                GetPluginDescriptionStatic(), CreateInstance);
38}
39
40void SymbolVendorWasm::Terminate() {
41  PluginManager::UnregisterPlugin(CreateInstance);
42}
43
44llvm::StringRef SymbolVendorWasm::GetPluginDescriptionStatic() {
45  return "Symbol vendor for WASM that looks for dwo files that match "
46         "executables.";
47}
48
49// CreateInstance
50//
51// Platforms can register a callback to use when creating symbol vendors to
52// allow for complex debug information file setups, and to also allow for
53// finding separate debug information files.
54SymbolVendor *
55SymbolVendorWasm::CreateInstance(const lldb::ModuleSP &module_sp,
56                                 lldb_private::Stream *feedback_strm) {
57  if (!module_sp)
58    return nullptr;
59
60  ObjectFileWasm *obj_file =
61      llvm::dyn_cast_or_null<ObjectFileWasm>(module_sp->GetObjectFile());
62  if (!obj_file)
63    return nullptr;
64
65  // If the main object file already contains debug info, then we are done.
66  if (obj_file->GetSectionList()->FindSectionByType(
67          lldb::eSectionTypeDWARFDebugInfo, true))
68    return nullptr;
69
70  LLDB_SCOPED_TIMERF("SymbolVendorWasm::CreateInstance (module = %s)",
71                     module_sp->GetFileSpec().GetPath().c_str());
72
73  ModuleSpec module_spec;
74  module_spec.GetFileSpec() = obj_file->GetFileSpec();
75  FileSystem::Instance().Resolve(module_spec.GetFileSpec());
76  module_spec.GetUUID() = obj_file->GetUUID();
77
78  // A Wasm module may have a custom section named "external_debug_info" whose
79  // content is the absolute or relative path of the Wasm module that contains
80  // debug symbols for this module.
81  std::optional<FileSpec> symbol_file_spec =
82      obj_file->GetExternalDebugInfoFileSpec();
83  if (!symbol_file_spec)
84    return nullptr;
85  module_spec.GetSymbolFileSpec() = *symbol_file_spec;
86
87  FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
88  FileSpec sym_fspec =
89      PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
90  if (!sym_fspec)
91    return nullptr;
92
93  DataBufferSP sym_file_data_sp;
94  lldb::offset_t sym_file_data_offset = 0;
95  ObjectFileSP sym_objfile_sp = ObjectFile::FindPlugin(
96      module_sp, &sym_fspec, 0, FileSystem::Instance().GetByteSize(sym_fspec),
97      sym_file_data_sp, sym_file_data_offset);
98  if (!sym_objfile_sp)
99    return nullptr;
100
101  // This objfile is for debugging purposes.
102  sym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo);
103
104  SymbolVendorWasm *symbol_vendor = new SymbolVendorWasm(module_sp);
105
106  // Get the module unified section list and add our debug sections to
107  // that.
108  SectionList *module_section_list = module_sp->GetSectionList();
109  SectionList *objfile_section_list = sym_objfile_sp->GetSectionList();
110
111  if (!module_section_list || !objfile_section_list)
112    return nullptr;
113
114  static const SectionType g_sections[] = {
115      eSectionTypeDWARFDebugAbbrev,   eSectionTypeDWARFDebugAddr,
116      eSectionTypeDWARFDebugAranges,  eSectionTypeDWARFDebugCuIndex,
117      eSectionTypeDWARFDebugFrame,    eSectionTypeDWARFDebugInfo,
118      eSectionTypeDWARFDebugLine,     eSectionTypeDWARFDebugLineStr,
119      eSectionTypeDWARFDebugLoc,      eSectionTypeDWARFDebugLocLists,
120      eSectionTypeDWARFDebugMacInfo,  eSectionTypeDWARFDebugMacro,
121      eSectionTypeDWARFDebugPubNames, eSectionTypeDWARFDebugPubTypes,
122      eSectionTypeDWARFDebugRanges,   eSectionTypeDWARFDebugRngLists,
123      eSectionTypeDWARFDebugStr,      eSectionTypeDWARFDebugStrOffsets,
124      eSectionTypeDWARFDebugTypes};
125  for (SectionType section_type : g_sections) {
126    if (SectionSP section_sp =
127            objfile_section_list->FindSectionByType(section_type, true)) {
128      if (SectionSP module_section_sp =
129              module_section_list->FindSectionByType(section_type, true))
130        module_section_list->ReplaceSection(module_section_sp->GetID(),
131                                            section_sp);
132      else
133        module_section_list->AddSection(section_sp);
134    }
135  }
136
137  symbol_vendor->AddSymbolFileRepresentation(sym_objfile_sp);
138  return symbol_vendor;
139}
140