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.8" PRIx64, 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 return section_sp->GetModule(); 396 397 return this->GetCompileUnit()->GetModule(); 398 } 399 400 CompileUnit * 401 Function::CalculateSymbolContextCompileUnit () 402 { 403 return this->GetCompileUnit(); 404 } 405 406 Function * 407 Function::CalculateSymbolContextFunction () 408 { 409 return this; 410 } 411 412 //Symbol * 413 //Function::CalculateSymbolContextSymbol () 414 //{ 415 // return // TODO: find the symbol for the function??? 416 //} 417 418 419 void 420 Function::DumpSymbolContext(Stream *s) 421 { 422 m_comp_unit->DumpSymbolContext(s); 423 s->Printf(", Function{0x%8.8" PRIx64 "}", GetID()); 424 } 425 426 size_t 427 Function::MemorySize () const 428 { 429 size_t mem_size = sizeof(Function) + m_block.MemorySize(); 430 return mem_size; 431 } 432 433 clang::DeclContext * 434 Function::GetClangDeclContext() 435 { 436 SymbolContext sc; 437 438 CalculateSymbolContext (&sc); 439 440 if (!sc.module_sp) 441 return NULL; 442 443 SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor(); 444 445 if (!sym_vendor) 446 return NULL; 447 448 SymbolFile *sym_file = sym_vendor->GetSymbolFile(); 449 450 if (!sym_file) 451 return NULL; 452 453 return sym_file->GetClangDeclContextForTypeUID (sc, m_uid); 454 } 455 456 Type* 457 Function::GetType() 458 { 459 if (m_type == NULL) 460 { 461 SymbolContext sc; 462 463 CalculateSymbolContext (&sc); 464 465 if (!sc.module_sp) 466 return NULL; 467 468 SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor(); 469 470 if (sym_vendor == NULL) 471 return NULL; 472 473 SymbolFile *sym_file = sym_vendor->GetSymbolFile(); 474 475 if (sym_file == NULL) 476 return NULL; 477 478 m_type = sym_file->ResolveTypeUID(m_type_uid); 479 } 480 return m_type; 481 } 482 483 const Type* 484 Function::GetType() const 485 { 486 return m_type; 487 } 488 489 clang_type_t 490 Function::GetReturnClangType () 491 { 492 Type *type = GetType(); 493 if (type) 494 { 495 clang::QualType clang_type (clang::QualType::getFromOpaquePtr(type->GetClangFullType())); 496 const clang::FunctionType *function_type = llvm::dyn_cast<clang::FunctionType> (clang_type); 497 if (function_type) 498 return function_type->getResultType().getAsOpaquePtr(); 499 } 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