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