mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-15 00:19:22 +02:00
FpDebug: refactor stack unwinding for AVR
This commit is contained in:
parent
53474705c4
commit
3b833564d5
@ -58,6 +58,8 @@ type
|
|||||||
FIsSteppingBreakPoint: boolean;
|
FIsSteppingBreakPoint: boolean;
|
||||||
FDidResetInstructionPointer: Boolean;
|
FDidResetInstructionPointer: Boolean;
|
||||||
FHasThreadState: boolean;
|
FHasThreadState: boolean;
|
||||||
|
FUnwinder: TDbgStackUnwinder;
|
||||||
|
|
||||||
function ReadDebugReg(ind: byte; out AVal: TDbgPtr): boolean;
|
function ReadDebugReg(ind: byte; out AVal: TDbgPtr): boolean;
|
||||||
function WriteDebugReg(ind: byte; AVal: PtrUInt): boolean;
|
function WriteDebugReg(ind: byte; AVal: PtrUInt): boolean;
|
||||||
|
|
||||||
@ -73,6 +75,7 @@ type
|
|||||||
function RequestInternalPause: Boolean;
|
function RequestInternalPause: Boolean;
|
||||||
function CheckSignalForPostponing(AWaitedStatus: integer): Boolean;
|
function CheckSignalForPostponing(AWaitedStatus: integer): Boolean;
|
||||||
procedure ResetPauseStates;
|
procedure ResetPauseStates;
|
||||||
|
function GetStackUnwinder: TDbgStackUnwinder; override;
|
||||||
public
|
public
|
||||||
constructor Create(const AProcess: TDbgProcess; const AID: Integer; const AHandle: THandle); override;
|
constructor Create(const AProcess: TDbgProcess; const AID: Integer; const AHandle: THandle); override;
|
||||||
function ResetInstructionPointerAfterBreakpoint: boolean; override;
|
function ResetInstructionPointerAfterBreakpoint: boolean; override;
|
||||||
@ -85,8 +88,6 @@ type
|
|||||||
function GetStackBasePointerRegisterValue: TDbgPtr; override;
|
function GetStackBasePointerRegisterValue: TDbgPtr; override;
|
||||||
procedure SetStackPointerRegisterValue(AValue: TDbgPtr); override;
|
procedure SetStackPointerRegisterValue(AValue: TDbgPtr); override;
|
||||||
function GetStackPointerRegisterValue: TDbgPtr; override;
|
function GetStackPointerRegisterValue: TDbgPtr; override;
|
||||||
|
|
||||||
procedure PrepareCallStackEntryList(AFrameRequired: Integer = -1); override;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TDbgAvrProcess }
|
{ TDbgAvrProcess }
|
||||||
@ -161,6 +162,7 @@ type
|
|||||||
property Count: integer read DataCount;
|
property Count: integer read DataCount;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
@ -363,6 +365,13 @@ begin
|
|||||||
FDidResetInstructionPointer := False;
|
FDidResetInstructionPointer := False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgAvrThread.GetStackUnwinder: TDbgStackUnwinder;
|
||||||
|
begin
|
||||||
|
if FUnwinder = nil then
|
||||||
|
FUnwinder := TDbgStackUnwinderAVR.Create(Process);
|
||||||
|
Result := FUnwinder;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TDbgAvrThread.Create(const AProcess: TDbgProcess;
|
constructor TDbgAvrThread.Create(const AProcess: TDbgProcess;
|
||||||
const AID: Integer; const AHandle: THandle);
|
const AID: Integer; const AHandle: THandle);
|
||||||
begin
|
begin
|
||||||
@ -526,128 +535,6 @@ begin
|
|||||||
ReadDebugReg(SPindex, result);
|
ReadDebugReg(SPindex, result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDbgAvrThread.PrepareCallStackEntryList(AFrameRequired: Integer);
|
|
||||||
const
|
|
||||||
MAX_FRAMES = 50000; // safety net
|
|
||||||
// To read RAM, add data space offset to address
|
|
||||||
DataOffset = $800000;
|
|
||||||
Size = 2;
|
|
||||||
var
|
|
||||||
Address, FrameBase, LastFrameBase: TDBGPtr;
|
|
||||||
CountNeeded, CodeReadErrCnt: integer;
|
|
||||||
AnEntry: TDbgCallstackEntry;
|
|
||||||
R: TDbgRegisterValue;
|
|
||||||
NextIdx: LongInt;
|
|
||||||
OutSideFrame: Boolean;
|
|
||||||
StackPtr: TDBGPtr;
|
|
||||||
startPC, endPC: TDBGPtr;
|
|
||||||
returnAddrStackOffset: word;
|
|
||||||
b: byte;
|
|
||||||
begin
|
|
||||||
// TODO: use AFrameRequired // check if already partly done
|
|
||||||
if FCallStackEntryList = nil then
|
|
||||||
FCallStackEntryList := TDbgCallstackEntryList.Create;
|
|
||||||
if AFrameRequired = -2 then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
if (AFrameRequired >= 0) and (AFrameRequired < FCallStackEntryList.Count) then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
FCallStackEntryList.FreeObjects:=true;
|
|
||||||
if FCallStackEntryList.Count > 0 then begin
|
|
||||||
AnEntry := FCallStackEntryList[FCallStackEntryList.Count - 1];
|
|
||||||
R := AnEntry.RegisterValueList.FindRegisterByDwarfIndex(PCindex);
|
|
||||||
if R = nil then exit;
|
|
||||||
Address := R.NumValue;
|
|
||||||
R := AnEntry.RegisterValueList.FindRegisterByDwarfIndex(28);
|
|
||||||
if R = nil then exit;
|
|
||||||
FrameBase := R.NumValue;
|
|
||||||
R := AnEntry.RegisterValueList.FindRegisterByDwarfIndex(29);
|
|
||||||
if R = nil then exit;
|
|
||||||
FrameBase := FrameBase + (byte(R.NumValue) shl 8);
|
|
||||||
|
|
||||||
R := AnEntry.RegisterValueList.FindRegisterByDwarfIndex(SPindex);
|
|
||||||
if R = nil then exit;
|
|
||||||
StackPtr := R.NumValue;
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
Address := GetInstructionPointerRegisterValue;
|
|
||||||
FrameBase := GetStackBasePointerRegisterValue;
|
|
||||||
StackPtr := GetStackPointerRegisterValue;
|
|
||||||
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, PCindex);
|
|
||||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPtr, IntToStr(StackPtr),Size, SPindex);
|
|
||||||
|
|
||||||
// Y pointer register [r28:r29] is used as frame pointer for AVR
|
|
||||||
// Store these to enable stack based parameters to be read correctly
|
|
||||||
// as they are frame pointer relative and dwarf stores the frame pointer under r28
|
|
||||||
//AnEntry.RegisterValueList.DbgRegisterAutoCreate[nFP].SetValue(FrameBase, IntToStr(FrameBase),Size, FPindex);
|
|
||||||
b := byte(FrameBase);
|
|
||||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate['r28'].SetValue(b, IntToStr(b),Size, 28);
|
|
||||||
b := (FrameBase and $FF00) shr 8;
|
|
||||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate['r29'].SetValue(b, IntToStr(b),Size, 29);
|
|
||||||
|
|
||||||
FCallStackEntryList.Add(AnEntry);
|
|
||||||
end;
|
|
||||||
|
|
||||||
NextIdx := FCallStackEntryList.Count;
|
|
||||||
if AFrameRequired < 0 then
|
|
||||||
AFrameRequired := MaxInt;
|
|
||||||
CountNeeded := AFrameRequired - FCallStackEntryList.Count;
|
|
||||||
LastFrameBase := 0;
|
|
||||||
CodeReadErrCnt := 0;
|
|
||||||
while (CountNeeded > 0) and (FrameBase <> 0) and (FrameBase > LastFrameBase) do
|
|
||||||
begin
|
|
||||||
// Get start/end PC of proc from debug info
|
|
||||||
if not Self.Process.FindProcStartEndPC(Address, startPC, endPC) then
|
|
||||||
begin
|
|
||||||
// Give up for now, it is complicated to locate prologue/epilogue in general without proc limits
|
|
||||||
// ToDo: Perhaps interpret .debug_frame info if available,
|
|
||||||
// or scan forward from address until an epilogue is found.
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if not TAvrAsmDecoder(Process.Disassembler).GetFunctionFrameReturnAddress(Address, startPC, endPC, returnAddrStackOffset, OutSideFrame) then
|
|
||||||
begin
|
|
||||||
OutSideFrame := False;
|
|
||||||
end;
|
|
||||||
LastFrameBase := FrameBase;
|
|
||||||
|
|
||||||
if OutSideFrame then begin
|
|
||||||
// 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
|
|
||||||
// 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 - 1; // 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, PCindex);
|
|
||||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPtr, IntToStr(StackPtr),Size, SPindex);
|
|
||||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate['r28'].SetValue(byte(FrameBase), IntToStr(b),Size, 28);
|
|
||||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate['r29'].SetValue((FrameBase and $FF00) shr 8, IntToStr(b),Size, 29);
|
|
||||||
|
|
||||||
FCallStackEntryList.Add(AnEntry);
|
|
||||||
Dec(CountNeeded);
|
|
||||||
inc(NextIdx);
|
|
||||||
CodeReadErrCnt := 0;
|
|
||||||
if (NextIdx > MAX_FRAMES) then
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
if CountNeeded > 0 then // there was an error / not possible to read more frames
|
|
||||||
FCallStackEntryList.SetHasReadAllAvailableFrames;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TDbgAvrProcess }
|
{ TDbgAvrProcess }
|
||||||
|
|
||||||
procedure TDbgAvrProcess.InitializeLoaders;
|
procedure TDbgAvrProcess.InitializeLoaders;
|
||||||
|
@ -47,8 +47,6 @@ type
|
|||||||
|
|
||||||
TAvrAsmDecoder = class;
|
TAvrAsmDecoder = class;
|
||||||
|
|
||||||
{ TX86DisassemblerInstruction }
|
|
||||||
|
|
||||||
{ TAvrAsmInstruction }
|
{ TAvrAsmInstruction }
|
||||||
|
|
||||||
TAvrAsmInstruction = class(TDbgAsmInstruction)
|
TAvrAsmInstruction = class(TDbgAsmInstruction)
|
||||||
@ -86,6 +84,7 @@ type
|
|||||||
returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean;
|
returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean;
|
||||||
function FParseEpilogue(AnAddress, AStartPC, AEndPC: TDBGPtr; out
|
function FParseEpilogue(AnAddress, AStartPC, AEndPC: TDBGPtr; out
|
||||||
returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean;
|
returnAddressOffset: word; out AnIsOutsideFrame: Boolean): Boolean;
|
||||||
|
|
||||||
protected
|
protected
|
||||||
function GetLastErrorWasMemReadErr: Boolean; override;
|
function GetLastErrorWasMemReadErr: Boolean; override;
|
||||||
function GetMaxInstrSize: integer; override;
|
function GetMaxInstrSize: integer; override;
|
||||||
@ -94,10 +93,11 @@ type
|
|||||||
function ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal): Boolean; inline;
|
function ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal): Boolean; inline;
|
||||||
|
|
||||||
public
|
public
|
||||||
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); override;
|
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String; out AnInfo: TDbgInstInfo); override; overload;
|
||||||
|
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); override; overload;
|
||||||
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; override;
|
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; override;
|
||||||
|
|
||||||
// Don't use, ot really suited to AVR ABI
|
// Don't use, not really suited to AVR ABI
|
||||||
function GetFunctionFrameInfo(AnAddress: TDBGPtr; out
|
function GetFunctionFrameInfo(AnAddress: TDBGPtr; out
|
||||||
AnIsOutsideFrame: Boolean): Boolean; override;
|
AnIsOutsideFrame: Boolean): Boolean; override;
|
||||||
|
|
||||||
@ -113,10 +113,36 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TDbgStackUnwinderAVR }
|
||||||
|
|
||||||
|
TDbgStackUnwinderAVR = class(TDbgStackUnwinder)
|
||||||
|
private
|
||||||
|
FThread: TDbgThread;
|
||||||
|
FProcess: TDbgProcess;
|
||||||
|
FAddressSize: Integer;
|
||||||
|
FLastFrameBaseIncreased: Boolean;
|
||||||
|
FCodeReadErrCnt: integer;
|
||||||
|
protected
|
||||||
|
property Process: TDbgProcess read FProcess;
|
||||||
|
property Thread: TDbgThread read FThread;
|
||||||
|
property AddressSize: Integer read FAddressSize;
|
||||||
|
public
|
||||||
|
constructor Create(AProcess: TDbgProcess);
|
||||||
|
procedure InitForThread(AThread: TDbgThread); override;
|
||||||
|
procedure InitForFrame(ACurrentFrame: TDbgCallstackEntry; out CodePointer,
|
||||||
|
StackPointer, FrameBasePointer: TDBGPtr); override;
|
||||||
|
procedure GetTopFrame(out CodePointer, StackPointer, FrameBasePointer: TDBGPtr;
|
||||||
|
out ANewFrame: TDbgCallstackEntry); override;
|
||||||
|
function Unwind(AFrameIndex: integer; var CodePointer, StackPointer,
|
||||||
|
FrameBasePointer: TDBGPtr; ACurrentFrame: TDbgCallstackEntry; out
|
||||||
|
ANewFrame: TDbgCallstackEntry): TTDbgStackUnwindResult; override;
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
StrUtils, LazClasses, Math;
|
StrUtils, LazClasses, Math,
|
||||||
|
FpDbgAvrClasses;
|
||||||
|
|
||||||
var
|
var
|
||||||
DBG_WARNINGS: PLazLoggerLogGroup;
|
DBG_WARNINGS: PLazLoggerLogGroup;
|
||||||
@ -556,7 +582,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAvrAsmDecoder.Disassemble(var AAddress: Pointer; out
|
procedure TAvrAsmDecoder.Disassemble(var AAddress: Pointer; out
|
||||||
ACodeBytes: String; out ACode: String);
|
ACodeBytes: String; out ACode: String; out AnInfo: TDbgInstInfo);
|
||||||
var
|
var
|
||||||
CodeIdx, r, d, k, q: byte;
|
CodeIdx, r, d, k, q: byte;
|
||||||
a: SmallInt;
|
a: SmallInt;
|
||||||
@ -565,6 +591,7 @@ var
|
|||||||
s1: string;
|
s1: string;
|
||||||
_set: boolean;
|
_set: boolean;
|
||||||
begin
|
begin
|
||||||
|
AnInfo := default(TDbgInstInfo);
|
||||||
pcode := AAddress;
|
pcode := AAddress;
|
||||||
CodeIdx := 0;
|
CodeIdx := 0;
|
||||||
code := pcode[CodeIdx];
|
code := pcode[CodeIdx];
|
||||||
@ -1156,6 +1183,18 @@ begin
|
|||||||
ACodeBytes := ACodeBytes + HexStr(pcode[k], 2);
|
ACodeBytes := ACodeBytes + HexStr(pcode[k], 2);
|
||||||
|
|
||||||
Inc(AAddress, CodeIdx);
|
Inc(AAddress, CodeIdx);
|
||||||
|
|
||||||
|
// Todo: Indicate whether currrent instruction has a destination code address
|
||||||
|
// call jump branch(?)
|
||||||
|
// Return information in AnInfo
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAvrAsmDecoder.Disassemble(var AAddress: Pointer; out
|
||||||
|
ACodeBytes: String; out ACode: String);
|
||||||
|
var
|
||||||
|
AnInfo: TDbgInstInfo;
|
||||||
|
begin
|
||||||
|
Disassemble(AAddress, ACodeBytes, ACode, AnInfo);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAvrAsmDecoder.GetInstructionInfo(AnAddress: TDBGPtr
|
function TAvrAsmDecoder.GetInstructionInfo(AnAddress: TDBGPtr
|
||||||
@ -1222,6 +1261,132 @@ begin
|
|||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TDbgStackUnwinderAVR }
|
||||||
|
|
||||||
|
constructor TDbgStackUnwinderAVR.Create(AProcess: TDbgProcess);
|
||||||
|
begin
|
||||||
|
FProcess := AProcess;
|
||||||
|
FAddressSize := 2;
|
||||||
|
FLastFrameBaseIncreased := True;
|
||||||
|
FCodeReadErrCnt := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDbgStackUnwinderAVR.InitForThread(AThread: TDbgThread);
|
||||||
|
begin
|
||||||
|
FThread := AThread;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDbgStackUnwinderAVR.InitForFrame(ACurrentFrame: TDbgCallstackEntry;
|
||||||
|
out CodePointer, StackPointer, FrameBasePointer: TDBGPtr);
|
||||||
|
var
|
||||||
|
R: TDbgRegisterValue;
|
||||||
|
begin
|
||||||
|
CodePointer := ACurrentFrame.AnAddress;
|
||||||
|
|
||||||
|
// Frame pointer is r29:r28 (if used)
|
||||||
|
FrameBasePointer := ACurrentFrame.FrameAdress;
|
||||||
|
|
||||||
|
//Could update using GetStackBasePointerRegisterValue
|
||||||
|
|
||||||
|
//R := ACurrentFrame.RegisterValueList.FindRegisterByDwarfIndex(FDwarfNumBP);
|
||||||
|
//if R <> nil then
|
||||||
|
// FrameBasePointer := R.NumValue;
|
||||||
|
|
||||||
|
StackPointer := 0;
|
||||||
|
R := ACurrentFrame.RegisterValueList.FindRegisterByDwarfIndex(SPindex);
|
||||||
|
if R = nil then exit;
|
||||||
|
StackPointer := R.NumValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDbgStackUnwinderAVR.GetTopFrame(out CodePointer, StackPointer,
|
||||||
|
FrameBasePointer: TDBGPtr; out ANewFrame: TDbgCallstackEntry);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
R: TDbgRegisterValue;
|
||||||
|
begin
|
||||||
|
CodePointer := Thread.GetInstructionPointerRegisterValue;
|
||||||
|
StackPointer := Thread.GetStackPointerRegisterValue;
|
||||||
|
FrameBasePointer := Thread.GetStackBasePointerRegisterValue;
|
||||||
|
ANewFrame := TDbgCallstackEntry.create(Thread, 0, FrameBasePointer, CodePointer);
|
||||||
|
|
||||||
|
i := Thread.RegisterValueList.Count;
|
||||||
|
while i > 0 do begin
|
||||||
|
dec(i);
|
||||||
|
R := Thread.RegisterValueList[i];
|
||||||
|
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[R.Name].SetValue(R.NumValue, R.StrValue, R.Size, R.DwarfIdx);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDbgStackUnwinderAVR.Unwind(AFrameIndex: integer; var CodePointer,
|
||||||
|
StackPointer, FrameBasePointer: TDBGPtr; ACurrentFrame: TDbgCallstackEntry;
|
||||||
|
out ANewFrame: TDbgCallstackEntry): TTDbgStackUnwindResult;
|
||||||
|
const
|
||||||
|
MAX_FRAMES = 50000; // safety net
|
||||||
|
// To read RAM, add data space offset to address
|
||||||
|
DataOffset = $800000;
|
||||||
|
Size = 2;
|
||||||
|
var
|
||||||
|
NextIdx: LongInt;
|
||||||
|
LastFrameBase: TDBGPtr;
|
||||||
|
OutSideFrame: Boolean;
|
||||||
|
StackPtr: TDBGPtr;
|
||||||
|
startPC, endPC: TDBGPtr;
|
||||||
|
returnAddrStackOffset: word;
|
||||||
|
b: byte;
|
||||||
|
begin
|
||||||
|
ANewFrame := nil;
|
||||||
|
Result := suFailed;
|
||||||
|
|
||||||
|
if StackPointer = 0 then
|
||||||
|
exit;
|
||||||
|
if not FLastFrameBaseIncreased then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
OutSideFrame := False;
|
||||||
|
LastFrameBase := FrameBasePointer;
|
||||||
|
|
||||||
|
// Get start/end PC of proc from debug info
|
||||||
|
if not Self.Process.FindProcStartEndPC(CodePointer, startPC, endPC) then
|
||||||
|
begin
|
||||||
|
// Give up for now, it is complicated to locate prologue/epilogue in general without proc limits
|
||||||
|
// ToDo: Perhaps interpret .debug_frame info if available,
|
||||||
|
// or scan forward from address until an epilogue is found.
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not TAvrAsmDecoder(Process.Disassembler).GetFunctionFrameReturnAddress(CodePointer, startPC, endPC, returnAddrStackOffset, OutSideFrame) then
|
||||||
|
begin
|
||||||
|
OutSideFrame := False;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if OutSideFrame then begin
|
||||||
|
// 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, CodePointer) or (CodePointer = 0) then exit;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// Inside stack frame, return PC should be located by offset from FP
|
||||||
|
if not Process.ReadData(DataOffset or (FrameBasePointer + returnAddrStackOffset), Size, CodePointer) or (CodePointer = 0) then exit;
|
||||||
|
end;
|
||||||
|
// Convert return address from BE to LE, shl 1 to get byte address
|
||||||
|
CodePointer := BEtoN(word(CodePointer)) shl 1;
|
||||||
|
{$PUSH}{$R-}{$Q-}
|
||||||
|
StackPtr := FrameBasePointer + returnAddrStackOffset + Size - 1; // After popping return-addr from "StackPtr"
|
||||||
|
FrameBasePointer := StackPtr; // Estimate of previous FP
|
||||||
|
{$POP}
|
||||||
|
|
||||||
|
FLastFrameBaseIncreased := (FrameBasePointer <> 0) and (FrameBasePointer > LastFrameBase);
|
||||||
|
|
||||||
|
ANewFrame:= TDbgCallstackEntry.create(Thread, NextIdx, FrameBasePointer, CodePointer);
|
||||||
|
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[nPC].SetValue(CodePointer, IntToStr(CodePointer),Size, PCindex);
|
||||||
|
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPtr, IntToStr(StackPtr),Size, SPindex);
|
||||||
|
ANewFrame.RegisterValueList.DbgRegisterAutoCreate['r28'].SetValue(byte(FrameBasePointer), IntToStr(b),Size, 28);
|
||||||
|
ANewFrame.RegisterValueList.DbgRegisterAutoCreate['r29'].SetValue((FrameBasePointer and $FF00) shr 8, IntToStr(b),Size, 29);
|
||||||
|
|
||||||
|
FCodeReadErrCnt := 0;
|
||||||
|
Result := suSuccess;
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user