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