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