399 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H10#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H11 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 25class DWARFASTParserClang;26 27namespace lldb_private::plugin {28namespace dwarf {29class SymbolFileDWARF;30class DWARFCompileUnit;31class DWARFDebugAranges;32class DWARFDeclContext;33 34class SymbolFileDWARFDebugMap : public SymbolFileCommon {35 /// LLVM RTTI support.36 static char ID;37 38public: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(&ID); }45 /// \}46 47 // Static Functions48 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 Destructors59 SymbolFileDWARFDebugMap(lldb::ObjectFileSP objfile_sp);60 ~SymbolFileDWARFDebugMap() override;61 62 uint32_t CalculateAbilities() override;63 void InitializeObject() override;64 65 // Compile Unit function calls66 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 bool85 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, llvm::StringRef filter,133 bool show_color) override;134 135 /// List separate oso files.136 bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only,137 bool load_all_debug_info = false) override;138 139 // PluginInterface protocol140 llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }141 142 // Statistics overrides.143 ModuleList GetDebugInfoModules() override;144 145 void146 GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override;147 148 llvm::Expected<SymbolContext>149 ResolveFunctionCallLabel(FunctionCallLabel &label) override;150 151protected:152 enum { kHaveInitializedOSOs = (1 << 0), kNumFlags };153 154 friend class DebugMapModule;155 friend class ::DWARFASTParserClang;156 friend class DWARFCompileUnit;157 friend class SymbolFileDWARF;158 struct OSOInfo {159 lldb::ModuleSP module_sp;160 161 OSOInfo() : module_sp() {}162 };163 164 typedef std::shared_ptr<OSOInfo> OSOInfoSP;165 166 typedef RangeDataVector<lldb::addr_t, lldb::addr_t, lldb::addr_t>167 FileRangeMap;168 169 // Class specific types170 struct CompileUnitInfo {171 FileSpec so_file;172 ConstString oso_path;173 llvm::sys::TimePoint<> oso_mod_time;174 Status oso_load_error;175 OSOInfoSP oso_sp;176 /// The compile units that an object file contains.177 llvm::SmallVector<lldb::CompUnitSP, 2> compile_units_sps;178 /// A map from the compile unit ID to its index in the vector.179 llvm::SmallDenseMap<uint64_t, uint64_t, 2> id_to_index_map;180 uint32_t first_symbol_index = UINT32_MAX;181 uint32_t last_symbol_index = UINT32_MAX;182 uint32_t first_symbol_id = UINT32_MAX;183 uint32_t last_symbol_id = UINT32_MAX;184 FileRangeMap file_range_map;185 bool file_range_map_valid = false;186 187 CompileUnitInfo() = default;188 189 const FileRangeMap &GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile);190 };191 192 // Protected Member Functions193 void InitOSO();194 195 /// This function actually returns the number of object files, which may be196 /// less than the actual number of compile units, since an object file may197 /// contain more than one compile unit. SymbolFileDWARFDebugMap looks up the198 /// number of compile units by reading the nlist symbol table, which199 /// currently, on macOS, only reports one compile unit per object file, and200 /// there's no efficient way to calculate the actual number of compile units201 /// upfront.202 uint32_t CalculateNumCompileUnits() override;203 204 /// This function actually returns the first compile unit the object file at205 /// the given index contains.206 lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;207 208 static uint32_t GetOSOIndexFromUserID(lldb::user_id_t uid) {209 std::optional<uint32_t> OsoNum = DIERef(uid).file_index();210 lldbassert(OsoNum && "Invalid OSO Index");211 return *OsoNum;212 }213 214 static SymbolFileDWARF *GetSymbolFileAsSymbolFileDWARF(SymbolFile *sym_file);215 216 bool GetFileSpecForSO(uint32_t oso_idx, FileSpec &file_spec);217 218 CompileUnitInfo *GetCompUnitInfo(const SymbolContext &sc);219 CompileUnitInfo *GetCompUnitInfo(const CompileUnit &comp_unit);220 221 size_t GetCompUnitInfosForModule(const Module *oso_module,222 std::vector<CompileUnitInfo *> &cu_infos);223 224 Module *GetModuleByCompUnitInfo(CompileUnitInfo *comp_unit_info);225 226 Module *GetModuleByOSOIndex(uint32_t oso_idx);227 228 ObjectFile *GetObjectFileByCompUnitInfo(CompileUnitInfo *comp_unit_info);229 230 ObjectFile *GetObjectFileByOSOIndex(uint32_t oso_idx);231 232 uint32_t GetCompUnitInfoIndex(const CompileUnitInfo *comp_unit_info);233 234 SymbolFileDWARF *GetSymbolFile(const SymbolContext &sc);235 SymbolFileDWARF *GetSymbolFile(const CompileUnit &comp_unit);236 237 SymbolFileDWARF *GetSymbolFileByCompUnitInfo(CompileUnitInfo *comp_unit_info);238 239 SymbolFileDWARF *GetSymbolFileByOSOIndex(uint32_t oso_idx);240 241 /// If closure returns \ref IterationAction::Continue, iteration242 /// continues. Otherwise, iteration terminates.243 void244 ForEachSymbolFile(std::string description,245 std::function<IterationAction(SymbolFileDWARF &)> closure);246 247 CompileUnitInfo *GetCompileUnitInfoForSymbolWithIndex(uint32_t symbol_idx,248 uint32_t *oso_idx_ptr);249 250 CompileUnitInfo *GetCompileUnitInfoForSymbolWithID(lldb::user_id_t symbol_id,251 uint32_t *oso_idx_ptr);252 253 static int254 SymbolContainsSymbolWithIndex(uint32_t *symbol_idx_ptr,255 const CompileUnitInfo *comp_unit_info);256 257 static int SymbolContainsSymbolWithID(lldb::user_id_t *symbol_idx_ptr,258 const CompileUnitInfo *comp_unit_info);259 260 void261 PrivateFindGlobalVariables(ConstString name,262 const CompilerDeclContext &parent_decl_ctx,263 const std::vector<uint32_t> &name_symbol_indexes,264 uint32_t max_matches, VariableList &variables);265 266 void SetCompileUnit(SymbolFileDWARF *oso_dwarf,267 const lldb::CompUnitSP &cu_sp);268 269 /// Returns the compile unit associated with the dwarf compile unit. This may270 /// be one of the extra compile units an object file contains which isn't271 /// reachable by ParseCompileUnitAtIndex(uint32_t).272 lldb::CompUnitSP GetCompileUnit(SymbolFileDWARF *oso_dwarf,273 DWARFCompileUnit &dwarf_cu);274 275 CompileUnitInfo *GetCompileUnitInfo(SymbolFileDWARF *oso_dwarf);276 277 DWARFDIE FindDefinitionDIE(const DWARFDIE &die);278 279 lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE(280 const DWARFDIE &die, ConstString type_name, bool must_be_implementation);281 282 llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &283 GetForwardDeclCompilerTypeToDIE() {284 return m_forward_decl_compiler_type_to_die;285 }286 287 UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() {288 return m_unique_ast_type_map;289 }290 291 llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> &GetDIEToType() {292 return m_die_to_type;293 }294 295 // OSOEntry296 class OSOEntry {297 public:298 OSOEntry() = default;299 300 OSOEntry(uint32_t exe_sym_idx, lldb::addr_t oso_file_addr)301 : m_exe_sym_idx(exe_sym_idx), m_oso_file_addr(oso_file_addr) {}302 303 uint32_t GetExeSymbolIndex() const { return m_exe_sym_idx; }304 305 bool operator<(const OSOEntry &rhs) const {306 return m_exe_sym_idx < rhs.m_exe_sym_idx;307 }308 309 lldb::addr_t GetOSOFileAddress() const { return m_oso_file_addr; }310 311 void SetOSOFileAddress(lldb::addr_t oso_file_addr) {312 m_oso_file_addr = oso_file_addr;313 }314 315 protected:316 uint32_t m_exe_sym_idx = UINT32_MAX;317 lldb::addr_t m_oso_file_addr = LLDB_INVALID_ADDRESS;318 };319 320 typedef RangeDataVector<lldb::addr_t, lldb::addr_t, OSOEntry> DebugMap;321 322 // Member Variables323 std::bitset<kNumFlags> m_flags;324 std::vector<CompileUnitInfo> m_compile_unit_infos;325 std::vector<uint32_t> m_func_indexes; // Sorted by address326 std::vector<uint32_t> m_glob_indexes;327 std::map<std::pair<ConstString, llvm::sys::TimePoint<>>, OSOInfoSP> m_oso_map;328 // A map from CompilerType to the struct/class/union/enum DIE (might be a329 // declaration or a definition) that is used to construct it.330 llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef>331 m_forward_decl_compiler_type_to_die;332 UniqueDWARFASTTypeMap m_unique_ast_type_map;333 llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> m_die_to_type;334 335 DebugMap m_debug_map;336 337 // When an object file from the debug map gets parsed in338 // SymbolFileDWARF, it needs to tell the debug map about the object339 // files addresses by calling this function once for each N_FUN,340 // N_GSYM and N_STSYM and after all entries in the debug map have341 // been matched up, FinalizeOSOFileRanges() should be called.342 bool AddOSOFileRange(CompileUnitInfo *cu_info, lldb::addr_t exe_file_addr,343 lldb::addr_t exe_byte_size, lldb::addr_t oso_file_addr,344 lldb::addr_t oso_byte_size);345 346 // Called after calling AddOSOFileRange() for each object file debug347 // map entry to finalize the info for the unlinked compile unit.348 void FinalizeOSOFileRanges(CompileUnitInfo *cu_info);349 350 /// Convert \a addr from a .o file address, to an executable address.351 ///352 /// \param[in] addr353 /// A section offset address from a .o file354 ///355 /// \return356 /// Returns true if \a addr was converted to be an executable357 /// section/offset address, false otherwise.358 bool LinkOSOAddress(Address &addr);359 360 /// Convert a .o file "file address" to an executable "file address".361 ///362 /// \param[in] oso_symfile363 /// The DWARF symbol file that contains \a oso_file_addr364 ///365 /// \param[in] oso_file_addr366 /// A .o file "file address" to convert.367 ///368 /// \return369 /// LLDB_INVALID_ADDRESS if \a oso_file_addr is not in the370 /// linked executable, otherwise a valid "file address" from the371 /// linked executable that contains the debug map.372 lldb::addr_t LinkOSOFileAddress(SymbolFileDWARF *oso_symfile,373 lldb::addr_t oso_file_addr);374 375 /// Given a line table full of lines with "file addresses" that are376 /// for a .o file represented by \a oso_symfile, link a new line table377 /// and return it.378 ///379 /// \param[in] oso_symfile380 /// The DWARF symbol file that produced the \a line_table381 ///382 /// \param[in] line_table383 /// A pointer to the line table.384 ///385 /// \return386 /// Returns a valid line table full of linked addresses, or NULL387 /// if none of the line table addresses exist in the main388 /// executable.389 LineTable *LinkOSOLineTable(SymbolFileDWARF *oso_symfile,390 LineTable *line_table);391 392 size_t AddOSOARanges(SymbolFileDWARF *dwarf2Data,393 DWARFDebugAranges *debug_aranges);394};395} // namespace dwarf396} // namespace lldb_private::plugin397 398#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H399