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