1254721Semaste//===-- CompileUnit.cpp -----------------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/Symbol/CompileUnit.h"
11254721Semaste#include "lldb/Core/Module.h"
12254721Semaste#include "lldb/Core/Language.h"
13254721Semaste#include "lldb/Symbol/LineTable.h"
14254721Semaste#include "lldb/Symbol/SymbolVendor.h"
15254721Semaste#include "lldb/Symbol/VariableList.h"
16254721Semaste
17254721Semasteusing namespace lldb;
18254721Semasteusing namespace lldb_private;
19254721Semaste
20254721SemasteCompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, const char *pathname, const lldb::user_id_t cu_sym_id, lldb::LanguageType language) :
21254721Semaste    ModuleChild(module_sp),
22254721Semaste    FileSpec (pathname, false),
23254721Semaste    UserID(cu_sym_id),
24254721Semaste    m_user_data (user_data),
25254721Semaste    m_language (language),
26254721Semaste    m_flags (0),
27254721Semaste    m_functions (),
28254721Semaste    m_support_files (),
29254721Semaste    m_line_table_ap (),
30254721Semaste    m_variables()
31254721Semaste{
32254721Semaste    if (language != eLanguageTypeUnknown)
33254721Semaste        m_flags.Set(flagsParsedLanguage);
34254721Semaste    assert(module_sp);
35254721Semaste}
36254721Semaste
37254721SemasteCompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, const FileSpec &fspec, const lldb::user_id_t cu_sym_id, lldb::LanguageType language) :
38254721Semaste    ModuleChild(module_sp),
39254721Semaste    FileSpec (fspec),
40254721Semaste    UserID(cu_sym_id),
41254721Semaste    m_user_data (user_data),
42254721Semaste    m_language (language),
43254721Semaste    m_flags (0),
44254721Semaste    m_functions (),
45254721Semaste    m_support_files (),
46254721Semaste    m_line_table_ap (),
47254721Semaste    m_variables()
48254721Semaste{
49254721Semaste    if (language != eLanguageTypeUnknown)
50254721Semaste        m_flags.Set(flagsParsedLanguage);
51254721Semaste    assert(module_sp);
52254721Semaste}
53254721Semaste
54254721SemasteCompileUnit::~CompileUnit ()
55254721Semaste{
56254721Semaste}
57254721Semaste
58254721Semastevoid
59254721SemasteCompileUnit::CalculateSymbolContext(SymbolContext* sc)
60254721Semaste{
61254721Semaste    sc->comp_unit = this;
62254721Semaste    GetModule()->CalculateSymbolContext(sc);
63254721Semaste}
64254721Semaste
65254721SemasteModuleSP
66254721SemasteCompileUnit::CalculateSymbolContextModule ()
67254721Semaste{
68254721Semaste    return GetModule();
69254721Semaste}
70254721Semaste
71254721SemasteCompileUnit *
72254721SemasteCompileUnit::CalculateSymbolContextCompileUnit ()
73254721Semaste{
74254721Semaste    return this;
75254721Semaste}
76254721Semaste
77254721Semastevoid
78254721SemasteCompileUnit::DumpSymbolContext(Stream *s)
79254721Semaste{
80254721Semaste    GetModule()->DumpSymbolContext(s);
81254721Semaste    s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID());
82254721Semaste}
83254721Semaste
84254721Semaste
85254721Semastevoid
86254721SemasteCompileUnit::GetDescription(Stream *s, lldb::DescriptionLevel level) const
87254721Semaste{
88254721Semaste    Language language(m_language);
89254721Semaste    *s << "id = " << (const UserID&)*this << ", file = \"" << (const FileSpec&)*this << "\", language = \"" << language << '"';
90254721Semaste}
91254721Semaste
92254721Semaste
93254721Semaste//----------------------------------------------------------------------
94254721Semaste// Dump the current contents of this object. No functions that cause on
95254721Semaste// demand parsing of functions, globals, statics are called, so this
96254721Semaste// is a good function to call to get an idea of the current contents of
97254721Semaste// the CompileUnit object.
98254721Semaste//----------------------------------------------------------------------
99254721Semastevoid
100254721SemasteCompileUnit::Dump(Stream *s, bool show_context) const
101254721Semaste{
102254721Semaste    s->Printf("%p: ", this);
103254721Semaste    s->Indent();
104254721Semaste    *s << "CompileUnit" << (const UserID&)*this
105254721Semaste        << ", language = \"" << (const Language&)*this
106254721Semaste        << "\", file = '" << (const FileSpec&)*this << "'\n";
107254721Semaste
108254721Semaste//  m_types.Dump(s);
109254721Semaste
110254721Semaste    if (m_variables.get())
111254721Semaste    {
112254721Semaste        s->IndentMore();
113254721Semaste        m_variables->Dump(s, show_context);
114254721Semaste        s->IndentLess();
115254721Semaste    }
116254721Semaste
117254721Semaste    if (!m_functions.empty())
118254721Semaste    {
119254721Semaste        s->IndentMore();
120254721Semaste        std::vector<FunctionSP>::const_iterator pos;
121254721Semaste        std::vector<FunctionSP>::const_iterator end = m_functions.end();
122254721Semaste        for (pos = m_functions.begin(); pos != end; ++pos)
123254721Semaste        {
124254721Semaste            (*pos)->Dump(s, show_context);
125254721Semaste        }
126254721Semaste
127254721Semaste        s->IndentLess();
128254721Semaste        s->EOL();
129254721Semaste    }
130254721Semaste}
131254721Semaste
132254721Semaste//----------------------------------------------------------------------
133254721Semaste// Add a function to this compile unit
134254721Semaste//----------------------------------------------------------------------
135254721Semastevoid
136254721SemasteCompileUnit::AddFunction(FunctionSP& funcSP)
137254721Semaste{
138254721Semaste    // TODO: order these by address
139254721Semaste    m_functions.push_back(funcSP);
140254721Semaste}
141254721Semaste
142254721SemasteFunctionSP
143254721SemasteCompileUnit::GetFunctionAtIndex (size_t idx)
144254721Semaste{
145254721Semaste    FunctionSP funcSP;
146254721Semaste    if (idx < m_functions.size())
147254721Semaste        funcSP = m_functions[idx];
148254721Semaste    return funcSP;
149254721Semaste}
150254721Semaste
151254721Semaste//----------------------------------------------------------------------
152254721Semaste// Find functions using the a Mangled::Tokens token list. This
153254721Semaste// function currently implements an interative approach designed to find
154254721Semaste// all instances of certain functions. It isn't designed to the the
155254721Semaste// quickest way to lookup functions as it will need to iterate through
156254721Semaste// all functions and see if they match, though it does provide a powerful
157254721Semaste// and context sensitive way to search for all functions with a certain
158254721Semaste// name, all functions in a namespace, or all functions of a template
159254721Semaste// type. See Mangled::Tokens::Parse() comments for more information.
160254721Semaste//
161254721Semaste// The function prototype will need to change to return a list of
162254721Semaste// results. It was originally used to help debug the Mangled class
163254721Semaste// and the Mangled::Tokens::MatchesQuery() function and it currently
164254721Semaste// will print out a list of matching results for the functions that
165254721Semaste// are currently in this compile unit.
166254721Semaste//
167254721Semaste// A FindFunctions method should be called prior to this that takes
168254721Semaste// a regular function name (const char * or ConstString as a parameter)
169254721Semaste// before resorting to this slower but more complete function. The
170254721Semaste// other FindFunctions method should be able to take advantage of any
171254721Semaste// accelerator tables available in the debug information (which is
172254721Semaste// parsed by the SymbolFile parser plug-ins and registered with each
173254721Semaste// Module).
174254721Semaste//----------------------------------------------------------------------
175254721Semaste//void
176254721Semaste//CompileUnit::FindFunctions(const Mangled::Tokens& tokens)
177254721Semaste//{
178254721Semaste//  if (!m_functions.empty())
179254721Semaste//  {
180254721Semaste//      Stream s(stdout);
181254721Semaste//      std::vector<FunctionSP>::const_iterator pos;
182254721Semaste//      std::vector<FunctionSP>::const_iterator end = m_functions.end();
183254721Semaste//      for (pos = m_functions.begin(); pos != end; ++pos)
184254721Semaste//      {
185254721Semaste//          const ConstString& demangled = (*pos)->Mangled().Demangled();
186254721Semaste//          if (demangled)
187254721Semaste//          {
188254721Semaste//              const Mangled::Tokens& func_tokens = (*pos)->Mangled().GetTokens();
189254721Semaste//              if (func_tokens.MatchesQuery (tokens))
190254721Semaste//                  s << "demangled MATCH found: " << demangled << "\n";
191254721Semaste//          }
192254721Semaste//      }
193254721Semaste//  }
194254721Semaste//}
195254721Semaste
196254721SemasteFunctionSP
197254721SemasteCompileUnit::FindFunctionByUID (lldb::user_id_t func_uid)
198254721Semaste{
199254721Semaste    FunctionSP funcSP;
200254721Semaste    if (!m_functions.empty())
201254721Semaste    {
202254721Semaste        std::vector<FunctionSP>::const_iterator pos;
203254721Semaste        std::vector<FunctionSP>::const_iterator end = m_functions.end();
204254721Semaste        for (pos = m_functions.begin(); pos != end; ++pos)
205254721Semaste        {
206254721Semaste            if ((*pos)->GetID() == func_uid)
207254721Semaste            {
208254721Semaste                funcSP = *pos;
209254721Semaste                break;
210254721Semaste            }
211254721Semaste        }
212254721Semaste    }
213254721Semaste    return funcSP;
214254721Semaste}
215254721Semaste
216254721Semaste
217254721Semastelldb::LanguageType
218254721SemasteCompileUnit::GetLanguage()
219254721Semaste{
220254721Semaste    if (m_language == eLanguageTypeUnknown)
221254721Semaste    {
222254721Semaste        if (m_flags.IsClear(flagsParsedLanguage))
223254721Semaste        {
224254721Semaste            m_flags.Set(flagsParsedLanguage);
225254721Semaste            SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor();
226254721Semaste            if (symbol_vendor)
227254721Semaste            {
228254721Semaste                SymbolContext sc;
229254721Semaste                CalculateSymbolContext(&sc);
230254721Semaste                m_language = symbol_vendor->ParseCompileUnitLanguage(sc);
231254721Semaste            }
232254721Semaste        }
233254721Semaste    }
234254721Semaste    return m_language;
235254721Semaste}
236254721Semaste
237254721SemasteLineTable*
238254721SemasteCompileUnit::GetLineTable()
239254721Semaste{
240254721Semaste    if (m_line_table_ap.get() == NULL)
241254721Semaste    {
242254721Semaste        if (m_flags.IsClear(flagsParsedLineTable))
243254721Semaste        {
244254721Semaste            m_flags.Set(flagsParsedLineTable);
245254721Semaste            SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor();
246254721Semaste            if (symbol_vendor)
247254721Semaste            {
248254721Semaste                SymbolContext sc;
249254721Semaste                CalculateSymbolContext(&sc);
250254721Semaste                symbol_vendor->ParseCompileUnitLineTable(sc);
251254721Semaste            }
252254721Semaste        }
253254721Semaste    }
254254721Semaste    return m_line_table_ap.get();
255254721Semaste}
256254721Semaste
257254721Semastevoid
258254721SemasteCompileUnit::SetLineTable(LineTable* line_table)
259254721Semaste{
260254721Semaste    if (line_table == NULL)
261254721Semaste        m_flags.Clear(flagsParsedLineTable);
262254721Semaste    else
263254721Semaste        m_flags.Set(flagsParsedLineTable);
264254721Semaste    m_line_table_ap.reset(line_table);
265254721Semaste}
266254721Semaste
267254721SemasteVariableListSP
268254721SemasteCompileUnit::GetVariableList(bool can_create)
269254721Semaste{
270254721Semaste    if (m_variables.get() == NULL && can_create)
271254721Semaste    {
272254721Semaste        SymbolContext sc;
273254721Semaste        CalculateSymbolContext(&sc);
274254721Semaste        assert(sc.module_sp);
275254721Semaste        sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
276254721Semaste    }
277254721Semaste
278254721Semaste    return m_variables;
279254721Semaste}
280254721Semaste
281254721Semasteuint32_t
282254721SemasteCompileUnit::FindLineEntry (uint32_t start_idx, uint32_t line, const FileSpec* file_spec_ptr, bool exact, LineEntry *line_entry_ptr)
283254721Semaste{
284254721Semaste    uint32_t file_idx = 0;
285254721Semaste
286254721Semaste    if (file_spec_ptr)
287254721Semaste    {
288254721Semaste        file_idx = GetSupportFiles().FindFileIndex (1, *file_spec_ptr, true);
289254721Semaste        if (file_idx == UINT32_MAX)
290254721Semaste            return UINT32_MAX;
291254721Semaste    }
292254721Semaste    else
293254721Semaste    {
294254721Semaste        // All the line table entries actually point to the version of the Compile
295254721Semaste        // Unit that is in the support files (the one at 0 was artifically added.)
296254721Semaste        // So prefer the one further on in the support files if it exists...
297254721Semaste        FileSpecList &support_files = GetSupportFiles();
298254721Semaste        const bool full = true;
299254721Semaste        file_idx = support_files.FindFileIndex (1, support_files.GetFileSpecAtIndex(0), full);
300254721Semaste        if (file_idx == UINT32_MAX)
301254721Semaste            file_idx = 0;
302254721Semaste    }
303254721Semaste    LineTable *line_table = GetLineTable();
304254721Semaste    if (line_table)
305254721Semaste        return line_table->FindLineEntryIndexByFileIndex (start_idx, file_idx, line, exact, line_entry_ptr);
306254721Semaste    return UINT32_MAX;
307254721Semaste}
308254721Semaste
309254721Semaste
310254721Semaste
311254721Semaste
312254721Semasteuint32_t
313254721SemasteCompileUnit::ResolveSymbolContext
314254721Semaste(
315254721Semaste    const FileSpec& file_spec,
316254721Semaste    uint32_t line,
317254721Semaste    bool check_inlines,
318254721Semaste    bool exact,
319254721Semaste    uint32_t resolve_scope,
320254721Semaste    SymbolContextList &sc_list
321254721Semaste)
322254721Semaste{
323254721Semaste    // First find all of the file indexes that match our "file_spec". If
324254721Semaste    // "file_spec" has an empty directory, then only compare the basenames
325254721Semaste    // when finding file indexes
326254721Semaste    std::vector<uint32_t> file_indexes;
327263363Semaste    const bool full_match = (bool)file_spec.GetDirectory();
328254721Semaste    bool file_spec_matches_cu_file_spec = FileSpec::Equal(file_spec, *this, full_match);
329254721Semaste
330254721Semaste    // If we are not looking for inlined functions and our file spec doesn't
331254721Semaste    // match then we are done...
332254721Semaste    if (file_spec_matches_cu_file_spec == false && check_inlines == false)
333254721Semaste        return 0;
334254721Semaste
335254721Semaste    uint32_t file_idx = GetSupportFiles().FindFileIndex (1, file_spec, true);
336254721Semaste    while (file_idx != UINT32_MAX)
337254721Semaste    {
338254721Semaste        file_indexes.push_back (file_idx);
339254721Semaste        file_idx = GetSupportFiles().FindFileIndex (file_idx + 1, file_spec, true);
340254721Semaste    }
341254721Semaste
342254721Semaste    const size_t num_file_indexes = file_indexes.size();
343254721Semaste    if (num_file_indexes == 0)
344254721Semaste        return 0;
345254721Semaste
346254721Semaste    const uint32_t prev_size = sc_list.GetSize();
347254721Semaste
348254721Semaste    SymbolContext sc(GetModule());
349254721Semaste    sc.comp_unit = this;
350254721Semaste
351254721Semaste
352254721Semaste    if (line != 0)
353254721Semaste    {
354254721Semaste        LineTable *line_table = sc.comp_unit->GetLineTable();
355254721Semaste
356254721Semaste        if (line_table != NULL)
357254721Semaste        {
358254721Semaste            uint32_t found_line;
359254721Semaste            uint32_t line_idx;
360254721Semaste
361254721Semaste            if (num_file_indexes == 1)
362254721Semaste            {
363254721Semaste                // We only have a single support file that matches, so use
364254721Semaste                // the line table function that searches for a line entries
365254721Semaste                // that match a single support file index
366254721Semaste                LineEntry line_entry;
367254721Semaste                line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes.front(), line, exact, &line_entry);
368254721Semaste
369254721Semaste                // If "exact == true", then "found_line" will be the same
370254721Semaste                // as "line". If "exact == false", the "found_line" will be the
371254721Semaste                // closest line entry with a line number greater than "line" and
372254721Semaste                // we will use this for our subsequent line exact matches below.
373254721Semaste                found_line = line_entry.line;
374254721Semaste
375254721Semaste                while (line_idx != UINT32_MAX)
376254721Semaste                {
377254721Semaste                    // If they only asked for the line entry, then we're done, we can just copy that over.
378254721Semaste                    // But if they wanted more than just the line number, fill it in.
379254721Semaste                    if (resolve_scope == eSymbolContextLineEntry)
380254721Semaste                    {
381254721Semaste                        sc.line_entry = line_entry;
382254721Semaste                    }
383254721Semaste                    else
384254721Semaste                    {
385254721Semaste                        line_entry.range.GetBaseAddress().CalculateSymbolContext(&sc, resolve_scope);
386254721Semaste                    }
387254721Semaste
388254721Semaste                    sc_list.Append(sc);
389254721Semaste                    line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes.front(), found_line, true, &line_entry);
390254721Semaste                }
391254721Semaste            }
392254721Semaste            else
393254721Semaste            {
394254721Semaste                // We found multiple support files that match "file_spec" so use
395254721Semaste                // the line table function that searches for a line entries
396254721Semaste                // that match a multiple support file indexes.
397254721Semaste                LineEntry line_entry;
398254721Semaste                line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes, line, exact, &line_entry);
399254721Semaste
400254721Semaste                // If "exact == true", then "found_line" will be the same
401254721Semaste                // as "line". If "exact == false", the "found_line" will be the
402254721Semaste                // closest line entry with a line number greater than "line" and
403254721Semaste                // we will use this for our subsequent line exact matches below.
404254721Semaste                found_line = line_entry.line;
405254721Semaste
406254721Semaste                while (line_idx != UINT32_MAX)
407254721Semaste                {
408254721Semaste                    if (resolve_scope == eSymbolContextLineEntry)
409254721Semaste                    {
410254721Semaste                        sc.line_entry = line_entry;
411254721Semaste                    }
412254721Semaste                    else
413254721Semaste                    {
414254721Semaste                        line_entry.range.GetBaseAddress().CalculateSymbolContext(&sc, resolve_scope);
415254721Semaste                    }
416254721Semaste
417254721Semaste                    sc_list.Append(sc);
418254721Semaste                    line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes, found_line, true, &line_entry);
419254721Semaste                }
420254721Semaste            }
421254721Semaste        }
422254721Semaste    }
423254721Semaste    else if (file_spec_matches_cu_file_spec && !check_inlines)
424254721Semaste    {
425254721Semaste        // only append the context if we aren't looking for inline call sites
426254721Semaste        // by file and line and if the file spec matches that of the compile unit
427254721Semaste        sc_list.Append(sc);
428254721Semaste    }
429254721Semaste    return sc_list.GetSize() - prev_size;
430254721Semaste}
431254721Semaste
432254721Semastevoid
433254721SemasteCompileUnit::SetVariableList(VariableListSP &variables)
434254721Semaste{
435254721Semaste    m_variables = variables;
436254721Semaste}
437254721Semaste
438254721SemasteFileSpecList&
439254721SemasteCompileUnit::GetSupportFiles ()
440254721Semaste{
441254721Semaste    if (m_support_files.GetSize() == 0)
442254721Semaste    {
443254721Semaste        if (m_flags.IsClear(flagsParsedSupportFiles))
444254721Semaste        {
445254721Semaste            m_flags.Set(flagsParsedSupportFiles);
446254721Semaste            SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor();
447254721Semaste            if (symbol_vendor)
448254721Semaste            {
449254721Semaste                SymbolContext sc;
450254721Semaste                CalculateSymbolContext(&sc);
451254721Semaste                symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files);
452254721Semaste            }
453254721Semaste        }
454254721Semaste    }
455254721Semaste    return m_support_files;
456254721Semaste}
457254721Semaste
458254721Semastevoid *
459254721SemasteCompileUnit::GetUserData () const
460254721Semaste{
461254721Semaste    return m_user_data;
462254721Semaste}
463254721Semaste
464254721Semaste
465