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