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