1 //===-- CompileUnit.cpp -----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Symbol/CompileUnit.h" 11 #include "lldb/Core/Module.h" 12 #include "lldb/Symbol/LineTable.h" 13 #include "lldb/Symbol/SymbolVendor.h" 14 #include "lldb/Symbol/VariableList.h" 15 #include "lldb/Target/Language.h" 16 17 using namespace lldb; 18 using namespace lldb_private; 19 20 CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, 21 const char *pathname, const lldb::user_id_t cu_sym_id, 22 lldb::LanguageType language, 23 lldb_private::LazyBool is_optimized) 24 : ModuleChild(module_sp), FileSpec(pathname, false), UserID(cu_sym_id), 25 m_user_data(user_data), m_language(language), m_flags(0), 26 m_support_files(), m_line_table_ap(), m_variables(), 27 m_is_optimized(is_optimized) { 28 if (language != eLanguageTypeUnknown) 29 m_flags.Set(flagsParsedLanguage); 30 assert(module_sp); 31 } 32 33 CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, 34 const FileSpec &fspec, const lldb::user_id_t cu_sym_id, 35 lldb::LanguageType language, 36 lldb_private::LazyBool is_optimized) 37 : ModuleChild(module_sp), FileSpec(fspec), UserID(cu_sym_id), 38 m_user_data(user_data), m_language(language), m_flags(0), 39 m_support_files(), m_line_table_ap(), m_variables(), 40 m_is_optimized(is_optimized) { 41 if (language != eLanguageTypeUnknown) 42 m_flags.Set(flagsParsedLanguage); 43 assert(module_sp); 44 } 45 46 CompileUnit::~CompileUnit() {} 47 48 void CompileUnit::CalculateSymbolContext(SymbolContext *sc) { 49 sc->comp_unit = this; 50 GetModule()->CalculateSymbolContext(sc); 51 } 52 53 ModuleSP CompileUnit::CalculateSymbolContextModule() { return GetModule(); } 54 55 CompileUnit *CompileUnit::CalculateSymbolContextCompileUnit() { return this; } 56 57 void CompileUnit::DumpSymbolContext(Stream *s) { 58 GetModule()->DumpSymbolContext(s); 59 s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID()); 60 } 61 62 void CompileUnit::GetDescription(Stream *s, 63 lldb::DescriptionLevel level) const { 64 const char *language = Language::GetNameForLanguageType(m_language); 65 *s << "id = " << (const UserID &)*this << ", file = \"" 66 << (const FileSpec &)*this << "\", language = \"" << language << '"'; 67 } 68 69 void CompileUnit::ForeachFunction( 70 llvm::function_ref<bool(const FunctionSP &)> lambda) const { 71 std::vector<lldb::FunctionSP> sorted_functions; 72 sorted_functions.reserve(m_functions_by_uid.size()); 73 for (auto &p : m_functions_by_uid) 74 sorted_functions.push_back(p.second); 75 std::sort(sorted_functions.begin(), sorted_functions.end(), 76 [](const lldb::FunctionSP &a, const lldb::FunctionSP &b) { 77 return a->GetID() < b->GetID(); 78 }); 79 80 for (auto &f : sorted_functions) 81 if (lambda(f)) 82 return; 83 } 84 85 //---------------------------------------------------------------------- 86 // Dump the current contents of this object. No functions that cause on demand 87 // parsing of functions, globals, statics are called, so this is a good 88 // function to call to get an idea of the current contents of the CompileUnit 89 // object. 90 //---------------------------------------------------------------------- 91 void CompileUnit::Dump(Stream *s, bool show_context) const { 92 const char *language = Language::GetNameForLanguageType(m_language); 93 94 s->Printf("%p: ", static_cast<const void *>(this)); 95 s->Indent(); 96 *s << "CompileUnit" << static_cast<const UserID &>(*this) << ", language = \"" 97 << language << "\", file = '" << static_cast<const FileSpec &>(*this) 98 << "'\n"; 99 100 // m_types.Dump(s); 101 102 if (m_variables.get()) { 103 s->IndentMore(); 104 m_variables->Dump(s, show_context); 105 s->IndentLess(); 106 } 107 108 if (!m_functions_by_uid.empty()) { 109 s->IndentMore(); 110 ForeachFunction([&s, show_context](const FunctionSP &f) { 111 f->Dump(s, show_context); 112 return false; 113 }); 114 115 s->IndentLess(); 116 s->EOL(); 117 } 118 } 119 120 //---------------------------------------------------------------------- 121 // Add a function to this compile unit 122 //---------------------------------------------------------------------- 123 void CompileUnit::AddFunction(FunctionSP &funcSP) { 124 m_functions_by_uid[funcSP->GetID()] = funcSP; 125 } 126 127 //---------------------------------------------------------------------- 128 // Find functions using the Mangled::Tokens token list. This function currently 129 // implements an interactive approach designed to find all instances of certain 130 // functions. It isn't designed to the quickest way to lookup functions as it 131 // will need to iterate through all functions and see if they match, though it 132 // does provide a powerful and context sensitive way to search for all 133 // functions with a certain name, all functions in a namespace, or all 134 // functions of a template type. See Mangled::Tokens::Parse() comments for more 135 // information. 136 // 137 // The function prototype will need to change to return a list of results. It 138 // was originally used to help debug the Mangled class and the 139 // Mangled::Tokens::MatchesQuery() function and it currently will print out a 140 // list of matching results for the functions that are currently in this 141 // compile unit. 142 // 143 // A FindFunctions method should be called prior to this that takes 144 // a regular function name (const char * or ConstString as a parameter) before 145 // resorting to this slower but more complete function. The other FindFunctions 146 // method should be able to take advantage of any accelerator tables available 147 // in the debug information (which is parsed by the SymbolFile parser plug-ins 148 // and registered with each Module). 149 //---------------------------------------------------------------------- 150 // void 151 // CompileUnit::FindFunctions(const Mangled::Tokens& tokens) 152 //{ 153 // if (!m_functions.empty()) 154 // { 155 // Stream s(stdout); 156 // std::vector<FunctionSP>::const_iterator pos; 157 // std::vector<FunctionSP>::const_iterator end = m_functions.end(); 158 // for (pos = m_functions.begin(); pos != end; ++pos) 159 // { 160 // const ConstString& demangled = (*pos)->Mangled().Demangled(); 161 // if (demangled) 162 // { 163 // const Mangled::Tokens& func_tokens = 164 // (*pos)->Mangled().GetTokens(); 165 // if (func_tokens.MatchesQuery (tokens)) 166 // s << "demangled MATCH found: " << demangled << "\n"; 167 // } 168 // } 169 // } 170 //} 171 172 FunctionSP CompileUnit::FindFunctionByUID(lldb::user_id_t func_uid) { 173 auto it = m_functions_by_uid.find(func_uid); 174 if (it == m_functions_by_uid.end()) 175 return FunctionSP(); 176 return it->second; 177 } 178 179 lldb::LanguageType CompileUnit::GetLanguage() { 180 if (m_language == eLanguageTypeUnknown) { 181 if (m_flags.IsClear(flagsParsedLanguage)) { 182 m_flags.Set(flagsParsedLanguage); 183 SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); 184 if (symbol_vendor) { 185 SymbolContext sc; 186 CalculateSymbolContext(&sc); 187 m_language = symbol_vendor->ParseCompileUnitLanguage(sc); 188 } 189 } 190 } 191 return m_language; 192 } 193 194 LineTable *CompileUnit::GetLineTable() { 195 if (m_line_table_ap.get() == nullptr) { 196 if (m_flags.IsClear(flagsParsedLineTable)) { 197 m_flags.Set(flagsParsedLineTable); 198 SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); 199 if (symbol_vendor) { 200 SymbolContext sc; 201 CalculateSymbolContext(&sc); 202 symbol_vendor->ParseCompileUnitLineTable(sc); 203 } 204 } 205 } 206 return m_line_table_ap.get(); 207 } 208 209 void CompileUnit::SetLineTable(LineTable *line_table) { 210 if (line_table == nullptr) 211 m_flags.Clear(flagsParsedLineTable); 212 else 213 m_flags.Set(flagsParsedLineTable); 214 m_line_table_ap.reset(line_table); 215 } 216 217 DebugMacros *CompileUnit::GetDebugMacros() { 218 if (m_debug_macros_sp.get() == nullptr) { 219 if (m_flags.IsClear(flagsParsedDebugMacros)) { 220 m_flags.Set(flagsParsedDebugMacros); 221 SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); 222 if (symbol_vendor) { 223 SymbolContext sc; 224 CalculateSymbolContext(&sc); 225 symbol_vendor->ParseCompileUnitDebugMacros(sc); 226 } 227 } 228 } 229 230 return m_debug_macros_sp.get(); 231 } 232 233 void CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) { 234 if (debug_macros_sp.get() == nullptr) 235 m_flags.Clear(flagsParsedDebugMacros); 236 else 237 m_flags.Set(flagsParsedDebugMacros); 238 m_debug_macros_sp = debug_macros_sp; 239 } 240 241 VariableListSP CompileUnit::GetVariableList(bool can_create) { 242 if (m_variables.get() == nullptr && can_create) { 243 SymbolContext sc; 244 CalculateSymbolContext(&sc); 245 assert(sc.module_sp); 246 sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc); 247 } 248 249 return m_variables; 250 } 251 252 uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line, 253 const FileSpec *file_spec_ptr, bool exact, 254 LineEntry *line_entry_ptr) { 255 uint32_t file_idx = 0; 256 257 if (file_spec_ptr) { 258 file_idx = GetSupportFiles().FindFileIndex(1, *file_spec_ptr, true); 259 if (file_idx == UINT32_MAX) 260 return UINT32_MAX; 261 } else { 262 // All the line table entries actually point to the version of the Compile 263 // Unit that is in the support files (the one at 0 was artificially added.) 264 // So prefer the one further on in the support files if it exists... 265 FileSpecList &support_files = GetSupportFiles(); 266 const bool full = true; 267 file_idx = support_files.FindFileIndex( 268 1, support_files.GetFileSpecAtIndex(0), full); 269 if (file_idx == UINT32_MAX) 270 file_idx = 0; 271 } 272 LineTable *line_table = GetLineTable(); 273 if (line_table) 274 return line_table->FindLineEntryIndexByFileIndex(start_idx, file_idx, line, 275 exact, line_entry_ptr); 276 return UINT32_MAX; 277 } 278 279 uint32_t CompileUnit::ResolveSymbolContext(const FileSpec &file_spec, 280 uint32_t line, bool check_inlines, 281 bool exact, uint32_t resolve_scope, 282 SymbolContextList &sc_list) { 283 // First find all of the file indexes that match our "file_spec". If 284 // "file_spec" has an empty directory, then only compare the basenames when 285 // finding file indexes 286 std::vector<uint32_t> file_indexes; 287 const bool full_match = (bool)file_spec.GetDirectory(); 288 bool file_spec_matches_cu_file_spec = 289 FileSpec::Equal(file_spec, *this, full_match); 290 291 // If we are not looking for inlined functions and our file spec doesn't 292 // match then we are done... 293 if (file_spec_matches_cu_file_spec == false && check_inlines == false) 294 return 0; 295 296 uint32_t file_idx = 297 GetSupportFiles().FindFileIndex(1, file_spec, true); 298 while (file_idx != UINT32_MAX) { 299 file_indexes.push_back(file_idx); 300 file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true); 301 } 302 303 const size_t num_file_indexes = file_indexes.size(); 304 if (num_file_indexes == 0) 305 return 0; 306 307 const uint32_t prev_size = sc_list.GetSize(); 308 309 SymbolContext sc(GetModule()); 310 sc.comp_unit = this; 311 312 if (line != 0) { 313 LineTable *line_table = sc.comp_unit->GetLineTable(); 314 315 if (line_table != nullptr) { 316 uint32_t found_line; 317 uint32_t line_idx; 318 319 if (num_file_indexes == 1) { 320 // We only have a single support file that matches, so use the line 321 // table function that searches for a line entries that match a single 322 // support file index 323 LineEntry line_entry; 324 line_idx = line_table->FindLineEntryIndexByFileIndex( 325 0, file_indexes.front(), line, exact, &line_entry); 326 327 // If "exact == true", then "found_line" will be the same as "line". If 328 // "exact == false", the "found_line" will be the closest line entry 329 // with a line number greater than "line" and we will use this for our 330 // subsequent line exact matches below. 331 found_line = line_entry.line; 332 333 while (line_idx != UINT32_MAX) { 334 // If they only asked for the line entry, then we're done, we can 335 // just copy that over. But if they wanted more than just the line 336 // number, fill it in. 337 if (resolve_scope == eSymbolContextLineEntry) { 338 sc.line_entry = line_entry; 339 } else { 340 line_entry.range.GetBaseAddress().CalculateSymbolContext( 341 &sc, resolve_scope); 342 } 343 344 sc_list.Append(sc); 345 line_idx = line_table->FindLineEntryIndexByFileIndex( 346 line_idx + 1, file_indexes.front(), found_line, true, 347 &line_entry); 348 } 349 } else { 350 // We found multiple support files that match "file_spec" so use the 351 // line table function that searches for a line entries that match a 352 // multiple support file indexes. 353 LineEntry line_entry; 354 line_idx = line_table->FindLineEntryIndexByFileIndex( 355 0, file_indexes, line, exact, &line_entry); 356 357 // If "exact == true", then "found_line" will be the same as "line". If 358 // "exact == false", the "found_line" will be the closest line entry 359 // with a line number greater than "line" and we will use this for our 360 // subsequent line exact matches below. 361 found_line = line_entry.line; 362 363 while (line_idx != UINT32_MAX) { 364 if (resolve_scope == eSymbolContextLineEntry) { 365 sc.line_entry = line_entry; 366 } else { 367 line_entry.range.GetBaseAddress().CalculateSymbolContext( 368 &sc, resolve_scope); 369 } 370 371 sc_list.Append(sc); 372 line_idx = line_table->FindLineEntryIndexByFileIndex( 373 line_idx + 1, file_indexes, found_line, true, &line_entry); 374 } 375 } 376 } 377 } else if (file_spec_matches_cu_file_spec && !check_inlines) { 378 // only append the context if we aren't looking for inline call sites by 379 // file and line and if the file spec matches that of the compile unit 380 sc_list.Append(sc); 381 } 382 return sc_list.GetSize() - prev_size; 383 } 384 385 bool CompileUnit::GetIsOptimized() { 386 if (m_is_optimized == eLazyBoolCalculate) { 387 m_is_optimized = eLazyBoolNo; 388 if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) { 389 SymbolContext sc; 390 CalculateSymbolContext(&sc); 391 if (symbol_vendor->ParseCompileUnitIsOptimized(sc)) 392 m_is_optimized = eLazyBoolYes; 393 } 394 } 395 return m_is_optimized; 396 } 397 398 void CompileUnit::SetVariableList(VariableListSP &variables) { 399 m_variables = variables; 400 } 401 402 const std::vector<ConstString> &CompileUnit::GetImportedModules() { 403 if (m_imported_modules.empty() && 404 m_flags.IsClear(flagsParsedImportedModules)) { 405 m_flags.Set(flagsParsedImportedModules); 406 if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) { 407 SymbolContext sc; 408 CalculateSymbolContext(&sc); 409 symbol_vendor->ParseImportedModules(sc, m_imported_modules); 410 } 411 } 412 return m_imported_modules; 413 } 414 415 FileSpecList &CompileUnit::GetSupportFiles() { 416 if (m_support_files.GetSize() == 0) { 417 if (m_flags.IsClear(flagsParsedSupportFiles)) { 418 m_flags.Set(flagsParsedSupportFiles); 419 SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); 420 if (symbol_vendor) { 421 SymbolContext sc; 422 CalculateSymbolContext(&sc); 423 symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files); 424 } 425 } 426 } 427 return m_support_files; 428 } 429 430 void *CompileUnit::GetUserData() const { return m_user_data; } 431