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 
28 LLDB_PLUGIN_DEFINE(SymbolVendorPECOFF)
29 
30 // SymbolVendorPECOFF constructor
31 SymbolVendorPECOFF::SymbolVendorPECOFF(const lldb::ModuleSP &module_sp)
32     : SymbolVendor(module_sp) {}
33 
34 void SymbolVendorPECOFF::Initialize() {
35   PluginManager::RegisterPlugin(GetPluginNameStatic(),
36                                 GetPluginDescriptionStatic(), CreateInstance);
37 }
38 
39 void SymbolVendorPECOFF::Terminate() {
40   PluginManager::UnregisterPlugin(CreateInstance);
41 }
42 
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 *
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   SymbolVendorPECOFF *symbol_vendor = new SymbolVendorPECOFF(module_sp);
106 
107   // Get the module unified section list and add our debug sections to
108   // that.
109   SectionList *module_section_list = module_sp->GetSectionList();
110   SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList();
111   if (!objfile_section_list || !module_section_list)
112     return nullptr;
113 
114   static const SectionType g_sections[] = {
115       eSectionTypeDWARFDebugAbbrev,   eSectionTypeDWARFDebugAranges,
116       eSectionTypeDWARFDebugFrame,    eSectionTypeDWARFDebugInfo,
117       eSectionTypeDWARFDebugLine,     eSectionTypeDWARFDebugLoc,
118       eSectionTypeDWARFDebugLocLists, eSectionTypeDWARFDebugMacInfo,
119       eSectionTypeDWARFDebugNames,    eSectionTypeDWARFDebugPubNames,
120       eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges,
121       eSectionTypeDWARFDebugStr,      eSectionTypeDWARFDebugTypes,
122   };
123   for (SectionType section_type : g_sections) {
124     if (SectionSP section_sp =
125             objfile_section_list->FindSectionByType(section_type, true)) {
126       if (SectionSP module_section_sp =
127               module_section_list->FindSectionByType(section_type, true))
128         module_section_list->ReplaceSection(module_section_sp->GetID(),
129                                             section_sp);
130       else
131         module_section_list->AddSection(section_sp);
132     }
133   }
134 
135   symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
136   return symbol_vendor;
137 }
138