CompileUnit.cpp revision 12bec71b323dc520f0e985a86e09c4712559e115
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
16using namespace lldb;
17using namespace lldb_private;
18
19CompileUnit::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
34CompileUnit::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
49CompileUnit::~CompileUnit ()
50{
51}
52
53void
54CompileUnit::CalculateSymbolContext(SymbolContext* sc)
55{
56    sc->comp_unit = this;
57    GetModule()->CalculateSymbolContext(sc);
58}
59
60void
61CompileUnit::DumpSymbolContext(Stream *s)
62{
63    GetModule()->DumpSymbolContext(s);
64    s->Printf(", CompileUnit{0x%8.8x}", GetID());
65}
66
67
68void
69CompileUnit::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//----------------------------------------------------------------------
82void
83CompileUnit::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//----------------------------------------------------------------------
118void
119CompileUnit::AddFunction(FunctionSP& funcSP)
120{
121    // TODO: order these by address
122    m_functions.push_back(funcSP);
123}
124
125FunctionSP
126CompileUnit::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
179FunctionSP
180CompileUnit::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
200LineTable*
201CompileUnit::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
220void
221CompileUnit::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
230VariableListSP
231CompileUnit::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
244uint32_t
245CompileUnit::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
274uint32_t
275CompileUnit::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
341void
342CompileUnit::SetVariableList(VariableListSP &variables)
343{
344    m_variables = variables;
345}
346
347FileSpecList&
348CompileUnit::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
367void *
368CompileUnit::GetUserData () const
369{
370    return m_user_data;
371}
372
373
374