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 VariableListSP 272 CompileUnit::GetVariableList(bool can_create) 273 { 274 if (m_variables.get() == nullptr && can_create) 275 { 276 SymbolContext sc; 277 CalculateSymbolContext(&sc); 278 assert(sc.module_sp); 279 sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc); 280 } 281 282 return m_variables; 283 } 284 285 uint32_t 286 CompileUnit::FindLineEntry (uint32_t start_idx, uint32_t line, const FileSpec* file_spec_ptr, bool exact, LineEntry *line_entry_ptr) 287 { 288 uint32_t file_idx = 0; 289 290 if (file_spec_ptr) 291 { 292 file_idx = GetSupportFiles().FindFileIndex (1, *file_spec_ptr, true); 293 if (file_idx == UINT32_MAX) 294 return UINT32_MAX; 295 } 296 else 297 { 298 // All the line table entries actually point to the version of the Compile 299 // Unit that is in the support files (the one at 0 was artificially added.) 300 // So prefer the one further on in the support files if it exists... 301 FileSpecList &support_files = GetSupportFiles(); 302 const bool full = true; 303 file_idx = support_files.FindFileIndex (1, support_files.GetFileSpecAtIndex(0), full); 304 if (file_idx == UINT32_MAX) 305 file_idx = 0; 306 } 307 LineTable *line_table = GetLineTable(); 308 if (line_table) 309 return line_table->FindLineEntryIndexByFileIndex (start_idx, file_idx, line, exact, line_entry_ptr); 310 return UINT32_MAX; 311 } 312 313 314 315 316 uint32_t 317 CompileUnit::ResolveSymbolContext 318 ( 319 const FileSpec& file_spec, 320 uint32_t line, 321 bool check_inlines, 322 bool exact, 323 uint32_t resolve_scope, 324 SymbolContextList &sc_list 325 ) 326 { 327 // First find all of the file indexes that match our "file_spec". If 328 // "file_spec" has an empty directory, then only compare the basenames 329 // when finding file indexes 330 std::vector<uint32_t> file_indexes; 331 const bool full_match = (bool)file_spec.GetDirectory(); 332 const bool remove_backup_dots = true; 333 bool file_spec_matches_cu_file_spec = FileSpec::Equal(file_spec, *this, full_match, remove_backup_dots); 334 335 // If we are not looking for inlined functions and our file spec doesn't 336 // match then we are done... 337 if (file_spec_matches_cu_file_spec == false && check_inlines == false) 338 return 0; 339 340 uint32_t file_idx = GetSupportFiles().FindFileIndex (1, file_spec, true, remove_backup_dots); 341 while (file_idx != UINT32_MAX) 342 { 343 file_indexes.push_back (file_idx); 344 file_idx = GetSupportFiles().FindFileIndex (file_idx + 1, file_spec, true, remove_backup_dots); 345 } 346 347 const size_t num_file_indexes = file_indexes.size(); 348 if (num_file_indexes == 0) 349 return 0; 350 351 const uint32_t prev_size = sc_list.GetSize(); 352 353 SymbolContext sc(GetModule()); 354 sc.comp_unit = this; 355 356 357 if (line != 0) 358 { 359 LineTable *line_table = sc.comp_unit->GetLineTable(); 360 361 if (line_table != nullptr) 362 { 363 uint32_t found_line; 364 uint32_t line_idx; 365 366 if (num_file_indexes == 1) 367 { 368 // We only have a single support file that matches, so use 369 // the line table function that searches for a line entries 370 // that match a single support file index 371 LineEntry line_entry; 372 line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes.front(), line, exact, &line_entry); 373 374 // If "exact == true", then "found_line" will be the same 375 // as "line". If "exact == false", the "found_line" will be the 376 // closest line entry with a line number greater than "line" and 377 // we will use this for our subsequent line exact matches below. 378 found_line = line_entry.line; 379 380 while (line_idx != UINT32_MAX) 381 { 382 // If they only asked for the line entry, then we're done, we can just copy that over. 383 // But if they wanted more than just the line number, fill it in. 384 if (resolve_scope == eSymbolContextLineEntry) 385 { 386 sc.line_entry = line_entry; 387 } 388 else 389 { 390 line_entry.range.GetBaseAddress().CalculateSymbolContext(&sc, resolve_scope); 391 } 392 393 sc_list.Append(sc); 394 line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes.front(), found_line, true, &line_entry); 395 } 396 } 397 else 398 { 399 // We found multiple support files that match "file_spec" so use 400 // the line table function that searches for a line entries 401 // that match a multiple support file indexes. 402 LineEntry line_entry; 403 line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes, 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 (resolve_scope == eSymbolContextLineEntry) 414 { 415 sc.line_entry = line_entry; 416 } 417 else 418 { 419 line_entry.range.GetBaseAddress().CalculateSymbolContext(&sc, resolve_scope); 420 } 421 422 sc_list.Append(sc); 423 line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes, found_line, true, &line_entry); 424 } 425 } 426 } 427 } 428 else if (file_spec_matches_cu_file_spec && !check_inlines) 429 { 430 // only append the context if we aren't looking for inline call sites 431 // by file and line and if the file spec matches that of the compile unit 432 sc_list.Append(sc); 433 } 434 return sc_list.GetSize() - prev_size; 435 } 436 437 bool 438 CompileUnit::GetIsOptimized () 439 { 440 return m_is_optimized; 441 } 442 443 void 444 CompileUnit::SetVariableList(VariableListSP &variables) 445 { 446 m_variables = variables; 447 } 448 449 const std::vector<ConstString> & 450 CompileUnit::GetImportedModules () 451 { 452 if (m_imported_modules.empty() && 453 m_flags.IsClear(flagsParsedImportedModules)) 454 { 455 m_flags.Set(flagsParsedImportedModules); 456 if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) 457 { 458 SymbolContext sc; 459 CalculateSymbolContext(&sc); 460 symbol_vendor->ParseImportedModules(sc, m_imported_modules); 461 } 462 } 463 return m_imported_modules; 464 } 465 466 FileSpecList& 467 CompileUnit::GetSupportFiles () 468 { 469 if (m_support_files.GetSize() == 0) 470 { 471 if (m_flags.IsClear(flagsParsedSupportFiles)) 472 { 473 m_flags.Set(flagsParsedSupportFiles); 474 SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor(); 475 if (symbol_vendor) 476 { 477 SymbolContext sc; 478 CalculateSymbolContext(&sc); 479 symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files); 480 } 481 } 482 } 483 return m_support_files; 484 } 485 486 void * 487 CompileUnit::GetUserData () const 488 { 489 return m_user_data; 490 } 491 492 493