blob: 8f51210bea889f9d13bc9866a8d6e8f9f1c7daaa [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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
Greg Clayton9488b742010-07-28 02:04:09 +000019CompileUnit::CompileUnit (Module *module, void *user_data, const char *pathname, const lldb::user_id_t cu_sym_id, lldb::LanguageType language) :
Chris Lattner24943d22010-06-08 16:52:24 +000020 ModuleChild(module),
Greg Clayton537a7a82010-10-20 20:54:39 +000021 FileSpec (pathname, false),
Chris Lattner24943d22010-06-08 16:52:24 +000022 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
Greg Clayton9488b742010-07-28 02:04:09 +000034CompileUnit::CompileUnit (Module *module, void *user_data, const FileSpec &fspec, const lldb::user_id_t cu_sym_id, lldb::LanguageType language) :
Chris Lattner24943d22010-06-08 16:52:24 +000035 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
Greg Claytonc51ffbf2011-08-12 21:40:01 +000060Module *
61CompileUnit::CalculateSymbolContextModule ()
62{
63 return GetModule();
64}
65
66CompileUnit *
67CompileUnit::CalculateSymbolContextCompileUnit ()
68{
69 return this;
70}
71
Chris Lattner24943d22010-06-08 16:52:24 +000072void
73CompileUnit::DumpSymbolContext(Stream *s)
74{
75 GetModule()->DumpSymbolContext(s);
76 s->Printf(", CompileUnit{0x%8.8x}", GetID());
77}
78
79
Greg Clayton12bec712010-06-28 21:30:43 +000080void
81CompileUnit::GetDescription(Stream *s, lldb::DescriptionLevel level) const
82{
Greg Claytonc67b7d12010-09-10 01:30:46 +000083 *s << "id = " << (const UserID&)*this << ", file = \"" << (const FileSpec&)*this << "\", language = \"" << (const Language&)*this << '"';
Greg Clayton12bec712010-06-28 21:30:43 +000084}
85
Chris Lattner24943d22010-06-08 16:52:24 +000086
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: ", (int)sizeof(void*) * 2, this);
97 s->Indent();
98 *s << "CompileUnit" << (const UserID&)*this
Greg Claytonc67b7d12010-09-10 01:30:46 +000099 << ", language = \"" << (const Language&)*this
100 << "\", file = '" << (const FileSpec&)*this << "'\n";
Chris Lattner24943d22010-06-08 16:52:24 +0000101
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, 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);
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 file_idx = support_files.FindFileIndex (1, support_files.GetFileSpecAtIndex(0));
273 if (file_idx == UINT32_MAX)
274 file_idx = 0;
275 }
276 LineTable *line_table = GetLineTable();
277 if (line_table)
278 return line_table->FindLineEntryIndexByFileIndex (start_idx, file_idx, line, true, line_entry_ptr);
279 return UINT32_MAX;
280}
281
282
283
284
285uint32_t
286CompileUnit::ResolveSymbolContext
287(
288 const FileSpec& file_spec,
289 uint32_t line,
290 bool check_inlines,
291 bool exact,
292 uint32_t resolve_scope,
293 SymbolContextList &sc_list
294)
295{
Greg Clayton8019d7f2010-09-12 06:24:05 +0000296 // First find all of the file indexes that match our "file_spec". If
297 // "file_spec" has an empty directory, then only compare the basenames
298 // when finding file indexes
299 std::vector<uint32_t> file_indexes;
Greg Clayton801417e2011-07-07 01:59:51 +0000300 bool file_spec_matches_cu_file_spec = FileSpec::Equal(file_spec, this, !file_spec.GetDirectory().IsEmpty());
Greg Clayton8019d7f2010-09-12 06:24:05 +0000301
302 // If we are not looking for inlined functions and our file spec doesn't
303 // match then we are done...
304 if (file_spec_matches_cu_file_spec == false && check_inlines == false)
305 return 0;
306
307 uint32_t file_idx = GetSupportFiles().FindFileIndex (1, file_spec);
308 while (file_idx != UINT32_MAX)
Chris Lattner24943d22010-06-08 16:52:24 +0000309 {
Greg Clayton8019d7f2010-09-12 06:24:05 +0000310 file_indexes.push_back (file_idx);
311 file_idx = GetSupportFiles().FindFileIndex (file_idx + 1, file_spec);
312 }
313
314 const size_t num_file_indexes = file_indexes.size();
315 if (num_file_indexes == 0)
316 return 0;
Chris Lattner24943d22010-06-08 16:52:24 +0000317
Greg Clayton8019d7f2010-09-12 06:24:05 +0000318 const uint32_t prev_size = sc_list.GetSize();
Chris Lattner24943d22010-06-08 16:52:24 +0000319
Greg Clayton8019d7f2010-09-12 06:24:05 +0000320 SymbolContext sc(GetModule());
321 sc.comp_unit = this;
Chris Lattner24943d22010-06-08 16:52:24 +0000322
Greg Clayton8019d7f2010-09-12 06:24:05 +0000323
324 if (line != 0)
325 {
326 LineTable *line_table = sc.comp_unit->GetLineTable();
327
328 if (line_table != NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000329 {
Greg Clayton8019d7f2010-09-12 06:24:05 +0000330 uint32_t found_line;
331 uint32_t line_idx;
332
333 if (num_file_indexes == 1)
Chris Lattner24943d22010-06-08 16:52:24 +0000334 {
Greg Clayton8019d7f2010-09-12 06:24:05 +0000335 // We only have a single support file that matches, so use
336 // the line table function that searches for a line entries
337 // that match a single support file index
338 line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes.front(), line, exact, &sc.line_entry);
Chris Lattner24943d22010-06-08 16:52:24 +0000339
Greg Clayton8019d7f2010-09-12 06:24:05 +0000340 // If "exact == true", then "found_line" will be the same
341 // as "line". If "exact == false", the "found_line" will be the
342 // closest line entry with a line number greater than "line" and
343 // we will use this for our subsequent line exact matches below.
344 found_line = sc.line_entry.line;
345
Greg Clayton178710c2010-09-14 02:20:48 +0000346 while (line_idx != UINT32_MAX)
Chris Lattner24943d22010-06-08 16:52:24 +0000347 {
Greg Clayton8019d7f2010-09-12 06:24:05 +0000348 sc_list.Append(sc);
349 line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes.front(), found_line, true, &sc.line_entry);
350 }
351 }
352 else
353 {
354 // We found multiple support files that match "file_spec" so use
355 // the line table function that searches for a line entries
356 // that match a multiple support file indexes.
357 line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes, line, exact, &sc.line_entry);
Chris Lattner24943d22010-06-08 16:52:24 +0000358
Greg Clayton8019d7f2010-09-12 06:24:05 +0000359 // If "exact == true", then "found_line" will be the same
360 // as "line". If "exact == false", the "found_line" will be the
361 // closest line entry with a line number greater than "line" and
362 // we will use this for our subsequent line exact matches below.
363 found_line = sc.line_entry.line;
Chris Lattner24943d22010-06-08 16:52:24 +0000364
Greg Clayton178710c2010-09-14 02:20:48 +0000365 while (line_idx != UINT32_MAX)
Greg Clayton8019d7f2010-09-12 06:24:05 +0000366 {
367 sc_list.Append(sc);
368 line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes, found_line, true, &sc.line_entry);
Chris Lattner24943d22010-06-08 16:52:24 +0000369 }
370 }
371 }
Greg Clayton8019d7f2010-09-12 06:24:05 +0000372 }
373 else if (file_spec_matches_cu_file_spec && !check_inlines)
374 {
375 // only append the context if we aren't looking for inline call sites
376 // by file and line and if the file spec matches that of the compile unit
377 sc_list.Append(sc);
Chris Lattner24943d22010-06-08 16:52:24 +0000378 }
379 return sc_list.GetSize() - prev_size;
380}
381
382void
383CompileUnit::SetVariableList(VariableListSP &variables)
384{
385 m_variables = variables;
386}
387
388FileSpecList&
389CompileUnit::GetSupportFiles ()
390{
391 if (m_support_files.GetSize() == 0)
392 {
393 if (m_flags.IsClear(flagsParsedSupportFiles))
394 {
395 m_flags.Set(flagsParsedSupportFiles);
396 SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor();
397 if (symbol_vendor)
398 {
399 SymbolContext sc;
400 CalculateSymbolContext(&sc);
401 symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files);
402 }
403 }
404 }
405 return m_support_files;
406}
407
408void *
409CompileUnit::GetUserData () const
410{
411 return m_user_data;
412}
413
414