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 17using namespace lldb; 18using namespace lldb_private; 19 20CompileUnit::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 37CompileUnit::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 54CompileUnit::~CompileUnit () 55{ 56} 57 58void 59CompileUnit::CalculateSymbolContext(SymbolContext* sc) 60{ 61 sc->comp_unit = this; 62 GetModule()->CalculateSymbolContext(sc); 63} 64 65ModuleSP 66CompileUnit::CalculateSymbolContextModule () 67{ 68 return GetModule(); 69} 70 71CompileUnit * 72CompileUnit::CalculateSymbolContextCompileUnit () 73{ 74 return this; 75} 76 77void 78CompileUnit::DumpSymbolContext(Stream *s) 79{ 80 GetModule()->DumpSymbolContext(s); 81 s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID()); 82} 83 84 85void 86CompileUnit::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//---------------------------------------------------------------------- 99void 100CompileUnit::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//---------------------------------------------------------------------- 135void 136CompileUnit::AddFunction(FunctionSP& funcSP) 137{ 138 // TODO: order these by address 139 m_functions.push_back(funcSP); 140} 141 142FunctionSP 143CompileUnit::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 196FunctionSP 197CompileUnit::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 217lldb::LanguageType 218CompileUnit::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 237LineTable* 238CompileUnit::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 257void 258CompileUnit::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 267VariableListSP 268CompileUnit::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 281uint32_t 282CompileUnit::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 312uint32_t 313CompileUnit::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 432void 433CompileUnit::SetVariableList(VariableListSP &variables) 434{ 435 m_variables = variables; 436} 437 438FileSpecList& 439CompileUnit::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 458void * 459CompileUnit::GetUserData () const 460{ 461 return m_user_data; 462} 463 464 465