//===-- Module.cpp ----------------------------------------------*- C++ -*-===// // // 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/Core/Module.h" #include "lldb/Core/AddressRange.h" #include "lldb/Core/AddressResolverFileLine.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/Mangled.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/SearchFilter.h" #include "lldb/Core/Section.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Symtab.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeMap.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Language.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #if defined(_WIN32) #include "lldb/Host/windows/PosixApi.h" #endif #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include namespace lldb_private { class CompilerDeclContext; } namespace lldb_private { class VariableList; } using namespace lldb; using namespace lldb_private; // Shared pointers to modules track module lifetimes in targets and in the // global module, but this collection will track all module objects that are // still alive typedef std::vector ModuleCollection; static ModuleCollection &GetModuleCollection() { // This module collection needs to live past any module, so we could either // make it a shared pointer in each module or just leak is. Since it is only // an empty vector by the time all the modules have gone away, we just leak // it for now. If we decide this is a big problem we can introduce a // Finalize method that will tear everything down in a predictable order. static ModuleCollection *g_module_collection = nullptr; if (g_module_collection == nullptr) g_module_collection = new ModuleCollection(); return *g_module_collection; } std::recursive_mutex &Module::GetAllocationModuleCollectionMutex() { // NOTE: The mutex below must be leaked since the global module list in // the ModuleList class will get torn at some point, and we can't know if it // will tear itself down before the "g_module_collection_mutex" below will. // So we leak a Mutex object below to safeguard against that static std::recursive_mutex *g_module_collection_mutex = nullptr; if (g_module_collection_mutex == nullptr) g_module_collection_mutex = new std::recursive_mutex; // NOTE: known leak return *g_module_collection_mutex; } size_t Module::GetNumberAllocatedModules() { std::lock_guard guard( GetAllocationModuleCollectionMutex()); return GetModuleCollection().size(); } Module *Module::GetAllocatedModuleAtIndex(size_t idx) { std::lock_guard guard( GetAllocationModuleCollectionMutex()); ModuleCollection &modules = GetModuleCollection(); if (idx < modules.size()) return modules[idx]; return nullptr; } Module::Module(const ModuleSpec &module_spec) : m_object_offset(0), m_file_has_changed(false), m_first_file_changed_log(false) { // Scope for locker below... { std::lock_guard guard( GetAllocationModuleCollectionMutex()); GetModuleCollection().push_back(this); } Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_MODULES)); if (log != nullptr) LLDB_LOGF(log, "%p Module::Module((%s) '%s%s%s%s')", static_cast(this), module_spec.GetArchitecture().GetArchitectureName(), module_spec.GetFileSpec().GetPath().c_str(), module_spec.GetObjectName().IsEmpty() ? "" : "(", module_spec.GetObjectName().IsEmpty() ? "" : module_spec.GetObjectName().AsCString(""), module_spec.GetObjectName().IsEmpty() ? "" : ")"); // First extract all module specifications from the file using the local file // path. If there are no specifications, then don't fill anything in ModuleSpecList modules_specs; if (ObjectFile::GetModuleSpecifications(module_spec.GetFileSpec(), 0, 0, modules_specs) == 0) return; // Now make sure that one of the module specifications matches what we just // extract. We might have a module specification that specifies a file // "/usr/lib/dyld" with UUID XXX, but we might have a local version of // "/usr/lib/dyld" that has // UUID YYY and we don't want those to match. If they don't match, just don't // fill any ivars in so we don't accidentally grab the wrong file later since // they don't match... ModuleSpec matching_module_spec; if (!modules_specs.FindMatchingModuleSpec(module_spec, matching_module_spec)) { if (log) { LLDB_LOGF(log, "Found local object file but the specs didn't match"); } return; } if (module_spec.GetFileSpec()) m_mod_time = FileSystem::Instance().GetModificationTime(module_spec.GetFileSpec()); else if (matching_module_spec.GetFileSpec()) m_mod_time = FileSystem::Instance().GetModificationTime(matching_module_spec.GetFileSpec()); // Copy the architecture from the actual spec if we got one back, else use // the one that was specified if (matching_module_spec.GetArchitecture().IsValid()) m_arch = matching_module_spec.GetArchitecture(); else if (module_spec.GetArchitecture().IsValid()) m_arch = module_spec.GetArchitecture(); // Copy the file spec over and use the specified one (if there was one) so we // don't use a path that might have gotten resolved a path in // 'matching_module_spec' if (module_spec.GetFileSpec()) m_file = module_spec.GetFileSpec(); else if (matching_module_spec.GetFileSpec()) m_file = matching_module_spec.GetFileSpec(); // Copy the platform file spec over if (module_spec.GetPlatformFileSpec()) m_platform_file = module_spec.GetPlatformFileSpec(); else if (matching_module_spec.GetPlatformFileSpec()) m_platform_file = matching_module_spec.GetPlatformFileSpec(); // Copy the symbol file spec over if (module_spec.GetSymbolFileSpec()) m_symfile_spec = module_spec.GetSymbolFileSpec(); else if (matching_module_spec.GetSymbolFileSpec()) m_symfile_spec = matching_module_spec.GetSymbolFileSpec(); // Copy the object name over if (matching_module_spec.GetObjectName()) m_object_name = matching_module_spec.GetObjectName(); else m_object_name = module_spec.GetObjectName(); // Always trust the object offset (file offset) and object modification time // (for mod time in a BSD static archive) of from the matching module // specification m_object_offset = matching_module_spec.GetObjectOffset(); m_object_mod_time = matching_module_spec.GetObjectModificationTime(); } Module::Module(const FileSpec &file_spec, const ArchSpec &arch, const ConstString *object_name, lldb::offset_t object_offset, const llvm::sys::TimePoint<> &object_mod_time) : m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)), m_arch(arch), m_file(file_spec), m_object_offset(object_offset), m_object_mod_time(object_mod_time), m_file_has_changed(false), m_first_file_changed_log(false) { // Scope for locker below... { std::lock_guard guard( GetAllocationModuleCollectionMutex()); GetModuleCollection().push_back(this); } if (object_name) m_object_name = *object_name; Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_MODULES)); if (log != nullptr) LLDB_LOGF(log, "%p Module::Module((%s) '%s%s%s%s')", static_cast(this), m_arch.GetArchitectureName(), m_file.GetPath().c_str(), m_object_name.IsEmpty() ? "" : "(", m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""), m_object_name.IsEmpty() ? "" : ")"); } Module::Module() : m_object_offset(0), m_file_has_changed(false), m_first_file_changed_log(false) { std::lock_guard guard( GetAllocationModuleCollectionMutex()); GetModuleCollection().push_back(this); } Module::~Module() { // Lock our module down while we tear everything down to make sure we don't // get any access to the module while it is being destroyed std::lock_guard guard(m_mutex); // Scope for locker below... { std::lock_guard guard( GetAllocationModuleCollectionMutex()); ModuleCollection &modules = GetModuleCollection(); ModuleCollection::iterator end = modules.end(); ModuleCollection::iterator pos = std::find(modules.begin(), end, this); assert(pos != end); modules.erase(pos); } Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_MODULES)); if (log != nullptr) LLDB_LOGF(log, "%p Module::~Module((%s) '%s%s%s%s')", static_cast(this), m_arch.GetArchitectureName(), m_file.GetPath().c_str(), m_object_name.IsEmpty() ? "" : "(", m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""), m_object_name.IsEmpty() ? "" : ")"); // Release any auto pointers before we start tearing down our member // variables since the object file and symbol files might need to make // function calls back into this module object. The ordering is important // here because symbol files can require the module object file. So we tear // down the symbol file first, then the object file. m_sections_up.reset(); m_symfile_up.reset(); m_objfile_sp.reset(); } ObjectFile *Module::GetMemoryObjectFile(const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Status &error, size_t size_to_read) { if (m_objfile_sp) { error.SetErrorString("object file already exists"); } else { std::lock_guard guard(m_mutex); if (process_sp) { m_did_load_objfile = true; auto data_up = std::make_unique(size_to_read, 0); Status readmem_error; const size_t bytes_read = process_sp->ReadMemory(header_addr, data_up->GetBytes(), data_up->GetByteSize(), readmem_error); if (bytes_read == size_to_read) { DataBufferSP data_sp(data_up.release()); m_objfile_sp = ObjectFile::FindPlugin(shared_from_this(), process_sp, header_addr, data_sp); if (m_objfile_sp) { StreamString s; s.Printf("0x%16.16" PRIx64, header_addr); m_object_name.SetString(s.GetString()); // Once we get the object file, update our module with the object // file's architecture since it might differ in vendor/os if some // parts were unknown. m_arch = m_objfile_sp->GetArchitecture(); // Augment the arch with the target's information in case // we are unable to extract the os/environment from memory. m_arch.MergeFrom(process_sp->GetTarget().GetArchitecture()); } else { error.SetErrorString("unable to find suitable object file plug-in"); } } else { error.SetErrorStringWithFormat("unable to read header from memory: %s", readmem_error.AsCString()); } } else { error.SetErrorString("invalid process"); } } return m_objfile_sp.get(); } const lldb_private::UUID &Module::GetUUID() { if (!m_did_set_uuid.load()) { std::lock_guard guard(m_mutex); if (!m_did_set_uuid.load()) { ObjectFile *obj_file = GetObjectFile(); if (obj_file != nullptr) { m_uuid = obj_file->GetUUID(); m_did_set_uuid = true; } } } return m_uuid; } void Module::SetUUID(const lldb_private::UUID &uuid) { std::lock_guard guard(m_mutex); if (!m_did_set_uuid) { m_uuid = uuid; m_did_set_uuid = true; } else { lldbassert(0 && "Attempting to overwrite the existing module UUID"); } } llvm::Expected Module::GetTypeSystemForLanguage(LanguageType language) { return m_type_system_map.GetTypeSystemForLanguage(language, this, true); } void Module::ParseAllDebugSymbols() { std::lock_guard guard(m_mutex); size_t num_comp_units = GetNumCompileUnits(); if (num_comp_units == 0) return; SymbolContext sc; sc.module_sp = shared_from_this(); SymbolFile *symbols = GetSymbolFile(); for (size_t cu_idx = 0; cu_idx < num_comp_units; cu_idx++) { sc.comp_unit = symbols->GetCompileUnitAtIndex(cu_idx).get(); if (!sc.comp_unit) continue; symbols->ParseVariablesForContext(sc); symbols->ParseFunctions(*sc.comp_unit); sc.comp_unit->ForeachFunction([&sc, &symbols](const FunctionSP &f) { symbols->ParseBlocksRecursive(*f); // Parse the variables for this function and all its blocks sc.function = f.get(); symbols->ParseVariablesForContext(sc); return false; }); // Parse all types for this compile unit symbols->ParseTypes(*sc.comp_unit); } } void Module::CalculateSymbolContext(SymbolContext *sc) { sc->module_sp = shared_from_this(); } ModuleSP Module::CalculateSymbolContextModule() { return shared_from_this(); } void Module::DumpSymbolContext(Stream *s) { s->Printf(", Module{%p}", static_cast(this)); } size_t Module::GetNumCompileUnits() { std::lock_guard guard(m_mutex); static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "Module::GetNumCompileUnits (module = %p)", static_cast(this)); if (SymbolFile *symbols = GetSymbolFile()) return symbols->GetNumCompileUnits(); return 0; } CompUnitSP Module::GetCompileUnitAtIndex(size_t index) { std::lock_guard guard(m_mutex); size_t num_comp_units = GetNumCompileUnits(); CompUnitSP cu_sp; if (index < num_comp_units) { if (SymbolFile *symbols = GetSymbolFile()) cu_sp = symbols->GetCompileUnitAtIndex(index); } return cu_sp; } bool Module::ResolveFileAddress(lldb::addr_t vm_addr, Address &so_addr) { std::lock_guard guard(m_mutex); static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "Module::ResolveFileAddress (vm_addr = 0x%" PRIx64 ")", vm_addr); SectionList *section_list = GetSectionList(); if (section_list) return so_addr.ResolveAddressUsingFileSections(vm_addr, section_list); return false; } uint32_t Module::ResolveSymbolContextForAddress( const Address &so_addr, lldb::SymbolContextItem resolve_scope, SymbolContext &sc, bool resolve_tail_call_address) { std::lock_guard guard(m_mutex); uint32_t resolved_flags = 0; // Clear the result symbol context in case we don't find anything, but don't // clear the target sc.Clear(false); // Get the section from the section/offset address. SectionSP section_sp(so_addr.GetSection()); // Make sure the section matches this module before we try and match anything if (section_sp && section_sp->GetModule().get() == this) { // If the section offset based address resolved itself, then this is the // right module. sc.module_sp = shared_from_this(); resolved_flags |= eSymbolContextModule; SymbolFile *symfile = GetSymbolFile(); if (!symfile) return resolved_flags; // Resolve the compile unit, function, block, line table or line entry if // requested. if (resolve_scope & eSymbolContextCompUnit || resolve_scope & eSymbolContextFunction || resolve_scope & eSymbolContextBlock || resolve_scope & eSymbolContextLineEntry || resolve_scope & eSymbolContextVariable) { resolved_flags |= symfile->ResolveSymbolContext(so_addr, resolve_scope, sc); } // Resolve the symbol if requested, but don't re-look it up if we've // already found it. if (resolve_scope & eSymbolContextSymbol && !(resolved_flags & eSymbolContextSymbol)) { Symtab *symtab = symfile->GetSymtab(); if (symtab && so_addr.IsSectionOffset()) { Symbol *matching_symbol = nullptr; symtab->ForEachSymbolContainingFileAddress( so_addr.GetFileAddress(), [&matching_symbol](Symbol *symbol) -> bool { if (symbol->GetType() != eSymbolTypeInvalid) { matching_symbol = symbol; return false; // Stop iterating } return true; // Keep iterating }); sc.symbol = matching_symbol; if (!sc.symbol && resolve_scope & eSymbolContextFunction && !(resolved_flags & eSymbolContextFunction)) { bool verify_unique = false; // No need to check again since // ResolveSymbolContext failed to find a // symbol at this address. if (ObjectFile *obj_file = sc.module_sp->GetObjectFile()) sc.symbol = obj_file->ResolveSymbolForAddress(so_addr, verify_unique); } if (sc.symbol) { if (sc.symbol->IsSynthetic()) { // We have a synthetic symbol so lets check if the object file from // the symbol file in the symbol vendor is different than the // object file for the module, and if so search its symbol table to // see if we can come up with a better symbol. For example dSYM // files on MacOSX have an unstripped symbol table inside of them. ObjectFile *symtab_objfile = symtab->GetObjectFile(); if (symtab_objfile && symtab_objfile->IsStripped()) { ObjectFile *symfile_objfile = symfile->GetObjectFile(); if (symfile_objfile != symtab_objfile) { Symtab *symfile_symtab = symfile_objfile->GetSymtab(); if (symfile_symtab) { Symbol *symbol = symfile_symtab->FindSymbolContainingFileAddress( so_addr.GetFileAddress()); if (symbol && !symbol->IsSynthetic()) { sc.symbol = symbol; } } } } } resolved_flags |= eSymbolContextSymbol; } } } // For function symbols, so_addr may be off by one. This is a convention // consistent with FDE row indices in eh_frame sections, but requires extra // logic here to permit symbol lookup for disassembly and unwind. if (resolve_scope & eSymbolContextSymbol && !(resolved_flags & eSymbolContextSymbol) && resolve_tail_call_address && so_addr.IsSectionOffset()) { Address previous_addr = so_addr; previous_addr.Slide(-1); bool do_resolve_tail_call_address = false; // prevent recursion const uint32_t flags = ResolveSymbolContextForAddress( previous_addr, resolve_scope, sc, do_resolve_tail_call_address); if (flags & eSymbolContextSymbol) { AddressRange addr_range; if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) { if (addr_range.GetBaseAddress().GetSection() == so_addr.GetSection()) { // If the requested address is one past the address range of a // function (i.e. a tail call), or the decremented address is the // start of a function (i.e. some forms of trampoline), indicate // that the symbol has been resolved. if (so_addr.GetOffset() == addr_range.GetBaseAddress().GetOffset() || so_addr.GetOffset() == addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize()) { resolved_flags |= flags; } } else { sc.symbol = nullptr; // Don't trust the symbol if the sections didn't match. } } } } } return resolved_flags; } uint32_t Module::ResolveSymbolContextForFilePath( const char *file_path, uint32_t line, bool check_inlines, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { FileSpec file_spec(file_path); return ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines, resolve_scope, sc_list); } uint32_t Module::ResolveSymbolContextsForFileSpec( const FileSpec &file_spec, uint32_t line, bool check_inlines, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { std::lock_guard guard(m_mutex); static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "Module::ResolveSymbolContextForFilePath (%s:%u, " "check_inlines = %s, resolve_scope = 0x%8.8x)", file_spec.GetPath().c_str(), line, check_inlines ? "yes" : "no", resolve_scope); const uint32_t initial_count = sc_list.GetSize(); if (SymbolFile *symbols = GetSymbolFile()) symbols->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list); return sc_list.GetSize() - initial_count; } void Module::FindGlobalVariables(ConstString name, const CompilerDeclContext *parent_decl_ctx, size_t max_matches, VariableList &variables) { if (SymbolFile *symbols = GetSymbolFile()) symbols->FindGlobalVariables(name, parent_decl_ctx, max_matches, variables); } void Module::FindGlobalVariables(const RegularExpression ®ex, size_t max_matches, VariableList &variables) { SymbolFile *symbols = GetSymbolFile(); if (symbols) symbols->FindGlobalVariables(regex, max_matches, variables); } void Module::FindCompileUnits(const FileSpec &path, SymbolContextList &sc_list) { const size_t num_compile_units = GetNumCompileUnits(); SymbolContext sc; sc.module_sp = shared_from_this(); for (size_t i = 0; i < num_compile_units; ++i) { sc.comp_unit = GetCompileUnitAtIndex(i).get(); if (sc.comp_unit) { if (FileSpec::Match(path, sc.comp_unit->GetPrimaryFile())) sc_list.Append(sc); } } } Module::LookupInfo::LookupInfo(ConstString name, FunctionNameType name_type_mask, LanguageType language) : m_name(name), m_lookup_name(), m_language(language), m_name_type_mask(eFunctionNameTypeNone), m_match_name_after_lookup(false) { const char *name_cstr = name.GetCString(); llvm::StringRef basename; llvm::StringRef context; if (name_type_mask & eFunctionNameTypeAuto) { if (CPlusPlusLanguage::IsCPPMangledName(name_cstr)) m_name_type_mask = eFunctionNameTypeFull; else if ((language == eLanguageTypeUnknown || Language::LanguageIsObjC(language)) && ObjCLanguage::IsPossibleObjCMethodName(name_cstr)) m_name_type_mask = eFunctionNameTypeFull; else if (Language::LanguageIsC(language)) { m_name_type_mask = eFunctionNameTypeFull; } else { if ((language == eLanguageTypeUnknown || Language::LanguageIsObjC(language)) && ObjCLanguage::IsPossibleObjCSelector(name_cstr)) m_name_type_mask |= eFunctionNameTypeSelector; CPlusPlusLanguage::MethodName cpp_method(name); basename = cpp_method.GetBasename(); if (basename.empty()) { if (CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context, basename)) m_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase); else m_name_type_mask |= eFunctionNameTypeFull; } else { m_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase); } } } else { m_name_type_mask = name_type_mask; if (name_type_mask & eFunctionNameTypeMethod || name_type_mask & eFunctionNameTypeBase) { // If they've asked for a CPP method or function name and it can't be // that, we don't even need to search for CPP methods or names. CPlusPlusLanguage::MethodName cpp_method(name); if (cpp_method.IsValid()) { basename = cpp_method.GetBasename(); if (!cpp_method.GetQualifiers().empty()) { // There is a "const" or other qualifier following the end of the // function parens, this can't be a eFunctionNameTypeBase m_name_type_mask &= ~(eFunctionNameTypeBase); if (m_name_type_mask == eFunctionNameTypeNone) return; } } else { // If the CPP method parser didn't manage to chop this up, try to fill // in the base name if we can. If a::b::c is passed in, we need to just // look up "c", and then we'll filter the result later. CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context, basename); } } if (name_type_mask & eFunctionNameTypeSelector) { if (!ObjCLanguage::IsPossibleObjCSelector(name_cstr)) { m_name_type_mask &= ~(eFunctionNameTypeSelector); if (m_name_type_mask == eFunctionNameTypeNone) return; } } // Still try and get a basename in case someone specifies a name type mask // of eFunctionNameTypeFull and a name like "A::func" if (basename.empty()) { if (name_type_mask & eFunctionNameTypeFull && !CPlusPlusLanguage::IsCPPMangledName(name_cstr)) { CPlusPlusLanguage::MethodName cpp_method(name); basename = cpp_method.GetBasename(); if (basename.empty()) CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context, basename); } } } if (!basename.empty()) { // The name supplied was a partial C++ path like "a::count". In this case // we want to do a lookup on the basename "count" and then make sure any // matching results contain "a::count" so that it would match "b::a::count" // and "a::count". This is why we set "match_name_after_lookup" to true m_lookup_name.SetString(basename); m_match_name_after_lookup = true; } else { // The name is already correct, just use the exact name as supplied, and we // won't need to check if any matches contain "name" m_lookup_name = name; m_match_name_after_lookup = false; } } void Module::LookupInfo::Prune(SymbolContextList &sc_list, size_t start_idx) const { if (m_match_name_after_lookup && m_name) { SymbolContext sc; size_t i = start_idx; while (i < sc_list.GetSize()) { if (!sc_list.GetContextAtIndex(i, sc)) break; ConstString full_name(sc.GetFunctionName()); if (full_name && ::strstr(full_name.GetCString(), m_name.GetCString()) == nullptr) { sc_list.RemoveContextAtIndex(i); } else { ++i; } } } // If we have only full name matches we might have tried to set breakpoint on // "func" and specified eFunctionNameTypeFull, but we might have found // "a::func()", "a::b::func()", "c::func()", "func()" and "func". Only // "func()" and "func" should end up matching. if (m_name_type_mask == eFunctionNameTypeFull) { SymbolContext sc; size_t i = start_idx; while (i < sc_list.GetSize()) { if (!sc_list.GetContextAtIndex(i, sc)) break; // Make sure the mangled and demangled names don't match before we try to // pull anything out ConstString mangled_name(sc.GetFunctionName(Mangled::ePreferMangled)); ConstString full_name(sc.GetFunctionName()); if (mangled_name != m_name && full_name != m_name) { CPlusPlusLanguage::MethodName cpp_method(full_name); if (cpp_method.IsValid()) { if (cpp_method.GetContext().empty()) { if (cpp_method.GetBasename().compare(m_name.GetStringRef()) != 0) { sc_list.RemoveContextAtIndex(i); continue; } } else { std::string qualified_name; llvm::StringRef anon_prefix("(anonymous namespace)"); if (cpp_method.GetContext() == anon_prefix) qualified_name = cpp_method.GetBasename().str(); else qualified_name = cpp_method.GetScopeQualifiedName(); if (qualified_name != m_name.GetCString()) { sc_list.RemoveContextAtIndex(i); continue; } } } } ++i; } } } void Module::FindFunctions(ConstString name, const CompilerDeclContext *parent_decl_ctx, FunctionNameType name_type_mask, bool include_symbols, bool include_inlines, SymbolContextList &sc_list) { const size_t old_size = sc_list.GetSize(); // Find all the functions (not symbols, but debug information functions... SymbolFile *symbols = GetSymbolFile(); if (name_type_mask & eFunctionNameTypeAuto) { LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown); if (symbols) { symbols->FindFunctions(lookup_info.GetLookupName(), parent_decl_ctx, lookup_info.GetNameTypeMask(), include_inlines, sc_list); // Now check our symbol table for symbols that are code symbols if // requested if (include_symbols) { Symtab *symtab = symbols->GetSymtab(); if (symtab) symtab->FindFunctionSymbols(lookup_info.GetLookupName(), lookup_info.GetNameTypeMask(), sc_list); } } const size_t new_size = sc_list.GetSize(); if (old_size < new_size) lookup_info.Prune(sc_list, old_size); } else { if (symbols) { symbols->FindFunctions(name, parent_decl_ctx, name_type_mask, include_inlines, sc_list); // Now check our symbol table for symbols that are code symbols if // requested if (include_symbols) { Symtab *symtab = symbols->GetSymtab(); if (symtab) symtab->FindFunctionSymbols(name, name_type_mask, sc_list); } } } } void Module::FindFunctions(const RegularExpression ®ex, bool include_symbols, bool include_inlines, SymbolContextList &sc_list) { const size_t start_size = sc_list.GetSize(); if (SymbolFile *symbols = GetSymbolFile()) { symbols->FindFunctions(regex, include_inlines, sc_list); // Now check our symbol table for symbols that are code symbols if // requested if (include_symbols) { Symtab *symtab = symbols->GetSymtab(); if (symtab) { std::vector symbol_indexes; symtab->AppendSymbolIndexesMatchingRegExAndType( regex, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes); const size_t num_matches = symbol_indexes.size(); if (num_matches) { SymbolContext sc(this); const size_t end_functions_added_index = sc_list.GetSize(); size_t num_functions_added_to_sc_list = end_functions_added_index - start_size; if (num_functions_added_to_sc_list == 0) { // No functions were added, just symbols, so we can just append // them for (size_t i = 0; i < num_matches; ++i) { sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]); SymbolType sym_type = sc.symbol->GetType(); if (sc.symbol && (sym_type == eSymbolTypeCode || sym_type == eSymbolTypeResolver)) sc_list.Append(sc); } } else { typedef std::map FileAddrToIndexMap; FileAddrToIndexMap file_addr_to_index; for (size_t i = start_size; i < end_functions_added_index; ++i) { const SymbolContext &sc = sc_list[i]; if (sc.block) continue; file_addr_to_index[sc.function->GetAddressRange() .GetBaseAddress() .GetFileAddress()] = i; } FileAddrToIndexMap::const_iterator end = file_addr_to_index.end(); // Functions were added so we need to merge symbols into any // existing function symbol contexts for (size_t i = start_size; i < num_matches; ++i) { sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]); SymbolType sym_type = sc.symbol->GetType(); if (sc.symbol && sc.symbol->ValueIsAddress() && (sym_type == eSymbolTypeCode || sym_type == eSymbolTypeResolver)) { FileAddrToIndexMap::const_iterator pos = file_addr_to_index.find( sc.symbol->GetAddressRef().GetFileAddress()); if (pos == end) sc_list.Append(sc); else sc_list[pos->second].symbol = sc.symbol; } } } } } } } } void Module::FindAddressesForLine(const lldb::TargetSP target_sp, const FileSpec &file, uint32_t line, Function *function, std::vector
&output_local, std::vector
&output_extern) { SearchFilterByModule filter(target_sp, m_file); AddressResolverFileLine resolver(file, line, true); resolver.ResolveAddress(filter); for (size_t n = 0; n < resolver.GetNumberOfAddresses(); n++) { Address addr = resolver.GetAddressRangeAtIndex(n).GetBaseAddress(); Function *f = addr.CalculateSymbolContextFunction(); if (f && f == function) output_local.push_back(addr); else output_extern.push_back(addr); } } void Module::FindTypes_Impl( ConstString name, const CompilerDeclContext *parent_decl_ctx, size_t max_matches, llvm::DenseSet &searched_symbol_files, TypeMap &types) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); if (SymbolFile *symbols = GetSymbolFile()) symbols->FindTypes(name, parent_decl_ctx, max_matches, searched_symbol_files, types); } void Module::FindTypesInNamespace(ConstString type_name, const CompilerDeclContext *parent_decl_ctx, size_t max_matches, TypeList &type_list) { TypeMap types_map; llvm::DenseSet searched_symbol_files; FindTypes_Impl(type_name, parent_decl_ctx, max_matches, searched_symbol_files, types_map); if (types_map.GetSize()) { SymbolContext sc; sc.module_sp = shared_from_this(); sc.SortTypeList(types_map, type_list); } } lldb::TypeSP Module::FindFirstType(const SymbolContext &sc, ConstString name, bool exact_match) { TypeList type_list; llvm::DenseSet searched_symbol_files; FindTypes(name, exact_match, 1, searched_symbol_files, type_list); if (type_list.GetSize()) return type_list.GetTypeAtIndex(0); return TypeSP(); } void Module::FindTypes( ConstString name, bool exact_match, size_t max_matches, llvm::DenseSet &searched_symbol_files, TypeList &types) { const char *type_name_cstr = name.GetCString(); llvm::StringRef type_scope; llvm::StringRef type_basename; TypeClass type_class = eTypeClassAny; TypeMap typesmap; if (Type::GetTypeScopeAndBasename(type_name_cstr, type_scope, type_basename, type_class)) { // Check if "name" starts with "::" which means the qualified type starts // from the root namespace and implies and exact match. The typenames we // get back from clang do not start with "::" so we need to strip this off // in order to get the qualified names to match exact_match = type_scope.consume_front("::"); ConstString type_basename_const_str(type_basename); FindTypes_Impl(type_basename_const_str, nullptr, max_matches, searched_symbol_files, typesmap); if (typesmap.GetSize()) typesmap.RemoveMismatchedTypes(type_scope, type_basename, type_class, exact_match); } else { // The type is not in a namespace/class scope, just search for it by // basename if (type_class != eTypeClassAny && !type_basename.empty()) { // The "type_name_cstr" will have been modified if we have a valid type // class prefix (like "struct", "class", "union", "typedef" etc). FindTypes_Impl(ConstString(type_basename), nullptr, UINT_MAX, searched_symbol_files, typesmap); typesmap.RemoveMismatchedTypes(type_scope, type_basename, type_class, exact_match); } else { FindTypes_Impl(name, nullptr, UINT_MAX, searched_symbol_files, typesmap); if (exact_match) { std::string name_str(name.AsCString("")); typesmap.RemoveMismatchedTypes(type_scope, name_str, type_class, exact_match); } } } if (typesmap.GetSize()) { SymbolContext sc; sc.module_sp = shared_from_this(); sc.SortTypeList(typesmap, types); } } void Module::FindTypes( llvm::ArrayRef pattern, LanguageSet languages, llvm::DenseSet &searched_symbol_files, TypeMap &types) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); if (SymbolFile *symbols = GetSymbolFile()) symbols->FindTypes(pattern, languages, searched_symbol_files, types); } SymbolFile *Module::GetSymbolFile(bool can_create, Stream *feedback_strm) { if (!m_did_load_symfile.load()) { std::lock_guard guard(m_mutex); if (!m_did_load_symfile.load() && can_create) { ObjectFile *obj_file = GetObjectFile(); if (obj_file != nullptr) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); m_symfile_up.reset( SymbolVendor::FindPlugin(shared_from_this(), feedback_strm)); m_did_load_symfile = true; } } } return m_symfile_up ? m_symfile_up->GetSymbolFile() : nullptr; } Symtab *Module::GetSymtab() { if (SymbolFile *symbols = GetSymbolFile()) return symbols->GetSymtab(); return nullptr; } void Module::SetFileSpecAndObjectName(const FileSpec &file, ConstString object_name) { // Container objects whose paths do not specify a file directly can call this // function to correct the file and object names. m_file = file; m_mod_time = FileSystem::Instance().GetModificationTime(file); m_object_name = object_name; } const ArchSpec &Module::GetArchitecture() const { return m_arch; } std::string Module::GetSpecificationDescription() const { std::string spec(GetFileSpec().GetPath()); if (m_object_name) { spec += '('; spec += m_object_name.GetCString(); spec += ')'; } return spec; } void Module::GetDescription(llvm::raw_ostream &s, lldb::DescriptionLevel level) { std::lock_guard guard(m_mutex); if (level >= eDescriptionLevelFull) { if (m_arch.IsValid()) s << llvm::formatv("({0}) ", m_arch.GetArchitectureName()); } if (level == eDescriptionLevelBrief) { const char *filename = m_file.GetFilename().GetCString(); if (filename) s << filename; } else { char path[PATH_MAX]; if (m_file.GetPath(path, sizeof(path))) s << path; } const char *object_name = m_object_name.GetCString(); if (object_name) s << llvm::formatv("({0})", object_name); } void Module::ReportError(const char *format, ...) { if (format && format[0]) { StreamString strm; strm.PutCString("error: "); GetDescription(strm.AsRawOstream(), lldb::eDescriptionLevelBrief); strm.PutChar(' '); va_list args; va_start(args, format); strm.PrintfVarArg(format, args); va_end(args); const int format_len = strlen(format); if (format_len > 0) { const char last_char = format[format_len - 1]; if (last_char != '\n' && last_char != '\r') strm.EOL(); } Host::SystemLog(Host::eSystemLogError, "%s", strm.GetData()); } } bool Module::FileHasChanged() const { if (!m_file_has_changed) m_file_has_changed = (FileSystem::Instance().GetModificationTime(m_file) != m_mod_time); return m_file_has_changed; } void Module::ReportErrorIfModifyDetected(const char *format, ...) { if (!m_first_file_changed_log) { if (FileHasChanged()) { m_first_file_changed_log = true; if (format) { StreamString strm; strm.PutCString("error: the object file "); GetDescription(strm.AsRawOstream(), lldb::eDescriptionLevelFull); strm.PutCString(" has been modified\n"); va_list args; va_start(args, format); strm.PrintfVarArg(format, args); va_end(args); const int format_len = strlen(format); if (format_len > 0) { const char last_char = format[format_len - 1]; if (last_char != '\n' && last_char != '\r') strm.EOL(); } strm.PutCString("The debug session should be aborted as the original " "debug information has been overwritten.\n"); Host::SystemLog(Host::eSystemLogError, "%s", strm.GetData()); } } } } void Module::ReportWarning(const char *format, ...) { if (format && format[0]) { StreamString strm; strm.PutCString("warning: "); GetDescription(strm.AsRawOstream(), lldb::eDescriptionLevelFull); strm.PutChar(' '); va_list args; va_start(args, format); strm.PrintfVarArg(format, args); va_end(args); const int format_len = strlen(format); if (format_len > 0) { const char last_char = format[format_len - 1]; if (last_char != '\n' && last_char != '\r') strm.EOL(); } Host::SystemLog(Host::eSystemLogWarning, "%s", strm.GetData()); } } void Module::LogMessage(Log *log, const char *format, ...) { if (log != nullptr) { StreamString log_message; GetDescription(log_message.AsRawOstream(), lldb::eDescriptionLevelFull); log_message.PutCString(": "); va_list args; va_start(args, format); log_message.PrintfVarArg(format, args); va_end(args); log->PutCString(log_message.GetData()); } } void Module::LogMessageVerboseBacktrace(Log *log, const char *format, ...) { if (log != nullptr) { StreamString log_message; GetDescription(log_message.AsRawOstream(), lldb::eDescriptionLevelFull); log_message.PutCString(": "); va_list args; va_start(args, format); log_message.PrintfVarArg(format, args); va_end(args); if (log->GetVerbose()) { std::string back_trace; llvm::raw_string_ostream stream(back_trace); llvm::sys::PrintStackTrace(stream); log_message.PutCString(back_trace); } log->PutCString(log_message.GetData()); } } void Module::Dump(Stream *s) { std::lock_guard guard(m_mutex); // s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); s->Indent(); s->Printf("Module %s%s%s%s\n", m_file.GetPath().c_str(), m_object_name ? "(" : "", m_object_name ? m_object_name.GetCString() : "", m_object_name ? ")" : ""); s->IndentMore(); ObjectFile *objfile = GetObjectFile(); if (objfile) objfile->Dump(s); if (SymbolFile *symbols = GetSymbolFile()) symbols->Dump(*s); s->IndentLess(); } ConstString Module::GetObjectName() const { return m_object_name; } ObjectFile *Module::GetObjectFile() { if (!m_did_load_objfile.load()) { std::lock_guard guard(m_mutex); if (!m_did_load_objfile.load()) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString("")); DataBufferSP data_sp; lldb::offset_t data_offset = 0; const lldb::offset_t file_size = FileSystem::Instance().GetByteSize(m_file); if (file_size > m_object_offset) { m_did_load_objfile = true; m_objfile_sp = ObjectFile::FindPlugin( shared_from_this(), &m_file, m_object_offset, file_size - m_object_offset, data_sp, data_offset); if (m_objfile_sp) { // Once we get the object file, update our module with the object // file's architecture since it might differ in vendor/os if some // parts were unknown. But since the matching arch might already be // more specific than the generic COFF architecture, only merge in // those values that overwrite unspecified unknown values. m_arch.MergeFrom(m_objfile_sp->GetArchitecture()); } else { ReportError("failed to load objfile for %s", GetFileSpec().GetPath().c_str()); } } } } return m_objfile_sp.get(); } SectionList *Module::GetSectionList() { // Populate m_sections_up with sections from objfile. if (!m_sections_up) { ObjectFile *obj_file = GetObjectFile(); if (obj_file != nullptr) obj_file->CreateSections(*GetUnifiedSectionList()); } return m_sections_up.get(); } void Module::SectionFileAddressesChanged() { ObjectFile *obj_file = GetObjectFile(); if (obj_file) obj_file->SectionFileAddressesChanged(); if (SymbolFile *symbols = GetSymbolFile()) symbols->SectionFileAddressesChanged(); } UnwindTable &Module::GetUnwindTable() { if (!m_unwind_table) m_unwind_table.emplace(*this); return *m_unwind_table; } SectionList *Module::GetUnifiedSectionList() { if (!m_sections_up) m_sections_up = std::make_unique(); return m_sections_up.get(); } const Symbol *Module::FindFirstSymbolWithNameAndType(ConstString name, SymbolType symbol_type) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer( func_cat, "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)", name.AsCString(), symbol_type); if (Symtab *symtab = GetSymtab()) return symtab->FindFirstSymbolWithNameAndType( name, symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny); return nullptr; } void Module::SymbolIndicesToSymbolContextList( Symtab *symtab, std::vector &symbol_indexes, SymbolContextList &sc_list) { // No need to protect this call using m_mutex all other method calls are // already thread safe. size_t num_indices = symbol_indexes.size(); if (num_indices > 0) { SymbolContext sc; CalculateSymbolContext(&sc); for (size_t i = 0; i < num_indices; i++) { sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]); if (sc.symbol) sc_list.Append(sc); } } } void Module::FindFunctionSymbols(ConstString name, uint32_t name_type_mask, SymbolContextList &sc_list) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "Module::FindSymbolsFunctions (name = %s, mask = 0x%8.8x)", name.AsCString(), name_type_mask); if (Symtab *symtab = GetSymtab()) symtab->FindFunctionSymbols(name, name_type_mask, sc_list); } void Module::FindSymbolsWithNameAndType(ConstString name, SymbolType symbol_type, SymbolContextList &sc_list) { // No need to protect this call using m_mutex all other method calls are // already thread safe. static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer( func_cat, "Module::FindSymbolsWithNameAndType (name = %s, type = %i)", name.AsCString(), symbol_type); if (Symtab *symtab = GetSymtab()) { std::vector symbol_indexes; symtab->FindAllSymbolsWithNameAndType(name, symbol_type, symbol_indexes); SymbolIndicesToSymbolContextList(symtab, symbol_indexes, sc_list); } } void Module::FindSymbolsMatchingRegExAndType(const RegularExpression ®ex, SymbolType symbol_type, SymbolContextList &sc_list) { // No need to protect this call using m_mutex all other method calls are // already thread safe. static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer( func_cat, "Module::FindSymbolsMatchingRegExAndType (regex = %s, type = %i)", regex.GetText().str().c_str(), symbol_type); if (Symtab *symtab = GetSymtab()) { std::vector symbol_indexes; symtab->FindAllSymbolsMatchingRexExAndType( regex, symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes); SymbolIndicesToSymbolContextList(symtab, symbol_indexes, sc_list); } } void Module::PreloadSymbols() { std::lock_guard guard(m_mutex); SymbolFile *sym_file = GetSymbolFile(); if (!sym_file) return; // Prime the symbol file first, since it adds symbols to the symbol table. sym_file->PreloadSymbols(); // Now we can prime the symbol table. if (Symtab *symtab = sym_file->GetSymtab()) symtab->PreloadSymbols(); } void Module::SetSymbolFileFileSpec(const FileSpec &file) { if (!FileSystem::Instance().Exists(file)) return; if (m_symfile_up) { // Remove any sections in the unified section list that come from the // current symbol vendor. SectionList *section_list = GetSectionList(); SymbolFile *symbol_file = GetSymbolFile(); if (section_list && symbol_file) { ObjectFile *obj_file = symbol_file->GetObjectFile(); // Make sure we have an object file and that the symbol vendor's objfile // isn't the same as the module's objfile before we remove any sections // for it... if (obj_file) { // Check to make sure we aren't trying to specify the file we already // have if (obj_file->GetFileSpec() == file) { // We are being told to add the exact same file that we already have // we don't have to do anything. return; } // Cleare the current symtab as we are going to replace it with a new // one obj_file->ClearSymtab(); // Clear the unwind table too, as that may also be affected by the // symbol file information. m_unwind_table.reset(); // The symbol file might be a directory bundle ("/tmp/a.out.dSYM") // instead of a full path to the symbol file within the bundle // ("/tmp/a.out.dSYM/Contents/Resources/DWARF/a.out"). So we need to // check this if (FileSystem::Instance().IsDirectory(file)) { std::string new_path(file.GetPath()); std::string old_path(obj_file->GetFileSpec().GetPath()); if (old_path.find(new_path) == 0) { // We specified the same bundle as the symbol file that we already // have return; } } if (obj_file != m_objfile_sp.get()) { size_t num_sections = section_list->GetNumSections(0); for (size_t idx = num_sections; idx > 0; --idx) { lldb::SectionSP section_sp( section_list->GetSectionAtIndex(idx - 1)); if (section_sp->GetObjectFile() == obj_file) { section_list->DeleteSection(idx - 1); } } } } } // Keep all old symbol files around in case there are any lingering type // references in any SBValue objects that might have been handed out. m_old_symfiles.push_back(std::move(m_symfile_up)); } m_symfile_spec = file; m_symfile_up.reset(); m_did_load_symfile = false; } bool Module::IsExecutable() { if (GetObjectFile() == nullptr) return false; else return GetObjectFile()->IsExecutable(); } bool Module::IsLoadedInTarget(Target *target) { ObjectFile *obj_file = GetObjectFile(); if (obj_file) { SectionList *sections = GetSectionList(); if (sections != nullptr) { size_t num_sections = sections->GetSize(); for (size_t sect_idx = 0; sect_idx < num_sections; sect_idx++) { SectionSP section_sp = sections->GetSectionAtIndex(sect_idx); if (section_sp->GetLoadBaseAddress(target) != LLDB_INVALID_ADDRESS) { return true; } } } } return false; } bool Module::LoadScriptingResourceInTarget(Target *target, Status &error, Stream *feedback_stream) { if (!target) { error.SetErrorString("invalid destination Target"); return false; } LoadScriptFromSymFile should_load = target->TargetProperties::GetLoadScriptFromSymbolFile(); if (should_load == eLoadScriptFromSymFileFalse) return false; Debugger &debugger = target->GetDebugger(); const ScriptLanguage script_language = debugger.GetScriptLanguage(); if (script_language != eScriptLanguageNone) { PlatformSP platform_sp(target->GetPlatform()); if (!platform_sp) { error.SetErrorString("invalid Platform"); return false; } FileSpecList file_specs = platform_sp->LocateExecutableScriptingResources( target, *this, feedback_stream); const uint32_t num_specs = file_specs.GetSize(); if (num_specs) { ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); if (script_interpreter) { for (uint32_t i = 0; i < num_specs; ++i) { FileSpec scripting_fspec(file_specs.GetFileSpecAtIndex(i)); if (scripting_fspec && FileSystem::Instance().Exists(scripting_fspec)) { if (should_load == eLoadScriptFromSymFileWarn) { if (feedback_stream) feedback_stream->Printf( "warning: '%s' contains a debug script. To run this script " "in " "this debug session:\n\n command script import " "\"%s\"\n\n" "To run all discovered debug scripts in this session:\n\n" " settings set target.load-script-from-symbol-file " "true\n", GetFileSpec().GetFileNameStrippingExtension().GetCString(), scripting_fspec.GetPath().c_str()); return false; } StreamString scripting_stream; scripting_fspec.Dump(scripting_stream.AsRawOstream()); const bool init_lldb_globals = false; bool did_load = script_interpreter->LoadScriptingModule( scripting_stream.GetData(), init_lldb_globals, error); if (!did_load) return false; } } } else { error.SetErrorString("invalid ScriptInterpreter"); return false; } } } return true; } bool Module::SetArchitecture(const ArchSpec &new_arch) { if (!m_arch.IsValid()) { m_arch = new_arch; return true; } return m_arch.IsCompatibleMatch(new_arch); } bool Module::SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset, bool &changed) { ObjectFile *object_file = GetObjectFile(); if (object_file != nullptr) { changed = object_file->SetLoadAddress(target, value, value_is_offset); return true; } else { changed = false; } return false; } bool Module::MatchesModuleSpec(const ModuleSpec &module_ref) { const UUID &uuid = module_ref.GetUUID(); if (uuid.IsValid()) { // If the UUID matches, then nothing more needs to match... return (uuid == GetUUID()); } const FileSpec &file_spec = module_ref.GetFileSpec(); if (!FileSpec::Match(file_spec, m_file) && !FileSpec::Match(file_spec, m_platform_file)) return false; const FileSpec &platform_file_spec = module_ref.GetPlatformFileSpec(); if (!FileSpec::Match(platform_file_spec, GetPlatformFileSpec())) return false; const ArchSpec &arch = module_ref.GetArchitecture(); if (arch.IsValid()) { if (!m_arch.IsCompatibleMatch(arch)) return false; } ConstString object_name = module_ref.GetObjectName(); if (object_name) { if (object_name != GetObjectName()) return false; } return true; } bool Module::FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const { std::lock_guard guard(m_mutex); return m_source_mappings.FindFile(orig_spec, new_spec); } bool Module::RemapSourceFile(llvm::StringRef path, std::string &new_path) const { std::lock_guard guard(m_mutex); return m_source_mappings.RemapPath(path, new_path); } bool Module::MergeArchitecture(const ArchSpec &arch_spec) { if (!arch_spec.IsValid()) return false; LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_MODULES), "module has arch %s, merging/replacing with arch %s", m_arch.GetTriple().getTriple().c_str(), arch_spec.GetTriple().getTriple().c_str()); if (!m_arch.IsCompatibleMatch(arch_spec)) { // The new architecture is different, we just need to replace it. return SetArchitecture(arch_spec); } // Merge bits from arch_spec into "merged_arch" and set our architecture. ArchSpec merged_arch(m_arch); merged_arch.MergeFrom(arch_spec); // SetArchitecture() is a no-op if m_arch is already valid. m_arch = ArchSpec(); return SetArchitecture(merged_arch); } llvm::VersionTuple Module::GetVersion() { if (ObjectFile *obj_file = GetObjectFile()) return obj_file->GetVersion(); return llvm::VersionTuple(); } bool Module::GetIsDynamicLinkEditor() { ObjectFile *obj_file = GetObjectFile(); if (obj_file) return obj_file->GetIsDynamicLinkEditor(); return false; }