Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame^] | 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 | |