1 | //===-- SymbolFileDWARFDebugMap.h ------------------------------*- C++ -*-===// |
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 | #ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H |
10 | #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H |
11 | |
12 | #include "DIERef.h" |
13 | #include "lldb/Symbol/SymbolFile.h" |
14 | #include "lldb/Utility/RangeMap.h" |
15 | #include "llvm/Support/Chrono.h" |
16 | #include <bitset> |
17 | #include <map> |
18 | #include <optional> |
19 | #include <vector> |
20 | |
21 | #include "UniqueDWARFASTType.h" |
22 | #include "lldb/Utility/StructuredData.h" |
23 | #include "lldb/lldb-private-enumerations.h" |
24 | |
25 | class DWARFASTParserClang; |
26 | |
27 | namespace lldb_private::plugin { |
28 | namespace dwarf { |
29 | class SymbolFileDWARF; |
30 | class DWARFCompileUnit; |
31 | class DWARFDebugAranges; |
32 | class DWARFDeclContext; |
33 | |
34 | class SymbolFileDWARFDebugMap : public SymbolFileCommon { |
35 | /// LLVM RTTI support. |
36 | static char ID; |
37 | |
38 | public: |
39 | /// LLVM RTTI support. |
40 | /// \{ |
41 | bool isA(const void *ClassID) const override { |
42 | return ClassID == &ID || SymbolFileCommon::isA(ClassID); |
43 | } |
44 | static bool classof(const SymbolFile *obj) { return obj->isA(ClassID: &ID); } |
45 | /// \} |
46 | |
47 | // Static Functions |
48 | static void Initialize(); |
49 | |
50 | static void Terminate(); |
51 | |
52 | static llvm::StringRef GetPluginNameStatic() { return "dwarf-debugmap" ; } |
53 | |
54 | static llvm::StringRef GetPluginDescriptionStatic(); |
55 | |
56 | static SymbolFile *CreateInstance(lldb::ObjectFileSP objfile_sp); |
57 | |
58 | // Constructors and Destructors |
59 | SymbolFileDWARFDebugMap(lldb::ObjectFileSP objfile_sp); |
60 | ~SymbolFileDWARFDebugMap() override; |
61 | |
62 | uint32_t CalculateAbilities() override; |
63 | void InitializeObject() override; |
64 | |
65 | // Compile Unit function calls |
66 | lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override; |
67 | XcodeSDK ParseXcodeSDK(CompileUnit &comp_unit) override; |
68 | llvm::SmallSet<lldb::LanguageType, 4> |
69 | ParseAllLanguages(CompileUnit &comp_unit) override; |
70 | size_t ParseFunctions(CompileUnit &comp_unit) override; |
71 | bool ParseLineTable(CompileUnit &comp_unit) override; |
72 | bool ParseDebugMacros(CompileUnit &comp_unit) override; |
73 | |
74 | bool ForEachExternalModule(CompileUnit &, llvm::DenseSet<SymbolFile *> &, |
75 | llvm::function_ref<bool(Module &)>) override; |
76 | |
77 | bool ParseSupportFiles(CompileUnit &comp_unit, |
78 | SupportFileList &support_files) override; |
79 | |
80 | bool ParseIsOptimized(CompileUnit &comp_unit) override; |
81 | |
82 | size_t ParseTypes(CompileUnit &comp_unit) override; |
83 | |
84 | bool |
85 | ParseImportedModules(const SymbolContext &sc, |
86 | std::vector<SourceModule> &imported_modules) override; |
87 | size_t ParseBlocksRecursive(Function &func) override; |
88 | size_t ParseVariablesForContext(const SymbolContext &sc) override; |
89 | |
90 | Type *ResolveTypeUID(lldb::user_id_t type_uid) override; |
91 | std::optional<ArrayInfo> |
92 | GetDynamicArrayInfoForUID(lldb::user_id_t type_uid, |
93 | const ExecutionContext *exe_ctx) override; |
94 | |
95 | CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override; |
96 | CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override; |
97 | std::vector<CompilerContext> |
98 | GetCompilerContextForUID(lldb::user_id_t uid) override; |
99 | void ParseDeclsForContext(CompilerDeclContext decl_ctx) override; |
100 | |
101 | bool CompleteType(CompilerType &compiler_type) override; |
102 | uint32_t ResolveSymbolContext(const Address &so_addr, |
103 | lldb::SymbolContextItem resolve_scope, |
104 | SymbolContext &sc) override; |
105 | uint32_t ResolveSymbolContext(const SourceLocationSpec &src_location_spec, |
106 | lldb::SymbolContextItem resolve_scope, |
107 | SymbolContextList &sc_list) override; |
108 | |
109 | Status CalculateFrameVariableError(StackFrame &frame) override; |
110 | |
111 | void FindGlobalVariables(ConstString name, |
112 | const CompilerDeclContext &parent_decl_ctx, |
113 | uint32_t max_matches, |
114 | VariableList &variables) override; |
115 | void FindGlobalVariables(const RegularExpression ®ex, uint32_t max_matches, |
116 | VariableList &variables) override; |
117 | void FindFunctions(const Module::LookupInfo &lookup_info, |
118 | const CompilerDeclContext &parent_decl_ctx, |
119 | bool include_inlines, SymbolContextList &sc_list) override; |
120 | void FindFunctions(const RegularExpression ®ex, bool include_inlines, |
121 | SymbolContextList &sc_list) override; |
122 | void FindTypes(const lldb_private::TypeQuery &match, |
123 | lldb_private::TypeResults &results) override; |
124 | CompilerDeclContext FindNamespace(ConstString name, |
125 | const CompilerDeclContext &parent_decl_ctx, |
126 | bool only_root_namespaces) override; |
127 | void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, |
128 | TypeList &type_list) override; |
129 | std::vector<std::unique_ptr<CallEdge>> |
130 | ParseCallEdgesInFunction(UserID func_id) override; |
131 | |
132 | void DumpClangAST(Stream &s) override; |
133 | |
134 | /// List separate oso files. |
135 | bool GetSeparateDebugInfo(StructuredData::Dictionary &d, |
136 | bool errors_only) override; |
137 | |
138 | // PluginInterface protocol |
139 | llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } |
140 | |
141 | // Statistics overrides. |
142 | ModuleList GetDebugInfoModules() override; |
143 | |
144 | void |
145 | GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override; |
146 | |
147 | protected: |
148 | enum { kHaveInitializedOSOs = (1 << 0), kNumFlags }; |
149 | |
150 | friend class DebugMapModule; |
151 | friend class ::DWARFASTParserClang; |
152 | friend class DWARFCompileUnit; |
153 | friend class SymbolFileDWARF; |
154 | struct OSOInfo { |
155 | lldb::ModuleSP module_sp; |
156 | |
157 | OSOInfo() : module_sp() {} |
158 | }; |
159 | |
160 | typedef std::shared_ptr<OSOInfo> OSOInfoSP; |
161 | |
162 | typedef RangeDataVector<lldb::addr_t, lldb::addr_t, lldb::addr_t> |
163 | FileRangeMap; |
164 | |
165 | // Class specific types |
166 | struct CompileUnitInfo { |
167 | FileSpec so_file; |
168 | ConstString oso_path; |
169 | llvm::sys::TimePoint<> oso_mod_time; |
170 | Status oso_load_error; |
171 | OSOInfoSP oso_sp; |
172 | /// The compile units that an object file contains. |
173 | llvm::SmallVector<lldb::CompUnitSP, 2> compile_units_sps; |
174 | /// A map from the compile unit ID to its index in the vector. |
175 | llvm::SmallDenseMap<uint64_t, uint64_t, 2> id_to_index_map; |
176 | uint32_t first_symbol_index = UINT32_MAX; |
177 | uint32_t last_symbol_index = UINT32_MAX; |
178 | uint32_t first_symbol_id = UINT32_MAX; |
179 | uint32_t last_symbol_id = UINT32_MAX; |
180 | FileRangeMap file_range_map; |
181 | bool file_range_map_valid = false; |
182 | |
183 | CompileUnitInfo() = default; |
184 | |
185 | const FileRangeMap &GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile); |
186 | }; |
187 | |
188 | // Protected Member Functions |
189 | void InitOSO(); |
190 | |
191 | /// This function actually returns the number of object files, which may be |
192 | /// less than the actual number of compile units, since an object file may |
193 | /// contain more than one compile unit. SymbolFileDWARFDebugMap looks up the |
194 | /// number of compile units by reading the nlist symbol table, which |
195 | /// currently, on macOS, only reports one compile unit per object file, and |
196 | /// there's no efficient way to calculate the actual number of compile units |
197 | /// upfront. |
198 | uint32_t CalculateNumCompileUnits() override; |
199 | |
200 | /// This function actually returns the first compile unit the object file at |
201 | /// the given index contains. |
202 | lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; |
203 | |
204 | static uint32_t GetOSOIndexFromUserID(lldb::user_id_t uid) { |
205 | std::optional<uint32_t> OsoNum = DIERef(uid).file_index(); |
206 | lldbassert(OsoNum && "Invalid OSO Index" ); |
207 | return *OsoNum; |
208 | } |
209 | |
210 | static SymbolFileDWARF *GetSymbolFileAsSymbolFileDWARF(SymbolFile *sym_file); |
211 | |
212 | bool GetFileSpecForSO(uint32_t oso_idx, FileSpec &file_spec); |
213 | |
214 | CompileUnitInfo *GetCompUnitInfo(const SymbolContext &sc); |
215 | CompileUnitInfo *GetCompUnitInfo(const CompileUnit &comp_unit); |
216 | |
217 | size_t GetCompUnitInfosForModule(const Module *oso_module, |
218 | std::vector<CompileUnitInfo *> &cu_infos); |
219 | |
220 | Module *GetModuleByCompUnitInfo(CompileUnitInfo *comp_unit_info); |
221 | |
222 | Module *GetModuleByOSOIndex(uint32_t oso_idx); |
223 | |
224 | ObjectFile *GetObjectFileByCompUnitInfo(CompileUnitInfo *comp_unit_info); |
225 | |
226 | ObjectFile *GetObjectFileByOSOIndex(uint32_t oso_idx); |
227 | |
228 | uint32_t GetCompUnitInfoIndex(const CompileUnitInfo *comp_unit_info); |
229 | |
230 | SymbolFileDWARF *GetSymbolFile(const SymbolContext &sc); |
231 | SymbolFileDWARF *GetSymbolFile(const CompileUnit &comp_unit); |
232 | |
233 | SymbolFileDWARF *GetSymbolFileByCompUnitInfo(CompileUnitInfo *comp_unit_info); |
234 | |
235 | SymbolFileDWARF *GetSymbolFileByOSOIndex(uint32_t oso_idx); |
236 | |
237 | /// If closure returns \ref IterationAction::Continue, iteration |
238 | /// continues. Otherwise, iteration terminates. |
239 | void |
240 | ForEachSymbolFile(std::function<IterationAction(SymbolFileDWARF *)> closure) { |
241 | for (uint32_t oso_idx = 0, num_oso_idxs = m_compile_unit_infos.size(); |
242 | oso_idx < num_oso_idxs; ++oso_idx) { |
243 | if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx)) { |
244 | if (closure(oso_dwarf) == IterationAction::Stop) |
245 | return; |
246 | } |
247 | } |
248 | } |
249 | |
250 | CompileUnitInfo *GetCompileUnitInfoForSymbolWithIndex(uint32_t symbol_idx, |
251 | uint32_t *oso_idx_ptr); |
252 | |
253 | CompileUnitInfo *GetCompileUnitInfoForSymbolWithID(lldb::user_id_t symbol_id, |
254 | uint32_t *oso_idx_ptr); |
255 | |
256 | static int |
257 | SymbolContainsSymbolWithIndex(uint32_t *symbol_idx_ptr, |
258 | const CompileUnitInfo *comp_unit_info); |
259 | |
260 | static int SymbolContainsSymbolWithID(lldb::user_id_t *symbol_idx_ptr, |
261 | const CompileUnitInfo *comp_unit_info); |
262 | |
263 | void |
264 | PrivateFindGlobalVariables(ConstString name, |
265 | const CompilerDeclContext &parent_decl_ctx, |
266 | const std::vector<uint32_t> &name_symbol_indexes, |
267 | uint32_t max_matches, VariableList &variables); |
268 | |
269 | void SetCompileUnit(SymbolFileDWARF *oso_dwarf, |
270 | const lldb::CompUnitSP &cu_sp); |
271 | |
272 | /// Returns the compile unit associated with the dwarf compile unit. This may |
273 | /// be one of the extra compile units an object file contains which isn't |
274 | /// reachable by ParseCompileUnitAtIndex(uint32_t). |
275 | lldb::CompUnitSP GetCompileUnit(SymbolFileDWARF *oso_dwarf, |
276 | DWARFCompileUnit &dwarf_cu); |
277 | |
278 | CompileUnitInfo *GetCompileUnitInfo(SymbolFileDWARF *oso_dwarf); |
279 | |
280 | lldb::TypeSP FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die); |
281 | |
282 | bool Supports_DW_AT_APPLE_objc_complete_type(SymbolFileDWARF *skip_dwarf_oso); |
283 | |
284 | lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE( |
285 | const DWARFDIE &die, ConstString type_name, bool must_be_implementation); |
286 | |
287 | UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() { |
288 | return m_unique_ast_type_map; |
289 | } |
290 | |
291 | // OSOEntry |
292 | class OSOEntry { |
293 | public: |
294 | OSOEntry() = default; |
295 | |
296 | OSOEntry(uint32_t exe_sym_idx, lldb::addr_t oso_file_addr) |
297 | : m_exe_sym_idx(exe_sym_idx), m_oso_file_addr(oso_file_addr) {} |
298 | |
299 | uint32_t GetExeSymbolIndex() const { return m_exe_sym_idx; } |
300 | |
301 | bool operator<(const OSOEntry &rhs) const { |
302 | return m_exe_sym_idx < rhs.m_exe_sym_idx; |
303 | } |
304 | |
305 | lldb::addr_t GetOSOFileAddress() const { return m_oso_file_addr; } |
306 | |
307 | void SetOSOFileAddress(lldb::addr_t oso_file_addr) { |
308 | m_oso_file_addr = oso_file_addr; |
309 | } |
310 | |
311 | protected: |
312 | uint32_t m_exe_sym_idx = UINT32_MAX; |
313 | lldb::addr_t m_oso_file_addr = LLDB_INVALID_ADDRESS; |
314 | }; |
315 | |
316 | typedef RangeDataVector<lldb::addr_t, lldb::addr_t, OSOEntry> DebugMap; |
317 | |
318 | // Member Variables |
319 | std::bitset<kNumFlags> m_flags; |
320 | std::vector<CompileUnitInfo> m_compile_unit_infos; |
321 | std::vector<uint32_t> m_func_indexes; // Sorted by address |
322 | std::vector<uint32_t> m_glob_indexes; |
323 | std::map<std::pair<ConstString, llvm::sys::TimePoint<>>, OSOInfoSP> m_oso_map; |
324 | UniqueDWARFASTTypeMap m_unique_ast_type_map; |
325 | LazyBool m_supports_DW_AT_APPLE_objc_complete_type; |
326 | DebugMap m_debug_map; |
327 | |
328 | // When an object file from the debug map gets parsed in |
329 | // SymbolFileDWARF, it needs to tell the debug map about the object |
330 | // files addresses by calling this function once for each N_FUN, |
331 | // N_GSYM and N_STSYM and after all entries in the debug map have |
332 | // been matched up, FinalizeOSOFileRanges() should be called. |
333 | bool AddOSOFileRange(CompileUnitInfo *cu_info, lldb::addr_t exe_file_addr, |
334 | lldb::addr_t exe_byte_size, lldb::addr_t oso_file_addr, |
335 | lldb::addr_t oso_byte_size); |
336 | |
337 | // Called after calling AddOSOFileRange() for each object file debug |
338 | // map entry to finalize the info for the unlinked compile unit. |
339 | void FinalizeOSOFileRanges(CompileUnitInfo *cu_info); |
340 | |
341 | /// Convert \a addr from a .o file address, to an executable address. |
342 | /// |
343 | /// \param[in] addr |
344 | /// A section offset address from a .o file |
345 | /// |
346 | /// \return |
347 | /// Returns true if \a addr was converted to be an executable |
348 | /// section/offset address, false otherwise. |
349 | bool LinkOSOAddress(Address &addr); |
350 | |
351 | /// Convert a .o file "file address" to an executable "file address". |
352 | /// |
353 | /// \param[in] oso_symfile |
354 | /// The DWARF symbol file that contains \a oso_file_addr |
355 | /// |
356 | /// \param[in] oso_file_addr |
357 | /// A .o file "file address" to convert. |
358 | /// |
359 | /// \return |
360 | /// LLDB_INVALID_ADDRESS if \a oso_file_addr is not in the |
361 | /// linked executable, otherwise a valid "file address" from the |
362 | /// linked executable that contains the debug map. |
363 | lldb::addr_t LinkOSOFileAddress(SymbolFileDWARF *oso_symfile, |
364 | lldb::addr_t oso_file_addr); |
365 | |
366 | /// Given a line table full of lines with "file addresses" that are |
367 | /// for a .o file represented by \a oso_symfile, link a new line table |
368 | /// and return it. |
369 | /// |
370 | /// \param[in] oso_symfile |
371 | /// The DWARF symbol file that produced the \a line_table |
372 | /// |
373 | /// \param[in] line_table |
374 | /// A pointer to the line table. |
375 | /// |
376 | /// \return |
377 | /// Returns a valid line table full of linked addresses, or NULL |
378 | /// if none of the line table addresses exist in the main |
379 | /// executable. |
380 | LineTable *LinkOSOLineTable(SymbolFileDWARF *oso_symfile, |
381 | LineTable *line_table); |
382 | |
383 | size_t AddOSOARanges(SymbolFileDWARF *dwarf2Data, |
384 | DWARFDebugAranges *debug_aranges); |
385 | }; |
386 | } // namespace dwarf |
387 | } // namespace lldb_private::plugin |
388 | |
389 | #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H |
390 | |