1 | //===-- SymbolVendorELF.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 "SymbolVendorELF.h" |
10 | |
11 | #include <cstring> |
12 | |
13 | #include "Plugins/ObjectFile/ELF/ObjectFileELF.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(SymbolVendorELF) |
28 | |
29 | // SymbolVendorELF constructor |
30 | SymbolVendorELF::SymbolVendorELF(const lldb::ModuleSP &module_sp) |
31 | : SymbolVendor(module_sp) {} |
32 | |
33 | void SymbolVendorELF::Initialize() { |
34 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
35 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance); |
36 | } |
37 | |
38 | void SymbolVendorELF::Terminate() { |
39 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
40 | } |
41 | |
42 | llvm::StringRef SymbolVendorELF::GetPluginDescriptionStatic() { |
43 | return "Symbol vendor for ELF that looks for dSYM files that match " |
44 | "executables." ; |
45 | } |
46 | |
47 | // If this is needed elsewhere, it can be exported/moved. |
48 | static bool IsDwpSymbolFile(const lldb::ModuleSP &module_sp, |
49 | const FileSpec &file_spec) { |
50 | DataBufferSP dwp_file_data_sp; |
51 | lldb::offset_t dwp_file_data_offset = 0; |
52 | // Try to create an ObjectFile from the file_spec. |
53 | ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin( |
54 | module_sp, file_spec: &file_spec, file_offset: 0, file_size: FileSystem::Instance().GetByteSize(file_spec), |
55 | data_sp&: dwp_file_data_sp, data_offset&: dwp_file_data_offset); |
56 | // The presence of a debug_cu_index section is the key identifying feature of |
57 | // a DWP file. Make sure we don't fill in the section list on dwp_obj_file |
58 | // (by calling GetSectionList(false)) as this function could be called before |
59 | // we may have all the symbol files collected and available. |
60 | return dwp_obj_file && ObjectFileELF::classof(obj: dwp_obj_file.get()) && |
61 | dwp_obj_file->GetSectionList(update_module_section_list: false)->FindSectionByType( |
62 | sect_type: eSectionTypeDWARFDebugCuIndex, check_children: false); |
63 | } |
64 | |
65 | // CreateInstance |
66 | // |
67 | // Platforms can register a callback to use when creating symbol vendors to |
68 | // allow for complex debug information file setups, and to also allow for |
69 | // finding separate debug information files. |
70 | SymbolVendor * |
71 | SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, |
72 | lldb_private::Stream *feedback_strm) { |
73 | if (!module_sp) |
74 | return nullptr; |
75 | |
76 | ObjectFileELF *obj_file = |
77 | llvm::dyn_cast_or_null<ObjectFileELF>(Val: module_sp->GetObjectFile()); |
78 | if (!obj_file) |
79 | return nullptr; |
80 | |
81 | lldb_private::UUID uuid = obj_file->GetUUID(); |
82 | if (!uuid) |
83 | return nullptr; |
84 | |
85 | // If the main object file already contains debug info, then we are done. |
86 | if (obj_file->GetSectionList()->FindSectionByType( |
87 | sect_type: lldb::eSectionTypeDWARFDebugInfo, check_children: true)) |
88 | return nullptr; |
89 | |
90 | // If the module specified a filespec, use that. |
91 | FileSpec fspec = module_sp->GetSymbolFileFileSpec(); |
92 | // Otherwise, try gnu_debuglink, if one exists. |
93 | if (!fspec) |
94 | fspec = obj_file->GetDebugLink().value_or(u: FileSpec()); |
95 | |
96 | LLDB_SCOPED_TIMERF("SymbolVendorELF::CreateInstance (module = %s)" , |
97 | module_sp->GetFileSpec().GetPath().c_str()); |
98 | |
99 | ModuleSpec module_spec; |
100 | |
101 | module_spec.GetFileSpec() = obj_file->GetFileSpec(); |
102 | FileSystem::Instance().Resolve(file_spec&: module_spec.GetFileSpec()); |
103 | module_spec.GetSymbolFileSpec() = fspec; |
104 | module_spec.GetUUID() = uuid; |
105 | FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); |
106 | FileSpec dsym_fspec = PluginManager::LocateExecutableSymbolFile( |
107 | module_spec, default_search_paths: search_paths, map&: module_sp->GetSymbolLocatorStatistics()); |
108 | if (!dsym_fspec || IsDwpSymbolFile(module_sp, file_spec: dsym_fspec)) { |
109 | // If we have a stripped binary or if we have a DWP file, SymbolLocator |
110 | // plugins may be able to give us an unstripped binary or an |
111 | // 'only-keep-debug' stripped file. |
112 | ModuleSpec unstripped_spec = PluginManager::LocateExecutableObjectFile( |
113 | module_spec, map&: module_sp->GetSymbolLocatorStatistics()); |
114 | if (!unstripped_spec) |
115 | return nullptr; |
116 | // The default SymbolLocator plugin returns the original binary if no other |
117 | // plugin finds something better. |
118 | if (unstripped_spec.GetFileSpec() == module_spec.GetFileSpec()) |
119 | return nullptr; |
120 | dsym_fspec = unstripped_spec.GetFileSpec(); |
121 | } |
122 | |
123 | DataBufferSP dsym_file_data_sp; |
124 | lldb::offset_t dsym_file_data_offset = 0; |
125 | ObjectFileSP dsym_objfile_sp = ObjectFile::FindPlugin( |
126 | module_sp, file_spec: &dsym_fspec, file_offset: 0, file_size: FileSystem::Instance().GetByteSize(file_spec: dsym_fspec), |
127 | data_sp&: dsym_file_data_sp, data_offset&: dsym_file_data_offset); |
128 | if (!dsym_objfile_sp) |
129 | return nullptr; |
130 | // This objfile is for debugging purposes. Sadly, ObjectFileELF won't |
131 | // be able to figure this out consistently as the symbol file may not |
132 | // have stripped the code sections, etc. |
133 | dsym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo); |
134 | |
135 | SymbolVendorELF *symbol_vendor = new SymbolVendorELF(module_sp); |
136 | |
137 | // Get the module unified section list and add our debug sections to |
138 | // that. |
139 | SectionList *module_section_list = module_sp->GetSectionList(); |
140 | SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList(); |
141 | |
142 | if (!module_section_list || !objfile_section_list) |
143 | return nullptr; |
144 | |
145 | static const SectionType g_sections[] = { |
146 | eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAddr, |
147 | eSectionTypeDWARFDebugAranges, eSectionTypeDWARFDebugCuIndex, |
148 | eSectionTypeDWARFDebugFrame, eSectionTypeDWARFDebugInfo, |
149 | eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLineStr, |
150 | eSectionTypeDWARFDebugLoc, eSectionTypeDWARFDebugLocLists, |
151 | eSectionTypeDWARFDebugMacInfo, eSectionTypeDWARFDebugMacro, |
152 | eSectionTypeDWARFDebugNames, eSectionTypeDWARFDebugPubNames, |
153 | eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, |
154 | eSectionTypeDWARFDebugRngLists, eSectionTypeDWARFDebugStr, |
155 | eSectionTypeDWARFDebugStrOffsets, eSectionTypeDWARFDebugTypes, |
156 | eSectionTypeELFSymbolTable, eSectionTypeDWARFGNUDebugAltLink, |
157 | }; |
158 | for (SectionType section_type : g_sections) { |
159 | if (SectionSP section_sp = |
160 | objfile_section_list->FindSectionByType(sect_type: section_type, check_children: true)) { |
161 | if (SectionSP module_section_sp = |
162 | module_section_list->FindSectionByType(sect_type: section_type, check_children: true)) |
163 | module_section_list->ReplaceSection(sect_id: module_section_sp->GetID(), |
164 | section_sp); |
165 | else |
166 | module_section_list->AddSection(section_sp); |
167 | } |
168 | } |
169 | |
170 | symbol_vendor->AddSymbolFileRepresentation(objfile_sp: dsym_objfile_sp); |
171 | return symbol_vendor; |
172 | } |
173 | |