diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp b/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp new file mode 100644 index 000000000000..5fb9b6b9f729 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp @@ -0,0 +1,413 @@ +//===-- CompileUnit.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/Symbol/CompileUnit.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/Language.h" + +using namespace lldb; +using namespace lldb_private; + +CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, + const char *pathname, const lldb::user_id_t cu_sym_id, + lldb::LanguageType language, + lldb_private::LazyBool is_optimized) + : ModuleChild(module_sp), FileSpec(pathname), UserID(cu_sym_id), + m_user_data(user_data), m_language(language), m_flags(0), + m_support_files(), m_line_table_up(), m_variables(), + m_is_optimized(is_optimized) { + if (language != eLanguageTypeUnknown) + m_flags.Set(flagsParsedLanguage); + assert(module_sp); +} + +CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, + const FileSpec &fspec, const lldb::user_id_t cu_sym_id, + lldb::LanguageType language, + lldb_private::LazyBool is_optimized) + : ModuleChild(module_sp), FileSpec(fspec), UserID(cu_sym_id), + m_user_data(user_data), m_language(language), m_flags(0), + m_support_files(), m_line_table_up(), m_variables(), + m_is_optimized(is_optimized) { + if (language != eLanguageTypeUnknown) + m_flags.Set(flagsParsedLanguage); + assert(module_sp); +} + +CompileUnit::~CompileUnit() {} + +void CompileUnit::CalculateSymbolContext(SymbolContext *sc) { + sc->comp_unit = this; + GetModule()->CalculateSymbolContext(sc); +} + +ModuleSP CompileUnit::CalculateSymbolContextModule() { return GetModule(); } + +CompileUnit *CompileUnit::CalculateSymbolContextCompileUnit() { return this; } + +void CompileUnit::DumpSymbolContext(Stream *s) { + GetModule()->DumpSymbolContext(s); + s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID()); +} + +void CompileUnit::GetDescription(Stream *s, + lldb::DescriptionLevel level) const { + const char *language = Language::GetNameForLanguageType(m_language); + *s << "id = " << (const UserID &)*this << ", file = \"" + << (const FileSpec &)*this << "\", language = \"" << language << '"'; +} + +void CompileUnit::ForeachFunction( + llvm::function_ref<bool(const FunctionSP &)> lambda) const { + std::vector<lldb::FunctionSP> sorted_functions; + sorted_functions.reserve(m_functions_by_uid.size()); + for (auto &p : m_functions_by_uid) + sorted_functions.push_back(p.second); + llvm::sort(sorted_functions.begin(), sorted_functions.end(), + [](const lldb::FunctionSP &a, const lldb::FunctionSP &b) { + return a->GetID() < b->GetID(); + }); + + for (auto &f : sorted_functions) + if (lambda(f)) + return; +} + +// Dump the current contents of this object. No functions that cause on demand +// parsing of functions, globals, statics are called, so this is a good +// function to call to get an idea of the current contents of the CompileUnit +// object. +void CompileUnit::Dump(Stream *s, bool show_context) const { + const char *language = Language::GetNameForLanguageType(m_language); + + s->Printf("%p: ", static_cast<const void *>(this)); + s->Indent(); + *s << "CompileUnit" << static_cast<const UserID &>(*this) << ", language = \"" + << language << "\", file = '" << static_cast<const FileSpec &>(*this) + << "'\n"; + + // m_types.Dump(s); + + if (m_variables.get()) { + s->IndentMore(); + m_variables->Dump(s, show_context); + s->IndentLess(); + } + + if (!m_functions_by_uid.empty()) { + s->IndentMore(); + ForeachFunction([&s, show_context](const FunctionSP &f) { + f->Dump(s, show_context); + return false; + }); + + s->IndentLess(); + s->EOL(); + } +} + +// Add a function to this compile unit +void CompileUnit::AddFunction(FunctionSP &funcSP) { + m_functions_by_uid[funcSP->GetID()] = funcSP; +} + +// Find functions using the Mangled::Tokens token list. This function currently +// implements an interactive approach designed to find all instances of certain +// functions. It isn't designed to the quickest way to lookup functions as it +// will need to iterate through all functions and see if they match, though it +// does provide a powerful and context sensitive way to search for all +// functions with a certain name, all functions in a namespace, or all +// functions of a template type. See Mangled::Tokens::Parse() comments for more +// information. +// +// The function prototype will need to change to return a list of results. It +// was originally used to help debug the Mangled class and the +// Mangled::Tokens::MatchesQuery() function and it currently will print out a +// list of matching results for the functions that are currently in this +// compile unit. +// +// A FindFunctions method should be called prior to this that takes +// a regular function name (const char * or ConstString as a parameter) before +// resorting to this slower but more complete function. The other FindFunctions +// method should be able to take advantage of any accelerator tables available +// in the debug information (which is parsed by the SymbolFile parser plug-ins +// and registered with each Module). +// void +// CompileUnit::FindFunctions(const Mangled::Tokens& tokens) +//{ +// if (!m_functions.empty()) +// { +// Stream s(stdout); +// std::vector<FunctionSP>::const_iterator pos; +// std::vector<FunctionSP>::const_iterator end = m_functions.end(); +// for (pos = m_functions.begin(); pos != end; ++pos) +// { +// const ConstString& demangled = (*pos)->Mangled().Demangled(); +// if (demangled) +// { +// const Mangled::Tokens& func_tokens = +// (*pos)->Mangled().GetTokens(); +// if (func_tokens.MatchesQuery (tokens)) +// s << "demangled MATCH found: " << demangled << "\n"; +// } +// } +// } +//} + +FunctionSP CompileUnit::FindFunctionByUID(lldb::user_id_t func_uid) { + auto it = m_functions_by_uid.find(func_uid); + if (it == m_functions_by_uid.end()) + return FunctionSP(); + return it->second; +} + +lldb::LanguageType CompileUnit::GetLanguage() { + if (m_language == eLanguageTypeUnknown) { + if (m_flags.IsClear(flagsParsedLanguage)) { + m_flags.Set(flagsParsedLanguage); + SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); + if (symbol_vendor) { + m_language = symbol_vendor->ParseLanguage(*this); + } + } + } + return m_language; +} + +LineTable *CompileUnit::GetLineTable() { + if (m_line_table_up == nullptr) { + if (m_flags.IsClear(flagsParsedLineTable)) { + m_flags.Set(flagsParsedLineTable); + SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); + if (symbol_vendor) + symbol_vendor->ParseLineTable(*this); + } + } + return m_line_table_up.get(); +} + +void CompileUnit::SetLineTable(LineTable *line_table) { + if (line_table == nullptr) + m_flags.Clear(flagsParsedLineTable); + else + m_flags.Set(flagsParsedLineTable); + m_line_table_up.reset(line_table); +} + +DebugMacros *CompileUnit::GetDebugMacros() { + if (m_debug_macros_sp.get() == nullptr) { + if (m_flags.IsClear(flagsParsedDebugMacros)) { + m_flags.Set(flagsParsedDebugMacros); + SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); + if (symbol_vendor) { + symbol_vendor->ParseDebugMacros(*this); + } + } + } + + return m_debug_macros_sp.get(); +} + +void CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) { + if (debug_macros_sp.get() == nullptr) + m_flags.Clear(flagsParsedDebugMacros); + else + m_flags.Set(flagsParsedDebugMacros); + m_debug_macros_sp = debug_macros_sp; +} + +VariableListSP CompileUnit::GetVariableList(bool can_create) { + if (m_variables.get() == nullptr && can_create) { + SymbolContext sc; + CalculateSymbolContext(&sc); + assert(sc.module_sp); + sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc); + } + + return m_variables; +} + +uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line, + const FileSpec *file_spec_ptr, bool exact, + LineEntry *line_entry_ptr) { + uint32_t file_idx = 0; + + if (file_spec_ptr) { + file_idx = GetSupportFiles().FindFileIndex(1, *file_spec_ptr, true); + if (file_idx == UINT32_MAX) + return UINT32_MAX; + } else { + // All the line table entries actually point to the version of the Compile + // Unit that is in the support files (the one at 0 was artificially added.) + // So prefer the one further on in the support files if it exists... + const FileSpecList &support_files = GetSupportFiles(); + const bool full = true; + file_idx = support_files.FindFileIndex( + 1, support_files.GetFileSpecAtIndex(0), full); + if (file_idx == UINT32_MAX) + file_idx = 0; + } + LineTable *line_table = GetLineTable(); + if (line_table) + return line_table->FindLineEntryIndexByFileIndex(start_idx, file_idx, line, + exact, line_entry_ptr); + return UINT32_MAX; +} + +uint32_t CompileUnit::ResolveSymbolContext(const FileSpec &file_spec, + uint32_t line, bool check_inlines, + bool exact, + SymbolContextItem resolve_scope, + SymbolContextList &sc_list) { + // First find all of the file indexes that match our "file_spec". If + // "file_spec" has an empty directory, then only compare the basenames when + // finding file indexes + std::vector<uint32_t> file_indexes; + const bool full_match = (bool)file_spec.GetDirectory(); + bool file_spec_matches_cu_file_spec = + FileSpec::Equal(file_spec, *this, full_match); + + // If we are not looking for inlined functions and our file spec doesn't + // match then we are done... + if (!file_spec_matches_cu_file_spec && !check_inlines) + return 0; + + uint32_t file_idx = + GetSupportFiles().FindFileIndex(1, file_spec, true); + while (file_idx != UINT32_MAX) { + file_indexes.push_back(file_idx); + file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true); + } + + const size_t num_file_indexes = file_indexes.size(); + if (num_file_indexes == 0) + return 0; + + const uint32_t prev_size = sc_list.GetSize(); + + SymbolContext sc(GetModule()); + sc.comp_unit = this; + + if (line != 0) { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table != nullptr) { + uint32_t found_line; + uint32_t line_idx; + + if (num_file_indexes == 1) { + // We only have a single support file that matches, so use the line + // table function that searches for a line entries that match a single + // support file index + LineEntry line_entry; + line_idx = line_table->FindLineEntryIndexByFileIndex( + 0, file_indexes.front(), line, exact, &line_entry); + + // If "exact == true", then "found_line" will be the same as "line". If + // "exact == false", the "found_line" will be the closest line entry + // with a line number greater than "line" and we will use this for our + // subsequent line exact matches below. + found_line = line_entry.line; + + while (line_idx != UINT32_MAX) { + // If they only asked for the line entry, then we're done, we can + // just copy that over. But if they wanted more than just the line + // number, fill it in. + if (resolve_scope == eSymbolContextLineEntry) { + sc.line_entry = line_entry; + } else { + line_entry.range.GetBaseAddress().CalculateSymbolContext( + &sc, resolve_scope); + } + + sc_list.Append(sc); + line_idx = line_table->FindLineEntryIndexByFileIndex( + line_idx + 1, file_indexes.front(), found_line, true, + &line_entry); + } + } else { + // We found multiple support files that match "file_spec" so use the + // line table function that searches for a line entries that match a + // multiple support file indexes. + LineEntry line_entry; + line_idx = line_table->FindLineEntryIndexByFileIndex( + 0, file_indexes, line, exact, &line_entry); + + // If "exact == true", then "found_line" will be the same as "line". If + // "exact == false", the "found_line" will be the closest line entry + // with a line number greater than "line" and we will use this for our + // subsequent line exact matches below. + found_line = line_entry.line; + + while (line_idx != UINT32_MAX) { + if (resolve_scope == eSymbolContextLineEntry) { + sc.line_entry = line_entry; + } else { + line_entry.range.GetBaseAddress().CalculateSymbolContext( + &sc, resolve_scope); + } + + sc_list.Append(sc); + line_idx = line_table->FindLineEntryIndexByFileIndex( + line_idx + 1, file_indexes, found_line, true, &line_entry); + } + } + } + } else if (file_spec_matches_cu_file_spec && !check_inlines) { + // only append the context if we aren't looking for inline call sites by + // file and line and if the file spec matches that of the compile unit + sc_list.Append(sc); + } + return sc_list.GetSize() - prev_size; +} + +bool CompileUnit::GetIsOptimized() { + if (m_is_optimized == eLazyBoolCalculate) { + m_is_optimized = eLazyBoolNo; + if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) { + if (symbol_vendor->ParseIsOptimized(*this)) + m_is_optimized = eLazyBoolYes; + } + } + return m_is_optimized; +} + +void CompileUnit::SetVariableList(VariableListSP &variables) { + m_variables = variables; +} + +const std::vector<SourceModule> &CompileUnit::GetImportedModules() { + if (m_imported_modules.empty() && + m_flags.IsClear(flagsParsedImportedModules)) { + m_flags.Set(flagsParsedImportedModules); + if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) { + SymbolContext sc; + CalculateSymbolContext(&sc); + symbol_vendor->ParseImportedModules(sc, m_imported_modules); + } + } + return m_imported_modules; +} + +const FileSpecList &CompileUnit::GetSupportFiles() { + if (m_support_files.GetSize() == 0) { + if (m_flags.IsClear(flagsParsedSupportFiles)) { + m_flags.Set(flagsParsedSupportFiles); + SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); + if (symbol_vendor) { + symbol_vendor->ParseSupportFiles(*this, m_support_files); + } + } + } + return m_support_files; +} + +void *CompileUnit::GetUserData() const { return m_user_data; } |