1 | //===-- SymbolVendorPECOFF.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 "SymbolVendorPECOFF.h" |
10 | |
11 | #include <cstring> |
12 | |
13 | #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" |
14 | #include "lldb/Core/Module.h" |
15 | #include "lldb/Core/ModuleSpec.h" |
16 | #include "lldb/Core/PluginManager.h" |
17 | #include "lldb/Core/Section.h" |
18 | #include "lldb/Host/Host.h" |
19 | #include "lldb/Symbol/ObjectFile.h" |
20 | #include "lldb/Target/Target.h" |
21 | #include "lldb/Utility/StreamString.h" |
22 | #include "lldb/Utility/Timer.h" |
23 | |
24 | using namespace lldb; |
25 | using namespace lldb_private; |
26 | |
27 | LLDB_PLUGIN_DEFINE(SymbolVendorPECOFF) |
28 | |
29 | // SymbolVendorPECOFF constructor |
30 | SymbolVendorPECOFF::SymbolVendorPECOFF(const lldb::ModuleSP &module_sp) |
31 | : SymbolVendor(module_sp) {} |
32 | |
33 | void SymbolVendorPECOFF::Initialize() { |
34 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
35 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance); |
36 | } |
37 | |
38 | void SymbolVendorPECOFF::Terminate() { |
39 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
40 | } |
41 | |
42 | llvm::StringRef SymbolVendorPECOFF::GetPluginDescriptionStatic() { |
43 | return "Symbol vendor for PE/COFF that looks for dSYM files that match " |
44 | "executables." ; |
45 | } |
46 | |
47 | // CreateInstance |
48 | // |
49 | // Platforms can register a callback to use when creating symbol vendors to |
50 | // allow for complex debug information file setups, and to also allow for |
51 | // finding separate debug information files. |
52 | SymbolVendor * |
53 | SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP &module_sp, |
54 | lldb_private::Stream *feedback_strm) { |
55 | if (!module_sp) |
56 | return nullptr; |
57 | |
58 | ObjectFilePECOFF *obj_file = |
59 | llvm::dyn_cast_or_null<ObjectFilePECOFF>(Val: module_sp->GetObjectFile()); |
60 | if (!obj_file) |
61 | return nullptr; |
62 | |
63 | lldb_private::UUID uuid = obj_file->GetUUID(); |
64 | if (!uuid) |
65 | return nullptr; |
66 | |
67 | // If the main object file already contains debug info, then we are done. |
68 | if (obj_file->GetSectionList()->FindSectionByType( |
69 | sect_type: lldb::eSectionTypeDWARFDebugInfo, check_children: true)) |
70 | return nullptr; |
71 | |
72 | // If the module specified a filespec, use that. |
73 | FileSpec fspec = module_sp->GetSymbolFileFileSpec(); |
74 | // Otherwise, try gnu_debuglink, if one exists. |
75 | if (!fspec) |
76 | fspec = obj_file->GetDebugLink().value_or(u: FileSpec()); |
77 | |
78 | LLDB_SCOPED_TIMERF("SymbolVendorPECOFF::CreateInstance (module = %s)" , |
79 | module_sp->GetFileSpec().GetPath().c_str()); |
80 | |
81 | ModuleSpec module_spec; |
82 | |
83 | module_spec.GetFileSpec() = obj_file->GetFileSpec(); |
84 | FileSystem::Instance().Resolve(file_spec&: module_spec.GetFileSpec()); |
85 | module_spec.GetSymbolFileSpec() = fspec; |
86 | module_spec.GetUUID() = uuid; |
87 | FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); |
88 | FileSpec dsym_fspec = |
89 | PluginManager::LocateExecutableSymbolFile(module_spec, default_search_paths: search_paths); |
90 | if (!dsym_fspec) |
91 | return nullptr; |
92 | |
93 | DataBufferSP dsym_file_data_sp; |
94 | lldb::offset_t dsym_file_data_offset = 0; |
95 | ObjectFileSP dsym_objfile_sp = ObjectFile::FindPlugin( |
96 | module_sp, file_spec: &dsym_fspec, file_offset: 0, file_size: FileSystem::Instance().GetByteSize(file_spec: dsym_fspec), |
97 | data_sp&: dsym_file_data_sp, data_offset&: dsym_file_data_offset); |
98 | if (!dsym_objfile_sp) |
99 | return nullptr; |
100 | |
101 | // This objfile is for debugging purposes. |
102 | dsym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo); |
103 | |
104 | // Get the module unified section list and add our debug sections to |
105 | // that. |
106 | SectionList *module_section_list = module_sp->GetSectionList(); |
107 | SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList(); |
108 | if (!objfile_section_list || !module_section_list) |
109 | return nullptr; |
110 | |
111 | static const SectionType g_sections[] = { |
112 | eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAranges, |
113 | eSectionTypeDWARFDebugFrame, eSectionTypeDWARFDebugInfo, |
114 | eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLoc, |
115 | eSectionTypeDWARFDebugLocLists, eSectionTypeDWARFDebugMacInfo, |
116 | eSectionTypeDWARFDebugNames, eSectionTypeDWARFDebugPubNames, |
117 | eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, |
118 | eSectionTypeDWARFDebugStr, eSectionTypeDWARFDebugTypes, |
119 | }; |
120 | for (SectionType section_type : g_sections) { |
121 | if (SectionSP section_sp = |
122 | objfile_section_list->FindSectionByType(sect_type: section_type, check_children: true)) { |
123 | if (SectionSP module_section_sp = |
124 | module_section_list->FindSectionByType(sect_type: section_type, check_children: true)) |
125 | module_section_list->ReplaceSection(sect_id: module_section_sp->GetID(), |
126 | section_sp); |
127 | else |
128 | module_section_list->AddSection(section_sp); |
129 | } |
130 | } |
131 | |
132 | SymbolVendorPECOFF *symbol_vendor = new SymbolVendorPECOFF(module_sp); |
133 | symbol_vendor->AddSymbolFileRepresentation(objfile_sp: dsym_objfile_sp); |
134 | return symbol_vendor; |
135 | } |
136 | |