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/Symbol/ClangASTType.h"
14 #include "lldb/Symbol/ClangASTContext.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 "clang/AST/Type.h"
20 #include "clang/AST/CanonicalType.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.
28 // It is designed to contain the name, linkage name, and declaration
29 // location.
30 //----------------------------------------------------------------------
31 FunctionInfo::FunctionInfo (const char *name, const Declaration *decl_ptr) :
32     m_name(name),
33     m_declaration(decl_ptr)
34 {
35 }
36 
37 
38 FunctionInfo::FunctionInfo (const ConstString& name, const Declaration *decl_ptr) :
39     m_name(name),
40     m_declaration(decl_ptr)
41 {
42 }
43 
44 
45 FunctionInfo::~FunctionInfo()
46 {
47 }
48 
49 void
50 FunctionInfo::Dump(Stream *s, bool show_fullpaths) const
51 {
52     if (m_name)
53         *s << ", name = \"" << m_name << "\"";
54     m_declaration.Dump(s, show_fullpaths);
55 }
56 
57 
58 int
59 FunctionInfo::Compare(const FunctionInfo& a, const FunctionInfo& b)
60 {
61     int result = ConstString::Compare(a.GetName(), b.GetName());
62     if (result)
63         return result;
64 
65     return Declaration::Compare(a.m_declaration, b.m_declaration);
66 }
67 
68 
69 Declaration&
70 FunctionInfo::GetDeclaration()
71 {
72     return m_declaration;
73 }
74 
75 const Declaration&
76 FunctionInfo::GetDeclaration() const
77 {
78     return m_declaration;
79 }
80 
81 const ConstString&
82 FunctionInfo::GetName() const
83 {
84     return m_name;
85 }
86 
87 size_t
88 FunctionInfo::MemorySize() const
89 {
90     return m_name.MemorySize() + m_declaration.MemorySize();
91 }
92 
93 
94 InlineFunctionInfo::InlineFunctionInfo
95 (
96     const char *name,
97     const char *mangled,
98     const Declaration *decl_ptr,
99     const Declaration *call_decl_ptr
100 ) :
101     FunctionInfo(name, decl_ptr),
102     m_mangled(mangled, true),
103     m_call_decl (call_decl_ptr)
104 {
105 }
106 
107 InlineFunctionInfo::InlineFunctionInfo
108 (
109     const ConstString& name,
110     const Mangled &mangled,
111     const Declaration *decl_ptr,
112     const Declaration *call_decl_ptr
113 ) :
114     FunctionInfo(name, decl_ptr),
115     m_mangled(mangled),
116     m_call_decl (call_decl_ptr)
117 {
118 }
119 
120 InlineFunctionInfo::~InlineFunctionInfo()
121 {
122 }
123 
124 int
125 InlineFunctionInfo::Compare(const InlineFunctionInfo& a, const InlineFunctionInfo& b)
126 {
127 
128     int result = FunctionInfo::Compare(a, b);
129     if (result)
130         return result;
131     // only compare the mangled names if both have them
132     return Mangled::Compare(a.m_mangled, a.m_mangled);
133 }
134 
135 void
136 InlineFunctionInfo::Dump(Stream *s, bool show_fullpaths) const
137 {
138     FunctionInfo::Dump(s, show_fullpaths);
139     if (m_mangled)
140         m_mangled.Dump(s);
141 }
142 
143 void
144 InlineFunctionInfo::DumpStopContext (Stream *s) const
145 {
146 //    s->Indent("[inlined] ");
147     s->Indent();
148     if (m_mangled)
149         s->PutCString (m_mangled.GetName().AsCString());
150     else
151         s->PutCString (m_name.AsCString());
152 }
153 
154 
155 const ConstString &
156 InlineFunctionInfo::GetName () const
157 {
158     if (m_mangled)
159         return m_mangled.GetName();
160     return m_name;
161 }
162 
163 
164 Declaration &
165 InlineFunctionInfo::GetCallSite ()
166 {
167     return m_call_decl;
168 }
169 
170 const Declaration &
171 InlineFunctionInfo::GetCallSite () const
172 {
173     return m_call_decl;
174 }
175 
176 
177 Mangled&
178 InlineFunctionInfo::GetMangled()
179 {
180     return m_mangled;
181 }
182 
183 const Mangled&
184 InlineFunctionInfo::GetMangled() const
185 {
186     return m_mangled;
187 }
188 
189 size_t
190 InlineFunctionInfo::MemorySize() const
191 {
192     return FunctionInfo::MemorySize() + m_mangled.MemorySize();
193 }
194 
195 //----------------------------------------------------------------------
196 //
197 //----------------------------------------------------------------------
198 Function::Function
199 (
200     CompileUnit *comp_unit,
201     lldb::user_id_t func_uid,
202     lldb::user_id_t type_uid,
203     const Mangled &mangled,
204     Type * type,
205     const AddressRange& range
206 ) :
207     UserID (func_uid),
208     m_comp_unit (comp_unit),
209     m_type_uid (type_uid),
210     m_type (type),
211     m_mangled (mangled),
212     m_block (func_uid),
213     m_range (range),
214     m_frame_base (),
215     m_flags (),
216     m_prologue_byte_size (0)
217 {
218     m_block.SetParentScope(this);
219     assert(comp_unit != NULL);
220 }
221 
222 Function::Function
223 (
224     CompileUnit *comp_unit,
225     lldb::user_id_t func_uid,
226     lldb::user_id_t type_uid,
227     const char *mangled,
228     Type *type,
229     const AddressRange &range
230 ) :
231     UserID (func_uid),
232     m_comp_unit (comp_unit),
233     m_type_uid (type_uid),
234     m_type (type),
235     m_mangled (mangled, true),
236     m_block (func_uid),
237     m_range (range),
238     m_frame_base (),
239     m_flags (),
240     m_prologue_byte_size (0)
241 {
242     m_block.SetParentScope(this);
243     assert(comp_unit != NULL);
244 }
245 
246 
247 Function::~Function()
248 {
249 }
250 
251 void
252 Function::GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
253 {
254     line_no = 0;
255     source_file.Clear();
256 
257     if (m_comp_unit == NULL)
258         return;
259 
260     if (m_type != NULL && m_type->GetDeclaration().GetLine() != 0)
261     {
262         source_file = m_type->GetDeclaration().GetFile();
263         line_no = m_type->GetDeclaration().GetLine();
264     }
265     else
266     {
267         LineTable *line_table = m_comp_unit->GetLineTable();
268         if (line_table == NULL)
269             return;
270 
271         LineEntry line_entry;
272         if (line_table->FindLineEntryByAddress (GetAddressRange().GetBaseAddress(), line_entry, NULL))
273         {
274             line_no = line_entry.line;
275             source_file = line_entry.file;
276         }
277     }
278 }
279 
280 void
281 Function::GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
282 {
283     line_no = 0;
284     source_file.Clear();
285 
286     // The -1 is kind of cheesy, but I want to get the last line entry for the given function, not the
287     // first entry of the next.
288     Address scratch_addr(GetAddressRange().GetBaseAddress());
289     scratch_addr.SetOffset (scratch_addr.GetOffset() + GetAddressRange().GetByteSize() - 1);
290 
291     LineTable *line_table = m_comp_unit->GetLineTable();
292     if (line_table == NULL)
293         return;
294 
295     LineEntry line_entry;
296     if (line_table->FindLineEntryByAddress (scratch_addr, line_entry, NULL))
297     {
298         line_no = line_entry.line;
299         source_file = line_entry.file;
300     }
301 }
302 
303 Block &
304 Function::GetBlock (bool can_create)
305 {
306     if (!m_block.BlockInfoHasBeenParsed() && can_create)
307     {
308         SymbolContext sc;
309         CalculateSymbolContext(&sc);
310         if (sc.module_sp)
311         {
312             sc.module_sp->GetSymbolVendor()->ParseFunctionBlocks(sc);
313         }
314         else
315         {
316             ::fprintf (stderr,
317                        "unable to find module shared pointer for function '%s' in %s%s%s\n",
318                        GetName().GetCString(),
319                        m_comp_unit->GetDirectory().GetCString(),
320                        m_comp_unit->GetDirectory() ? "/" : "",
321                        m_comp_unit->GetFilename().GetCString());
322         }
323         m_block.SetBlockInfoHasBeenParsed (true, true);
324     }
325     return m_block;
326 }
327 
328 CompileUnit*
329 Function::GetCompileUnit()
330 {
331     return m_comp_unit;
332 }
333 
334 const CompileUnit*
335 Function::GetCompileUnit() const
336 {
337     return m_comp_unit;
338 }
339 
340 
341 void
342 Function::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target)
343 {
344     Type* func_type = GetType();
345     *s << "id = " << (const UserID&)*this << ", name = \"" << func_type->GetName() << "\", range = ";
346 
347     Address::DumpStyle fallback_style;
348     if (level == eDescriptionLevelVerbose)
349         fallback_style = Address::DumpStyleModuleWithFileAddress;
350     else
351         fallback_style = Address::DumpStyleFileAddress;
352     GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, fallback_style);
353 }
354 
355 void
356 Function::Dump(Stream *s, bool show_context) const
357 {
358     s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
359     s->Indent();
360     *s << "Function" << (const UserID&)*this;
361 
362     m_mangled.Dump(s);
363 
364 //  FunctionInfo::Dump(s);
365     if (m_type)
366     {
367         *s << ", type = " << (void*)m_type;
368         /// << " (";
369         ///m_type->DumpTypeName(s);
370         ///s->PutChar(')');
371     }
372     else if (m_type_uid != LLDB_INVALID_UID)
373         *s << ", type_uid = " << 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 void
390 Function::DumpSymbolContext(Stream *s)
391 {
392     m_comp_unit->DumpSymbolContext(s);
393     s->Printf(", Function{0x%8.8x}", GetID());
394 }
395 
396 size_t
397 Function::MemorySize () const
398 {
399     size_t mem_size = sizeof(Function) + m_block.MemorySize();
400     return mem_size;
401 }
402 
403 clang::DeclContext *
404 Function::GetClangDeclContext()
405 {
406     SymbolContext sc;
407 
408     CalculateSymbolContext (&sc);
409 
410     if (!sc.module_sp)
411         return NULL;
412 
413     SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
414 
415     if (!sym_vendor)
416         return NULL;
417 
418     SymbolFile *sym_file = sym_vendor->GetSymbolFile();
419 
420     if (!sym_file)
421         return NULL;
422 
423     return sym_file->GetClangDeclContextForTypeUID (sc, m_uid);
424 }
425 
426 Type*
427 Function::GetType()
428 {
429     return m_type;
430 }
431 
432 const Type*
433 Function::GetType() const
434 {
435     return m_type;
436 }
437 
438 clang_type_t
439 Function::GetReturnClangType ()
440 {
441     clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetClangFullType()));
442     const clang::FunctionType *function_type = llvm::dyn_cast<clang::FunctionType> (clang_type);
443     if (function_type)
444         return function_type->getResultType().getAsOpaquePtr();
445     return NULL;
446 }
447 
448 int
449 Function::GetArgumentCount ()
450 {
451     clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetClangFullType()));
452     assert (clang_type->isFunctionType());
453     if (!clang_type->isFunctionProtoType())
454         return -1;
455 
456     const clang::FunctionProtoType *function_proto_type = llvm::dyn_cast<clang::FunctionProtoType>(clang_type);
457     if (function_proto_type != NULL)
458         return function_proto_type->getNumArgs();
459 
460     return 0;
461 }
462 
463 clang_type_t
464 Function::GetArgumentTypeAtIndex (size_t idx)
465 {
466     clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetClangFullType()));
467     const clang::FunctionProtoType *function_proto_type = llvm::dyn_cast<clang::FunctionProtoType>(clang_type);
468     if (function_proto_type)
469     {
470         unsigned num_args = function_proto_type->getNumArgs();
471         if (idx >= num_args)
472             return NULL;
473 
474         return (function_proto_type->arg_type_begin())[idx].getAsOpaquePtr();
475     }
476     return NULL;
477 }
478 
479 bool
480 Function::IsVariadic ()
481 {
482    const clang::Type *clang_type = static_cast<clang::QualType *>(GetType()->GetClangFullType())->getTypePtr();
483    assert (clang_type->isFunctionType());
484    if (!clang_type->isFunctionProtoType())
485         return false;
486 
487     const clang::FunctionProtoType *function_proto_type = llvm::dyn_cast<clang::FunctionProtoType>(clang_type);
488     if (function_proto_type)
489         return function_proto_type->isVariadic();
490 
491     return false;
492 }
493 
494 uint32_t
495 Function::GetPrologueByteSize ()
496 {
497     if (m_prologue_byte_size == 0 && m_flags.IsClear(flagsCalculatedPrologueSize))
498     {
499         m_flags.Set(flagsCalculatedPrologueSize);
500         LineTable* line_table = m_comp_unit->GetLineTable ();
501         if (line_table)
502         {
503             LineEntry line_entry;
504             if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), line_entry))
505             {
506                 // We need to take the delta of the end of the first line entry
507                 // as a file address and the start file address of the function
508                 // in case the first line entry doesn't start at the beginning
509                 // of the function.
510                 const addr_t func_start_file_addr = m_range.GetBaseAddress().GetFileAddress();
511                 const addr_t line_entry_end_file_addr = line_entry.range.GetBaseAddress().GetFileAddress() + line_entry.range.GetByteSize();
512                 if (line_entry_end_file_addr > func_start_file_addr)
513                     m_prologue_byte_size = line_entry_end_file_addr - func_start_file_addr;
514             }
515         }
516     }
517     return m_prologue_byte_size;
518 }
519 
520 
521 
522