//===-- SymbolFileOnDemand.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Symbol/SymbolFileOnDemand.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/SymbolFile.h" #include #include using namespace lldb; using namespace lldb_private; char SymbolFileOnDemand::ID; SymbolFileOnDemand::SymbolFileOnDemand( std::unique_ptr &&symbol_file) : m_sym_file_impl(std::move(symbol_file)) {} SymbolFileOnDemand::~SymbolFileOnDemand() = default; uint32_t SymbolFileOnDemand::CalculateAbilities() { // Explicitly allow ability checking to pass though. // This should be a cheap operation. return m_sym_file_impl->CalculateAbilities(); } std::recursive_mutex &SymbolFileOnDemand::GetModuleMutex() const { return m_sym_file_impl->GetModuleMutex(); } void SymbolFileOnDemand::InitializeObject() { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } return m_sym_file_impl->InitializeObject(); } lldb::LanguageType SymbolFileOnDemand::ParseLanguage(CompileUnit &comp_unit) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); if (log) { lldb::LanguageType langType = m_sym_file_impl->ParseLanguage(comp_unit); if (langType != eLanguageTypeUnknown) LLDB_LOG(log, "Language {0} would return if hydrated.", langType); } return eLanguageTypeUnknown; } return m_sym_file_impl->ParseLanguage(comp_unit); } XcodeSDK SymbolFileOnDemand::ParseXcodeSDK(CompileUnit &comp_unit) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); XcodeSDK defaultValue{}; if (log) { XcodeSDK sdk = m_sym_file_impl->ParseXcodeSDK(comp_unit); if (!(sdk == defaultValue)) LLDB_LOG(log, "SDK {0} would return if hydrated.", sdk.GetString()); } return defaultValue; } return m_sym_file_impl->ParseXcodeSDK(comp_unit); } size_t SymbolFileOnDemand::ParseFunctions(CompileUnit &comp_unit) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return 0; } return m_sym_file_impl->ParseFunctions(comp_unit); } bool SymbolFileOnDemand::ParseLineTable(CompileUnit &comp_unit) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return false; } return m_sym_file_impl->ParseLineTable(comp_unit); } bool SymbolFileOnDemand::ParseDebugMacros(CompileUnit &comp_unit) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return false; } return m_sym_file_impl->ParseDebugMacros(comp_unit); } bool SymbolFileOnDemand::ForEachExternalModule( CompileUnit &comp_unit, llvm::DenseSet &visited_symbol_files, llvm::function_ref lambda) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); // Return false to not early exit. return false; } return m_sym_file_impl->ForEachExternalModule(comp_unit, visited_symbol_files, lambda); } bool SymbolFileOnDemand::ParseSupportFiles(CompileUnit &comp_unit, SupportFileList &support_files) { LLDB_LOG(GetLog(), "[{0}] {1} is not skipped: explicitly allowed to support breakpoint", GetSymbolFileName(), __FUNCTION__); // Explicitly allow this API through to support source line breakpoint. return m_sym_file_impl->ParseSupportFiles(comp_unit, support_files); } bool SymbolFileOnDemand::ParseIsOptimized(CompileUnit &comp_unit) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); if (log) { bool optimized = m_sym_file_impl->ParseIsOptimized(comp_unit); if (optimized) { LLDB_LOG(log, "Would return optimized if hydrated."); } } return false; } return m_sym_file_impl->ParseIsOptimized(comp_unit); } size_t SymbolFileOnDemand::ParseTypes(CompileUnit &comp_unit) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return 0; } return m_sym_file_impl->ParseTypes(comp_unit); } bool SymbolFileOnDemand::ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector &imported_modules) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); if (log) { std::vector tmp_imported_modules; bool succeed = m_sym_file_impl->ParseImportedModules(sc, tmp_imported_modules); if (succeed) LLDB_LOG(log, "{0} imported modules would be parsed if hydrated.", tmp_imported_modules.size()); } return false; } return m_sym_file_impl->ParseImportedModules(sc, imported_modules); } size_t SymbolFileOnDemand::ParseBlocksRecursive(Function &func) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return 0; } return m_sym_file_impl->ParseBlocksRecursive(func); } size_t SymbolFileOnDemand::ParseVariablesForContext(const SymbolContext &sc) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return 0; } return m_sym_file_impl->ParseVariablesForContext(sc); } Type *SymbolFileOnDemand::ResolveTypeUID(lldb::user_id_t type_uid) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); if (log) { Type *resolved_type = m_sym_file_impl->ResolveTypeUID(type_uid); if (resolved_type) LLDB_LOG(log, "Type would be parsed for {0} if hydrated.", type_uid); } return nullptr; } return m_sym_file_impl->ResolveTypeUID(type_uid); } std::optional SymbolFileOnDemand::GetDynamicArrayInfoForUID( lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return std::nullopt; } return m_sym_file_impl->GetDynamicArrayInfoForUID(type_uid, exe_ctx); } bool SymbolFileOnDemand::CompleteType(CompilerType &compiler_type) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return false; } return m_sym_file_impl->CompleteType(compiler_type); } CompilerDecl SymbolFileOnDemand::GetDeclForUID(lldb::user_id_t type_uid) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); if (log) { CompilerDecl parsed_decl = m_sym_file_impl->GetDeclForUID(type_uid); if (parsed_decl != CompilerDecl()) { LLDB_LOG(log, "CompilerDecl {0} would be parsed for {1} if hydrated.", parsed_decl.GetName(), type_uid); } } return CompilerDecl(); } return m_sym_file_impl->GetDeclForUID(type_uid); } CompilerDeclContext SymbolFileOnDemand::GetDeclContextForUID(lldb::user_id_t type_uid) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return CompilerDeclContext(); } return m_sym_file_impl->GetDeclContextForUID(type_uid); } CompilerDeclContext SymbolFileOnDemand::GetDeclContextContainingUID(lldb::user_id_t type_uid) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return CompilerDeclContext(); } return m_sym_file_impl->GetDeclContextContainingUID(type_uid); } void SymbolFileOnDemand::ParseDeclsForContext(CompilerDeclContext decl_ctx) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } return m_sym_file_impl->ParseDeclsForContext(decl_ctx); } uint32_t SymbolFileOnDemand::ResolveSymbolContext(const Address &so_addr, SymbolContextItem resolve_scope, SymbolContext &sc) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return 0; } return m_sym_file_impl->ResolveSymbolContext(so_addr, resolve_scope, sc); } Status SymbolFileOnDemand::CalculateFrameVariableError(StackFrame &frame) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return Status(); } return m_sym_file_impl->CalculateFrameVariableError(frame); } uint32_t SymbolFileOnDemand::ResolveSymbolContext( const SourceLocationSpec &src_location_spec, SymbolContextItem resolve_scope, SymbolContextList &sc_list) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return 0; } return m_sym_file_impl->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list); } void SymbolFileOnDemand::Dump(lldb_private::Stream &s) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } return m_sym_file_impl->Dump(s); } void SymbolFileOnDemand::DumpClangAST(lldb_private::Stream &s) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } return m_sym_file_impl->DumpClangAST(s); } void SymbolFileOnDemand::FindGlobalVariables(const RegularExpression ®ex, uint32_t max_matches, VariableList &variables) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } return m_sym_file_impl->FindGlobalVariables(regex, max_matches, variables); } void SymbolFileOnDemand::FindGlobalVariables( ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, VariableList &variables) { if (!m_debug_info_enabled) { Log *log = GetLog(); Symtab *symtab = GetSymtab(); if (!symtab) { LLDB_LOG(log, "[{0}] {1} is skipped - fail to get symtab", GetSymbolFileName(), __FUNCTION__); return; } Symbol *sym = symtab->FindFirstSymbolWithNameAndType( name, eSymbolTypeData, Symtab::eDebugAny, Symtab::eVisibilityAny); if (!sym) { LLDB_LOG(log, "[{0}] {1} is skipped - fail to find match in symtab", GetSymbolFileName(), __FUNCTION__); return; } LLDB_LOG(log, "[{0}] {1} is NOT skipped - found match in symtab", GetSymbolFileName(), __FUNCTION__); // Found match in symbol table hydrate debug info and // allow the FindGlobalVariables to go through. SetLoadDebugInfoEnabled(); } return m_sym_file_impl->FindGlobalVariables(name, parent_decl_ctx, max_matches, variables); } void SymbolFileOnDemand::FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) { if (!m_debug_info_enabled) { Log *log = GetLog(); Symtab *symtab = GetSymtab(); if (!symtab) { LLDB_LOG(log, "[{0}] {1} is skipped - fail to get symtab", GetSymbolFileName(), __FUNCTION__); return; } std::vector symbol_indexes; symtab->AppendSymbolIndexesMatchingRegExAndType( regex, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes); if (symbol_indexes.empty()) { LLDB_LOG(log, "[{0}] {1} is skipped - fail to find match in symtab", GetSymbolFileName(), __FUNCTION__); return; } LLDB_LOG(log, "[{0}] {1} is NOT skipped - found match in symtab", GetSymbolFileName(), __FUNCTION__); // Found match in symbol table hydrate debug info and // allow the FindFucntions to go through. SetLoadDebugInfoEnabled(); } return m_sym_file_impl->FindFunctions(regex, include_inlines, sc_list); } void SymbolFileOnDemand::FindFunctions( const Module::LookupInfo &lookup_info, const CompilerDeclContext &parent_decl_ctx, bool include_inlines, SymbolContextList &sc_list) { ConstString name = lookup_info.GetLookupName(); FunctionNameType name_type_mask = lookup_info.GetNameTypeMask(); if (!m_debug_info_enabled) { Log *log = GetLog(); Symtab *symtab = GetSymtab(); if (!symtab) { LLDB_LOG(log, "[{0}] {1}({2}) is skipped - fail to get symtab", GetSymbolFileName(), __FUNCTION__, name); return; } SymbolContextList sc_list_helper; symtab->FindFunctionSymbols(name, name_type_mask, sc_list_helper); if (sc_list_helper.GetSize() == 0) { LLDB_LOG(log, "[{0}] {1}({2}) is skipped - fail to find match in symtab", GetSymbolFileName(), __FUNCTION__, name); return; } LLDB_LOG(log, "[{0}] {1}({2}) is NOT skipped - found match in symtab", GetSymbolFileName(), __FUNCTION__, name); // Found match in symbol table hydrate debug info and // allow the FindFucntions to go through. SetLoadDebugInfoEnabled(); } return m_sym_file_impl->FindFunctions(lookup_info, parent_decl_ctx, include_inlines, sc_list); } void SymbolFileOnDemand::GetMangledNamesForFunction( const std::string &scope_qualified_name, std::vector &mangled_names) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1}({2}) is skipped", GetSymbolFileName(), __FUNCTION__, scope_qualified_name); return; } return m_sym_file_impl->GetMangledNamesForFunction(scope_qualified_name, mangled_names); } void SymbolFileOnDemand::FindTypes(const TypeQuery &match, TypeResults &results) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } return m_sym_file_impl->FindTypes(match, results); } void SymbolFileOnDemand::GetTypes(SymbolContextScope *sc_scope, TypeClass type_mask, TypeList &type_list) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } return m_sym_file_impl->GetTypes(sc_scope, type_mask, type_list); } llvm::Expected SymbolFileOnDemand::GetTypeSystemForLanguage(LanguageType language) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped for language type {2}", GetSymbolFileName(), __FUNCTION__, language); return llvm::createStringError( "GetTypeSystemForLanguage is skipped by SymbolFileOnDemand"); } return m_sym_file_impl->GetTypeSystemForLanguage(language); } CompilerDeclContext SymbolFileOnDemand::FindNamespace(ConstString name, const CompilerDeclContext &parent_decl_ctx, bool only_root_namespaces) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1}({2}) is skipped", GetSymbolFileName(), __FUNCTION__, name); return SymbolFile::FindNamespace(name, parent_decl_ctx, only_root_namespaces); } return m_sym_file_impl->FindNamespace(name, parent_decl_ctx, only_root_namespaces); } std::vector> SymbolFileOnDemand::ParseCallEdgesInFunction(UserID func_id) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); if (log) { std::vector> call_edges = m_sym_file_impl->ParseCallEdgesInFunction(func_id); if (call_edges.size() > 0) { LLDB_LOG(log, "{0} call edges would be parsed for {1} if hydrated.", call_edges.size(), func_id.GetID()); } } return {}; } return m_sym_file_impl->ParseCallEdgesInFunction(func_id); } lldb::UnwindPlanSP SymbolFileOnDemand::GetUnwindPlan(const Address &address, const RegisterInfoResolver &resolver) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return nullptr; } return m_sym_file_impl->GetUnwindPlan(address, resolver); } llvm::Expected SymbolFileOnDemand::GetParameterStackSize(Symbol &symbol) { if (!m_debug_info_enabled) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); if (log) { llvm::Expected stack_size = m_sym_file_impl->GetParameterStackSize(symbol); if (stack_size) { LLDB_LOG(log, "{0} stack size would return for symbol {1} if hydrated.", *stack_size, symbol.GetName()); } } return SymbolFile::GetParameterStackSize(symbol); } return m_sym_file_impl->GetParameterStackSize(symbol); } void SymbolFileOnDemand::PreloadSymbols() { m_preload_symbols = true; if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } return m_sym_file_impl->PreloadSymbols(); } uint64_t SymbolFileOnDemand::GetDebugInfoSize(bool load_all_debug_info) { // Always return the real debug info size. LLDB_LOG(GetLog(), "[{0}] {1} is not skipped", GetSymbolFileName(), __FUNCTION__); return m_sym_file_impl->GetDebugInfoSize(load_all_debug_info); } StatsDuration::Duration SymbolFileOnDemand::GetDebugInfoParseTime() { // Always return the real parse time. LLDB_LOG(GetLog(), "[{0}] {1} is not skipped", GetSymbolFileName(), __FUNCTION__); return m_sym_file_impl->GetDebugInfoParseTime(); } StatsDuration::Duration SymbolFileOnDemand::GetDebugInfoIndexTime() { // Always return the real index time. LLDB_LOG(GetLog(), "[{0}] {1} is not skipped", GetSymbolFileName(), __FUNCTION__); return m_sym_file_impl->GetDebugInfoIndexTime(); } void SymbolFileOnDemand::SetLoadDebugInfoEnabled() { if (m_debug_info_enabled) return; LLDB_LOG(GetLog(), "[{0}] Hydrate debug info", GetSymbolFileName()); m_debug_info_enabled = true; InitializeObject(); if (m_preload_symbols) PreloadSymbols(); } uint32_t SymbolFileOnDemand::GetNumCompileUnits() { LLDB_LOG(GetLog(), "[{0}] {1} is not skipped to support breakpoint hydration", GetSymbolFileName(), __FUNCTION__); return m_sym_file_impl->GetNumCompileUnits(); } CompUnitSP SymbolFileOnDemand::GetCompileUnitAtIndex(uint32_t idx) { LLDB_LOG(GetLog(), "[{0}] {1} is not skipped to support breakpoint hydration", GetSymbolFileName(), __FUNCTION__); return m_sym_file_impl->GetCompileUnitAtIndex(idx); } uint32_t SymbolFileOnDemand::GetAbilities() { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return 0; } return m_sym_file_impl->GetAbilities(); }