1 /* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2012-2016, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "DwarfImageDebugInfo.h" 9 10 #include <errno.h> 11 #include <stdio.h> 12 #include <unistd.h> 13 14 #include <algorithm> 15 #include <new> 16 17 #include <AutoDeleter.h> 18 #include <AutoLocker.h> 19 20 #include "Architecture.h" 21 #include "BasicFunctionDebugInfo.h" 22 #include "CLanguage.h" 23 #include "CompilationUnit.h" 24 #include "CppLanguage.h" 25 #include "CpuState.h" 26 #include "DebuggerInterface.h" 27 #include "DebugInfoEntries.h" 28 #include "Demangler.h" 29 #include "DisassembledCode.h" 30 #include "Dwarf.h" 31 #include "DwarfFile.h" 32 #include "DwarfFunctionDebugInfo.h" 33 #include "DwarfStackFrameDebugInfo.h" 34 #include "DwarfTargetInterface.h" 35 #include "DwarfTypeFactory.h" 36 #include "DwarfTypes.h" 37 #include "DwarfUtils.h" 38 #include "ElfFile.h" 39 #include "FileManager.h" 40 #include "FileSourceCode.h" 41 #include "FunctionID.h" 42 #include "FunctionInstance.h" 43 #include "GlobalTypeLookup.h" 44 #include "Image.h" 45 #include "ImageDebugInfo.h" 46 #include "InstructionInfo.h" 47 #include "LocatableFile.h" 48 #include "Register.h" 49 #include "RegisterMap.h" 50 #include "SourceFile.h" 51 #include "StackFrame.h" 52 #include "Statement.h" 53 #include "StringUtils.h" 54 #include "SymbolInfo.h" 55 #include "TargetAddressRangeList.h" 56 #include "Team.h" 57 #include "TeamFunctionSourceInformation.h" 58 #include "TeamMemory.h" 59 #include "Tracing.h" 60 #include "TypeLookupConstraints.h" 61 #include "UnsupportedLanguage.h" 62 #include "Variable.h" 63 #include "ValueLocation.h" 64 65 66 namespace { 67 68 69 // #pragma mark - HasTypePredicate 70 71 72 template<typename EntryType> 73 struct HasTypePredicate { 74 inline bool operator()(EntryType* entry) const 75 { 76 return entry->GetType() != NULL; 77 } 78 }; 79 80 } 81 82 83 // #pragma mark - BasicTargetInterface 84 85 86 struct DwarfImageDebugInfo::BasicTargetInterface : DwarfTargetInterface { 87 BasicTargetInterface(const Register* registers, int32 registerCount, 88 RegisterMap* fromDwarfMap, Architecture* architecture, 89 TeamMemory* teamMemory) 90 : 91 fRegisters(registers), 92 fRegisterCount(registerCount), 93 fFromDwarfMap(fromDwarfMap), 94 fArchitecture(architecture), 95 fTeamMemory(teamMemory) 96 { 97 fFromDwarfMap->AcquireReference(); 98 } 99 100 ~BasicTargetInterface() 101 { 102 fFromDwarfMap->ReleaseReference(); 103 } 104 105 virtual uint32 CountRegisters() const 106 { 107 return fRegisterCount; 108 } 109 110 virtual uint32 RegisterValueType(uint32 index) const 111 { 112 const Register* reg = _RegisterAt(index); 113 return reg != NULL ? reg->ValueType() : 0; 114 } 115 116 virtual bool GetRegisterValue(uint32 index, BVariant& _value) const 117 { 118 return false; 119 } 120 121 virtual bool SetRegisterValue(uint32 index, const BVariant& value) 122 { 123 return false; 124 } 125 126 virtual bool IsCalleePreservedRegister(uint32 index) const 127 { 128 const Register* reg = _RegisterAt(index); 129 return reg != NULL && reg->IsCalleePreserved(); 130 } 131 132 virtual status_t InitRegisterRules(CfaContext& context) const 133 { 134 return fArchitecture->InitRegisterRules(context); 135 } 136 137 virtual bool ReadMemory(target_addr_t address, void* buffer, 138 size_t size) const 139 { 140 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size); 141 return bytesRead >= 0 && (size_t)bytesRead == size; 142 } 143 144 virtual bool ReadValueFromMemory(target_addr_t address, 145 uint32 valueType, BVariant& _value) const 146 { 147 return fArchitecture->ReadValueFromMemory(address, valueType, _value) 148 == B_OK; 149 } 150 151 virtual bool ReadValueFromMemory(target_addr_t addressSpace, 152 target_addr_t address, uint32 valueType, BVariant& _value) const 153 { 154 return fArchitecture->ReadValueFromMemory(addressSpace, address, 155 valueType, _value) == B_OK; 156 } 157 158 protected: 159 const Register* _RegisterAt(uint32 dwarfIndex) const 160 { 161 int32 index = fFromDwarfMap->MapRegisterIndex(dwarfIndex); 162 return index >= 0 && index < fRegisterCount ? fRegisters + index : NULL; 163 } 164 165 protected: 166 const Register* fRegisters; 167 int32 fRegisterCount; 168 RegisterMap* fFromDwarfMap; 169 Architecture* fArchitecture; 170 TeamMemory* fTeamMemory; 171 }; 172 173 174 // #pragma mark - UnwindTargetInterface 175 176 177 struct DwarfImageDebugInfo::UnwindTargetInterface : BasicTargetInterface { 178 UnwindTargetInterface(const Register* registers, int32 registerCount, 179 RegisterMap* fromDwarfMap, RegisterMap* toDwarfMap, CpuState* cpuState, 180 Architecture* architecture, TeamMemory* teamMemory) 181 : 182 BasicTargetInterface(registers, registerCount, fromDwarfMap, 183 architecture, teamMemory), 184 fToDwarfMap(toDwarfMap), 185 fCpuState(cpuState) 186 { 187 fToDwarfMap->AcquireReference(); 188 fCpuState->AcquireReference(); 189 } 190 191 ~UnwindTargetInterface() 192 { 193 fToDwarfMap->ReleaseReference(); 194 fCpuState->ReleaseReference(); 195 } 196 197 virtual bool GetRegisterValue(uint32 index, BVariant& _value) const 198 { 199 const Register* reg = _RegisterAt(index); 200 if (reg == NULL) 201 return false; 202 return fCpuState->GetRegisterValue(reg, _value); 203 } 204 205 virtual bool SetRegisterValue(uint32 index, const BVariant& value) 206 { 207 const Register* reg = _RegisterAt(index); 208 if (reg == NULL) 209 return false; 210 return fCpuState->SetRegisterValue(reg, value); 211 } 212 213 private: 214 RegisterMap* fToDwarfMap; 215 CpuState* fCpuState; 216 }; 217 218 219 // #pragma mark - EntryListWrapper 220 221 222 /*! Wraps a DebugInfoEntryList, which is a typedef and thus cannot appear in 223 the header, since our policy disallows us to include DWARF headers there. 224 */ 225 struct DwarfImageDebugInfo::EntryListWrapper { 226 const DebugInfoEntryList& list; 227 228 EntryListWrapper(const DebugInfoEntryList& list) 229 : 230 list(list) 231 { 232 } 233 }; 234 235 236 // #pragma mark - DwarfImageDebugInfo::TypeNameKey 237 238 239 struct DwarfImageDebugInfo::TypeNameKey { 240 BString typeName; 241 242 TypeNameKey(const BString& typeName) 243 : 244 typeName(typeName) 245 { 246 } 247 248 uint32 HashValue() const 249 { 250 return StringUtils::HashValue(typeName); 251 } 252 253 bool operator==(const TypeNameKey& other) const 254 { 255 return typeName == other.typeName; 256 } 257 }; 258 259 260 // #pragma mark - DwarfImageDebugInfo::TypeNameEntry 261 262 263 struct DwarfImageDebugInfo::TypeNameEntry : TypeNameKey { 264 TypeNameEntry* next; 265 TypeEntryList types; 266 267 TypeNameEntry(const BString& name) 268 : 269 TypeNameKey(name), 270 types(10, false) 271 { 272 } 273 274 ~TypeNameEntry() 275 { 276 } 277 278 }; 279 280 281 // #pragma mark - DwarfImageDebugInfo::TypeNameEntryHashDefinition 282 283 284 struct DwarfImageDebugInfo::TypeNameEntryHashDefinition { 285 typedef TypeNameKey KeyType; 286 typedef TypeNameEntry ValueType; 287 288 size_t HashKey(const TypeNameKey& key) const 289 { 290 return key.HashValue(); 291 } 292 293 size_t Hash(const TypeNameEntry* value) const 294 { 295 return value->HashValue(); 296 } 297 298 bool Compare(const TypeNameKey& key, 299 const TypeNameEntry* value) const 300 { 301 return key == *value; 302 } 303 304 TypeNameEntry*& GetLink(TypeNameEntry* value) const 305 { 306 return value->next; 307 } 308 }; 309 310 311 // #pragma mark - DwarfImageDebugInfo::TypeEntryInfo 312 313 314 struct DwarfImageDebugInfo::TypeEntryInfo { 315 DIEType* type; 316 CompilationUnit* unit; 317 318 TypeEntryInfo(DIEType* type, CompilationUnit* unit) 319 : 320 type(type), 321 unit(unit) 322 { 323 } 324 }; 325 326 327 // #pragma mark - DwarfImageDebugInfo 328 329 330 DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo, 331 DebuggerInterface* interface, Architecture* architecture, 332 FileManager* fileManager, GlobalTypeLookup* typeLookup, 333 GlobalTypeCache* typeCache, TeamFunctionSourceInformation* sourceInfo, 334 DwarfFile* file) 335 : 336 fLock("dwarf image debug info"), 337 fImageInfo(imageInfo), 338 fDebuggerInterface(interface), 339 fArchitecture(architecture), 340 fFileManager(fileManager), 341 fTypeLookup(typeLookup), 342 fTypeCache(typeCache), 343 fSourceInfo(sourceInfo), 344 fTypeNameTable(NULL), 345 fFile(file), 346 fTextSegment(NULL), 347 fRelocationDelta(0), 348 fTextSectionStart(0), 349 fTextSectionEnd(0), 350 fPLTSectionStart(0), 351 fPLTSectionEnd(0) 352 { 353 fDebuggerInterface->AcquireReference(); 354 fFile->AcquireReference(); 355 fTypeCache->AcquireReference(); 356 } 357 358 359 DwarfImageDebugInfo::~DwarfImageDebugInfo() 360 { 361 fDebuggerInterface->ReleaseReference(); 362 fFile->ReleaseReference(); 363 fTypeCache->ReleaseReference(); 364 365 delete fTypeNameTable; 366 } 367 368 369 status_t 370 DwarfImageDebugInfo::Init() 371 { 372 status_t error = fLock.InitCheck(); 373 if (error != B_OK) 374 return error; 375 376 fTextSegment = fFile->GetElfFile()->TextSegment(); 377 if (fTextSegment == NULL) 378 return B_ENTRY_NOT_FOUND; 379 380 fRelocationDelta = fImageInfo.TextBase() - fTextSegment->LoadAddress(); 381 382 ElfSection* section = fFile->GetElfFile()->FindSection(".text"); 383 if (section != NULL) { 384 fTextSectionStart = section->LoadAddress() + fRelocationDelta; 385 fTextSectionEnd = fTextSectionStart + section->Size(); 386 } 387 388 section = fFile->GetElfFile()->FindSection(".plt"); 389 if (section != NULL) { 390 fPLTSectionStart = section->LoadAddress() + fRelocationDelta; 391 fPLTSectionEnd = fPLTSectionStart + section->Size(); 392 } 393 394 return _BuildTypeNameTable(); 395 } 396 397 398 status_t 399 DwarfImageDebugInfo::GetFunctions(const BObjectList<SymbolInfo>& symbols, 400 BObjectList<FunctionDebugInfo>& functions) 401 { 402 TRACE_IMAGES("DwarfImageDebugInfo::GetFunctions()\n"); 403 TRACE_IMAGES(" %" B_PRId32 " compilation units\n", 404 fFile->CountCompilationUnits()); 405 406 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i); 407 i++) { 408 DIECompileUnitBase* unitEntry = unit->UnitEntry(); 409 // printf(" %s:\n", unitEntry->Name()); 410 // printf(" address ranges:\n"); 411 // TargetAddressRangeList* rangeList = unitEntry->AddressRanges(); 412 // if (rangeList != NULL) { 413 // int32 count = rangeList->CountRanges(); 414 // for (int32 i = 0; i < count; i++) { 415 // TargetAddressRange range = rangeList->RangeAt(i); 416 // printf(" %#llx - %#llx\n", range.Start(), range.End()); 417 // } 418 // } else { 419 // printf(" %#llx - %#llx\n", (target_addr_t)unitEntry->LowPC(), 420 // (target_addr_t)unitEntry->HighPC()); 421 // } 422 423 // printf(" functions:\n"); 424 for (DebugInfoEntryList::ConstIterator it 425 = unitEntry->OtherChildren().GetIterator(); 426 DebugInfoEntry* entry = it.Next();) { 427 if (entry->Tag() != DW_TAG_subprogram) 428 continue; 429 430 DIESubprogram* subprogramEntry = static_cast<DIESubprogram*>(entry); 431 432 // ignore declarations and inlined functions 433 if (subprogramEntry->IsDeclaration() 434 || subprogramEntry->Inline() == DW_INL_inlined 435 || subprogramEntry->Inline() == DW_INL_declared_inlined) { 436 continue; 437 } 438 439 // get the name 440 BString name; 441 DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name); 442 if (name.Length() == 0) 443 continue; 444 445 // get the address ranges 446 TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit, 447 subprogramEntry->AddressRangesOffset()); 448 if (rangeList == NULL) { 449 target_addr_t lowPC = subprogramEntry->LowPC(); 450 target_addr_t highPC = subprogramEntry->HighPC(); 451 if (highPC <= lowPC) 452 continue; 453 454 rangeList = new(std::nothrow) TargetAddressRangeList( 455 TargetAddressRange(lowPC, highPC - lowPC)); 456 if (rangeList == NULL) 457 return B_NO_MEMORY; 458 // TODO: Clean up already added functions! 459 } 460 BReference<TargetAddressRangeList> rangeListReference(rangeList, 461 true); 462 463 // get the source location 464 const char* directoryPath = NULL; 465 const char* fileName = NULL; 466 int32 line = -1; 467 int32 column = -1; 468 DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry, 469 directoryPath, fileName, line, column); 470 471 LocatableFile* file = NULL; 472 if (fileName != NULL) { 473 file = fFileManager->GetSourceFile(directoryPath, 474 fileName); 475 } 476 BReference<LocatableFile> fileReference(file, true); 477 478 // create and add the functions 479 DwarfFunctionDebugInfo* function 480 = new(std::nothrow) DwarfFunctionDebugInfo(this, unit, 481 subprogramEntry, rangeList, name, file, 482 SourceLocation(line, std::max(column, (int32)0))); 483 if (function == NULL || !functions.AddItem(function)) { 484 delete function; 485 return B_NO_MEMORY; 486 // TODO: Clean up already added functions! 487 } 488 489 // BString name; 490 // DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name); 491 // printf(" subprogram entry: %p, name: %s, declaration: %d\n", 492 // subprogramEntry, name.String(), 493 // subprogramEntry->IsDeclaration()); 494 // 495 // rangeList = subprogramEntry->AddressRanges(); 496 // if (rangeList != NULL) { 497 // int32 count = rangeList->CountRanges(); 498 // for (int32 i = 0; i < count; i++) { 499 // TargetAddressRange range = rangeList->RangeAt(i); 500 // printf(" %#llx - %#llx\n", range.Start(), range.End()); 501 // } 502 // } else { 503 // printf(" %#llx - %#llx\n", 504 // (target_addr_t)subprogramEntry->LowPC(), 505 // (target_addr_t)subprogramEntry->HighPC()); 506 // } 507 } 508 } 509 510 if (fFile->CountCompilationUnits() != 0) 511 return B_OK; 512 513 // if we had no compilation units, fall back to providing basic 514 // debug infos with DWARF-supported call frame unwinding, 515 // if available. 516 if (fFile->HasFrameInformation()) { 517 return SpecificImageDebugInfo::GetFunctionsFromSymbols(symbols, 518 functions, fDebuggerInterface, fImageInfo, this); 519 } 520 521 return B_OK; 522 } 523 524 525 status_t 526 DwarfImageDebugInfo::GetType(GlobalTypeCache* cache, const BString& name, 527 const TypeLookupConstraints& constraints, Type*& _type) 528 { 529 TypeNameEntry* entry = fTypeNameTable->Lookup(name); 530 if (entry == NULL) 531 return B_ENTRY_NOT_FOUND; 532 533 for (int32 i = 0; TypeEntryInfo* info = entry->types.ItemAt(i); i++) { 534 DIEType* typeEntry = info->type; 535 if (constraints.HasTypeKind()) { 536 if (dwarf_tag_to_type_kind(typeEntry->Tag()) 537 != constraints.TypeKind()) { 538 continue; 539 } 540 541 if (!_EvaluateBaseTypeConstraints(typeEntry, constraints)) 542 continue; 543 } 544 545 if (constraints.HasSubtypeKind() 546 && dwarf_tag_to_subtype_kind(typeEntry->Tag()) 547 != constraints.SubtypeKind()) { 548 continue; 549 } 550 551 DwarfTypeContext* typeContext = new(std::nothrow) 552 DwarfTypeContext(fArchitecture, fImageInfo.ImageID(), fFile, 553 info->unit, NULL, 0, 0, fRelocationDelta, NULL, NULL); 554 if (typeContext == NULL) 555 return B_NO_MEMORY; 556 BReference<DwarfTypeContext> typeContextReference(typeContext, true); 557 558 // create the type 559 DwarfType* type; 560 DwarfTypeFactory typeFactory(typeContext, fTypeLookup, cache); 561 status_t error = typeFactory.CreateType(typeEntry, type); 562 if (error != B_OK) 563 continue; 564 565 _type = type; 566 return B_OK; 567 } 568 569 return B_ENTRY_NOT_FOUND; 570 } 571 572 573 bool 574 DwarfImageDebugInfo::HasType(const BString& name, 575 const TypeLookupConstraints& constraints) const 576 { 577 TypeNameEntry* entry = fTypeNameTable->Lookup(name); 578 if (entry == NULL) 579 return false; 580 581 for (int32 i = 0; TypeEntryInfo* info = entry->types.ItemAt(i); i++) { 582 DIEType* typeEntry = info->type; 583 if (constraints.HasTypeKind()) { 584 if (dwarf_tag_to_type_kind(typeEntry->Tag()) 585 != constraints.TypeKind()) { 586 continue; 587 } 588 589 if (!_EvaluateBaseTypeConstraints(typeEntry, constraints)) 590 continue; 591 } 592 593 if (constraints.HasSubtypeKind() 594 && dwarf_tag_to_subtype_kind(typeEntry->Tag()) 595 != constraints.SubtypeKind()) { 596 continue; 597 } 598 599 return true; 600 } 601 602 return false; 603 } 604 605 606 AddressSectionType 607 DwarfImageDebugInfo::GetAddressSectionType(target_addr_t address) 608 { 609 if (address >= fTextSectionStart && address < fTextSectionEnd) 610 return ADDRESS_SECTION_TYPE_FUNCTION; 611 612 if (address >= fPLTSectionStart && address < fPLTSectionEnd) 613 return ADDRESS_SECTION_TYPE_PLT; 614 615 return ADDRESS_SECTION_TYPE_UNKNOWN; 616 } 617 618 619 status_t 620 DwarfImageDebugInfo::CreateFrame(Image* image, 621 FunctionInstance* functionInstance, CpuState* cpuState, 622 bool getFullFrameInfo, ReturnValueInfoList* returnValueInfos, 623 StackFrame*& _frame, CpuState*& _previousCpuState) 624 { 625 DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>( 626 functionInstance->GetFunctionDebugInfo()); 627 628 FunctionID* functionID = functionInstance->GetFunctionID(); 629 BReference<FunctionID> functionIDReference; 630 if (functionID != NULL) 631 functionIDReference.SetTo(functionID, true); 632 633 DIESubprogram* entry = function != NULL 634 ? function->SubprogramEntry() : NULL; 635 636 TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p, " 637 "function: %s\n", entry, 638 functionID->FunctionName().String()); 639 640 int32 registerCount = fArchitecture->CountRegisters(); 641 const Register* registers = fArchitecture->Registers(); 642 643 // get the DWARF <-> architecture register maps 644 RegisterMap* toDwarfMap; 645 RegisterMap* fromDwarfMap; 646 status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap, 647 &fromDwarfMap); 648 if (error != B_OK) 649 return error; 650 BReference<RegisterMap> toDwarfMapReference(toDwarfMap, true); 651 BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true); 652 653 // create a clean CPU state for the previous frame 654 CpuState* previousCpuState; 655 error = fArchitecture->CreateCpuState(previousCpuState); 656 if (error != B_OK) 657 return error; 658 BReference<CpuState> previousCpuStateReference(previousCpuState, true); 659 660 // create the target interfaces 661 UnwindTargetInterface* inputInterface 662 = new(std::nothrow) UnwindTargetInterface(registers, registerCount, 663 fromDwarfMap, toDwarfMap, cpuState, fArchitecture, 664 fDebuggerInterface); 665 if (inputInterface == NULL) 666 return B_NO_MEMORY; 667 BReference<UnwindTargetInterface> inputInterfaceReference(inputInterface, 668 true); 669 670 UnwindTargetInterface* outputInterface 671 = new(std::nothrow) UnwindTargetInterface(registers, registerCount, 672 fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture, 673 fDebuggerInterface); 674 if (outputInterface == NULL) 675 return B_NO_MEMORY; 676 BReference<UnwindTargetInterface> outputInterfaceReference(outputInterface, 677 true); 678 679 // do the unwinding 680 target_addr_t instructionPointer 681 = cpuState->InstructionPointer() - fRelocationDelta; 682 target_addr_t framePointer; 683 CompilationUnit* unit = function != NULL ? function->GetCompilationUnit() 684 : NULL; 685 error = fFile->UnwindCallFrame(unit, fArchitecture->AddressSize(), entry, 686 instructionPointer, inputInterface, outputInterface, framePointer); 687 688 if (error != B_OK) { 689 TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error)); 690 return B_UNSUPPORTED; 691 } 692 693 TRACE_CFI_ONLY( 694 TRACE_CFI("unwound registers:\n"); 695 for (int32 i = 0; i < registerCount; i++) { 696 const Register* reg = registers + i; 697 BVariant value; 698 if (previousCpuState->GetRegisterValue(reg, value)) { 699 TRACE_CFI(" %3s: %#" B_PRIx64 "\n", reg->Name(), 700 value.ToUInt64()); 701 } else 702 TRACE_CFI(" %3s: undefined\n", reg->Name()); 703 } 704 ) 705 706 // create the stack frame debug info 707 DIESubprogram* subprogramEntry = function != NULL ? 708 function->SubprogramEntry() : NULL; 709 DwarfStackFrameDebugInfo* stackFrameDebugInfo 710 = new(std::nothrow) DwarfStackFrameDebugInfo(fArchitecture, 711 fImageInfo.ImageID(), fFile, unit, subprogramEntry, fTypeLookup, 712 fTypeCache, instructionPointer, framePointer, fRelocationDelta, 713 inputInterface, fromDwarfMap); 714 if (stackFrameDebugInfo == NULL) 715 return B_NO_MEMORY; 716 BReference<DwarfStackFrameDebugInfo> stackFrameDebugInfoReference( 717 stackFrameDebugInfo, true); 718 719 error = stackFrameDebugInfo->Init(); 720 if (error != B_OK) 721 return error; 722 723 // create the stack frame 724 StackFrame* frame = new(std::nothrow) StackFrame(STACK_FRAME_TYPE_STANDARD, 725 cpuState, framePointer, cpuState->InstructionPointer(), 726 stackFrameDebugInfo); 727 if (frame == NULL) 728 return B_NO_MEMORY; 729 BReference<StackFrame> frameReference(frame, true); 730 731 error = frame->Init(); 732 if (error != B_OK) 733 return error; 734 735 frame->SetReturnAddress(previousCpuState->InstructionPointer()); 736 // Note, this is correct, since we actually retrieved the return 737 // address. Our caller will fix the IP for us. 738 739 // The subprogram entry may not be available since this may be a case 740 // where .eh_frame was used to unwind the stack without other DWARF 741 // info being available. 742 if (subprogramEntry != NULL && getFullFrameInfo) { 743 // create function parameter objects 744 for (DebugInfoEntryList::ConstIterator it 745 = subprogramEntry->Parameters().GetIterator(); 746 DebugInfoEntry* entry = it.Next();) { 747 if (entry->Tag() != DW_TAG_formal_parameter) 748 continue; 749 750 BString parameterName; 751 DwarfUtils::GetDIEName(entry, parameterName); 752 if (parameterName.Length() == 0) 753 continue; 754 755 DIEFormalParameter* parameterEntry 756 = dynamic_cast<DIEFormalParameter*>(entry); 757 Variable* parameter; 758 if (stackFrameDebugInfo->CreateParameter(functionID, 759 parameterEntry, parameter) != B_OK) { 760 continue; 761 } 762 BReference<Variable> parameterReference(parameter, true); 763 764 if (!frame->AddParameter(parameter)) 765 return B_NO_MEMORY; 766 } 767 768 // create objects for the local variables 769 _CreateLocalVariables(unit, frame, functionID, *stackFrameDebugInfo, 770 instructionPointer, functionInstance->Address() - fRelocationDelta, 771 subprogramEntry->Variables(), subprogramEntry->Blocks()); 772 773 if (returnValueInfos != NULL && !returnValueInfos->IsEmpty()) { 774 _CreateReturnValues(returnValueInfos, image, frame, 775 *stackFrameDebugInfo); 776 } 777 } 778 779 _frame = frameReference.Detach(); 780 _previousCpuState = previousCpuStateReference.Detach(); 781 782 frame->SetPreviousCpuState(_previousCpuState); 783 784 return B_OK; 785 } 786 787 788 status_t 789 DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function, 790 target_addr_t address, Statement*& _statement) 791 { 792 TRACE_CODE("DwarfImageDebugInfo::GetStatement(function: %p, address: %#" 793 B_PRIx64 ")\n", _function, address); 794 795 DwarfFunctionDebugInfo* function 796 = dynamic_cast<DwarfFunctionDebugInfo*>(_function); 797 if (function == NULL) { 798 TRACE_LINES(" -> no dwarf function\n"); 799 // fall back to assembly 800 return fArchitecture->GetStatement(function, address, _statement); 801 } 802 803 AutoLocker<BLocker> locker(fLock); 804 805 // check whether we have the source code 806 CompilationUnit* unit = function->GetCompilationUnit(); 807 LocatableFile* file = function->SourceFile(); 808 if (file == NULL) { 809 TRACE_CODE(" -> no source file\n"); 810 811 // no source code -- rather return the assembly statement 812 return fArchitecture->GetStatement(function, address, _statement); 813 } 814 815 SourceCode* sourceCode = NULL; 816 status_t error = fSourceInfo->GetActiveSourceCode(_function, sourceCode); 817 BReference<SourceCode> sourceReference(sourceCode, true); 818 if (error != B_OK || dynamic_cast<DisassembledCode*>(sourceCode) != NULL) { 819 // either no source code or disassembly is currently active (i.e. 820 // due to failing to locate the source file on disk or the user 821 // deliberately switching to disassembly view). 822 // return the assembly statement. 823 return fArchitecture->GetStatement(function, address, _statement); 824 } 825 826 // get the index of the source file in the compilation unit for cheaper 827 // comparison below 828 int32 fileIndex = _GetSourceFileIndex(unit, file); 829 830 // Get the statement by executing the line number program for the 831 // compilation unit. 832 LineNumberProgram& program = unit->GetLineNumberProgram(); 833 if (!program.IsValid()) { 834 TRACE_CODE(" -> no line number program\n"); 835 return B_BAD_DATA; 836 } 837 838 // adjust address 839 address -= fRelocationDelta; 840 841 LineNumberProgram::State state; 842 program.GetInitialState(state); 843 844 target_addr_t statementAddress = 0; 845 int32 statementLine = -1; 846 int32 statementColumn = -1; 847 while (program.GetNextRow(state)) { 848 // skip statements of other files 849 if (state.file != fileIndex) 850 continue; 851 852 if (statementAddress != 0 853 && (state.isStatement || state.isSequenceEnd)) { 854 target_addr_t endAddress = state.address; 855 if (address >= statementAddress && address < endAddress) { 856 ContiguousStatement* statement = new(std::nothrow) 857 ContiguousStatement( 858 SourceLocation(statementLine, statementColumn), 859 TargetAddressRange(fRelocationDelta + statementAddress, 860 endAddress - statementAddress)); 861 if (statement == NULL) 862 return B_NO_MEMORY; 863 864 _statement = statement; 865 return B_OK; 866 } 867 868 statementAddress = 0; 869 } 870 871 if (state.isStatement) { 872 statementAddress = state.address; 873 statementLine = state.line - 1; 874 statementColumn = std::max(state.column - 1, (int32)0); 875 } 876 } 877 878 TRACE_CODE(" -> no line number program match\n"); 879 return B_ENTRY_NOT_FOUND; 880 } 881 882 883 status_t 884 DwarfImageDebugInfo::GetStatementAtSourceLocation(FunctionDebugInfo* _function, 885 const SourceLocation& sourceLocation, Statement*& _statement) 886 { 887 DwarfFunctionDebugInfo* function 888 = dynamic_cast<DwarfFunctionDebugInfo*>(_function); 889 if (function == NULL) 890 return B_BAD_VALUE; 891 892 target_addr_t functionStartAddress = function->Address() - fRelocationDelta; 893 target_addr_t functionEndAddress = functionStartAddress + function->Size(); 894 895 TRACE_LINES2("DwarfImageDebugInfo::GetStatementAtSourceLocation(%p, " 896 "(%" B_PRId32 ", %" B_PRId32 ")): function range: %#" B_PRIx64 " - %#" 897 B_PRIx64 "\n", function, sourceLocation.Line(), sourceLocation.Column(), 898 functionStartAddress, functionEndAddress); 899 900 AutoLocker<BLocker> locker(fLock); 901 902 // get the source file 903 LocatableFile* file = function->SourceFile(); 904 if (file == NULL) 905 return B_ENTRY_NOT_FOUND; 906 907 CompilationUnit* unit = function->GetCompilationUnit(); 908 909 // get the index of the source file in the compilation unit for cheaper 910 // comparison below 911 int32 fileIndex = _GetSourceFileIndex(unit, file); 912 913 // Get the statement by executing the line number program for the 914 // compilation unit. 915 LineNumberProgram& program = unit->GetLineNumberProgram(); 916 if (!program.IsValid()) 917 return B_BAD_DATA; 918 919 LineNumberProgram::State state; 920 program.GetInitialState(state); 921 922 target_addr_t statementAddress = 0; 923 int32 statementLine = -1; 924 int32 statementColumn = -1; 925 while (program.GetNextRow(state)) { 926 bool isOurFile = state.file == fileIndex; 927 928 if (statementAddress != 0 929 && (!isOurFile || state.isStatement || state.isSequenceEnd)) { 930 target_addr_t endAddress = state.address; 931 932 if (statementAddress < endAddress) { 933 TRACE_LINES2(" statement: %#" B_PRIx64 " - %#" B_PRIx64 934 ", location: (%" B_PRId32 ", %" B_PRId32 ")\n", 935 statementAddress, endAddress, statementLine, 936 statementColumn); 937 } 938 939 if (statementAddress < endAddress 940 && statementAddress >= functionStartAddress 941 && statementAddress < functionEndAddress 942 && statementLine == (int32)sourceLocation.Line() 943 && statementColumn == (int32)sourceLocation.Column()) { 944 TRACE_LINES2(" -> found statement!\n"); 945 946 ContiguousStatement* statement = new(std::nothrow) 947 ContiguousStatement( 948 SourceLocation(statementLine, statementColumn), 949 TargetAddressRange(fRelocationDelta + statementAddress, 950 endAddress - statementAddress)); 951 if (statement == NULL) 952 return B_NO_MEMORY; 953 954 _statement = statement; 955 return B_OK; 956 } 957 958 statementAddress = 0; 959 } 960 961 // skip statements of other files 962 if (!isOurFile) 963 continue; 964 965 if (state.isStatement) { 966 statementAddress = state.address; 967 statementLine = state.line - 1; 968 statementColumn = std::max(state.column - 1, (int32)0); 969 } 970 } 971 972 return B_ENTRY_NOT_FOUND; 973 } 974 975 976 status_t 977 DwarfImageDebugInfo::GetSourceLanguage(FunctionDebugInfo* _function, 978 SourceLanguage*& _language) 979 { 980 DwarfFunctionDebugInfo* function 981 = dynamic_cast<DwarfFunctionDebugInfo*>(_function); 982 if (function == NULL) 983 return B_BAD_VALUE; 984 985 SourceLanguage* language; 986 CompilationUnit* unit = function->GetCompilationUnit(); 987 switch (unit->UnitEntry()->Language()) { 988 case DW_LANG_C89: 989 case DW_LANG_C: 990 case DW_LANG_C99: 991 language = new(std::nothrow) CLanguage; 992 break; 993 case DW_LANG_C_plus_plus: 994 language = new(std::nothrow) CppLanguage; 995 break; 996 case 0: 997 default: 998 language = new(std::nothrow) UnsupportedLanguage; 999 break; 1000 } 1001 1002 if (language == NULL) 1003 return B_NO_MEMORY; 1004 1005 _language = language; 1006 return B_OK; 1007 } 1008 1009 1010 ssize_t 1011 DwarfImageDebugInfo::ReadCode(target_addr_t address, void* buffer, size_t size) 1012 { 1013 target_addr_t offset = address - fRelocationDelta 1014 - fTextSegment->LoadAddress() + fTextSegment->FileOffset(); 1015 ssize_t bytesRead = pread(fFile->GetElfFile()->FD(), buffer, size, offset); 1016 return bytesRead >= 0 ? bytesRead : errno; 1017 } 1018 1019 1020 status_t 1021 DwarfImageDebugInfo::AddSourceCodeInfo(LocatableFile* file, 1022 FileSourceCode* sourceCode) 1023 { 1024 bool addedAny = false; 1025 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i); 1026 i++) { 1027 int32 fileIndex = _GetSourceFileIndex(unit, file); 1028 if (fileIndex < 0) 1029 continue; 1030 1031 status_t error = _AddSourceCodeInfo(unit, sourceCode, fileIndex); 1032 if (error == B_NO_MEMORY) 1033 return error; 1034 addedAny |= error == B_OK; 1035 } 1036 1037 return addedAny ? B_OK : B_ENTRY_NOT_FOUND; 1038 } 1039 1040 1041 status_t 1042 DwarfImageDebugInfo::_AddSourceCodeInfo(CompilationUnit* unit, 1043 FileSourceCode* sourceCode, int32 fileIndex) 1044 { 1045 // Get the statements by executing the line number program for the 1046 // compilation unit and filtering the rows for our source file. 1047 LineNumberProgram& program = unit->GetLineNumberProgram(); 1048 if (!program.IsValid()) 1049 return B_BAD_DATA; 1050 1051 LineNumberProgram::State state; 1052 program.GetInitialState(state); 1053 1054 target_addr_t statementAddress = 0; 1055 int32 statementLine = -1; 1056 int32 statementColumn = -1; 1057 while (program.GetNextRow(state)) { 1058 TRACE_LINES2(" %#" B_PRIx64 " (%" B_PRId32 ", %" B_PRId32 ", %" 1059 B_PRId32 ") %d\n", state.address, state.file, state.line, 1060 state.column, state.isStatement); 1061 1062 bool isOurFile = state.file == fileIndex; 1063 1064 if (statementAddress != 0 1065 && (!isOurFile || state.isStatement || state.isSequenceEnd)) { 1066 target_addr_t endAddress = state.address; 1067 if (endAddress > statementAddress) { 1068 // add the statement 1069 status_t error = sourceCode->AddSourceLocation( 1070 SourceLocation(statementLine, statementColumn)); 1071 if (error != B_OK) 1072 return error; 1073 1074 TRACE_LINES2(" -> statement: %#" B_PRIx64 " - %#" B_PRIx64 1075 ", source location: (%" B_PRId32 ", %" B_PRId32 ")\n", 1076 statementAddress, endAddress, statementLine, 1077 statementColumn); 1078 } 1079 1080 statementAddress = 0; 1081 } 1082 1083 // skip statements of other files 1084 if (!isOurFile) 1085 continue; 1086 1087 if (state.isStatement) { 1088 statementAddress = state.address; 1089 statementLine = state.line - 1; 1090 statementColumn = std::max(state.column - 1, (int32)0); 1091 } 1092 } 1093 1094 return B_OK; 1095 } 1096 1097 1098 int32 1099 DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit, 1100 LocatableFile* sourceFile) const 1101 { 1102 // get the index of the source file in the compilation unit for cheaper 1103 // comparison below 1104 const char* directory; 1105 for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) { 1106 LocatableFile* file = fFileManager->GetSourceFile(directory, fileName); 1107 if (file != NULL) { 1108 file->ReleaseReference(); 1109 if (file == sourceFile) { 1110 return i + 1; 1111 // indices are one-based 1112 } 1113 } 1114 } 1115 1116 return -1; 1117 } 1118 1119 1120 status_t 1121 DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit, 1122 StackFrame* frame, FunctionID* functionID, 1123 DwarfStackFrameDebugInfo& factory, target_addr_t instructionPointer, 1124 target_addr_t lowPC, const EntryListWrapper& variableEntries, 1125 const EntryListWrapper& blockEntries) 1126 { 1127 TRACE_LOCALS("DwarfImageDebugInfo::_CreateLocalVariables(): ip: %#" B_PRIx64 1128 ", low PC: %#" B_PRIx64 "\n", instructionPointer, lowPC); 1129 1130 // iterate through the variables and add the ones in scope 1131 for (DebugInfoEntryList::ConstIterator it 1132 = variableEntries.list.GetIterator(); 1133 DIEVariable* variableEntry = dynamic_cast<DIEVariable*>(it.Next());) { 1134 1135 TRACE_LOCALS(" variableEntry %p, scope start: %" B_PRIu64 "\n", 1136 variableEntry, variableEntry->StartScope()); 1137 1138 // check the variable's scope 1139 if (instructionPointer < lowPC + variableEntry->StartScope()) 1140 continue; 1141 1142 // add the variable 1143 Variable* variable; 1144 if (factory.CreateLocalVariable(functionID, variableEntry, variable) 1145 != B_OK) { 1146 continue; 1147 } 1148 BReference<Variable> variableReference(variable, true); 1149 1150 if (!frame->AddLocalVariable(variable)) 1151 return B_NO_MEMORY; 1152 } 1153 1154 // iterate through the blocks and find the one we're currently in (if any) 1155 for (DebugInfoEntryList::ConstIterator it = blockEntries.list.GetIterator(); 1156 DIELexicalBlock* block = dynamic_cast<DIELexicalBlock*>(it.Next());) { 1157 1158 TRACE_LOCALS(" lexical block: %p\n", block); 1159 1160 // check whether the block has low/high PC attributes 1161 if (block->LowPC() != 0) { 1162 TRACE_LOCALS(" has lowPC\n"); 1163 1164 // yep, compare with the instruction pointer 1165 if (instructionPointer < block->LowPC() 1166 || instructionPointer >= block->HighPC()) { 1167 continue; 1168 } 1169 } else { 1170 TRACE_LOCALS(" no lowPC\n"); 1171 1172 // check the address ranges instead 1173 TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit, 1174 block->AddressRangesOffset()); 1175 if (rangeList == NULL) { 1176 TRACE_LOCALS(" failed to get ranges\n"); 1177 continue; 1178 } 1179 BReference<TargetAddressRangeList> rangeListReference(rangeList, 1180 true); 1181 1182 if (!rangeList->Contains(instructionPointer)) { 1183 TRACE_LOCALS(" ranges don't contain IP\n"); 1184 continue; 1185 } 1186 } 1187 1188 // found a block -- recurse 1189 return _CreateLocalVariables(unit, frame, functionID, factory, 1190 instructionPointer, lowPC, block->Variables(), block->Blocks()); 1191 } 1192 1193 return B_OK; 1194 } 1195 1196 1197 status_t 1198 DwarfImageDebugInfo::_CreateReturnValues(ReturnValueInfoList* returnValueInfos, 1199 Image* image, StackFrame* frame, DwarfStackFrameDebugInfo& factory) 1200 { 1201 for (int32 i = 0; i < returnValueInfos->CountItems(); i++) { 1202 Image* targetImage = image; 1203 ReturnValueInfo* valueInfo = returnValueInfos->ItemAt(i); 1204 target_addr_t subroutineAddress = valueInfo->SubroutineAddress(); 1205 CpuState* subroutineState = valueInfo->State(); 1206 if (!targetImage->ContainsAddress(subroutineAddress)) { 1207 // our current image doesn't contain the target function, 1208 // locate the one which does. 1209 targetImage = image->GetTeam()->ImageByAddress(subroutineAddress); 1210 if (targetImage == NULL) { 1211 // nothing we can do, try the next entry (if any) 1212 continue; 1213 } 1214 } 1215 1216 status_t result = B_OK; 1217 ImageDebugInfo* imageInfo = targetImage->GetImageDebugInfo(); 1218 if (imageInfo == NULL) { 1219 // the subroutine may have resolved to a different image 1220 // that doesn't have debug information available. 1221 continue; 1222 } 1223 1224 FunctionInstance* targetFunction; 1225 if (imageInfo->GetAddressSectionType(subroutineAddress) 1226 == ADDRESS_SECTION_TYPE_PLT) { 1227 result = fArchitecture->ResolvePICFunctionAddress( 1228 subroutineAddress, subroutineState, subroutineAddress); 1229 if (result != B_OK) 1230 continue; 1231 if (!targetImage->ContainsAddress(subroutineAddress)) { 1232 // the PLT entry doesn't necessarily point to a function 1233 // in the same image; as such we may need to try to 1234 // resolve the target address again. 1235 targetImage = image->GetTeam()->ImageByAddress( 1236 subroutineAddress); 1237 if (targetImage == NULL) 1238 continue; 1239 imageInfo = targetImage->GetImageDebugInfo(); 1240 if (imageInfo == NULL) { 1241 // As above, since the indirection here may have 1242 // landed us in an entirely different image, there is 1243 // no guarantee that debug info is available, 1244 // depending on which image it was. 1245 continue; 1246 } 1247 1248 } 1249 } 1250 1251 targetFunction = imageInfo->FunctionAtAddress(subroutineAddress); 1252 if (targetFunction != NULL) { 1253 DwarfFunctionDebugInfo* targetInfo = 1254 dynamic_cast<DwarfFunctionDebugInfo*>( 1255 targetFunction->GetFunctionDebugInfo()); 1256 if (targetInfo != NULL) { 1257 DIESubprogram* subProgram = targetInfo->SubprogramEntry(); 1258 DIEType* returnType = subProgram->ReturnType(); 1259 if (returnType == NULL) { 1260 // check if we have a specification, and if so, if that has 1261 // a return type 1262 subProgram = dynamic_cast<DIESubprogram*>( 1263 subProgram->Specification()); 1264 if (subProgram != NULL) 1265 returnType = subProgram->ReturnType(); 1266 1267 // function doesn't return a value, we're done. 1268 if (returnType == NULL) 1269 return B_OK; 1270 } 1271 1272 uint32 byteSize = 0; 1273 if (returnType->ByteSize() == NULL) { 1274 if (dynamic_cast<DIEAddressingType*>(returnType) != NULL) 1275 byteSize = fArchitecture->AddressSize(); 1276 } else 1277 byteSize = returnType->ByteSize()->constant; 1278 1279 // if we were unable to determine a size for the type, 1280 // simply default to the architecture's register width. 1281 if (byteSize == 0) 1282 byteSize = fArchitecture->AddressSize(); 1283 1284 ValueLocation* location; 1285 result = fArchitecture->GetReturnAddressLocation(frame, 1286 byteSize, location); 1287 if (result != B_OK) 1288 return result; 1289 1290 BReference<ValueLocation> locationReference(location, true); 1291 Variable* variable = NULL; 1292 BReference<FunctionID> idReference( 1293 targetFunction->GetFunctionID(), true); 1294 result = factory.CreateReturnValue(idReference, returnType, 1295 location, subroutineState, variable); 1296 if (result != B_OK) 1297 return result; 1298 1299 BReference<Variable> variableReference(variable, true); 1300 if (!frame->AddLocalVariable(variable)) 1301 return B_NO_MEMORY; 1302 } 1303 } 1304 } 1305 1306 return B_OK; 1307 } 1308 1309 1310 bool 1311 DwarfImageDebugInfo::_EvaluateBaseTypeConstraints(DIEType* type, 1312 const TypeLookupConstraints& constraints) const 1313 { 1314 if (constraints.HasBaseTypeName()) { 1315 BString baseEntryName; 1316 DIEType* baseTypeOwnerEntry = NULL; 1317 1318 switch (constraints.TypeKind()) { 1319 case TYPE_ADDRESS: 1320 { 1321 DIEAddressingType* addressType = 1322 dynamic_cast<DIEAddressingType*>(type); 1323 if (addressType != NULL) { 1324 baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( 1325 addressType, HasTypePredicate<DIEAddressingType>()); 1326 } 1327 break; 1328 } 1329 case TYPE_ARRAY: 1330 { 1331 DIEArrayType* arrayType = 1332 dynamic_cast<DIEArrayType*>(type); 1333 if (arrayType != NULL) { 1334 baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( 1335 arrayType, HasTypePredicate<DIEArrayType>()); 1336 } 1337 break; 1338 } 1339 default: 1340 break; 1341 } 1342 1343 if (baseTypeOwnerEntry != NULL) { 1344 DwarfUtils::GetFullyQualifiedDIEName(baseTypeOwnerEntry, 1345 baseEntryName); 1346 1347 if (baseEntryName != constraints.BaseTypeName()) 1348 return false; 1349 } 1350 } 1351 1352 return true; 1353 } 1354 1355 1356 status_t 1357 DwarfImageDebugInfo::_BuildTypeNameTable() 1358 { 1359 fTypeNameTable = new(std::nothrow) TypeNameTable; 1360 if (fTypeNameTable == NULL) 1361 return B_NO_MEMORY; 1362 1363 status_t error = fTypeNameTable->Init(); 1364 if (error != B_OK) 1365 return error; 1366 1367 // iterate through all compilation units 1368 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i); 1369 i++) { 1370 1371 // iterate through all types of the compilation unit 1372 for (DebugInfoEntryList::ConstIterator it 1373 = unit->UnitEntry()->Types().GetIterator(); 1374 DIEType* typeEntry = dynamic_cast<DIEType*>(it.Next());) { 1375 if (typeEntry->IsDeclaration()) 1376 continue; 1377 1378 BString typeEntryName; 1379 DwarfUtils::GetFullyQualifiedDIEName(typeEntry, typeEntryName); 1380 1381 TypeNameEntry* entry = fTypeNameTable->Lookup(typeEntryName); 1382 if (entry == NULL) { 1383 entry = new(std::nothrow) TypeNameEntry(typeEntryName); 1384 if (entry == NULL) 1385 return B_NO_MEMORY; 1386 1387 error = fTypeNameTable->Insert(entry); 1388 if (error != B_OK) 1389 return error; 1390 } 1391 1392 TypeEntryInfo* info = new(std::nothrow) TypeEntryInfo(typeEntry, 1393 unit); 1394 if (info == NULL) 1395 return B_NO_MEMORY; 1396 1397 if (!entry->types.AddItem(info)) { 1398 delete info; 1399 return B_NO_MEMORY; 1400 } 1401 } 1402 } 1403 1404 return B_OK; 1405 } 1406