diff options
| author | Rene Gollent <anevilyak@gmail.com> | 2012-07-11 21:56:15 -0400 |
|---|---|---|
| committer | Rene Gollent <anevilyak@gmail.com> | 2012-07-11 21:56:15 -0400 |
| commit | c4120026a5c8c365a57917ea923779c07df9aea0 (patch) | |
| tree | b71468a387d337e64f3e835d6d65ebe05f0f6eb8 | |
| parent | dfa21dfeabe22cd7df5de50e21bf1ad3678454b8 (diff) | |
Refactor previous commit.hrev44317
- Keep knowledge of the existence and need to search the different
frame sections contained within DwarfFile.
| -rw-r--r-- | src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp | 17 | ||||
| -rw-r--r-- | src/apps/debugger/dwarf/DwarfFile.cpp | 577 | ||||
| -rw-r--r-- | src/apps/debugger/dwarf/DwarfFile.h | 18 |
3 files changed, 311 insertions, 301 deletions
diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index f24f9b1299..4a9b5c5af6 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -555,21 +555,8 @@ DwarfImageDebugInfo::CreateFrame(Image* image, = cpuState->InstructionPointer() - fRelocationDelta; target_addr_t framePointer; CompilationUnit* unit = function->GetCompilationUnit(); - // first try .debug_frame - if (fFile->HasDebugFrameSection()) { - error = fFile->UnwindCallFrame(false, unit, - function->SubprogramEntry(), instructionPointer, inputInterface, - outputInterface, framePointer); - } else - error = B_ENTRY_NOT_FOUND; - - // if that section isn't present, or we couldn't find a match, - // try .eh_frame if possible. - if (error == B_ENTRY_NOT_FOUND && fFile->HasEHFrameSection()) { - error = fFile->UnwindCallFrame(true, unit, - function->SubprogramEntry(), instructionPointer, inputInterface, - outputInterface, framePointer); - } + error = fFile->UnwindCallFrame(unit, function->SubprogramEntry(), + instructionPointer, inputInterface, outputInterface, framePointer); if (error != B_OK) { TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error)); diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index aee71b4ce9..f07f10ae2a 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -535,292 +535,27 @@ DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const status_t -DwarfFile::UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit, +DwarfFile::UnwindCallFrame(CompilationUnit* unit, DIESubprogram* subprogramEntry, target_addr_t location, const DwarfTargetInterface* inputInterface, DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) { - ElfSection* currentFrameSection = (usingEHFrameSection) - ? fEHFrameSection : fDebugFrameSection; - - if (currentFrameSection == NULL) - return B_ENTRY_NOT_FOUND; + status_t result = 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. + // first try to find the FDE in .debug_frame + if (fDebugFrameSection != NULL) { + result = _UnwindCallFrame(false, unit, subprogramEntry, location, + inputInterface, outputInterface, _framePointer); } - - - TRACE_CFI("DwarfFile::UnwindCallFrame(%#llx)\n", location); - - DataReader dataReader((uint8*)currentFrameSection->Data(), - currentFrameSection->Size(), unit->AddressSize()); - - while (dataReader.BytesRemaining() > 0) { - // length - bool dwarf64; - TRACE_CFI_ONLY(off_t entryOffset = dataReader.Offset();) - uint64 length = dataReader.ReadInitialLength(dwarf64); - - TRACE_CFI("DwarfFile::UnwindCallFrame(): 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<uint64>(0) : dataReader.Read<uint32>(0); - - // 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(); - target_addr_t initialLocation = dataReader.ReadAddress(0); - target_size_t addressRange = dataReader.ReadAddress(0); - - if (dataReader.HasOverflow()) - return B_BAD_DATA; - - // In the GCC 4 .eh_frame initialLocation is relative to the offset - // of the address. - if (usingEHFrameSection && gcc4EHFrameSection) { - // Note: We need to cast to the exact address width, since the - // initialLocation value can be (and likely is) negative. - if (dwarf64) { - initialLocation = (uint64)currentFrameSection - ->LoadAddress() + (uint64)initialLocationOffset - + (uint64)initialLocation; - } else { - initialLocation = (uint32)currentFrameSection - ->LoadAddress() + (uint32)initialLocationOffset - + (uint32)initialLocation; - } - } - // 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; - - // 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: %llu (%lld), CIE offset: %#llx, " - "location: %#llx, range: %#llx\n", length, remaining, cieID, - initialLocation, addressRange); - - CfaContext context(location, initialLocation); - uint32 registerCount = outputInterface->CountRegisters(); - status_t error = context.Init(registerCount); - if (error != B_OK) - return error; - - error = outputInterface->InitRegisterRules(context); - if (error != B_OK) - return error; - - // process the CIE - CIEAugmentation cieAugmentation; - error = _ParseCIE(currentFrameSection, usingEHFrameSection, - unit, context, cieID, 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); - 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, 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: %#llx\n", frameAddress); - - // apply the register rules - for (uint32 i = 0; i < registerCount; i++) { - TRACE_CFI(" reg %lu\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: %lld\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, 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, 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); + // 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, subprogramEntry, location, + inputInterface, outputInterface, _framePointer); } - return B_ENTRY_NOT_FOUND; + return result; } @@ -1550,6 +1285,294 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit) status_t +DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit, + DIESubprogram* subprogramEntry, target_addr_t location, + const DwarfTargetInterface* inputInterface, + DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) +{ + ElfSection* currentFrameSection = (usingEHFrameSection) + ? 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(%#llx)\n", location); + + DataReader dataReader((uint8*)currentFrameSection->Data(), + currentFrameSection->Size(), unit->AddressSize()); + + while (dataReader.BytesRemaining() > 0) { + // length + bool dwarf64; + TRACE_CFI_ONLY(off_t entryOffset = dataReader.Offset();) + uint64 length = dataReader.ReadInitialLength(dwarf64); + + TRACE_CFI("DwarfFile::_UnwindCallFrame(): 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<uint64>(0) : dataReader.Read<uint32>(0); + + // 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(); + target_addr_t initialLocation = dataReader.ReadAddress(0); + target_size_t addressRange = dataReader.ReadAddress(0); + + if (dataReader.HasOverflow()) + return B_BAD_DATA; + + // In the GCC 4 .eh_frame initialLocation is relative to the offset + // of the address. + if (usingEHFrameSection && gcc4EHFrameSection) { + // Note: We need to cast to the exact address width, since the + // initialLocation value can be (and likely is) negative. + if (dwarf64) { + initialLocation = (uint64)currentFrameSection + ->LoadAddress() + (uint64)initialLocationOffset + + (uint64)initialLocation; + } else { + initialLocation = (uint32)currentFrameSection + ->LoadAddress() + (uint32)initialLocationOffset + + (uint32)initialLocation; + } + } + // 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; + + // 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: %llu (%lld), CIE offset: %#llx, " + "location: %#llx, range: %#llx\n", length, remaining, cieID, + initialLocation, addressRange); + + CfaContext context(location, initialLocation); + uint32 registerCount = outputInterface->CountRegisters(); + status_t error = context.Init(registerCount); + if (error != B_OK) + return error; + + error = outputInterface->InitRegisterRules(context); + if (error != B_OK) + return error; + + // process the CIE + CIEAugmentation cieAugmentation; + error = _ParseCIE(currentFrameSection, usingEHFrameSection, + unit, context, cieID, 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); + 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, 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: %#llx\n", frameAddress); + + // apply the register rules + for (uint32 i = 0; i < registerCount; i++) { + TRACE_CFI(" reg %lu\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: %lld\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, 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, 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); + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection, CompilationUnit* unit, CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation) diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index a7afede41f..b7d53b8351 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -39,13 +39,6 @@ public: const char* Name() const { return fName; } ElfFile* GetElfFile() const { return fElfFile; } - bool HasDebugFrameSection() const { - return fDebugFrameSection != NULL; - } - bool HasEHFrameSection() const { - return fEHFrameSection != NULL; - } - int32 CountCompilationUnits() const; CompilationUnit* CompilationUnitAt(int32 index) const; CompilationUnit* CompilationUnitForDIE( @@ -54,8 +47,7 @@ public: TargetAddressRangeList* ResolveRangeList(CompilationUnit* unit, uint64 offset) const; - status_t UnwindCallFrame(bool usingEHFrameSection, - CompilationUnit* unit, + status_t UnwindCallFrame(CompilationUnit* unit, DIESubprogram* subprogramEntry, target_addr_t location, const DwarfTargetInterface* inputInterface, @@ -121,6 +113,14 @@ private: status_t _ParseLineInfo(CompilationUnit* unit); + status_t _UnwindCallFrame(bool usingEHFrameSection, + CompilationUnit* unit, + DIESubprogram* subprogramEntry, + target_addr_t location, + const DwarfTargetInterface* inputInterface, + DwarfTargetInterface* outputInterface, + target_addr_t& _framePointer); + status_t _ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection, CompilationUnit* unit, |
