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 //----------------------------------------------------------------------
FunctionInfo(const char * name,const Declaration * decl_ptr)30 FunctionInfo::FunctionInfo (const char *name, const Declaration *decl_ptr) :
31 m_name(name),
32 m_declaration(decl_ptr)
33 {
34 }
35
36
FunctionInfo(const ConstString & name,const Declaration * decl_ptr)37 FunctionInfo::FunctionInfo (const ConstString& name, const Declaration *decl_ptr) :
38 m_name(name),
39 m_declaration(decl_ptr)
40 {
41 }
42
43
~FunctionInfo()44 FunctionInfo::~FunctionInfo()
45 {
46 }
47
48 void
Dump(Stream * s,bool show_fullpaths) const49 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
Compare(const FunctionInfo & a,const FunctionInfo & b)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&
GetDeclaration()69 FunctionInfo::GetDeclaration()
70 {
71 return m_declaration;
72 }
73
74 const Declaration&
GetDeclaration() const75 FunctionInfo::GetDeclaration() const
76 {
77 return m_declaration;
78 }
79
80 ConstString
GetName() const81 FunctionInfo::GetName() const
82 {
83 return m_name;
84 }
85
86 size_t
MemorySize() const87 FunctionInfo::MemorySize() const
88 {
89 return m_name.MemorySize() + m_declaration.MemorySize();
90 }
91
92
InlineFunctionInfo(const char * name,const char * mangled,const Declaration * decl_ptr,const Declaration * call_decl_ptr)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
InlineFunctionInfo(const ConstString & name,const Mangled & mangled,const Declaration * decl_ptr,const Declaration * call_decl_ptr)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
~InlineFunctionInfo()119 InlineFunctionInfo::~InlineFunctionInfo()
120 {
121 }
122
123 int
Compare(const InlineFunctionInfo & a,const InlineFunctionInfo & b)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
Dump(Stream * s,bool show_fullpaths) const135 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
DumpStopContext(Stream * s,LanguageType language) const143 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
GetName(LanguageType language) const155 InlineFunctionInfo::GetName (LanguageType language) const
156 {
157 if (m_mangled)
158 return m_mangled.GetName(language);
159 return m_name;
160 }
161
162 ConstString
GetDisplayName(LanguageType language) const163 InlineFunctionInfo::GetDisplayName (LanguageType language) const
164 {
165 if (m_mangled)
166 return m_mangled.GetDisplayDemangledName(language);
167 return m_name;
168 }
169
170 Declaration &
GetCallSite()171 InlineFunctionInfo::GetCallSite ()
172 {
173 return m_call_decl;
174 }
175
176 const Declaration &
GetCallSite() const177 InlineFunctionInfo::GetCallSite () const
178 {
179 return m_call_decl;
180 }
181
182
183 Mangled&
GetMangled()184 InlineFunctionInfo::GetMangled()
185 {
186 return m_mangled;
187 }
188
189 const Mangled&
GetMangled() const190 InlineFunctionInfo::GetMangled() const
191 {
192 return m_mangled;
193 }
194
195 size_t
MemorySize() const196 InlineFunctionInfo::MemorySize() const
197 {
198 return FunctionInfo::MemorySize() + m_mangled.MemorySize();
199 }
200
201 //----------------------------------------------------------------------
202 //
203 //----------------------------------------------------------------------
Function(CompileUnit * comp_unit,lldb::user_id_t func_uid,lldb::user_id_t type_uid,const Mangled & mangled,Type * type,const AddressRange & range)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
Function(CompileUnit * comp_unit,lldb::user_id_t func_uid,lldb::user_id_t type_uid,const char * mangled,Type * type,const AddressRange & range)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
~Function()253 Function::~Function()
254 {
255 }
256
257 void
GetStartLineSourceInfo(FileSpec & source_file,uint32_t & line_no)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
GetEndLineSourceInfo(FileSpec & source_file,uint32_t & line_no)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 &
GetBlock(bool can_create)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*
GetCompileUnit()333 Function::GetCompileUnit()
334 {
335 return m_comp_unit;
336 }
337
338 const CompileUnit*
GetCompileUnit() const339 Function::GetCompileUnit() const
340 {
341 return m_comp_unit;
342 }
343
344
345 void
GetDescription(Stream * s,lldb::DescriptionLevel level,Target * target)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
Dump(Stream * s,bool show_context) const362 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
CalculateSymbolContext(SymbolContext * sc)383 Function::CalculateSymbolContext(SymbolContext* sc)
384 {
385 sc->function = this;
386 m_comp_unit->CalculateSymbolContext(sc);
387 }
388
389 ModuleSP
CalculateSymbolContextModule()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 *
CalculateSymbolContextCompileUnit()400 Function::CalculateSymbolContextCompileUnit ()
401 {
402 return this->GetCompileUnit();
403 }
404
405 Function *
CalculateSymbolContextFunction()406 Function::CalculateSymbolContextFunction ()
407 {
408 return this;
409 }
410
411 lldb::DisassemblerSP
GetInstructions(const ExecutionContext & exe_ctx,const char * flavor,bool prefer_file_cache)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
GetDisassembly(const ExecutionContext & exe_ctx,const char * flavor,bool prefer_file_cache,Stream & strm)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
DumpSymbolContext(Stream * s)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
MemorySize() const463 Function::MemorySize () const
464 {
465 size_t mem_size = sizeof(Function) + m_block.MemorySize();
466 return mem_size;
467 }
468
469 ConstString
GetDisplayName() const470 Function::GetDisplayName () const
471 {
472 if (!m_mangled)
473 return ConstString();
474 return m_mangled.GetDisplayDemangledName(GetLanguage());
475 }
476
477 clang::DeclContext *
GetClangDeclContext()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*
GetType()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*
GetType() const528 Function::GetType() const
529 {
530 return m_type;
531 }
532
533 ClangASTType
GetClangType()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
GetPrologueByteSize()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
GetLanguage() const621 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
GetName() const630 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
GetNameNoArguments() const639 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