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