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