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