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