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 
LLDB_PLUGIN_DEFINE(SymbolVendorPECOFF)27 LLDB_PLUGIN_DEFINE(SymbolVendorPECOFF)
28 
29 // SymbolVendorPECOFF constructor
30 SymbolVendorPECOFF::SymbolVendorPECOFF(const lldb::ModuleSP &module_sp)
31     : SymbolVendor(module_sp) {}
32 
Initialize()33 void SymbolVendorPECOFF::Initialize() {
34   PluginManager::RegisterPlugin(GetPluginNameStatic(),
35                                 GetPluginDescriptionStatic(), CreateInstance);
36 }
37 
Terminate()38 void SymbolVendorPECOFF::Terminate() {
39   PluginManager::UnregisterPlugin(CreateInstance);
40 }
41 
GetPluginDescriptionStatic()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 *
CreateInstance(const lldb::ModuleSP & module_sp,lldb_private::Stream * feedback_strm)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>(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           lldb::eSectionTypeDWARFDebugInfo, 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(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(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, 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, &dsym_fspec, 0, FileSystem::Instance().GetByteSize(dsym_fspec),
97       dsym_file_data_sp, 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(section_type, true)) {
123       if (SectionSP module_section_sp =
124               module_section_list->FindSectionByType(section_type, true))
125         module_section_list->ReplaceSection(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(dsym_objfile_sp);
134   return symbol_vendor;
135 }
136