From 7f341cbe68222d10e54e54dd70bfad91bd12d9a7 Mon Sep 17 00:00:00 2001 From: ccrause Date: Sun, 4 Jul 2021 08:42:34 +0200 Subject: [PATCH] Tweak PrepareCallStackEntryList to cater for avr-gcc ABI. Added TAvrAsmDecoder.GetFunctionFrameReturnAddress to scan prologue and epilogue for frame information. --- components/fpdebug/fpdbgavrclasses.pas | 66 ++-- components/fpdebug/fpdbgdisasavr.pp | 409 +++++++++++++++++++++---- 2 files changed, 374 insertions(+), 101 deletions(-) diff --git a/components/fpdebug/fpdbgavrclasses.pas b/components/fpdebug/fpdbgavrclasses.pas index 0d7490e577..c192a14718 100644 --- a/components/fpdebug/fpdbgavrclasses.pas +++ b/components/fpdebug/fpdbgavrclasses.pas @@ -167,7 +167,7 @@ var implementation uses - FpDbgDisasAvr; + FpDbgDisasAvr, FpDbgDwarfDataClasses, FpDbgInfo; var DBG_VERBOSE, DBG_WARNINGS: PLazLoggerLogGroup; @@ -499,21 +499,24 @@ const MAX_FRAMES = 50000; // safety net // Use fake dwarf indexes, these seem to be for lookup in RegisterValueList only? PC = 0; - BP = 1; + FP = 1; SP = 2; nPC = 'PC'; - nBP = 'BP'; + nFP = 'FP'; nSP = 'SP'; + // To read RAM, add data space offset to address DataOffset = $800000; Size = 2; var - Address, FrameBase, LastFrameBase: QWord; + Address, FrameBase, LastFrameBase: TDBGPtr; CountNeeded, CodeReadErrCnt: integer; AnEntry: TDbgCallstackEntry; R: TDbgRegisterValue; NextIdx: LongInt; OutSideFrame: Boolean; StackPtr: TDBGPtr; + startPC, endPC: TDBGPtr; + returnAddrStackOffset: word; begin // TODO: use AFrameRequired // check if already partly done if FCallStackEntryList = nil then @@ -530,7 +533,7 @@ begin R := AnEntry.RegisterValueList.FindRegisterByDwarfIndex(PC); if R = nil then exit; Address := R.NumValue; - R := AnEntry.RegisterValueList.FindRegisterByDwarfIndex(BP); + R := AnEntry.RegisterValueList.FindRegisterByDwarfIndex(FP); if R = nil then exit; FrameBase := R.NumValue; R := AnEntry.RegisterValueList.FindRegisterByDwarfIndex(SP); @@ -544,7 +547,7 @@ begin AnEntry := TDbgCallstackEntry.create(Self, 0, FrameBase, Address); // Top level could be without entry in registerlist / same as GetRegisterValueList / but some code tries to find it here .... AnEntry.RegisterValueList.DbgRegisterAutoCreate[nPC].SetValue(Address, IntToStr(Address),Size, PC); - AnEntry.RegisterValueList.DbgRegisterAutoCreate[nBP].SetValue(FrameBase, IntToStr(FrameBase),Size, BP); + AnEntry.RegisterValueList.DbgRegisterAutoCreate[nFP].SetValue(FrameBase, IntToStr(FrameBase),Size, FP); AnEntry.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPtr, IntToStr(StackPtr),Size, SP); FCallStackEntryList.Add(AnEntry); end; @@ -557,48 +560,45 @@ begin CodeReadErrCnt := 0; while (CountNeeded > 0) and (FrameBase <> 0) and (FrameBase > LastFrameBase) do begin - if not Process.Disassembler.GetFunctionFrameInfo(Address, OutSideFrame) then begin - if Process.Disassembler.LastErrorWasMemReadErr then begin - inc(CodeReadErrCnt); - if CodeReadErrCnt > 5 then break; // If the code cannot be read the stack pointer is wrong. - end; + // Get start/end PC of proc from debug info + if not Self.Process.FindProcStartEndPC(Address, startPC, endPC) then + begin + startPC := 0; + endPC := 0; + end; + + if not TAvrAsmDecoder(Process.Disassembler).GetFunctionFrameReturnAddress(Address, startPC, endPC, returnAddrStackOffset, OutSideFrame) then + begin OutSideFrame := False; end; LastFrameBase := FrameBase; - if (not OutSideFrame) and (NextIdx = 1) and (AnEntry.ProcSymbol <> nil) then begin - OutSideFrame := Address = LocToAddrOrNil(AnEntry.ProcSymbol.Address); // the top frame must be outside frame, if it is at entrypoint / needed for exceptions - end; - if OutSideFrame then begin - // at start of prologue, before pushing starts, so return PC should be at current SP+1 - // To read SRAM this needs to be masked by $800000 - if not Process.ReadData(DataOffset or (StackPtr + Size), Size, Address) or (Address = 0) then Break; - // Convert return address from BE to LE, shl 1 to get byte address - Address := BEtoN(word(Address)) shl 1; - {$PUSH}{$R-}{$Q-} - StackPtr := StackPtr + 1 * Size + 1; // After popping return-addr from "StackPtr" - LastFrameBase := LastFrameBase - 1; // Make the loop think thas LastFrameBase was smaller - {$POP} + // Before adjustment of frame pointer, or after restoration of frame pointer, + // return PC should be located by offset from SP + if not Process.ReadData(DataOffset or (StackPtr + returnAddrStackOffset), Size, Address) or (Address = 0) then Break; end else begin - // Need to add localsize and saved register count to frame pointer (Y) to locate saved return PC - break; - //{$PUSH}{$R-}{$Q-} - //StackPtr := FrameBase + 2 * Size; // After popping return-addr from "FrameBase + Size" - //{$POP} - //if not Process.ReadData(DataOffset or (FrameBase + Size), Size, Address) or (Address = 0) then Break; - //if not Process.ReadData(DataOffset or FrameBase, Size, FrameBase) then Break; + // Inside stack frame, return PC should be located by offset from FP + if not Process.ReadData(DataOffset or (FrameBase + returnAddrStackOffset), Size, Address) or (Address = 0) then Break; end; + // Convert return address from BE to LE, shl 1 to get byte address + Address := BEtoN(word(Address)) shl 1; + {$PUSH}{$R-}{$Q-} + StackPtr := FrameBase + returnAddrStackOffset + Size; // After popping return-addr from "StackPtr" + FrameBase := StackPtr; // Estimate of previous FP + LastFrameBase := LastFrameBase - 1; // Make the loop think that LastFrameBase was smaller + {$POP} + AnEntry := TDbgCallstackEntry.create(Self, NextIdx, FrameBase, Address); AnEntry.RegisterValueList.DbgRegisterAutoCreate[nPC].SetValue(Address, IntToStr(Address),Size, PC); - AnEntry.RegisterValueList.DbgRegisterAutoCreate[nBP].SetValue(FrameBase, IntToStr(FrameBase),Size, BP); + AnEntry.RegisterValueList.DbgRegisterAutoCreate[nFP].SetValue(FrameBase, IntToStr(FrameBase),Size, FP); AnEntry.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPtr, IntToStr(StackPtr),Size, SP); FCallStackEntryList.Add(AnEntry); Dec(CountNeeded); inc(NextIdx); CodeReadErrCnt := 0; - If (NextIdx > MAX_FRAMES) then + if (NextIdx > MAX_FRAMES) then break; end; if CountNeeded > 0 then // there was an error / not possible to read more frames diff --git a/components/fpdebug/fpdbgdisasavr.pp b/components/fpdebug/fpdbgdisasavr.pp index fdbd877cda..e6a603b8ab 100644 --- a/components/fpdebug/fpdbgdisasavr.pp +++ b/components/fpdebug/fpdbgdisasavr.pp @@ -74,11 +74,17 @@ type TAvrAsmDecoder = class(TDbgAsmDecoder) private const MAX_CODEBIN_LEN = 20*2; // About 20 instructions + MaxPrologueSize = 64; // Bytes, so ~32 instructions + MaxEpilogueSize = MaxPrologueSize; // Perhaps a bit smaller, since the locals/parameters do not have to be initialized private FProcess: TDbgProcess; FLastErrWasMem: Boolean; FCodeBin: array[0..MAX_CODEBIN_LEN-1] of byte; FLastInstr: TAvrAsmInstruction; + function FParsePrologue(AnAddress, AStartPC, AEndPC: TDBGPtr; out + returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean; + function FParseEpilogue(AnAddress, AStartPC, AEndPC: TDBGPtr; out + returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean; protected function GetLastErrorWasMemReadErr: Boolean; override; function GetMaxInstrSize: integer; override; @@ -90,10 +96,17 @@ type procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); override; function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; override; - // returns byte len of call instruction at AAddress // 0 if not a call intruction + // Don't use, ot really suited to AVR ABI function GetFunctionFrameInfo(AnAddress: TDBGPtr; out AnIsOutsideFrame: Boolean): Boolean; override; + // Rather use the next function to locate the call return address. + // AStartPC & AEndPC indicates proc limits to help with scanning for prologue/epilogue + // returnAddressOffset gives the offset to return address relative to Y pointer (r28:r29) inside frame + // else returnAddressOffset gives the offset to return address relative to SP + function GetFunctionFrameReturnAddress(AnAddress, AStartPC, AEndPC: TDBGPtr; out + returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean; + constructor Create(AProcess: TDbgProcess); override; destructor Destroy; end; @@ -102,7 +115,10 @@ type implementation uses - StrUtils, LazClasses; + StrUtils, LazClasses, Math; + +var + DBG_WARNINGS: PLazLoggerLogGroup; const opRegReg = '%s r%d, r%d'; @@ -128,6 +144,28 @@ const branchIfSetNames: array[0..7] of string = ('brcs', 'breq', 'brmi', 'brvs', 'brlt', 'brhs', 'brts', 'brie'); branchIfClrNames: array[0..7] of string = ('brcc', 'brne', 'brpl', 'brvc', 'brge', 'brhc', 'brtc', 'brid'); + OpCodeNOP = $0000; + OpCodeLoadSPL = $B7CD; // in r28, 0x3d + OpCodeLoadSPH = $B7DE; // in r29, 0x3e + OpCodeLoadSRegR0 = $B60F; // in r0, 0x3f + OpCodeLoadSRegR16 = $B70F; // in r16, 0x3f, avrtiny subarch + OpCodeCli = $94F8; // cli + OpCodeSetSPH = $BFDE; // out 0x3e, r29 + OpCodeSetSPL = $BFCD; // out 0x3d, r28 + OpCodeSetSregR0 = $BE0F; // out 0x3f, r0 + OpCodeSetSregR16 = $BF0F; // out 0x3f, r16 + OpCodeRet = $9508; // ret + OpCodeReti = $9518; // reti + + OpCodePushMask = $920F; // PUSH 1001 001d dddd 1111 + OpCodePopMask = $900F; // POP 1001 000d dddd 1111 + // Frame pointer is r28:r29, so fix register index in opcode + OpCodeAdjustFrameLMask = $50C0; // subi r28, k, 0101 kkkk dddd kkkk, rd = 16 + d + OpCodeAdjustFrameHMask = $40D0; // sbci r28, k, 0100 kkkk dddd kkkk, rd = 16 + d + // Not yet implemented in FPC, but more compact option + OpCodeAdjustFrameMask = $9720; // sbiw r28, k, 1001 0111 kkdd kkkk, rd = 24 + d*2 + OpCodeStoreOnStackMask = $8208; // std Y+2, r24 10q0 qq1r rrrr 1qqq + procedure get_r_d_10(o: word; out r, d: byte); begin r := ((o shr 5) and $10) or (o and $f); @@ -214,6 +252,272 @@ begin Result := 4; end; +type + TPrologueState = (psStart, psPush, psLoadSPL, psLoadSPH, psLoadSreg, + psModifySPL, psModifySPH, psWriteSPH, psWriteSreg, psWriteSPL, psCopyParams); + +function TAvrAsmDecoder.FParsePrologue(AnAddress, AStartPC, AEndPC: TDBGPtr; + out returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean; +var + ADataLen: Cardinal; + AData: PByte; + opcode, frameOffset: word; + d, k: byte; + stackState: TPrologueState; +begin +{ AVR function entry example + 3e: df 93 push r29 + 40: cf 93 push r28 + 42: 3f 92 push r3 + 44: 2f 92 push r2 + + // Load SP and calculate BP + 46: cd b7 in r28, 0x3d ; 61 // SPL + 48: de b7 in r29, 0x3e ; 62 // SPH + 4a: c6 50 subi r28, 0x06 ; 6 + 4c: d0 40 sbci r29, 0x00 ; 0 + // Disable interrupts + 4e: 0f b6 in r0, 0x3f ; 63 + 50: f8 94 cli + // Then write out new SP + 52: de bf out 0x3e, r29 ; 62 + // Interleaved with restoring SREG + 54: 0f be out 0x3f, r0 ; 63 + 56: cd bf out 0x3d, r28 ; 61 + // Copy param to stack + 58: 8a 83 std Y+2, r24 ; 0x02 + 5a: 9b 83 std Y+3, r25 ; 0x03 +} + + ADataLen := Min(MaxPrologueSize, AnAddress - AStartPC); + Result := ReadCodeAt(AStartPC, ADataLen); + if not Result then + exit; + + AData := @FCodeBin[0]; + // SP points to next empty slot, previous data is before current SP + returnAddressOffset := 1; + AnIsOutsideFrame := true; + stackState := psStart; + frameOffset := 0; + + // Loop until prologue buffer is empty, or stepped inside stack frame + while (ADataLen > 1) and AnIsOutsideFrame do + begin + opcode := AData[0] or (AData[1] shl 8); + inc(AData, 2); + dec(ADataLen, 2); + + case opcode of + OpCodeNOP: ; + OpCodeLoadSPL: stackState := psLoadSPL; + OpCodeLoadSPH: stackState := psLoadSPH; + OpCodeLoadSRegR0, OpCodeLoadSRegR16: stackState := psLoadSreg; + OpCodeCli: ; + OpCodeSetSPH: stackState := psWriteSPH; + OpCodeSetSregR0, OpCodeSetSregR16: stackState := psWriteSreg; + OpCodeSetSPL: stackState := psWriteSPL; + else + // Push a register onto stack + if (opcode and OpCodePushMask) = OpCodePushMask then + begin + if stackState <= psPush then + begin + inc(returnAddressOffset); + stackState := psPush; + end + else + DebugLn(DBG_WARNINGS, ['Invalid stack state for PUSH opcode: ', stackState]); + end + else if (opcode and OpCodeAdjustFrameLMask) = OpCodeAdjustFrameLMask then + begin + if stackState >= psLoadSPH then + begin + stackState := psModifySPL; + // Decode register and constant + get_k_r16(opcode, d, k); + frameOffset := frameOffset + k; + end + else + DebugLn(DBG_WARNINGS, ['Invalid stack state for OpCodeAdjustFrameLMask opcode: ', stackState]); + end + else if (opcode and OpCodeAdjustFrameHMask) = OpCodeAdjustFrameHMask then + begin + if stackState >= psLoadSPH then + begin + stackState := psModifySPH; + // Decode register and constant + get_k_r16(opcode, d, k); + frameOffset := frameOffset + (k shl 8); + end + else + DebugLn(DBG_WARNINGS, ['Invalid stack state for OpCodeAdjustFrameHMask opcode: ', stackState]); + end + else if (opcode and OpCodeAdjustFrameMask) = OpCodeAdjustFrameMask then + begin + if stackState >= psLoadSPH then + begin + stackState := psModifySPH; + // Decode constant in SBIW opcode + k := ((opcode and $00c0) shr 2) or (opcode and $f); + frameOffset := frameOffset + k; + end + else + DebugLn(DBG_WARNINGS, ['Invalid stack state for OpCodeAdjustFrameMask opcode: ', stackState]); + end + else if (opcode and OpCodeStoreOnStackMask) = OpCodeStoreOnStackMask then + begin + if stackState >= psWriteSPL then + begin + stackState := psCopyParams; + end + else + DebugLn(DBG_WARNINGS, ['Invalid stack state for OpCodeStoreOnStackMask opcode: ', stackState]); + end + else // Any other opcode isn't part of prologue + begin + AnIsOutsideFrame := false; + end; + end; + end; + + // Check if frame pointer was updated + if (stackState >= psWriteSPL) and (frameOffset > 0) then + begin + AnIsOutsideFrame := false; + returnAddressOffset := returnAddressOffset + frameOffset; + end + else + AnIsOutsideFrame := true; +end; + +type + // State sequence runs in reverse direction + TEpilogueState = (esStart, esRet, esPop, esWriteSPH, esWriteSreg, esWriteSPL, + esLoadSreg, esModifyFPH, esModifyFPL); + +function TAvrAsmDecoder.FParseEpilogue(AnAddress, AStartPC, AEndPC: TDBGPtr; + out returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean; +var + ADataLen: Cardinal; + AData: PByte; + opcode, frameOffset: word; + d, k: byte; + stackState: TEpilogueState; +begin +{ AVR function epilogue example + // Move FP to previous frame + ba: cd 5f subi r28, 0xFD ; 253 + bc: df 4f sbci r29, 0xFF ; 255 + + // Update SP + be: 0f b6 in r0, 0x3f ; 63 + c0: f8 94 cli + c2: de bf out 0x3e, r29 ; 62 + c4: 0f be out 0x3f, r0 ; 63 + c6: cd bf out 0x3d, r28 ; 61 + + // Restore saved regs + c8: cf 91 pop r28 + ca: df 91 pop r29 + cc: 08 95 ret +} + + ADataLen := Min(MaxEpilogueSize, AEndPC - AnAddress); + Result := ReadCodeAt(AEndPC - ADataLen, ADataLen); + if not Result then + exit; + + AData := @FCodeBin[ADataLen - 2]; + // SP points to next empty slot, previous data is before current SP + returnAddressOffset := 1; + AnIsOutsideFrame := true; + stackState := esStart; + frameOffset := 0; + + // Loop until epilogue buffer is empty, or stepped inside stack frame + while (ADataLen > 1) and AnIsOutsideFrame do + begin + opcode := AData[0] or (AData[1] shl 8); + dec(AData, 2); + dec(ADataLen, 2); + + case opcode of + OpCodeNOP: ; + OpCodeLoadSRegR0, OpCodeLoadSRegR16: stackState := esLoadSreg; + OpCodeCli: ; + OpCodeSetSPH: stackState := esWriteSPH; + OpCodeSetSregR0, OpCodeSetSregR16: stackState := esWriteSreg; + OpCodeSetSPL: stackState := esWriteSPL; + OpCodeRet, OpCodeReti: stackState := esRet; + else + // Push a register onto stack + if (opcode and OpCodePopMask) = OpCodePopMask then + begin + if stackState <= esPop then + begin + inc(returnAddressOffset); + stackState := esPop; + end + else + DebugLn(DBG_WARNINGS, ['Invalid stack state for POP opcode: ', stackState]); + end + else if (opcode and OpCodeAdjustFrameLMask) = OpCodeAdjustFrameLMask then + begin + if stackState < esModifyFPL then + begin + stackState := esModifyFPL; + // Decode register and constant + get_k_r16(opcode, d, k); + // Normally subtract negative values to increase FP + k := (256 - word(k)); + frameOffset := frameOffset + k; + end + else + DebugLn(DBG_WARNINGS, ['Invalid stack state for OpCodeAdjustFrameLMask opcode: ', stackState]); + end + else if (opcode and OpCodeAdjustFrameHMask) = OpCodeAdjustFrameHMask then + begin + if stackState < esModifyFPH then + begin + stackState := esModifyFPH; + // Decode register and constant + get_k_r16(opcode, d, k); + // Normally subtract negative values to increase FP, + carry bit + k := (256 - word(k) - 1); + frameOffset := frameOffset + (k shl 8); + end + else + DebugLn(DBG_WARNINGS, ['Invalid stack state for OpCodeAdjustFrameHMask opcode: ', stackState]); + end + else // Any other opcode isn't part of prologue + begin + AnIsOutsideFrame := false; + end; + end; + end; + + // Check before frame pointer gets adjusted + if (stackState >= esModifyFPL) and (frameOffset > 0) then + begin + AnIsOutsideFrame := false; + returnAddressOffset := returnAddressOffset + frameOffset; + end + // Frame pointer inconsistent, so work relative to SP + // Unreliable, SP can be adjusted inside frame + //else if (stackState = esModifyFPH) then + //begin + // AnIsOutsideFrame := true; + // returnAddressOffset := returnAddressOffset + frameOffset; + //end + //else if (stackState > esPop) then + //begin + // + //end + else + AnIsOutsideFrame := true; +end; + function TAvrAsmDecoder.GetLastErrorWasMemReadErr: Boolean; begin Result := FLastErrWasMem; @@ -373,12 +677,12 @@ begin ACode := format(opRegConstHex8, ['cpi', d, k]); end; $4000: - begin // SBCI Subtract Immediate With Carry 0101 10 kkkk dddd kkkk + begin // SBCI Subtract Immediate With Carry 0100 kkkk dddd kkkk get_k_r16(code, d, k); ACode := format(opRegConstHex8, ['sbci', d, k]); end; $5000: - begin // SUB Subtract Immediate 0101 10 kkkk dddd kkkk + begin // SUB Subtract Immediate 0101 kkkk dddd kkkk get_k_r16(code, d, k); ACode := format(opRegConstHex8, ['subi', d, k]); end; @@ -858,75 +1162,46 @@ end; function TAvrAsmDecoder.GetFunctionFrameInfo(AnAddress: TDBGPtr; out AnIsOutsideFrame: Boolean): Boolean; +begin + Result := False; +end; + +function TAvrAsmDecoder.GetFunctionFrameReturnAddress(AnAddress, AStartPC, + AEndPC: TDBGPtr; out returnAddressOffset: word; out AnIsOutsideFrame: Boolean + ): Boolean; var ADataLen: Cardinal; AData: PByte; begin -{ AVR function entry example - 3e: df 93 push r29 - 40: cf 93 push r28 - 42: 3f 92 push r3 - 44: 2f 92 push r2 + { Cases to consider: + A - if (AStartPC + MaxPrologueSize < AnAddress) and (AnAddress + MaxEpilogueSize < AEndPC) + then currently inside stack frame. Parse prologue to figure out + offset from frame pointer to return address. - // Load SP and calculate BP - 46: cd b7 in r28, 0x3d ; 61 // SPL - 48: de b7 in r29, 0x3e ; 62 // SPH - 4a: c6 50 subi r28, 0x06 ; 6 - 4c: d0 40 sbci r29, 0x00 ; 0 - // Disable interrupts - 4e: 0f b6 in r0, 0x3f ; 63 - 50: f8 94 cli - // Then write out new SP - 52: de bf out 0x3e, r29 ; 62 - // Interleaved with restoring SREG - 54: 0f be out 0x3f, r0 ; 63 - 56: cd bf out 0x3d, r28 ; 61 - // Copy param to stack - 58: 8a 83 std Y+2, r24 ; 0x02 - 5a: 9b 83 std Y+3, r25 ; 0x03 -} + B - if (AStartPC + MaxPrologueSize < AnAddress) + then possibly before final stack frame. Need to parse prologue up to AnAddress + to figure out how far the stack has moved since entry to calculate offset + from SP to return address. If frame pointer has been configured before + AnAddress, assume inside frame and return offset relative to frame pointer. - // Should be an even size - ADataLen := MAX_CODEBIN_LEN; // Not sure how much data to process?? - Result := False; - if not ReadCodeAt(AnAddress, ADataLen) then + C - if (AnAddress + MaxEpilogueSize < AEndPC) + then possibly inside frame teardown. Need to reverse parse epilogue up to AnAddress + to figure out how much frame will unwind to calculate offset to return address. + If frame pointer has been restored before AnAddress then ouside frame. + } + + if (AnAddress = AStartPC) or (AnAddress = AEndPC) then + begin + // Frame not yet constructed, so return address is located via SP + offset + returnAddressOffset := 1; + AnIsOutsideFrame := true; exit; - AData := @FCodeBin[0]; - - while (ADataLen > 0) and (AData[0] = $00) and (AData[1] = $00) do begin // nop - inc(AData, 2); - dec(ADataLen, 2); - end; - Result := ADataLen > 0; - if not Result then - exit; - - AnIsOutsideFrame := False; - // in r28, 0x3d = cd b7 - if (AData[0] = $cd) and (AData[1] = $b7) then begin - AnIsOutsideFrame := True; - exit; - end; - - // ret / reti $9508 / $9518 - if (AData[0] in [$08, $18]) and (AData[1] = $95) then begin - AnIsOutsideFrame := True; - exit; - end; - - // Swallow push instructions until the loading of SPL - // // PUSH 1001 001d dddd 1111 - if ((AData[0] and $0f) = $0f) and ((Adata[1] and $92) = $92) then begin // push - while (ADataLen > 1) and ((AData[0] and $0f) = $0f) and ((Adata[1] and $92) = $92) do begin - inc(AData, 2); - dec(ADataLen, 2); - end; - // in r28, 0x3d = cd b7 - if (AData[0] = $cd) and (AData[1] = $b7) then begin - AnIsOutsideFrame := True; - exit; - end; - end; + end + //else if (AStartPC + MaxPrologueSize > AnAddress) then + else if (AnAddress - AStartPC) < (AEndPC - AnAddress) then + result := FParsePrologue(AnAddress, AStartPC, AEndPC, returnAddressOffset, AnIsOutsideFrame) + else + result := FParseEpilogue(AnAddress, AStartPC, AEndPC, returnAddressOffset, AnIsOutsideFrame); end; constructor TAvrAsmDecoder.Create(AProcess: TDbgProcess); @@ -940,9 +1215,7 @@ begin inherited Destroy; end; -//var DBG_WARNINGS: PLazLoggerLogGroup; initialization - //DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} ); end.