1//===-- Function.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/Function.h"
11#include "lldb/Core/Module.h"
12#include "lldb/Core/Section.h"
13#include "lldb/Host/Host.h"
14#include "lldb/Symbol/ClangASTType.h"
15#include "lldb/Symbol/CompileUnit.h"
16#include "lldb/Symbol/LineTable.h"
17#include "lldb/Symbol/SymbolFile.h"
18#include "lldb/Symbol/SymbolVendor.h"
19#include "llvm/Support/Casting.h"
20
21using namespace lldb;
22using namespace lldb_private;
23
24//----------------------------------------------------------------------
25// Basic function information is contained in the FunctionInfo class.
26// It is designed to contain the name, linkage name, and declaration
27// location.
28//----------------------------------------------------------------------
29FunctionInfo::FunctionInfo (const char *name, const Declaration *decl_ptr) :
30    m_name(name),
31    m_declaration(decl_ptr)
32{
33}
34
35
36FunctionInfo::FunctionInfo (const ConstString& name, const Declaration *decl_ptr) :
37    m_name(name),
38    m_declaration(decl_ptr)
39{
40}
41
42
43FunctionInfo::~FunctionInfo()
44{
45}
46
47void
48FunctionInfo::Dump(Stream *s, bool show_fullpaths) const
49{
50    if (m_name)
51        *s << ", name = \"" << m_name << "\"";
52    m_declaration.Dump(s, show_fullpaths);
53}
54
55
56int
57FunctionInfo::Compare(const FunctionInfo& a, const FunctionInfo& b)
58{
59    int result = ConstString::Compare(a.GetName(), b.GetName());
60    if (result)
61        return result;
62
63    return Declaration::Compare(a.m_declaration, b.m_declaration);
64}
65
66
67Declaration&
68FunctionInfo::GetDeclaration()
69{
70    return m_declaration;
71}
72
73const Declaration&
74FunctionInfo::GetDeclaration() const
75{
76    return m_declaration;
77}
78
79const ConstString&
80FunctionInfo::GetName() const
81{
82    return m_name;
83}
84
85size_t
86FunctionInfo::MemorySize() const
87{
88    return m_name.MemorySize() + m_declaration.MemorySize();
89}
90
91
92InlineFunctionInfo::InlineFunctionInfo
93(
94    const char *name,
95    const char *mangled,
96    const Declaration *decl_ptr,
97    const Declaration *call_decl_ptr
98) :
99    FunctionInfo(name, decl_ptr),
100    m_mangled(ConstString(mangled), true),
101    m_call_decl (call_decl_ptr)
102{
103}
104
105InlineFunctionInfo::InlineFunctionInfo
106(
107    const ConstString& name,
108    const Mangled &mangled,
109    const Declaration *decl_ptr,
110    const Declaration *call_decl_ptr
111) :
112    FunctionInfo(name, decl_ptr),
113    m_mangled(mangled),
114    m_call_decl (call_decl_ptr)
115{
116}
117
118InlineFunctionInfo::~InlineFunctionInfo()
119{
120}
121
122int
123InlineFunctionInfo::Compare(const InlineFunctionInfo& a, const InlineFunctionInfo& b)
124{
125
126    int result = FunctionInfo::Compare(a, b);
127    if (result)
128        return result;
129    // only compare the mangled names if both have them
130    return Mangled::Compare(a.m_mangled, a.m_mangled);
131}
132
133void
134InlineFunctionInfo::Dump(Stream *s, bool show_fullpaths) const
135{
136    FunctionInfo::Dump(s, show_fullpaths);
137    if (m_mangled)
138        m_mangled.Dump(s);
139}
140
141void
142InlineFunctionInfo::DumpStopContext (Stream *s) const
143{
144//    s->Indent("[inlined] ");
145    s->Indent();
146    if (m_mangled)
147        s->PutCString (m_mangled.GetName().AsCString());
148    else
149        s->PutCString (m_name.AsCString());
150}
151
152
153const ConstString &
154InlineFunctionInfo::GetName () const
155{
156    if (m_mangled)
157        return m_mangled.GetName();
158    return m_name;
159}
160
161
162Declaration &
163InlineFunctionInfo::GetCallSite ()
164{
165    return m_call_decl;
166}
167
168const Declaration &
169InlineFunctionInfo::GetCallSite () const
170{
171    return m_call_decl;
172}
173
174
175Mangled&
176InlineFunctionInfo::GetMangled()
177{
178    return m_mangled;
179}
180
181const Mangled&
182InlineFunctionInfo::GetMangled() const
183{
184    return m_mangled;
185}
186
187size_t
188InlineFunctionInfo::MemorySize() const
189{
190    return FunctionInfo::MemorySize() + m_mangled.MemorySize();
191}
192
193//----------------------------------------------------------------------
194//
195//----------------------------------------------------------------------
196Function::Function
197(
198    CompileUnit *comp_unit,
199    lldb::user_id_t func_uid,
200    lldb::user_id_t type_uid,
201    const Mangled &mangled,
202    Type * type,
203    const AddressRange& range
204) :
205    UserID (func_uid),
206    m_comp_unit (comp_unit),
207    m_type_uid (type_uid),
208    m_type (type),
209    m_mangled (mangled),
210    m_block (func_uid),
211    m_range (range),
212    m_frame_base (),
213    m_flags (),
214    m_prologue_byte_size (0)
215{
216    m_block.SetParentScope(this);
217    assert(comp_unit != NULL);
218}
219
220Function::Function
221(
222    CompileUnit *comp_unit,
223    lldb::user_id_t func_uid,
224    lldb::user_id_t type_uid,
225    const char *mangled,
226    Type *type,
227    const AddressRange &range
228) :
229    UserID (func_uid),
230    m_comp_unit (comp_unit),
231    m_type_uid (type_uid),
232    m_type (type),
233    m_mangled (ConstString(mangled), true),
234    m_block (func_uid),
235    m_range (range),
236    m_frame_base (),
237    m_flags (),
238    m_prologue_byte_size (0)
239{
240    m_block.SetParentScope(this);
241    assert(comp_unit != NULL);
242}
243
244
245Function::~Function()
246{
247}
248
249void
250Function::GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
251{
252    line_no = 0;
253    source_file.Clear();
254
255    if (m_comp_unit == NULL)
256        return;
257
258    if (m_type != NULL && m_type->GetDeclaration().GetLine() != 0)
259    {
260        source_file = m_type->GetDeclaration().GetFile();
261        line_no = m_type->GetDeclaration().GetLine();
262    }
263    else
264    {
265        LineTable *line_table = m_comp_unit->GetLineTable();
266        if (line_table == NULL)
267            return;
268
269        LineEntry line_entry;
270        if (line_table->FindLineEntryByAddress (GetAddressRange().GetBaseAddress(), line_entry, NULL))
271        {
272            line_no = line_entry.line;
273            source_file = line_entry.file;
274        }
275    }
276}
277
278void
279Function::GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
280{
281    line_no = 0;
282    source_file.Clear();
283
284    // The -1 is kind of cheesy, but I want to get the last line entry for the given function, not the
285    // first entry of the next.
286    Address scratch_addr(GetAddressRange().GetBaseAddress());
287    scratch_addr.SetOffset (scratch_addr.GetOffset() + GetAddressRange().GetByteSize() - 1);
288
289    LineTable *line_table = m_comp_unit->GetLineTable();
290    if (line_table == NULL)
291        return;
292
293    LineEntry line_entry;
294    if (line_table->FindLineEntryByAddress (scratch_addr, line_entry, NULL))
295    {
296        line_no = line_entry.line;
297        source_file = line_entry.file;
298    }
299}
300
301Block &
302Function::GetBlock (bool can_create)
303{
304    if (!m_block.BlockInfoHasBeenParsed() && can_create)
305    {
306        SymbolContext sc;
307        CalculateSymbolContext(&sc);
308        if (sc.module_sp)
309        {
310            sc.module_sp->GetSymbolVendor()->ParseFunctionBlocks(sc);
311        }
312        else
313        {
314            Host::SystemLog (Host::eSystemLogError,
315                             "error: unable to find module shared pointer for function '%s' in %s\n",
316                             GetName().GetCString(),
317                             m_comp_unit->GetPath().c_str());
318        }
319        m_block.SetBlockInfoHasBeenParsed (true, true);
320    }
321    return m_block;
322}
323
324CompileUnit*
325Function::GetCompileUnit()
326{
327    return m_comp_unit;
328}
329
330const CompileUnit*
331Function::GetCompileUnit() const
332{
333    return m_comp_unit;
334}
335
336
337void
338Function::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target)
339{
340    Type* func_type = GetType();
341    const char *name = func_type ? func_type->GetName().AsCString() : "<unknown>";
342
343    *s << "id = " << (const UserID&)*this << ", name = \"" << name << "\", range = ";
344
345    Address::DumpStyle fallback_style;
346    if (level == eDescriptionLevelVerbose)
347        fallback_style = Address::DumpStyleModuleWithFileAddress;
348    else
349        fallback_style = Address::DumpStyleFileAddress;
350    GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, fallback_style);
351}
352
353void
354Function::Dump(Stream *s, bool show_context) const
355{
356    s->Printf("%p: ", this);
357    s->Indent();
358    *s << "Function" << (const UserID&)*this;
359
360    m_mangled.Dump(s);
361
362    if (m_type)
363    {
364        s->Printf(", type = %p", m_type);
365    }
366    else if (m_type_uid != LLDB_INVALID_UID)
367    {
368        s->Printf(", type_uid = 0x%8.8" PRIx64, m_type_uid);
369    }
370
371    s->EOL();
372    // Dump the root object
373    if (m_block.BlockInfoHasBeenParsed ())
374        m_block.Dump(s, m_range.GetBaseAddress().GetFileAddress(), INT_MAX, show_context);
375}
376
377
378void
379Function::CalculateSymbolContext(SymbolContext* sc)
380{
381    sc->function = this;
382    m_comp_unit->CalculateSymbolContext(sc);
383}
384
385ModuleSP
386Function::CalculateSymbolContextModule ()
387{
388    SectionSP section_sp (m_range.GetBaseAddress().GetSection());
389    if (section_sp)
390        return section_sp->GetModule();
391
392    return this->GetCompileUnit()->GetModule();
393}
394
395CompileUnit *
396Function::CalculateSymbolContextCompileUnit ()
397{
398    return this->GetCompileUnit();
399}
400
401Function *
402Function::CalculateSymbolContextFunction ()
403{
404    return this;
405}
406
407//Symbol *
408//Function::CalculateSymbolContextSymbol ()
409//{
410//    return // TODO: find the symbol for the function???
411//}
412
413
414void
415Function::DumpSymbolContext(Stream *s)
416{
417    m_comp_unit->DumpSymbolContext(s);
418    s->Printf(", Function{0x%8.8" PRIx64 "}", GetID());
419}
420
421size_t
422Function::MemorySize () const
423{
424    size_t mem_size = sizeof(Function) + m_block.MemorySize();
425    return mem_size;
426}
427
428clang::DeclContext *
429Function::GetClangDeclContext()
430{
431    SymbolContext sc;
432
433    CalculateSymbolContext (&sc);
434
435    if (!sc.module_sp)
436        return NULL;
437
438    SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
439
440    if (!sym_vendor)
441        return NULL;
442
443    SymbolFile *sym_file = sym_vendor->GetSymbolFile();
444
445    if (!sym_file)
446        return NULL;
447
448    return sym_file->GetClangDeclContextForTypeUID (sc, m_uid);
449}
450
451Type*
452Function::GetType()
453{
454    if (m_type == NULL)
455    {
456        SymbolContext sc;
457
458        CalculateSymbolContext (&sc);
459
460        if (!sc.module_sp)
461            return NULL;
462
463        SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
464
465        if (sym_vendor == NULL)
466            return NULL;
467
468        SymbolFile *sym_file = sym_vendor->GetSymbolFile();
469
470        if (sym_file == NULL)
471            return NULL;
472
473        m_type = sym_file->ResolveTypeUID(m_type_uid);
474    }
475    return m_type;
476}
477
478const Type*
479Function::GetType() const
480{
481    return m_type;
482}
483
484ClangASTType
485Function::GetClangType()
486{
487    Type *function_type = GetType();
488    if (function_type)
489        return function_type->GetClangFullType();
490    return ClangASTType();
491}
492
493uint32_t
494Function::GetPrologueByteSize ()
495{
496    if (m_prologue_byte_size == 0 && m_flags.IsClear(flagsCalculatedPrologueSize))
497    {
498        m_flags.Set(flagsCalculatedPrologueSize);
499        LineTable* line_table = m_comp_unit->GetLineTable ();
500        if (line_table)
501        {
502            LineEntry first_line_entry;
503            uint32_t first_line_entry_idx = UINT32_MAX;
504            if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), first_line_entry, &first_line_entry_idx))
505            {
506                // Make sure the first line entry isn't already the end of the prologue
507                addr_t prologue_end_file_addr = LLDB_INVALID_ADDRESS;
508                if (first_line_entry.is_prologue_end)
509                {
510                    prologue_end_file_addr = first_line_entry.range.GetBaseAddress().GetFileAddress();
511                }
512                else
513                {
514                    // Check the first few instructions and look for one that has
515                    // is_prologue_end set to true.
516                    const uint32_t last_line_entry_idx = first_line_entry_idx + 6;
517                    for (uint32_t idx = first_line_entry_idx + 1; idx < last_line_entry_idx; ++idx)
518                    {
519                        LineEntry line_entry;
520                        if (line_table->GetLineEntryAtIndex (idx, line_entry))
521                        {
522                            if (line_entry.is_prologue_end)
523                            {
524                                prologue_end_file_addr = line_entry.range.GetBaseAddress().GetFileAddress();
525                                break;
526                            }
527                        }
528                    }
529                }
530
531                // If we didn't find the end of the prologue in the line tables,
532                // then just use the end address of the first line table entry
533                if (prologue_end_file_addr == LLDB_INVALID_ADDRESS)
534                {
535                    // Check the first few instructions and look for one that has
536                    // a line number that's different than the first entry.
537                    const uint32_t last_line_entry_idx = first_line_entry_idx + 6;
538                    for (uint32_t idx = first_line_entry_idx + 1; idx < last_line_entry_idx; ++idx)
539                    {
540                        LineEntry line_entry;
541                        if (line_table->GetLineEntryAtIndex (idx, line_entry))
542                        {
543                            if (line_entry.line != first_line_entry.line)
544                            {
545                                prologue_end_file_addr = line_entry.range.GetBaseAddress().GetFileAddress();
546                                break;
547                            }
548                        }
549                    }
550
551                    if (prologue_end_file_addr == LLDB_INVALID_ADDRESS)
552                    {
553                        prologue_end_file_addr = first_line_entry.range.GetBaseAddress().GetFileAddress() + first_line_entry.range.GetByteSize();
554                    }
555                }
556                const addr_t func_start_file_addr = m_range.GetBaseAddress().GetFileAddress();
557                const addr_t func_end_file_addr = func_start_file_addr + m_range.GetByteSize();
558
559                // Verify that this prologue end file address in the function's
560                // address range just to be sure
561                if (func_start_file_addr < prologue_end_file_addr && prologue_end_file_addr < func_end_file_addr)
562                {
563                    m_prologue_byte_size = prologue_end_file_addr - func_start_file_addr;
564                }
565            }
566        }
567    }
568    return m_prologue_byte_size;
569}
570
571
572
573