Forum > Suggestions
Switching IDE context for selected callstack level
(1/1)
Alex_Krivtsov:
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=sharing
contains 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
Martin_fr:
To start with: What exactly gets fixed? What does not work before your changes?
Martin_fr:
--- Quote ---press the button and travel (doubleclick) along the callstack window lines to observe
--- End quote ---
If I take a guess: "double click" is meant to jump to source.
There is a toolbutton in the stackwindow (small green arrow) to select the line for inspection.
Alex_Krivtsov:
30 years old dream: to inspect variables at all levels of call stack of paused program.
Now jumping to any call point at the stack gains context switching: you can use watches, locals and source editor to inspect variables the same way as if you've got a breakpoint hit at this call. Current behavior at the lower stack levels permits inspecting of unit-defined globals and top level variables, replying 'not defined' to requests for locals of calling program.
Attached screenshot shows debug windows after double click on te 2nd line of call stack.
Editor shows the set breakpoint (39) and the current call point (41). Putting the cursor over 'n' gives
'n = 2
var
n: integer = longint' hint.
Call stack shows the break (0) and current context (1) stack levels
Watches and Local Variables show n=2 and s=$0000000001575548^: 'Label1-5-4-3' values corresponding to current context (n=1 at breakpoint obviously)
Martin_fr:
"Double click" does NOT select for inspection.
See the arrow in the left most column. In your case the arrow is inside the breakpoint, at index 0.
See the toolbutton with the green arrow? press it, and it changes the "inspect" frame.
Or use the "current" from context menu.
Navigation
[0] Message Index