vfs: check userland buffers before reading them.
[haiku.git] / src / kits / debugger / debug_info / DwarfImageDebugInfo.cpp
blobc38e6b83bb7015fcf9b369e4c7dd0cb7e99feadd
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 */
8 #include "DwarfImageDebugInfo.h"
10 #include <errno.h>
11 #include <stdio.h>
12 #include <unistd.h>
14 #include <algorithm>
15 #include <new>
17 #include <AutoDeleter.h>
18 #include <AutoLocker.h>
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"
66 namespace {
69 // #pragma mark - HasTypePredicate
72 template<typename EntryType>
73 struct HasTypePredicate {
74 inline bool operator()(EntryType* entry) const
76 return entry->GetType() != NULL;
83 // #pragma mark - BasicTargetInterface
86 struct DwarfImageDebugInfo::BasicTargetInterface : DwarfTargetInterface {
87 BasicTargetInterface(const Register* registers, int32 registerCount,
88 RegisterMap* fromDwarfMap, Architecture* architecture,
89 TeamMemory* teamMemory)
91 fRegisters(registers),
92 fRegisterCount(registerCount),
93 fFromDwarfMap(fromDwarfMap),
94 fArchitecture(architecture),
95 fTeamMemory(teamMemory)
97 fFromDwarfMap->AcquireReference();
100 ~BasicTargetInterface()
102 fFromDwarfMap->ReleaseReference();
105 virtual uint32 CountRegisters() const
107 return fRegisterCount;
110 virtual uint32 RegisterValueType(uint32 index) const
112 const Register* reg = _RegisterAt(index);
113 return reg != NULL ? reg->ValueType() : 0;
116 virtual bool GetRegisterValue(uint32 index, BVariant& _value) const
118 return false;
121 virtual bool SetRegisterValue(uint32 index, const BVariant& value)
123 return false;
126 virtual bool IsCalleePreservedRegister(uint32 index) const
128 const Register* reg = _RegisterAt(index);
129 return reg != NULL && reg->IsCalleePreserved();
132 virtual status_t InitRegisterRules(CfaContext& context) const
134 return fArchitecture->InitRegisterRules(context);
137 virtual bool ReadMemory(target_addr_t address, void* buffer,
138 size_t size) const
140 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size);
141 return bytesRead >= 0 && (size_t)bytesRead == size;
144 virtual bool ReadValueFromMemory(target_addr_t address,
145 uint32 valueType, BVariant& _value) const
147 return fArchitecture->ReadValueFromMemory(address, valueType, _value)
148 == B_OK;
151 virtual bool ReadValueFromMemory(target_addr_t addressSpace,
152 target_addr_t address, uint32 valueType, BVariant& _value) const
154 return fArchitecture->ReadValueFromMemory(addressSpace, address,
155 valueType, _value) == B_OK;
158 protected:
159 const Register* _RegisterAt(uint32 dwarfIndex) const
161 int32 index = fFromDwarfMap->MapRegisterIndex(dwarfIndex);
162 return index >= 0 && index < fRegisterCount ? fRegisters + index : NULL;
165 protected:
166 const Register* fRegisters;
167 int32 fRegisterCount;
168 RegisterMap* fFromDwarfMap;
169 Architecture* fArchitecture;
170 TeamMemory* fTeamMemory;
174 // #pragma mark - UnwindTargetInterface
177 struct DwarfImageDebugInfo::UnwindTargetInterface : BasicTargetInterface {
178 UnwindTargetInterface(const Register* registers, int32 registerCount,
179 RegisterMap* fromDwarfMap, RegisterMap* toDwarfMap, CpuState* cpuState,
180 Architecture* architecture, TeamMemory* teamMemory)
182 BasicTargetInterface(registers, registerCount, fromDwarfMap,
183 architecture, teamMemory),
184 fToDwarfMap(toDwarfMap),
185 fCpuState(cpuState)
187 fToDwarfMap->AcquireReference();
188 fCpuState->AcquireReference();
191 ~UnwindTargetInterface()
193 fToDwarfMap->ReleaseReference();
194 fCpuState->ReleaseReference();
197 virtual bool GetRegisterValue(uint32 index, BVariant& _value) const
199 const Register* reg = _RegisterAt(index);
200 if (reg == NULL)
201 return false;
202 return fCpuState->GetRegisterValue(reg, _value);
205 virtual bool SetRegisterValue(uint32 index, const BVariant& value)
207 const Register* reg = _RegisterAt(index);
208 if (reg == NULL)
209 return false;
210 return fCpuState->SetRegisterValue(reg, value);
213 private:
214 RegisterMap* fToDwarfMap;
215 CpuState* fCpuState;
219 // #pragma mark - EntryListWrapper
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.
225 struct DwarfImageDebugInfo::EntryListWrapper {
226 const DebugInfoEntryList& list;
228 EntryListWrapper(const DebugInfoEntryList& list)
230 list(list)
236 // #pragma mark - DwarfImageDebugInfo::TypeNameKey
239 struct DwarfImageDebugInfo::TypeNameKey {
240 BString typeName;
242 TypeNameKey(const BString& typeName)
244 typeName(typeName)
248 uint32 HashValue() const
250 return StringUtils::HashValue(typeName);
253 bool operator==(const TypeNameKey& other) const
255 return typeName == other.typeName;
260 // #pragma mark - DwarfImageDebugInfo::TypeNameEntry
263 struct DwarfImageDebugInfo::TypeNameEntry : TypeNameKey {
264 TypeNameEntry* next;
265 TypeEntryList types;
267 TypeNameEntry(const BString& name)
269 TypeNameKey(name),
270 types(10, true)
274 ~TypeNameEntry()
281 // #pragma mark - DwarfImageDebugInfo::TypeNameEntryHashDefinition
284 struct DwarfImageDebugInfo::TypeNameEntryHashDefinition {
285 typedef TypeNameKey KeyType;
286 typedef TypeNameEntry ValueType;
288 size_t HashKey(const TypeNameKey& key) const
290 return key.HashValue();
293 size_t Hash(const TypeNameEntry* value) const
295 return value->HashValue();
298 bool Compare(const TypeNameKey& key,
299 const TypeNameEntry* value) const
301 return key == *value;
304 TypeNameEntry*& GetLink(TypeNameEntry* value) const
306 return value->next;
311 // #pragma mark - DwarfImageDebugInfo::TypeEntryInfo
314 struct DwarfImageDebugInfo::TypeEntryInfo {
315 DIEType* type;
316 CompilationUnit* unit;
318 TypeEntryInfo(DIEType* type, CompilationUnit* unit)
320 type(type),
321 unit(unit)
327 // #pragma mark - DwarfImageDebugInfo
330 DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo,
331 DebuggerInterface* interface, Architecture* architecture,
332 FileManager* fileManager, GlobalTypeLookup* typeLookup,
333 GlobalTypeCache* typeCache, TeamFunctionSourceInformation* sourceInfo,
334 DwarfFile* file)
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)
353 fDebuggerInterface->AcquireReference();
354 fFile->AcquireReference();
355 fTypeCache->AcquireReference();
359 DwarfImageDebugInfo::~DwarfImageDebugInfo()
361 fDebuggerInterface->ReleaseReference();
362 fFile->ReleaseReference();
363 fTypeCache->ReleaseReference();
365 TypeNameEntry* entry = fTypeNameTable->Clear(true);
366 while (entry != NULL) {
367 TypeNameEntry* next = entry->next;
368 delete entry;
369 entry = next;
371 delete fTypeNameTable;
375 status_t
376 DwarfImageDebugInfo::Init()
378 status_t error = fLock.InitCheck();
379 if (error != B_OK)
380 return error;
382 fTextSegment = fFile->GetElfFile()->TextSegment();
383 if (fTextSegment == NULL)
384 return B_ENTRY_NOT_FOUND;
386 fRelocationDelta = fImageInfo.TextBase() - fTextSegment->LoadAddress();
388 ElfSection* section = fFile->GetElfFile()->FindSection(".text");
389 if (section != NULL) {
390 fTextSectionStart = section->LoadAddress() + fRelocationDelta;
391 fTextSectionEnd = fTextSectionStart + section->Size();
394 section = fFile->GetElfFile()->FindSection(".plt");
395 if (section != NULL) {
396 fPLTSectionStart = section->LoadAddress() + fRelocationDelta;
397 fPLTSectionEnd = fPLTSectionStart + section->Size();
400 return _BuildTypeNameTable();
404 status_t
405 DwarfImageDebugInfo::GetFunctions(const BObjectList<SymbolInfo>& symbols,
406 BObjectList<FunctionDebugInfo>& functions)
408 TRACE_IMAGES("DwarfImageDebugInfo::GetFunctions()\n");
409 TRACE_IMAGES(" %" B_PRId32 " compilation units\n",
410 fFile->CountCompilationUnits());
412 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
413 i++) {
414 DIECompileUnitBase* unitEntry = unit->UnitEntry();
415 // printf(" %s:\n", unitEntry->Name());
416 // printf(" address ranges:\n");
417 // TargetAddressRangeList* rangeList = unitEntry->AddressRanges();
418 // if (rangeList != NULL) {
419 // int32 count = rangeList->CountRanges();
420 // for (int32 i = 0; i < count; i++) {
421 // TargetAddressRange range = rangeList->RangeAt(i);
422 // printf(" %#llx - %#llx\n", range.Start(), range.End());
423 // }
424 // } else {
425 // printf(" %#llx - %#llx\n", (target_addr_t)unitEntry->LowPC(),
426 // (target_addr_t)unitEntry->HighPC());
427 // }
429 // printf(" functions:\n");
430 for (DebugInfoEntryList::ConstIterator it
431 = unitEntry->OtherChildren().GetIterator();
432 DebugInfoEntry* entry = it.Next();) {
433 if (entry->Tag() != DW_TAG_subprogram)
434 continue;
436 DIESubprogram* subprogramEntry = static_cast<DIESubprogram*>(entry);
438 // ignore declarations and inlined functions
439 if (subprogramEntry->IsDeclaration()
440 || subprogramEntry->Inline() == DW_INL_inlined
441 || subprogramEntry->Inline() == DW_INL_declared_inlined) {
442 continue;
445 // get the name
446 BString name;
447 DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name);
448 if (name.Length() == 0)
449 continue;
451 // get the address ranges
452 TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit,
453 subprogramEntry->AddressRangesOffset());
454 if (rangeList == NULL) {
455 target_addr_t lowPC = subprogramEntry->LowPC();
456 target_addr_t highPC = subprogramEntry->HighPC();
457 if (highPC <= lowPC)
458 continue;
460 rangeList = new(std::nothrow) TargetAddressRangeList(
461 TargetAddressRange(lowPC, highPC - lowPC));
462 if (rangeList == NULL)
463 return B_NO_MEMORY;
464 // TODO: Clean up already added functions!
466 BReference<TargetAddressRangeList> rangeListReference(rangeList,
467 true);
469 // get the source location
470 const char* directoryPath = NULL;
471 const char* fileName = NULL;
472 int32 line = -1;
473 int32 column = -1;
474 DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry,
475 directoryPath, fileName, line, column);
477 LocatableFile* file = NULL;
478 if (fileName != NULL) {
479 file = fFileManager->GetSourceFile(directoryPath,
480 fileName);
482 BReference<LocatableFile> fileReference(file, true);
484 // create and add the functions
485 DwarfFunctionDebugInfo* function
486 = new(std::nothrow) DwarfFunctionDebugInfo(this, unit,
487 subprogramEntry, rangeList, name, file,
488 SourceLocation(line, std::max(column, (int32)0)));
489 if (function == NULL || !functions.AddItem(function)) {
490 delete function;
491 return B_NO_MEMORY;
492 // TODO: Clean up already added functions!
495 // BString name;
496 // DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name);
497 // printf(" subprogram entry: %p, name: %s, declaration: %d\n",
498 // subprogramEntry, name.String(),
499 // subprogramEntry->IsDeclaration());
501 // rangeList = subprogramEntry->AddressRanges();
502 // if (rangeList != NULL) {
503 // int32 count = rangeList->CountRanges();
504 // for (int32 i = 0; i < count; i++) {
505 // TargetAddressRange range = rangeList->RangeAt(i);
506 // printf(" %#llx - %#llx\n", range.Start(), range.End());
507 // }
508 // } else {
509 // printf(" %#llx - %#llx\n",
510 // (target_addr_t)subprogramEntry->LowPC(),
511 // (target_addr_t)subprogramEntry->HighPC());
512 // }
516 if (fFile->CountCompilationUnits() != 0)
517 return B_OK;
519 // if we had no compilation units, fall back to providing basic
520 // debug infos with DWARF-supported call frame unwinding,
521 // if available.
522 if (fFile->HasFrameInformation()) {
523 return SpecificImageDebugInfo::GetFunctionsFromSymbols(symbols,
524 functions, fDebuggerInterface, fImageInfo, this);
527 return B_OK;
531 status_t
532 DwarfImageDebugInfo::GetType(GlobalTypeCache* cache, const BString& name,
533 const TypeLookupConstraints& constraints, Type*& _type)
535 TypeNameEntry* entry = fTypeNameTable->Lookup(name);
536 if (entry == NULL)
537 return B_ENTRY_NOT_FOUND;
539 for (int32 i = 0; TypeEntryInfo* info = entry->types.ItemAt(i); i++) {
540 DIEType* typeEntry = info->type;
541 if (constraints.HasTypeKind()) {
542 if (dwarf_tag_to_type_kind(typeEntry->Tag())
543 != constraints.TypeKind()) {
544 continue;
547 if (!_EvaluateBaseTypeConstraints(typeEntry, constraints))
548 continue;
551 if (constraints.HasSubtypeKind()
552 && dwarf_tag_to_subtype_kind(typeEntry->Tag())
553 != constraints.SubtypeKind()) {
554 continue;
557 DwarfTypeContext* typeContext = new(std::nothrow)
558 DwarfTypeContext(fArchitecture, fImageInfo.ImageID(), fFile,
559 info->unit, NULL, 0, 0, fRelocationDelta, NULL, NULL);
560 if (typeContext == NULL)
561 return B_NO_MEMORY;
562 BReference<DwarfTypeContext> typeContextReference(typeContext, true);
564 // create the type
565 DwarfType* type;
566 DwarfTypeFactory typeFactory(typeContext, fTypeLookup, cache);
567 status_t error = typeFactory.CreateType(typeEntry, type);
568 if (error != B_OK)
569 continue;
571 _type = type;
572 return B_OK;
575 return B_ENTRY_NOT_FOUND;
579 bool
580 DwarfImageDebugInfo::HasType(const BString& name,
581 const TypeLookupConstraints& constraints) const
583 TypeNameEntry* entry = fTypeNameTable->Lookup(name);
584 if (entry == NULL)
585 return false;
587 for (int32 i = 0; TypeEntryInfo* info = entry->types.ItemAt(i); i++) {
588 DIEType* typeEntry = info->type;
589 if (constraints.HasTypeKind()) {
590 if (dwarf_tag_to_type_kind(typeEntry->Tag())
591 != constraints.TypeKind()) {
592 continue;
595 if (!_EvaluateBaseTypeConstraints(typeEntry, constraints))
596 continue;
599 if (constraints.HasSubtypeKind()
600 && dwarf_tag_to_subtype_kind(typeEntry->Tag())
601 != constraints.SubtypeKind()) {
602 continue;
605 return true;
608 return false;
612 AddressSectionType
613 DwarfImageDebugInfo::GetAddressSectionType(target_addr_t address)
615 if (address >= fTextSectionStart && address < fTextSectionEnd)
616 return ADDRESS_SECTION_TYPE_FUNCTION;
618 if (address >= fPLTSectionStart && address < fPLTSectionEnd)
619 return ADDRESS_SECTION_TYPE_PLT;
621 return ADDRESS_SECTION_TYPE_UNKNOWN;
625 status_t
626 DwarfImageDebugInfo::CreateFrame(Image* image,
627 FunctionInstance* functionInstance, CpuState* cpuState,
628 bool getFullFrameInfo, ReturnValueInfoList* returnValueInfos,
629 StackFrame*& _frame, CpuState*& _previousCpuState)
631 DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>(
632 functionInstance->GetFunctionDebugInfo());
634 FunctionID* functionID = functionInstance->GetFunctionID();
635 BReference<FunctionID> functionIDReference;
636 if (functionID != NULL)
637 functionIDReference.SetTo(functionID, true);
639 DIESubprogram* entry = function != NULL
640 ? function->SubprogramEntry() : NULL;
642 TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p, "
643 "function: %s\n", entry,
644 functionID->FunctionName().String());
646 int32 registerCount = fArchitecture->CountRegisters();
647 const Register* registers = fArchitecture->Registers();
649 // get the DWARF <-> architecture register maps
650 RegisterMap* toDwarfMap;
651 RegisterMap* fromDwarfMap;
652 status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap,
653 &fromDwarfMap);
654 if (error != B_OK)
655 return error;
656 BReference<RegisterMap> toDwarfMapReference(toDwarfMap, true);
657 BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true);
659 // create a clean CPU state for the previous frame
660 CpuState* previousCpuState;
661 error = fArchitecture->CreateCpuState(previousCpuState);
662 if (error != B_OK)
663 return error;
664 BReference<CpuState> previousCpuStateReference(previousCpuState, true);
666 // create the target interfaces
667 UnwindTargetInterface* inputInterface
668 = new(std::nothrow) UnwindTargetInterface(registers, registerCount,
669 fromDwarfMap, toDwarfMap, cpuState, fArchitecture,
670 fDebuggerInterface);
671 if (inputInterface == NULL)
672 return B_NO_MEMORY;
673 BReference<UnwindTargetInterface> inputInterfaceReference(inputInterface,
674 true);
676 UnwindTargetInterface* outputInterface
677 = new(std::nothrow) UnwindTargetInterface(registers, registerCount,
678 fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture,
679 fDebuggerInterface);
680 if (outputInterface == NULL)
681 return B_NO_MEMORY;
682 BReference<UnwindTargetInterface> outputInterfaceReference(outputInterface,
683 true);
685 // do the unwinding
686 target_addr_t instructionPointer
687 = cpuState->InstructionPointer() - fRelocationDelta;
688 target_addr_t framePointer;
689 CompilationUnit* unit = function != NULL ? function->GetCompilationUnit()
690 : NULL;
691 error = fFile->UnwindCallFrame(unit, fArchitecture->AddressSize(), entry,
692 instructionPointer, inputInterface, outputInterface, framePointer);
694 if (error != B_OK) {
695 TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error));
696 return B_UNSUPPORTED;
699 TRACE_CFI_ONLY(
700 TRACE_CFI("unwound registers:\n");
701 for (int32 i = 0; i < registerCount; i++) {
702 const Register* reg = registers + i;
703 BVariant value;
704 if (previousCpuState->GetRegisterValue(reg, value)) {
705 TRACE_CFI(" %3s: %#" B_PRIx64 "\n", reg->Name(),
706 value.ToUInt64());
707 } else
708 TRACE_CFI(" %3s: undefined\n", reg->Name());
712 // create the stack frame debug info
713 DIESubprogram* subprogramEntry = function != NULL ?
714 function->SubprogramEntry() : NULL;
715 DwarfStackFrameDebugInfo* stackFrameDebugInfo
716 = new(std::nothrow) DwarfStackFrameDebugInfo(fArchitecture,
717 fImageInfo.ImageID(), fFile, unit, subprogramEntry, fTypeLookup,
718 fTypeCache, instructionPointer, framePointer, fRelocationDelta,
719 inputInterface, fromDwarfMap);
720 if (stackFrameDebugInfo == NULL)
721 return B_NO_MEMORY;
722 BReference<DwarfStackFrameDebugInfo> stackFrameDebugInfoReference(
723 stackFrameDebugInfo, true);
725 error = stackFrameDebugInfo->Init();
726 if (error != B_OK)
727 return error;
729 // create the stack frame
730 StackFrame* frame = new(std::nothrow) StackFrame(STACK_FRAME_TYPE_STANDARD,
731 cpuState, framePointer, cpuState->InstructionPointer(),
732 stackFrameDebugInfo);
733 if (frame == NULL)
734 return B_NO_MEMORY;
735 BReference<StackFrame> frameReference(frame, true);
737 error = frame->Init();
738 if (error != B_OK)
739 return error;
741 frame->SetReturnAddress(previousCpuState->InstructionPointer());
742 // Note, this is correct, since we actually retrieved the return
743 // address. Our caller will fix the IP for us.
745 // The subprogram entry may not be available since this may be a case
746 // where .eh_frame was used to unwind the stack without other DWARF
747 // info being available.
748 if (subprogramEntry != NULL && getFullFrameInfo) {
749 // create function parameter objects
750 for (DebugInfoEntryList::ConstIterator it
751 = subprogramEntry->Parameters().GetIterator();
752 DebugInfoEntry* entry = it.Next();) {
753 if (entry->Tag() != DW_TAG_formal_parameter)
754 continue;
756 BString parameterName;
757 DwarfUtils::GetDIEName(entry, parameterName);
758 if (parameterName.Length() == 0)
759 continue;
761 DIEFormalParameter* parameterEntry
762 = dynamic_cast<DIEFormalParameter*>(entry);
763 Variable* parameter;
764 if (stackFrameDebugInfo->CreateParameter(functionID,
765 parameterEntry, parameter) != B_OK) {
766 continue;
768 BReference<Variable> parameterReference(parameter, true);
770 if (!frame->AddParameter(parameter))
771 return B_NO_MEMORY;
774 // create objects for the local variables
775 _CreateLocalVariables(unit, frame, functionID, *stackFrameDebugInfo,
776 instructionPointer, functionInstance->Address() - fRelocationDelta,
777 subprogramEntry->Variables(), subprogramEntry->Blocks());
779 if (returnValueInfos != NULL && !returnValueInfos->IsEmpty()) {
780 _CreateReturnValues(returnValueInfos, image, frame,
781 *stackFrameDebugInfo);
785 _frame = frameReference.Detach();
786 _previousCpuState = previousCpuStateReference.Detach();
788 frame->SetPreviousCpuState(_previousCpuState);
790 return B_OK;
794 status_t
795 DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function,
796 target_addr_t address, Statement*& _statement)
798 TRACE_CODE("DwarfImageDebugInfo::GetStatement(function: %p, address: %#"
799 B_PRIx64 ")\n", _function, address);
801 DwarfFunctionDebugInfo* function
802 = dynamic_cast<DwarfFunctionDebugInfo*>(_function);
803 if (function == NULL) {
804 TRACE_LINES(" -> no dwarf function\n");
805 // fall back to assembly
806 return fArchitecture->GetStatement(function, address, _statement);
809 AutoLocker<BLocker> locker(fLock);
811 // check whether we have the source code
812 CompilationUnit* unit = function->GetCompilationUnit();
813 LocatableFile* file = function->SourceFile();
814 if (file == NULL) {
815 TRACE_CODE(" -> no source file\n");
817 // no source code -- rather return the assembly statement
818 return fArchitecture->GetStatement(function, address, _statement);
821 SourceCode* sourceCode = NULL;
822 status_t error = fSourceInfo->GetActiveSourceCode(_function, sourceCode);
823 BReference<SourceCode> sourceReference(sourceCode, true);
824 if (error != B_OK || dynamic_cast<DisassembledCode*>(sourceCode) != NULL) {
825 // either no source code or disassembly is currently active (i.e.
826 // due to failing to locate the source file on disk or the user
827 // deliberately switching to disassembly view).
828 // return the assembly statement.
829 return fArchitecture->GetStatement(function, address, _statement);
832 // get the index of the source file in the compilation unit for cheaper
833 // comparison below
834 int32 fileIndex = _GetSourceFileIndex(unit, file);
836 // Get the statement by executing the line number program for the
837 // compilation unit.
838 LineNumberProgram& program = unit->GetLineNumberProgram();
839 if (!program.IsValid()) {
840 TRACE_CODE(" -> no line number program\n");
841 return B_BAD_DATA;
844 // adjust address
845 address -= fRelocationDelta;
847 LineNumberProgram::State state;
848 program.GetInitialState(state);
850 target_addr_t statementAddress = 0;
851 int32 statementLine = -1;
852 int32 statementColumn = -1;
853 while (program.GetNextRow(state)) {
854 // skip statements of other files
855 if (state.file != fileIndex)
856 continue;
858 if (statementAddress != 0
859 && (state.isStatement || state.isSequenceEnd)) {
860 target_addr_t endAddress = state.address;
861 if (address >= statementAddress && address < endAddress) {
862 ContiguousStatement* statement = new(std::nothrow)
863 ContiguousStatement(
864 SourceLocation(statementLine, statementColumn),
865 TargetAddressRange(fRelocationDelta + statementAddress,
866 endAddress - statementAddress));
867 if (statement == NULL)
868 return B_NO_MEMORY;
870 _statement = statement;
871 return B_OK;
874 statementAddress = 0;
877 if (state.isStatement) {
878 statementAddress = state.address;
879 statementLine = state.line - 1;
880 statementColumn = std::max(state.column - 1, (int32)0);
884 TRACE_CODE(" -> no line number program match\n");
885 return B_ENTRY_NOT_FOUND;
889 status_t
890 DwarfImageDebugInfo::GetStatementAtSourceLocation(FunctionDebugInfo* _function,
891 const SourceLocation& sourceLocation, Statement*& _statement)
893 DwarfFunctionDebugInfo* function
894 = dynamic_cast<DwarfFunctionDebugInfo*>(_function);
895 if (function == NULL)
896 return B_BAD_VALUE;
898 target_addr_t functionStartAddress = function->Address() - fRelocationDelta;
899 target_addr_t functionEndAddress = functionStartAddress + function->Size();
901 TRACE_LINES2("DwarfImageDebugInfo::GetStatementAtSourceLocation(%p, "
902 "(%" B_PRId32 ", %" B_PRId32 ")): function range: %#" B_PRIx64 " - %#"
903 B_PRIx64 "\n", function, sourceLocation.Line(), sourceLocation.Column(),
904 functionStartAddress, functionEndAddress);
906 AutoLocker<BLocker> locker(fLock);
908 // get the source file
909 LocatableFile* file = function->SourceFile();
910 if (file == NULL)
911 return B_ENTRY_NOT_FOUND;
913 CompilationUnit* unit = function->GetCompilationUnit();
915 // get the index of the source file in the compilation unit for cheaper
916 // comparison below
917 int32 fileIndex = _GetSourceFileIndex(unit, file);
919 // Get the statement by executing the line number program for the
920 // compilation unit.
921 LineNumberProgram& program = unit->GetLineNumberProgram();
922 if (!program.IsValid())
923 return B_BAD_DATA;
925 LineNumberProgram::State state;
926 program.GetInitialState(state);
928 target_addr_t statementAddress = 0;
929 int32 statementLine = -1;
930 int32 statementColumn = -1;
931 while (program.GetNextRow(state)) {
932 bool isOurFile = state.file == fileIndex;
934 if (statementAddress != 0
935 && (!isOurFile || state.isStatement || state.isSequenceEnd)) {
936 target_addr_t endAddress = state.address;
938 if (statementAddress < endAddress) {
939 TRACE_LINES2(" statement: %#" B_PRIx64 " - %#" B_PRIx64
940 ", location: (%" B_PRId32 ", %" B_PRId32 ")\n",
941 statementAddress, endAddress, statementLine,
942 statementColumn);
945 if (statementAddress < endAddress
946 && statementAddress >= functionStartAddress
947 && statementAddress < functionEndAddress
948 && statementLine == (int32)sourceLocation.Line()
949 && statementColumn == (int32)sourceLocation.Column()) {
950 TRACE_LINES2(" -> found statement!\n");
952 ContiguousStatement* statement = new(std::nothrow)
953 ContiguousStatement(
954 SourceLocation(statementLine, statementColumn),
955 TargetAddressRange(fRelocationDelta + statementAddress,
956 endAddress - statementAddress));
957 if (statement == NULL)
958 return B_NO_MEMORY;
960 _statement = statement;
961 return B_OK;
964 statementAddress = 0;
967 // skip statements of other files
968 if (!isOurFile)
969 continue;
971 if (state.isStatement) {
972 statementAddress = state.address;
973 statementLine = state.line - 1;
974 statementColumn = std::max(state.column - 1, (int32)0);
978 return B_ENTRY_NOT_FOUND;
982 status_t
983 DwarfImageDebugInfo::GetSourceLanguage(FunctionDebugInfo* _function,
984 SourceLanguage*& _language)
986 DwarfFunctionDebugInfo* function
987 = dynamic_cast<DwarfFunctionDebugInfo*>(_function);
988 if (function == NULL)
989 return B_BAD_VALUE;
991 SourceLanguage* language;
992 CompilationUnit* unit = function->GetCompilationUnit();
993 switch (unit->UnitEntry()->Language()) {
994 case DW_LANG_C89:
995 case DW_LANG_C:
996 case DW_LANG_C99:
997 language = new(std::nothrow) CLanguage;
998 break;
999 case DW_LANG_C_plus_plus:
1000 language = new(std::nothrow) CppLanguage;
1001 break;
1002 case 0:
1003 default:
1004 language = new(std::nothrow) UnsupportedLanguage;
1005 break;
1008 if (language == NULL)
1009 return B_NO_MEMORY;
1011 _language = language;
1012 return B_OK;
1016 ssize_t
1017 DwarfImageDebugInfo::ReadCode(target_addr_t address, void* buffer, size_t size)
1019 target_addr_t offset = address - fRelocationDelta
1020 - fTextSegment->LoadAddress() + fTextSegment->FileOffset();
1021 ssize_t bytesRead = pread(fFile->GetElfFile()->FD(), buffer, size, offset);
1022 return bytesRead >= 0 ? bytesRead : errno;
1026 status_t
1027 DwarfImageDebugInfo::AddSourceCodeInfo(LocatableFile* file,
1028 FileSourceCode* sourceCode)
1030 bool addedAny = false;
1031 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
1032 i++) {
1033 int32 fileIndex = _GetSourceFileIndex(unit, file);
1034 if (fileIndex < 0)
1035 continue;
1037 status_t error = _AddSourceCodeInfo(unit, sourceCode, fileIndex);
1038 if (error == B_NO_MEMORY)
1039 return error;
1040 addedAny |= error == B_OK;
1043 return addedAny ? B_OK : B_ENTRY_NOT_FOUND;
1047 status_t
1048 DwarfImageDebugInfo::_AddSourceCodeInfo(CompilationUnit* unit,
1049 FileSourceCode* sourceCode, int32 fileIndex)
1051 // Get the statements by executing the line number program for the
1052 // compilation unit and filtering the rows for our source file.
1053 LineNumberProgram& program = unit->GetLineNumberProgram();
1054 if (!program.IsValid())
1055 return B_BAD_DATA;
1057 LineNumberProgram::State state;
1058 program.GetInitialState(state);
1060 target_addr_t statementAddress = 0;
1061 int32 statementLine = -1;
1062 int32 statementColumn = -1;
1063 while (program.GetNextRow(state)) {
1064 TRACE_LINES2(" %#" B_PRIx64 " (%" B_PRId32 ", %" B_PRId32 ", %"
1065 B_PRId32 ") %d\n", state.address, state.file, state.line,
1066 state.column, state.isStatement);
1068 bool isOurFile = state.file == fileIndex;
1070 if (statementAddress != 0
1071 && (!isOurFile || state.isStatement || state.isSequenceEnd)) {
1072 target_addr_t endAddress = state.address;
1073 if (endAddress > statementAddress) {
1074 // add the statement
1075 status_t error = sourceCode->AddSourceLocation(
1076 SourceLocation(statementLine, statementColumn));
1077 if (error != B_OK)
1078 return error;
1080 TRACE_LINES2(" -> statement: %#" B_PRIx64 " - %#" B_PRIx64
1081 ", source location: (%" B_PRId32 ", %" B_PRId32 ")\n",
1082 statementAddress, endAddress, statementLine,
1083 statementColumn);
1086 statementAddress = 0;
1089 // skip statements of other files
1090 if (!isOurFile)
1091 continue;
1093 if (state.isStatement) {
1094 statementAddress = state.address;
1095 statementLine = state.line - 1;
1096 statementColumn = std::max(state.column - 1, (int32)0);
1100 return B_OK;
1104 int32
1105 DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit,
1106 LocatableFile* sourceFile) const
1108 // get the index of the source file in the compilation unit for cheaper
1109 // comparison below
1110 const char* directory;
1111 for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
1112 LocatableFile* file = fFileManager->GetSourceFile(directory, fileName);
1113 if (file != NULL) {
1114 file->ReleaseReference();
1115 if (file == sourceFile) {
1116 return i + 1;
1117 // indices are one-based
1122 return -1;
1126 status_t
1127 DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit,
1128 StackFrame* frame, FunctionID* functionID,
1129 DwarfStackFrameDebugInfo& factory, target_addr_t instructionPointer,
1130 target_addr_t lowPC, const EntryListWrapper& variableEntries,
1131 const EntryListWrapper& blockEntries)
1133 TRACE_LOCALS("DwarfImageDebugInfo::_CreateLocalVariables(): ip: %#" B_PRIx64
1134 ", low PC: %#" B_PRIx64 "\n", instructionPointer, lowPC);
1136 // iterate through the variables and add the ones in scope
1137 for (DebugInfoEntryList::ConstIterator it
1138 = variableEntries.list.GetIterator();
1139 DIEVariable* variableEntry = dynamic_cast<DIEVariable*>(it.Next());) {
1141 TRACE_LOCALS(" variableEntry %p, scope start: %" B_PRIu64 "\n",
1142 variableEntry, variableEntry->StartScope());
1144 // check the variable's scope
1145 if (instructionPointer < lowPC + variableEntry->StartScope())
1146 continue;
1148 // add the variable
1149 Variable* variable;
1150 if (factory.CreateLocalVariable(functionID, variableEntry, variable)
1151 != B_OK) {
1152 continue;
1154 BReference<Variable> variableReference(variable, true);
1156 if (!frame->AddLocalVariable(variable))
1157 return B_NO_MEMORY;
1160 // iterate through the blocks and find the one we're currently in (if any)
1161 for (DebugInfoEntryList::ConstIterator it = blockEntries.list.GetIterator();
1162 DIELexicalBlock* block = dynamic_cast<DIELexicalBlock*>(it.Next());) {
1164 TRACE_LOCALS(" lexical block: %p\n", block);
1166 // check whether the block has low/high PC attributes
1167 if (block->LowPC() != 0) {
1168 TRACE_LOCALS(" has lowPC\n");
1170 // yep, compare with the instruction pointer
1171 if (instructionPointer < block->LowPC()
1172 || instructionPointer >= block->HighPC()) {
1173 continue;
1175 } else {
1176 TRACE_LOCALS(" no lowPC\n");
1178 // check the address ranges instead
1179 TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit,
1180 block->AddressRangesOffset());
1181 if (rangeList == NULL) {
1182 TRACE_LOCALS(" failed to get ranges\n");
1183 continue;
1185 BReference<TargetAddressRangeList> rangeListReference(rangeList,
1186 true);
1188 if (!rangeList->Contains(instructionPointer)) {
1189 TRACE_LOCALS(" ranges don't contain IP\n");
1190 continue;
1194 // found a block -- recurse
1195 return _CreateLocalVariables(unit, frame, functionID, factory,
1196 instructionPointer, lowPC, block->Variables(), block->Blocks());
1199 return B_OK;
1203 status_t
1204 DwarfImageDebugInfo::_CreateReturnValues(ReturnValueInfoList* returnValueInfos,
1205 Image* image, StackFrame* frame, DwarfStackFrameDebugInfo& factory)
1207 for (int32 i = 0; i < returnValueInfos->CountItems(); i++) {
1208 Image* targetImage = image;
1209 ReturnValueInfo* valueInfo = returnValueInfos->ItemAt(i);
1210 target_addr_t subroutineAddress = valueInfo->SubroutineAddress();
1211 CpuState* subroutineState = valueInfo->State();
1212 if (!targetImage->ContainsAddress(subroutineAddress)) {
1213 // our current image doesn't contain the target function,
1214 // locate the one which does.
1215 targetImage = image->GetTeam()->ImageByAddress(subroutineAddress);
1216 if (targetImage == NULL) {
1217 // nothing we can do, try the next entry (if any)
1218 continue;
1222 status_t result = B_OK;
1223 ImageDebugInfo* imageInfo = targetImage->GetImageDebugInfo();
1224 if (imageInfo == NULL) {
1225 // the subroutine may have resolved to a different image
1226 // that doesn't have debug information available.
1227 continue;
1230 FunctionInstance* targetFunction;
1231 if (imageInfo->GetAddressSectionType(subroutineAddress)
1232 == ADDRESS_SECTION_TYPE_PLT) {
1233 result = fArchitecture->ResolvePICFunctionAddress(
1234 subroutineAddress, subroutineState, subroutineAddress);
1235 if (result != B_OK)
1236 continue;
1237 if (!targetImage->ContainsAddress(subroutineAddress)) {
1238 // the PLT entry doesn't necessarily point to a function
1239 // in the same image; as such we may need to try to
1240 // resolve the target address again.
1241 targetImage = image->GetTeam()->ImageByAddress(
1242 subroutineAddress);
1243 if (targetImage == NULL)
1244 continue;
1245 imageInfo = targetImage->GetImageDebugInfo();
1246 if (imageInfo == NULL) {
1247 // As above, since the indirection here may have
1248 // landed us in an entirely different image, there is
1249 // no guarantee that debug info is available,
1250 // depending on which image it was.
1251 continue;
1257 targetFunction = imageInfo->FunctionAtAddress(subroutineAddress);
1258 if (targetFunction != NULL) {
1259 DwarfFunctionDebugInfo* targetInfo =
1260 dynamic_cast<DwarfFunctionDebugInfo*>(
1261 targetFunction->GetFunctionDebugInfo());
1262 if (targetInfo != NULL) {
1263 DIESubprogram* subProgram = targetInfo->SubprogramEntry();
1264 DIEType* returnType = subProgram->ReturnType();
1265 if (returnType == NULL) {
1266 // check if we have a specification, and if so, if that has
1267 // a return type
1268 subProgram = dynamic_cast<DIESubprogram*>(
1269 subProgram->Specification());
1270 if (subProgram != NULL)
1271 returnType = subProgram->ReturnType();
1273 // function doesn't return a value, we're done.
1274 if (returnType == NULL)
1275 return B_OK;
1278 uint32 byteSize = 0;
1279 if (returnType->ByteSize() == NULL) {
1280 if (dynamic_cast<DIEAddressingType*>(returnType) != NULL)
1281 byteSize = fArchitecture->AddressSize();
1282 } else
1283 byteSize = returnType->ByteSize()->constant;
1285 // if we were unable to determine a size for the type,
1286 // simply default to the architecture's register width.
1287 if (byteSize == 0)
1288 byteSize = fArchitecture->AddressSize();
1290 ValueLocation* location;
1291 result = fArchitecture->GetReturnAddressLocation(frame,
1292 byteSize, location);
1293 if (result != B_OK)
1294 return result;
1296 BReference<ValueLocation> locationReference(location, true);
1297 Variable* variable = NULL;
1298 BReference<FunctionID> idReference(
1299 targetFunction->GetFunctionID(), true);
1300 result = factory.CreateReturnValue(idReference, returnType,
1301 location, subroutineState, variable);
1302 if (result != B_OK)
1303 return result;
1305 BReference<Variable> variableReference(variable, true);
1306 if (!frame->AddLocalVariable(variable))
1307 return B_NO_MEMORY;
1312 return B_OK;
1316 bool
1317 DwarfImageDebugInfo::_EvaluateBaseTypeConstraints(DIEType* type,
1318 const TypeLookupConstraints& constraints) const
1320 if (constraints.HasBaseTypeName()) {
1321 BString baseEntryName;
1322 DIEType* baseTypeOwnerEntry = NULL;
1324 switch (constraints.TypeKind()) {
1325 case TYPE_ADDRESS:
1327 DIEAddressingType* addressType =
1328 dynamic_cast<DIEAddressingType*>(type);
1329 if (addressType != NULL) {
1330 baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
1331 addressType, HasTypePredicate<DIEAddressingType>());
1333 break;
1335 case TYPE_ARRAY:
1337 DIEArrayType* arrayType =
1338 dynamic_cast<DIEArrayType*>(type);
1339 if (arrayType != NULL) {
1340 baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
1341 arrayType, HasTypePredicate<DIEArrayType>());
1343 break;
1345 default:
1346 break;
1349 if (baseTypeOwnerEntry != NULL) {
1350 DwarfUtils::GetFullyQualifiedDIEName(baseTypeOwnerEntry,
1351 baseEntryName);
1353 if (baseEntryName != constraints.BaseTypeName())
1354 return false;
1358 return true;
1362 status_t
1363 DwarfImageDebugInfo::_BuildTypeNameTable()
1365 fTypeNameTable = new(std::nothrow) TypeNameTable;
1366 if (fTypeNameTable == NULL)
1367 return B_NO_MEMORY;
1369 status_t error = fTypeNameTable->Init();
1370 if (error != B_OK)
1371 return error;
1373 // iterate through all compilation units
1374 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
1375 i++) {
1377 // iterate through all types of the compilation unit
1378 for (DebugInfoEntryList::ConstIterator it
1379 = unit->UnitEntry()->Types().GetIterator();
1380 DIEType* typeEntry = dynamic_cast<DIEType*>(it.Next());) {
1381 if (typeEntry->IsDeclaration())
1382 continue;
1384 BString typeEntryName;
1385 DwarfUtils::GetFullyQualifiedDIEName(typeEntry, typeEntryName);
1387 TypeNameEntry* entry = fTypeNameTable->Lookup(typeEntryName);
1388 if (entry == NULL) {
1389 entry = new(std::nothrow) TypeNameEntry(typeEntryName);
1390 if (entry == NULL)
1391 return B_NO_MEMORY;
1393 error = fTypeNameTable->Insert(entry);
1394 if (error != B_OK)
1395 return error;
1398 TypeEntryInfo* info = new(std::nothrow) TypeEntryInfo(typeEntry,
1399 unit);
1400 if (info == NULL)
1401 return B_NO_MEMORY;
1403 if (!entry->types.AddItem(info)) {
1404 delete info;
1405 return B_NO_MEMORY;
1410 return B_OK;