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 *s << "id = " << (const UserID&)*this << ", name = \"" << func_type->GetName() << "\", range = "; 347 348 Address::DumpStyle fallback_style; 349 if (level == eDescriptionLevelVerbose) 350 fallback_style = Address::DumpStyleModuleWithFileAddress; 351 else 352 fallback_style = Address::DumpStyleFileAddress; 353 GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, fallback_style); 354 } 355 356 void 357 Function::Dump(Stream *s, bool show_context) const 358 { 359 s->Printf("%p: ", this); 360 s->Indent(); 361 *s << "Function" << (const UserID&)*this; 362 363 m_mangled.Dump(s); 364 365 if (m_type) 366 { 367 s->Printf(", type = %p", m_type); 368 } 369 else if (m_type_uid != LLDB_INVALID_UID) 370 { 371 s->Printf(", type_uid = 0x%8.8llx", m_type_uid); 372 } 373 374 s->EOL(); 375 // Dump the root object 376 if (m_block.BlockInfoHasBeenParsed ()) 377 m_block.Dump(s, m_range.GetBaseAddress().GetFileAddress(), INT_MAX, show_context); 378 } 379 380 381 void 382 Function::CalculateSymbolContext(SymbolContext* sc) 383 { 384 sc->function = this; 385 m_comp_unit->CalculateSymbolContext(sc); 386 } 387 388 ModuleSP 389 Function::CalculateSymbolContextModule () 390 { 391 SectionSP section_sp (m_range.GetBaseAddress().GetSection()); 392 if (section_sp) 393 { 394 SectionSP linked_section_sp (section_sp->GetLinkedSection()); 395 if (linked_section_sp) 396 return linked_section_sp->GetModule(); 397 else 398 return section_sp->GetModule(); 399 } 400 401 return this->GetCompileUnit()->GetModule(); 402 } 403 404 CompileUnit * 405 Function::CalculateSymbolContextCompileUnit () 406 { 407 return this->GetCompileUnit(); 408 } 409 410 Function * 411 Function::CalculateSymbolContextFunction () 412 { 413 return this; 414 } 415 416 //Symbol * 417 //Function::CalculateSymbolContextSymbol () 418 //{ 419 // return // TODO: find the symbol for the function??? 420 //} 421 422 423 void 424 Function::DumpSymbolContext(Stream *s) 425 { 426 m_comp_unit->DumpSymbolContext(s); 427 s->Printf(", Function{0x%8.8llx}", GetID()); 428 } 429 430 size_t 431 Function::MemorySize () const 432 { 433 size_t mem_size = sizeof(Function) + m_block.MemorySize(); 434 return mem_size; 435 } 436 437 clang::DeclContext * 438 Function::GetClangDeclContext() 439 { 440 SymbolContext sc; 441 442 CalculateSymbolContext (&sc); 443 444 if (!sc.module_sp) 445 return NULL; 446 447 SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor(); 448 449 if (!sym_vendor) 450 return NULL; 451 452 SymbolFile *sym_file = sym_vendor->GetSymbolFile(); 453 454 if (!sym_file) 455 return NULL; 456 457 return sym_file->GetClangDeclContextForTypeUID (sc, m_uid); 458 } 459 460 Type* 461 Function::GetType() 462 { 463 if (m_type == NULL) 464 { 465 SymbolContext sc; 466 467 CalculateSymbolContext (&sc); 468 469 if (!sc.module_sp) 470 return NULL; 471 472 SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor(); 473 474 if (sym_vendor == NULL) 475 return NULL; 476 477 SymbolFile *sym_file = sym_vendor->GetSymbolFile(); 478 479 if (sym_file == NULL) 480 return NULL; 481 482 m_type = sym_file->ResolveTypeUID(m_type_uid); 483 } 484 return m_type; 485 } 486 487 const Type* 488 Function::GetType() const 489 { 490 return m_type; 491 } 492 493 clang_type_t 494 Function::GetReturnClangType () 495 { 496 clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetClangFullType())); 497 const clang::FunctionType *function_type = llvm::dyn_cast<clang::FunctionType> (clang_type); 498 if (function_type) 499 return function_type->getResultType().getAsOpaquePtr(); 500 return NULL; 501 } 502 503 int 504 Function::GetArgumentCount () 505 { 506 clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetClangFullType())); 507 assert (clang_type->isFunctionType()); 508 if (!clang_type->isFunctionProtoType()) 509 return -1; 510 511 const clang::FunctionProtoType *function_proto_type = llvm::dyn_cast<clang::FunctionProtoType>(clang_type); 512 if (function_proto_type != NULL) 513 return function_proto_type->getNumArgs(); 514 515 return 0; 516 } 517 518 clang_type_t 519 Function::GetArgumentTypeAtIndex (size_t idx) 520 { 521 clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetClangFullType())); 522 const clang::FunctionProtoType *function_proto_type = llvm::dyn_cast<clang::FunctionProtoType>(clang_type); 523 if (function_proto_type) 524 { 525 unsigned num_args = function_proto_type->getNumArgs(); 526 if (idx >= num_args) 527 return NULL; 528 529 return (function_proto_type->arg_type_begin())[idx].getAsOpaquePtr(); 530 } 531 return NULL; 532 } 533 534 bool 535 Function::IsVariadic () 536 { 537 const clang::Type *clang_type = static_cast<clang::QualType *>(GetType()->GetClangFullType())->getTypePtr(); 538 assert (clang_type->isFunctionType()); 539 if (!clang_type->isFunctionProtoType()) 540 return false; 541 542 const clang::FunctionProtoType *function_proto_type = llvm::dyn_cast<clang::FunctionProtoType>(clang_type); 543 if (function_proto_type) 544 return function_proto_type->isVariadic(); 545 546 return false; 547 } 548 549 uint32_t 550 Function::GetPrologueByteSize () 551 { 552 if (m_prologue_byte_size == 0 && m_flags.IsClear(flagsCalculatedPrologueSize)) 553 { 554 m_flags.Set(flagsCalculatedPrologueSize); 555 LineTable* line_table = m_comp_unit->GetLineTable (); 556 if (line_table) 557 { 558 LineEntry first_line_entry; 559 uint32_t first_line_entry_idx = UINT32_MAX; 560 if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), first_line_entry, &first_line_entry_idx)) 561 { 562 // Make sure the first line entry isn't already the end of the prologue 563 addr_t prologue_end_file_addr = LLDB_INVALID_ADDRESS; 564 if (first_line_entry.is_prologue_end) 565 { 566 prologue_end_file_addr = first_line_entry.range.GetBaseAddress().GetFileAddress(); 567 } 568 else 569 { 570 // Check the first few instructions and look for one that has 571 // is_prologue_end set to true. 572 const uint32_t last_line_entry_idx = first_line_entry_idx + 6; 573 LineEntry line_entry; 574 for (uint32_t idx = first_line_entry_idx + 1; idx < last_line_entry_idx; ++idx) 575 { 576 if (line_table->GetLineEntryAtIndex (idx, line_entry)) 577 { 578 if (line_entry.is_prologue_end) 579 { 580 prologue_end_file_addr = line_entry.range.GetBaseAddress().GetFileAddress(); 581 break; 582 } 583 } 584 } 585 } 586 587 // If we didn't find the end of the prologue in the line tables, 588 // then just use the end address of the first line table entry 589 if (prologue_end_file_addr == LLDB_INVALID_ADDRESS) 590 { 591 prologue_end_file_addr = first_line_entry.range.GetBaseAddress().GetFileAddress() + first_line_entry.range.GetByteSize(); 592 } 593 const addr_t func_start_file_addr = m_range.GetBaseAddress().GetFileAddress(); 594 const addr_t func_end_file_addr = func_start_file_addr + m_range.GetByteSize(); 595 596 // Verify that this prologue end file address in the function's 597 // address range just to be sure 598 if (func_start_file_addr < prologue_end_file_addr && prologue_end_file_addr < func_end_file_addr) 599 { 600 m_prologue_byte_size = prologue_end_file_addr - func_start_file_addr; 601 } 602 } 603 } 604 } 605 return m_prologue_byte_size; 606 } 607 608 609 610