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 | |
25 | using namespace lldb; |
26 | using namespace lldb_private; |
27 | using namespace lldb_private::wasm; |
28 | |
29 | LLDB_PLUGIN_DEFINE(SymbolVendorWasm) |
30 | |
31 | // SymbolVendorWasm constructor |
32 | SymbolVendorWasm::SymbolVendorWasm(const lldb::ModuleSP &module_sp) |
33 | : SymbolVendor(module_sp) {} |
34 | |
35 | void SymbolVendorWasm::Initialize() { |
36 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
37 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance); |
38 | } |
39 | |
40 | void SymbolVendorWasm::Terminate() { |
41 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
42 | } |
43 | |
44 | llvm::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. |
54 | SymbolVendor * |
55 | SymbolVendorWasm::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>(Val: 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 | sect_type: lldb::eSectionTypeDWARFDebugInfo, check_children: 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(file_spec&: 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, default_search_paths: 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, file_spec: &sym_fspec, file_offset: 0, file_size: FileSystem::Instance().GetByteSize(file_spec: sym_fspec), |
97 | data_sp&: sym_file_data_sp, data_offset&: 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(sect_type: section_type, check_children: true)) { |
128 | if (SectionSP module_section_sp = |
129 | module_section_list->FindSectionByType(sect_type: section_type, check_children: true)) |
130 | module_section_list->ReplaceSection(sect_id: module_section_sp->GetID(), |
131 | section_sp); |
132 | else |
133 | module_section_list->AddSection(section_sp); |
134 | } |
135 | } |
136 | |
137 | symbol_vendor->AddSymbolFileRepresentation(objfile_sp: sym_objfile_sp); |
138 | return symbol_vendor; |
139 | } |
140 | |