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