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 16 using namespace lldb; 17 using namespace lldb_private; 18 19 CompileUnit::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 34 CompileUnit::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 49 CompileUnit::~CompileUnit () 50 { 51 } 52 53 void 54 CompileUnit::CalculateSymbolContext(SymbolContext* sc) 55 { 56 sc->comp_unit = this; 57 GetModule()->CalculateSymbolContext(sc); 58 } 59 60 Module * 61 CompileUnit::CalculateSymbolContextModule () 62 { 63 return GetModule(); 64 } 65 66 CompileUnit * 67 CompileUnit::CalculateSymbolContextCompileUnit () 68 { 69 return this; 70 } 71 72 void 73 CompileUnit::DumpSymbolContext(Stream *s) 74 { 75 GetModule()->DumpSymbolContext(s); 76 s->Printf(", CompileUnit{0x%8.8x}", GetID()); 77 } 78 79 80 void 81 CompileUnit::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 //---------------------------------------------------------------------- 93 void 94 CompileUnit::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 //---------------------------------------------------------------------- 129 void 130 CompileUnit::AddFunction(FunctionSP& funcSP) 131 { 132 // TODO: order these by address 133 m_functions.push_back(funcSP); 134 } 135 136 FunctionSP 137 CompileUnit::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 190 FunctionSP 191 CompileUnit::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 211 LineTable* 212 CompileUnit::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 231 void 232 CompileUnit::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 241 VariableListSP 242 CompileUnit::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 255 uint32_t 256 CompileUnit::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 286 uint32_t 287 CompileUnit::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 383 void 384 CompileUnit::SetVariableList(VariableListSP &variables) 385 { 386 m_variables = variables; 387 } 388 389 FileSpecList& 390 CompileUnit::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 409 void * 410 CompileUnit::GetUserData () const 411 { 412 return m_user_data; 413 } 414 415 416