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