diff --git a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp index da04aca4d3..fa035bfbfe 100644 --- a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp @@ -10,6 +10,7 @@ #include +#include "arch/Architecture.h" #include "DebuggerInterface.h" #include "DwarfFile.h" #include "DwarfImageDebugInfo.h" @@ -47,7 +48,7 @@ DwarfTeamDebugInfo::~DwarfTeamDebugInfo() status_t DwarfTeamDebugInfo::Init() { - fManager = new(std::nothrow) DwarfManager; + fManager = new(std::nothrow) DwarfManager(fArchitecture->AddressSize()); if (fManager == NULL) return B_NO_MEMORY; diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index fa38af5af1..8ef735321b 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -442,6 +442,45 @@ private: }; +// #pragma mark - FDELookupInfo + + +struct DwarfFile::FDELookupInfo { +public: + FDELookupInfo(target_addr_t start, target_addr_t end, + uint64 fdeOffset, uint64 cieOffset, bool ehFrame) + : + start(start), + end(end), + fdeOffset(fdeOffset), + cieOffset(cieOffset), + ehFrame(ehFrame) + { + } + + static int CompareFDEInfos(const FDELookupInfo* a, const FDELookupInfo* b) + { + if (a->start < b->start) + return -1; + else if (a->start > b->start) + return 1; + + return 0; + } + + inline bool ContainsAddress(target_addr_t address) const + { + return address >= start && address < end; + } + + target_addr_t start; + target_addr_t end; + uint64 fdeOffset; + uint64 cieOffset; + bool ehFrame; +}; + + // #pragma mark - DwarfFile @@ -462,8 +501,12 @@ DwarfFile::DwarfFile() fDebugPublicTypesSection(NULL), fDebugTypesSection(NULL), fCompilationUnits(20, true), + fTypeUnits(), + fDebugFrameInfos(100, true), + fEHFrameInfos(100, true), fTypesSectionRequired(false), fFinished(false), + fItaniumEHFrameFormat(false), fFinishError(B_OK) { } @@ -528,7 +571,7 @@ DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile) status_t -DwarfFile::Load(const BString& externalInfoFilePath) +DwarfFile::Load(uint8 addressSize, const BString& externalInfoFilePath) { status_t error = B_OK; if (fDebugInfoSection == NULL) { @@ -547,11 +590,27 @@ DwarfFile::Load(const BString& externalInfoFilePath) fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges"); fDebugLineSection = debugInfoFile->GetSection(".debug_line"); fDebugFrameSection = debugInfoFile->GetSection(".debug_frame"); + + if (fDebugFrameSection != NULL) { + error = _ParseFrameSection(fDebugFrameSection, addressSize, false, + fDebugFrameInfos); + if (error != B_OK) + return error; + } + // .eh_frame doesn't appear to get copied into separate debug // info files properly, therefore always use it off the main // executable image if (fEHFrameSection == NULL) fEHFrameSection = fElfFile->GetSection(".eh_frame"); + + if (fEHFrameSection != NULL) { + error = _ParseFrameSection(fEHFrameSection, addressSize, true, + fEHFrameInfos); + if (error != B_OK) + return error; + } + fDebugLocationSection = debugInfoFile->GetSection(".debug_loc"); fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes"); @@ -699,22 +758,12 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, const DwarfTargetInterface* inputInterface, DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) { - status_t result = B_ENTRY_NOT_FOUND; + FDELookupInfo* info = _GetContainingFDEInfo(location); + if (info == NULL) + return B_ENTRY_NOT_FOUND; - // first try to find the FDE in .debug_frame - if (fDebugFrameSection != NULL) { - result = _UnwindCallFrame(false, unit, addressSize, subprogramEntry, - location, inputInterface, outputInterface, _framePointer); - } - - // if .debug_frame isn't present, or if the FDE wasn't found there, - // try .eh_frame - if (result == B_ENTRY_NOT_FOUND && fEHFrameSection != NULL) { - result = _UnwindCallFrame(true, unit, addressSize, subprogramEntry, - location, inputInterface, outputInterface, _framePointer); - } - - return result; + return _UnwindCallFrame(unit, addressSize, subprogramEntry, location, info, + inputInterface, outputInterface, _framePointer); } @@ -1080,6 +1129,116 @@ DwarfFile::_ParseTypesSection() } +status_t +DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize, + bool ehFrame, FDEInfoList& infos) +{ + if (ehFrame) { + fItaniumEHFrameFormat = section->IsWritable(); + // Crude heuristic for recognizing GCC 4 (Itanium ABI) style + // .eh_frame sections. The ones generated by GCC 2 are writable, + // the ones generated by GCC 4 aren't. + } + + DataReader dataReader((uint8*)section->Data(), + section->Size(), addressSize); + + while (dataReader.BytesRemaining() > 0) { + // length + bool dwarf64; + off_t entryOffset = dataReader.Offset(); + uint64 length = dataReader.ReadInitialLength(dwarf64); + + TRACE_CFI("DwarfFile::_ParseFrameSection(): offset: %" B_PRIdOFF + ", length: %" B_PRId64 "\n", entryOffset, length); + + if (length > (uint64)dataReader.BytesRemaining()) + return B_BAD_DATA; + off_t lengthOffset = dataReader.Offset(); + + // CIE ID/CIE pointer + uint64 cieID = dwarf64 + ? dataReader.Read(0) : dataReader.Read(0); + + // In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does. + if (ehFrame + ? cieID == 0 + : (dwarf64 + ? cieID == 0xffffffffffffffffULL + : cieID == 0xffffffff)) { + // this is a CIE -- skip it + } else { + // this is a FDE + uint64 initialLocationOffset = dataReader.Offset(); + // In .eh_frame the CIE offset is a relative back offset. + if (ehFrame) { + if (cieID > (uint64)lengthOffset) { + TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max " + "possible: %" B_PRIu64 "\n", cieID, lengthOffset); + break; + } + // convert to a section relative offset + cieID = lengthOffset - cieID; + } + + + CfaContext context; + CIEAugmentation cieAugmentation; + // when using .eh_frame format, we need to parse the CIE's + // augmentation up front in order to know how the FDE's addresses + // will be represented + DataReader cieReader; + off_t cieRemaining; + status_t error = _ParseCIEHeader(section, ehFrame, NULL, + addressSize, context, cieID, cieAugmentation, cieReader, + cieRemaining); + if (error != B_OK) + return error; + if (cieReader.HasOverflow()) + return B_BAD_DATA; + if (cieRemaining < 0) + return B_BAD_DATA; + + target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress( + dataReader, fElfFile, section); + target_addr_t addressRange = cieAugmentation.ReadEncodedAddress( + dataReader, fElfFile, section, true); + + if (dataReader.HasOverflow()) + return B_BAD_DATA; + + if ((cieAugmentation.FDEAddressType() + & CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) { + initialLocation += initialLocationOffset; + } + + // for unknown reasons, the debug frame sections generated by gcc + // sometimes contain duplicates at different offsets within the + // section. In such a case, simply skip the duplicates. + FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation, + infos); + if (temp == NULL) { + FDELookupInfo* info = new(std::nothrow)FDELookupInfo( + initialLocation, initialLocation + addressRange - 1, + entryOffset, cieID, ehFrame); + if (info == NULL) + return B_NO_MEMORY; + + ObjectDeleter infoDeleter(info); + if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos)) + return B_NO_MEMORY; + + infoDeleter.Detach(); + } + } + + dataReader.SeekAbsolute(lengthOffset + length); + } + + return B_OK; +} + + status_t DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) { @@ -1705,305 +1864,230 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit) status_t -DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit, - uint8 addressSize, DIESubprogram* subprogramEntry, target_addr_t location, - const DwarfTargetInterface* inputInterface, +DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, + DIESubprogram* subprogramEntry, target_addr_t location, + const FDELookupInfo* info, const DwarfTargetInterface* inputInterface, DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) { - ElfSection* currentFrameSection = (usingEHFrameSection) + ElfSection* currentFrameSection = (info->ehFrame) ? fEHFrameSection : fDebugFrameSection; - if (currentFrameSection == NULL) - return B_ENTRY_NOT_FOUND; - - bool gcc4EHFrameSection = false; - if (usingEHFrameSection) { - gcc4EHFrameSection = !currentFrameSection->IsWritable(); - // Crude heuristic for recognizing GCC 4 (Itanium ABI) style - // .eh_frame sections. The ones generated by GCC 2 are writable, - // the ones generated by GCC 4 aren't. - } - TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location); DataReader dataReader((uint8*)currentFrameSection->Data(), currentFrameSection->Size(), unit != NULL ? unit->AddressSize() : addressSize); + dataReader.SeekAbsolute(info->fdeOffset); - while (dataReader.BytesRemaining() > 0) { - // length - bool dwarf64; - TRACE_CFI_ONLY(off_t entryOffset = dataReader.Offset();) - uint64 length = dataReader.ReadInitialLength(dwarf64); + bool dwarf64; + uint64 length = dataReader.ReadInitialLength(dwarf64); + uint64 lengthOffset = dataReader.Offset(); - TRACE_CFI("DwarfFile::_UnwindCallFrame(): offset: %" B_PRIdOFF - ", length: %" B_PRId64 "\n", entryOffset, length); + CfaContext context; + CIEAugmentation cieAugmentation; + // when using .eh_frame format, we need to parse the CIE's + // augmentation up front in order to know how the FDE's addresses + // will be represented + DataReader cieReader; + off_t cieRemaining; + status_t error = _ParseCIEHeader(currentFrameSection, + info->ehFrame, unit, addressSize, context, info->cieOffset, + cieAugmentation, cieReader, cieRemaining); + if (error != B_OK) + return error; + if (cieReader.HasOverflow()) + return B_BAD_DATA; + if (cieRemaining < 0) + return B_BAD_DATA; - if (length > (uint64)dataReader.BytesRemaining()) - return B_BAD_DATA; - off_t lengthOffset = dataReader.Offset(); + uint64 remaining = lengthOffset + length - info->fdeOffset; + if (remaining < 0) + return B_BAD_DATA; - // CIE ID/CIE pointer - uint64 cieID = dwarf64 - ? dataReader.Read(0) : dataReader.Read(0); + // skip CIE ID, initial offset and range, since we already know those + // from FDELookupInfo. + dwarf64 ? dataReader.Read(0) : dataReader.Read(0); + cieAugmentation.ReadEncodedAddress(dataReader, fElfFile, + currentFrameSection); + cieAugmentation.ReadEncodedAddress(dataReader, fElfFile, + currentFrameSection, true); - // In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does. - if (usingEHFrameSection - ? cieID == 0 - : (dwarf64 - ? cieID == 0xffffffffffffffffULL - : cieID == 0xffffffff)) { - // this is a CIE -- skip it - } else { - // this is a FDE - uint64 initialLocationOffset = dataReader.Offset(); - // In .eh_frame the CIE offset is a relative back offset. - if (usingEHFrameSection) { - if (cieID > (uint64)lengthOffset) { - TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max " - "possible: %" B_PRIu64 "\n", cieID, lengthOffset); - break; - } - // convert to a section relative offset - cieID = lengthOffset - cieID; - } + TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF + "), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", " + "range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(), + info->cieOffset, info->start, info->end - info->start); + context.SetLocation(location, info->start); + uint32 registerCount = outputInterface->CountRegisters(); + error = context.Init(registerCount); + if (error != B_OK) + return error; - CfaContext context; - CIEAugmentation cieAugmentation; - // when using .eh_frame format, we need to parse the CIE's - // augmentation up front in order to know how the FDE's addresses - // will be represented - DataReader cieReader; - off_t cieRemaining; - status_t error = _ParseCIEHeader(currentFrameSection, - usingEHFrameSection, unit, addressSize, context, cieID, - cieAugmentation, cieReader, cieRemaining); - if (error != B_OK) - return error; - if (cieReader.HasOverflow()) - return B_BAD_DATA; - if (cieRemaining < 0) - return B_BAD_DATA; + error = outputInterface->InitRegisterRules(context); + if (error != B_OK) + return error; - target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress( - dataReader, fElfFile, currentFrameSection); - target_addr_t addressRange = cieAugmentation.ReadEncodedAddress( - dataReader, fElfFile, currentFrameSection, true); + // process the CIE's frame info instructions + cieReader = cieReader.RestrictedReader(cieRemaining); + error = _ParseFrameInfoInstructions(unit, context, + cieReader, cieAugmentation); + if (error != B_OK) + return error; - if (dataReader.HasOverflow()) - return B_BAD_DATA; - - if ((cieAugmentation.FDEAddressType() - & CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) { - initialLocation += initialLocationOffset; - } - - // TODO: For GCC 2 .eh_frame sections things work differently: The - // initial locations are relocated by the runtime loader and - // afterwards point to the absolute addresses. Fortunately the - // relocations that always seem to be used are R_386_RELATIVE, so - // that the value we read from the file is already absolute - // (assuming an unchanged segment load address). - - TRACE_CFI("location: %" B_PRIx64 ", initial location: %" B_PRIx64 - ", address range: %" B_PRIx64 "\n", location, initialLocation, - addressRange); - - if (location >= initialLocation - && location < initialLocation + addressRange) { - // This is the FDE we're looking for. - off_t remaining = lengthOffset + length - - dataReader.Offset(); - if (remaining < 0) - return B_BAD_DATA; - - TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF - "), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", " - "range: %#" B_PRIx64 "\n", length, remaining, cieID, - initialLocation, addressRange); - - context.SetLocation(location, initialLocation); - uint32 registerCount = outputInterface->CountRegisters(); - error = context.Init(registerCount); - if (error != B_OK) - return error; - - error = outputInterface->InitRegisterRules(context); - if (error != B_OK) - return error; - - // process the CIE's frame info instructions - cieReader = cieReader.RestrictedReader(cieRemaining); - error = _ParseFrameInfoInstructions(unit, context, - cieReader, cieAugmentation); - if (error != B_OK) - return error; - - // read the FDE augmentation data (if any) - FDEAugmentation fdeAugmentation; - error = cieAugmentation.ReadFDEData(dataReader, - fdeAugmentation); - if (error != B_OK) { - TRACE_CFI(" failed to read FDE augmentation data!\n"); - return error; - } - // adjust remaining byte count to take augmentation bytes - // (if any) into account. - remaining = lengthOffset + length - - dataReader.Offset(); - - error = context.SaveInitialRuleSet(); - if (error != B_OK) - return error; - - DataReader restrictedReader = - dataReader.RestrictedReader(remaining); - error = _ParseFrameInfoInstructions(unit, context, - restrictedReader, cieAugmentation); - if (error != B_OK) - return error; - - TRACE_CFI(" found row!\n"); - - // apply the rules of the final row - // get the frameAddress first - target_addr_t frameAddress; - CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule(); - switch (cfaCfaRule->Type()) { - case CFA_CFA_RULE_REGISTER_OFFSET: - { - BVariant value; - if (!inputInterface->GetRegisterValue( - cfaCfaRule->Register(), value) - || !value.IsNumber()) { - return B_UNSUPPORTED; - } - frameAddress = value.ToUInt64() + cfaCfaRule->Offset(); - break; - } - case CFA_CFA_RULE_EXPRESSION: - { - error = EvaluateExpression(unit, addressSize, - subprogramEntry, - cfaCfaRule->Expression().block, - cfaCfaRule->Expression().size, - inputInterface, location, 0, 0, false, - frameAddress); - if (error != B_OK) - return error; - break; - } - case CFA_CFA_RULE_UNDEFINED: - default: - return B_BAD_VALUE; - } - - TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress); - - // apply the register rules - for (uint32 i = 0; i < registerCount; i++) { - TRACE_CFI(" reg %" B_PRIu32 "\n", i); - - uint32 valueType = outputInterface->RegisterValueType(i); - if (valueType == 0) - continue; - - CfaRule* rule = context.RegisterRule(i); - if (rule == NULL) - continue; - - // apply the rule - switch (rule->Type()) { - case CFA_RULE_SAME_VALUE: - { - TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n"); - - BVariant value; - if (inputInterface->GetRegisterValue(i, value)) - outputInterface->SetRegisterValue(i, value); - break; - } - case CFA_RULE_LOCATION_OFFSET: - { - TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %" - B_PRId64 "\n", rule->Offset()); - - BVariant value; - if (inputInterface->ReadValueFromMemory( - frameAddress + rule->Offset(), valueType, - value)) { - outputInterface->SetRegisterValue(i, value); - } - break; - } - case CFA_RULE_VALUE_OFFSET: - TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n"); - - outputInterface->SetRegisterValue(i, - frameAddress + rule->Offset()); - break; - case CFA_RULE_REGISTER: - { - TRACE_CFI(" -> CFA_RULE_REGISTER\n"); - - BVariant value; - if (inputInterface->GetRegisterValue( - rule->Register(), value)) { - outputInterface->SetRegisterValue(i, value); - } - break; - } - case CFA_RULE_LOCATION_EXPRESSION: - { - TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n"); - - target_addr_t address; - error = EvaluateExpression(unit, addressSize, - subprogramEntry, - rule->Expression().block, - rule->Expression().size, - inputInterface, location, frameAddress, - frameAddress, true, address); - BVariant value; - if (error == B_OK - && inputInterface->ReadValueFromMemory(address, - valueType, value)) { - outputInterface->SetRegisterValue(i, value); - } - break; - } - case CFA_RULE_VALUE_EXPRESSION: - { - TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n"); - - target_addr_t value; - error = EvaluateExpression(unit, addressSize, - subprogramEntry, - rule->Expression().block, - rule->Expression().size, - inputInterface, location, frameAddress, - frameAddress, true, value); - if (error == B_OK) - outputInterface->SetRegisterValue(i, value); - break; - } - case CFA_RULE_UNDEFINED: - TRACE_CFI(" -> CFA_RULE_UNDEFINED\n"); - default: - break; - } - } - - _framePointer = frameAddress; - return B_OK; - } - } - - dataReader.SeekAbsolute(lengthOffset + length); + // read the FDE augmentation data (if any) + FDEAugmentation fdeAugmentation; + error = cieAugmentation.ReadFDEData(dataReader, + fdeAugmentation); + if (error != B_OK) { + TRACE_CFI(" failed to read FDE augmentation data!\n"); + return error; } - return B_ENTRY_NOT_FOUND; + error = context.SaveInitialRuleSet(); + if (error != B_OK) + return error; + + DataReader restrictedReader = + dataReader.RestrictedReader(remaining); + error = _ParseFrameInfoInstructions(unit, context, + restrictedReader, cieAugmentation); + if (error != B_OK) + return error; + + TRACE_CFI(" found row!\n"); + + // apply the rules of the final row + // get the frameAddress first + target_addr_t frameAddress; + CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule(); + switch (cfaCfaRule->Type()) { + case CFA_CFA_RULE_REGISTER_OFFSET: + { + BVariant value; + if (!inputInterface->GetRegisterValue( + cfaCfaRule->Register(), value) + || !value.IsNumber()) { + return B_UNSUPPORTED; + } + frameAddress = value.ToUInt64() + cfaCfaRule->Offset(); + break; + } + case CFA_CFA_RULE_EXPRESSION: + { + error = EvaluateExpression(unit, addressSize, + subprogramEntry, + cfaCfaRule->Expression().block, + cfaCfaRule->Expression().size, + inputInterface, location, 0, 0, false, + frameAddress); + if (error != B_OK) + return error; + break; + } + case CFA_CFA_RULE_UNDEFINED: + default: + return B_BAD_VALUE; + } + + TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress); + + // apply the register rules + for (uint32 i = 0; i < registerCount; i++) { + TRACE_CFI(" reg %" B_PRIu32 "\n", i); + + uint32 valueType = outputInterface->RegisterValueType(i); + if (valueType == 0) + continue; + + CfaRule* rule = context.RegisterRule(i); + if (rule == NULL) + continue; + + // apply the rule + switch (rule->Type()) { + case CFA_RULE_SAME_VALUE: + { + TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n"); + + BVariant value; + if (inputInterface->GetRegisterValue(i, value)) + outputInterface->SetRegisterValue(i, value); + break; + } + case CFA_RULE_LOCATION_OFFSET: + { + TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %" + B_PRId64 "\n", rule->Offset()); + + BVariant value; + if (inputInterface->ReadValueFromMemory( + frameAddress + rule->Offset(), valueType, + value)) { + outputInterface->SetRegisterValue(i, value); + } + break; + } + case CFA_RULE_VALUE_OFFSET: + TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n"); + + outputInterface->SetRegisterValue(i, + frameAddress + rule->Offset()); + break; + case CFA_RULE_REGISTER: + { + TRACE_CFI(" -> CFA_RULE_REGISTER\n"); + + BVariant value; + if (inputInterface->GetRegisterValue( + rule->Register(), value)) { + outputInterface->SetRegisterValue(i, value); + } + break; + } + case CFA_RULE_LOCATION_EXPRESSION: + { + TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n"); + + target_addr_t address; + error = EvaluateExpression(unit, addressSize, + subprogramEntry, + rule->Expression().block, + rule->Expression().size, + inputInterface, location, frameAddress, + frameAddress, true, address); + BVariant value; + if (error == B_OK + && inputInterface->ReadValueFromMemory(address, + valueType, value)) { + outputInterface->SetRegisterValue(i, value); + } + break; + } + case CFA_RULE_VALUE_EXPRESSION: + { + TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n"); + + target_addr_t value; + error = EvaluateExpression(unit, addressSize, + subprogramEntry, + rule->Expression().block, + rule->Expression().size, + inputInterface, location, frameAddress, + frameAddress, true, value); + if (error == B_OK) + outputInterface->SetRegisterValue(i, value); + break; + } + case CFA_RULE_UNDEFINED: + TRACE_CFI(" -> CFA_RULE_UNDEFINED\n"); + default: + break; + } + } + + _framePointer = frameAddress; + + return B_OK; } @@ -2842,3 +2926,40 @@ DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const CompilationUnit* unit = fCompilationUnits.ItemAt(lower); return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL; } + + +DwarfFile::FDELookupInfo* +DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const +{ + FDELookupInfo* info = NULL; + if (fDebugFrameSection != NULL) { + info = _GetContainingFDEInfo(offset, fDebugFrameInfos); + if (info != NULL) + return info; + } + + return _GetContainingFDEInfo(offset, fEHFrameInfos); +} + + +DwarfFile::FDELookupInfo* +DwarfFile::_GetContainingFDEInfo(target_addr_t offset, + const FDEInfoList& infoList) const +{ + // binary search + int lower = 0; + int upper = infoList.CountItems() - 1; + if (upper < 0) + return NULL; + + while (lower < upper) { + int mid = (lower + upper + 1) / 2; + if (offset < infoList.ItemAt(mid)->start) + upper = mid - 1; + else + lower = mid; + } + + FDELookupInfo* info = infoList.ItemAt(lower); + return info->ContainsAddress(offset) ? info : NULL; +} diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index b778383c80..f43c23fb50 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -37,7 +37,8 @@ public: status_t StartLoading(const char* fileName, BString& _requiredExternalFile); - status_t Load(const BString& externalFilePath); + status_t Load(uint8 addressSize, + const BString& externalFilePath); status_t FinishLoading(); const char* Name() const { return fName; } @@ -108,14 +109,19 @@ private: struct ExpressionEvaluationContext; struct FDEAugmentation; struct CIEAugmentation; + struct FDELookupInfo; typedef DoublyLinkedList AbbreviationTableList; typedef BObjectList CompilationUnitList; typedef BOpenHashTable TypeUnitTable; + typedef BObjectList FDEInfoList; private: status_t _ParseDebugInfoSection(); status_t _ParseTypesSection(); + status_t _ParseFrameSection(ElfSection* section, + uint8 addressSize, bool ehFrame, + FDEInfoList& infos); status_t _ParseCompilationUnit(CompilationUnit* unit); status_t _ParseTypeUnit(TypeUnit* unit); status_t _ParseDebugInfoEntry(DataReader& dataReader, @@ -131,11 +137,11 @@ private: status_t _ParseLineInfo(CompilationUnit* unit); - status_t _UnwindCallFrame(bool usingEHFrameSection, - CompilationUnit* unit, + status_t _UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, DIESubprogram* subprogramEntry, target_addr_t location, + const FDELookupInfo* info, const DwarfTargetInterface* inputInterface, DwarfTargetInterface* outputInterface, target_addr_t& _framePointer); @@ -185,6 +191,13 @@ private: CompilationUnit* _GetContainingCompilationUnit( off_t refAddr) const; + FDELookupInfo* _GetContainingFDEInfo( + target_addr_t offset) const; + + FDELookupInfo* _GetContainingFDEInfo( + target_addr_t offset, + const FDEInfoList& infoList) const; + private: friend class DwarfFile::ExpressionEvaluationContext; @@ -207,8 +220,11 @@ private: DebugInfoEntryFactory fDebugInfoFactory; CompilationUnitList fCompilationUnits; TypeUnitTable fTypeUnits; + FDEInfoList fDebugFrameInfos; + FDEInfoList fEHFrameInfos; bool fTypesSectionRequired; bool fFinished; + bool fItaniumEHFrameFormat; status_t fFinishError; }; diff --git a/src/apps/debugger/dwarf/DwarfManager.cpp b/src/apps/debugger/dwarf/DwarfManager.cpp index 4f033da0c3..9f36611e8c 100644 --- a/src/apps/debugger/dwarf/DwarfManager.cpp +++ b/src/apps/debugger/dwarf/DwarfManager.cpp @@ -15,8 +15,9 @@ #include "DwarfFileLoadingState.h" -DwarfManager::DwarfManager() +DwarfManager::DwarfManager(uint8 addressSize) : + fAddressSize(addressSize), fLock("dwarf manager") { } @@ -65,7 +66,7 @@ DwarfManager::LoadFile(const char* fileName, DwarfFileLoadingState& _state) } } - error = file->Load(_state.locatedExternalInfoPath); + error = file->Load(fAddressSize, _state.locatedExternalInfoPath); if (error != B_OK) { _state.state = DWARF_FILE_LOADING_STATE_FAILED; return error; diff --git a/src/apps/debugger/dwarf/DwarfManager.h b/src/apps/debugger/dwarf/DwarfManager.h index 375402fc22..c15285c88b 100644 --- a/src/apps/debugger/dwarf/DwarfManager.h +++ b/src/apps/debugger/dwarf/DwarfManager.h @@ -17,7 +17,7 @@ struct DwarfFileLoadingState; class DwarfManager { public: - DwarfManager(); + DwarfManager(uint8 addressSize); ~DwarfManager(); status_t Init(); @@ -36,6 +36,7 @@ private: typedef DoublyLinkedList FileList; private: + uint8 fAddressSize; BLocker fLock; FileList fFiles; };