Tweak PrepareCallStackEntryList to cater for avr-gcc ABI. Added TAvrAsmDecoder.GetFunctionFrameReturnAddress to scan prologue and epilogue for frame information.

This commit is contained in:
ccrause 2021-07-04 08:42:34 +02:00
parent 02c76188e3
commit 7f341cbe68
2 changed files with 374 additions and 101 deletions

View File

@ -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

View File

@ -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.