Recent

Author Topic: Switching IDE context for selected callstack level  (Read 3056 times)

Alex_Krivtsov

  • Newbie
  • Posts: 3
Switching IDE context for selected callstack level
« on: September 22, 2023, 01:37:05 am »
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

  • Administrator
  • Hero Member
  • *
  • Posts: 10553
  • Debugger - SynEdit - and more
    • wiki
Re: Switching IDE context for selected callstack level
« Reply #1 on: September 22, 2023, 08:46:23 am »
To start with: What exactly gets fixed? What does not work before your changes?


Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10553
  • Debugger - SynEdit - and more
    • wiki
Re: Switching IDE context for selected callstack level
« Reply #2 on: September 22, 2023, 08:48:34 am »
Quote
press the button and travel (doubleclick) along the callstack window lines to observe

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

  • Newbie
  • Posts: 3
Re: Switching IDE context for selected callstack level
« Reply #3 on: September 22, 2023, 07:00:40 pm »
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

  • Administrator
  • Hero Member
  • *
  • Posts: 10553
  • Debugger - SynEdit - and more
    • wiki
Re: Switching IDE context for selected callstack level
« Reply #4 on: September 22, 2023, 11:02:13 pm »
"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.

« Last Edit: September 22, 2023, 11:06:13 pm by Martin_fr »

 

TinyPortal © 2005-2018