I've got a great pleasure reading LazarusSource novel volume 2 (IDE). Strongly recommended.
One result of this entertainment is the fulfillment of my 30 years old dream to inspect variables at all levels of call stack of paused program.
The solution consists of 28 minor corrections for 3.0RC1-fpc-3.2.2-win64 Lazarus listed below:
========================
C:\lazarus\ide\packages\idedebugger\callstackdlg.pp
1.
function TCallStackDlg.GetCurrentEntry: TIdeCallStackEntry;
...
562: //curv set global context frame number travelling through callstack window
evalFrameID:=idx;
2. - 3
procedure TCallStackDlg.lvCallStackDBLCLICK(Sender: TObject);
649: //curv
var
dbg: TDebuggerIntf;
begin
JumpToSource;
654://curv notify context-sensitive objects
dbg:=Fdebugger;
dbg.BreakPoints.DoStateChange(dsRun);
dbg.CallStack.DoStateChange(dsRun);
dbg.Locals.DoStateChange(dsRun);
dbg.Watches.DoStateChange(dsRun);
4.
procedure TCallStackDlg.DoDebuggerState(ADebugger: TDebuggerIntf;
AnOldState: TDBGState);
begin
239: //curv to populate new Fdebugger field on the 1st run
if Anoldstate=dsNone then Fdebugger:=Adebugger;
5.
uses
...
53: //curv to access evalFrameID
FpDbgClasses,
6.
TCallStackDlg = class(TDebuggerDlg)
...
125: //curv to access context sensitive objects
Fdebugger:TDebuggerIntf;
7. - 9.
var
...
177: //curv icon imageindex
imgIsContext:integer;
function TCallStackDlg.GetImageIndex(Entry: TIdeCallStackEntry): Integer;
...
309: //curv an icon for current context in callstack window
if Entry.Index=evalFrameID then
exit(imgIsContext);
procedure TCallStackDlg.FormCreate(Sender: TObject);
877: //curv I like this picture for callstack line of current context
imgIsContext := IDEImages.LoadImage('debugger_call_stack');
===========================
C:\lazarus\components\fpdebug\fpdbgclasses.pp
10. - 11.
910//curv context stack level global var
var
evalFrameID:integer;
4089: //curv initialize
evalFrameID:=0;
============================
C:\lazarus\components\lazdebuggers\lazdebuggerfp\fpdebugdebugger.pas
12. - 13.
procedure TFpThreadWorkerCallEntryUpdate.UpdateCallstackEntry_DecRef(
Data: PtrInt);
var
dbg: TFpDebugDebugger;
c: String;
864: //curv
DbgEntry:TDbgCallstackEntry;
Dline:integer;
...
884: //curv to populate new FrameAddress field of FCallstackEntry
DbgEntry:=FThread.CallStackentrylist.items[FCallstackEntry.Index];
Dline:= DbgEntry.line;
if FLine<>Dline then //seems to never happen
Fline:=Dline;
FCallstackEntry.FrameAddress:=DbgEntry.FrameAdress;
14.
procedure TFpDebugDebugger.FDbgControllerHitBreakpointEvent(
var continue: boolean; const Breakpoint: TFpDbgBreakpoint;
AnEventType: TFPDEvent; AMoreHitEventsPending: Boolean);
...
3788: //curv to evaluate break expression
evalFrameID:=0;
===========================
C:\lazarus\components\lazdebuggers\lazdebuggerfp\fpdebugdebuggerworkthreads.pas
15.
procedure TFpThreadWorkerEvaluateExpr.DoExecute;
begin
1288://curv FRes := EvaluateExpression(FExpression, FStackFrame, FThreadId,
// switches context for watches and editor
FRes := EvaluateExpression(FExpression, evalFrameID, FThreadId,
FDispFormat, FRepeatCnt, FEvalFlags, FResText, FResDbgType);
===========================
C:\lazarus\ide\packages\idedebugger\localsdlg.pp
16.
uses
...
//curv to use evalFrameID
FpDbgClasses,
17. - 18.
function TLocalsDlg.GetStackframe: Integer;
...
if Stack <> nil then
719://curv
if evalFrameID = 0
then Result := Stack.CurrentIndex
723: //curv this switches context for locals
else Result := evalFrameID
===========================
C:\lazarus\components\debuggerintf\dbgintfdebuggerbase.pp
19. - 26.
These 4 classes need moving DoStatechange procedure to public:
TDebuggerDataSupplier = class(TDebuggerDataSupplierBase) 217: 223:
TDBGBreakPoints = class(TBaseBreakPoints) 431: 435:
TWatchesSupplier = class(specialize TWatchesSupplierClassTemplate<TDebuggerDataSupplierBase>, IDbgWatchesSupplierIntf) 598: 602:
TLocalsSupplier = class(specialize TLocalsSupplierClassTemplate<TDebuggerDataSupplierBase>, IDbgLocalsSupplierIntf) 622: 625:
27. - 28.
TCallStackEntry = class(TFreeNotifyingObject)
...
839: //curv new field to carry frame base through various evaluating code
FFrameAddress: TDbgPtr;
885: //curv
property FrameAddress: TDbgPtr read FFrameAddress write FFrameaddress;
Having the whole project downloaded you can easily navigate through corrections using Find in Files (//curv)
The 'Projects' directory contains Project1 (hello factorial) I used to debug the solution. Run it, press the button and travel (doubleclick) along the callstack window lines to observe changes in watches, locals and code editor hints.
I am new in Lazarus, so I'll be thankful for recommendations where and how to publish my suggestion. I am very interested about independent testing.
lazarus.rar at
https://drive.google.com/file/d/1hhU3w0IfdjJKAmanXenm8X_S-66OuibY/view?usp=sharingcontains the complete set of 3.01 sources with my corrections and lazarus.exe to try them working.
Feel free to contact me through Krivtsov1947@gmail.com or here