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