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 17using namespace lldb; 18using namespace lldb_private; 19 20CompileUnit::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 38CompileUnit::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 56CompileUnit::~CompileUnit () 57{ 58} 59 60void 61CompileUnit::CalculateSymbolContext(SymbolContext* sc) 62{ 63 sc->comp_unit = this; 64 GetModule()->CalculateSymbolContext(sc); 65} 66 67ModuleSP 68CompileUnit::CalculateSymbolContextModule () 69{ 70 return GetModule(); 71} 72 73CompileUnit * 74CompileUnit::CalculateSymbolContextCompileUnit () 75{ 76 return this; 77} 78 79void 80CompileUnit::DumpSymbolContext(Stream *s) 81{ 82 GetModule()->DumpSymbolContext(s); 83 s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID()); 84} 85 86 87void 88CompileUnit::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//---------------------------------------------------------------------- 101void 102CompileUnit::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//---------------------------------------------------------------------- 139void 140CompileUnit::AddFunction(FunctionSP& funcSP) 141{ 142 // TODO: order these by address 143 m_functions.push_back(funcSP); 144} 145 146FunctionSP 147CompileUnit::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 200FunctionSP 201CompileUnit::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 221lldb::LanguageType 222CompileUnit::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 241LineTable* 242CompileUnit::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 261void 262CompileUnit::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 271DebugMacros* 272CompileUnit::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 292void 293CompileUnit::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 302VariableListSP 303CompileUnit::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 316uint32_t 317CompileUnit::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 347uint32_t 348CompileUnit::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 468bool 469CompileUnit::GetIsOptimized () 470{ 471 return m_is_optimized; 472} 473 474void 475CompileUnit::SetVariableList(VariableListSP &variables) 476{ 477 m_variables = variables; 478} 479 480const std::vector<ConstString> & 481CompileUnit::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 497FileSpecList& 498CompileUnit::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 517void * 518CompileUnit::GetUserData () const 519{ 520 return m_user_data; 521} 522 523 524