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