Recent

Author Topic: FpDebug breakpoint on "begin"  (Read 2966 times)

440bx

  • Hero Member
  • *****
  • Posts: 4198
FpDebug breakpoint on "begin"
« on: April 19, 2024, 09:46:38 pm »
Hello,

Please refer to the attachment. 

FpDebug considers a breakpoint placed on a "begin" statement to be invalid.  This is unexpected, I believe a "begin" should be a valid "break" location.

Also, in the breakpoints list (on the right), the little breakpoint bitmap is a little chopped.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

440bx

  • Hero Member
  • *****
  • Posts: 4198
Re: FpDebug breakpoint on "begin"
« Reply #1 on: April 19, 2024, 10:10:08 pm »
Hello,

This is not exactly an FpDebug thing but maybe FpDebug can mitigate the problem.  Please refer to the attachment.

In the attachment there is a breakpoint on line 3318 (dc := BeginPaint(...)) but the breakpoint is completely obscured by the Hint about "ps does not seem to be initialized".

At first sight it seems there is enough space to put the red breakpoint dot to the left of the little note bitmap.  Basically, if FpDebug could place its breakpoint indicator flush left there would be two (2) visible bitmaps at that location instead of just one.

Another possibility that does not entail moving the breakpoint indicator is to place the breakpoint indicator on top of of the Hint indicator (instead of having the Hint indicator on top as it is now.)  Personally, I think the breakpoint is a lot more important than the Hint. 
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9991
  • Debugger - SynEdit - and more
    • wiki
Re: FpDebug breakpoint on "begin"
« Reply #2 on: April 19, 2024, 10:50:39 pm »
The 2 icons being drawn in the same column is entirely an issue in the IDE (either SynEdit, or somewhere SourceEditor). Please report an issue (not fpdebug related) that the editor unnecessarily overlaps gutter icons.




Breakpoint on "begin" => I assume when you remove the breakpoint, then there is no blue dot on that line?  So the issue is that FPC does not generate code for that line.

Btw, with -O1 that can even happen for lines containing break or exit statements.

The reason why this works in gdb is, that gdb when given a line number will set the breakpoint at the next linenumber that has code (and stops at that next line...).
GDB does that even if it is 1000 lines below. The curious I can't find the breakpoint, but it stops on the first line of the first routine in the unit => because the breakpoint is on line 1 "unit foo;" so the next line with code...


Eventually FpDebug should have some smart way....
- a limit how many lines to look down
- determining if it is within the same function (though that will not work for the first line of a function)

For now, it has to be a line with code (actual asm statements attributed to the pascal statement on that line) in it (blue dot).

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9991
  • Debugger - SynEdit - and more
    • wiki
Re: FpDebug breakpoint on "begin"
« Reply #3 on: April 19, 2024, 10:57:37 pm »
Talking about begin statements (and end)...

The "begin" of a procedure/function has code, the so called "prologue" => in this code the stack frame (storage for locals) is set up. So when paused on that line, locals (and params) contain trash.

Fpc currently does not mark this line as epilogue (though fpdebug is missing the interpretation of this mark too, but given its absence...).

So the debugger gives no notice that those values are not yet initialized.

Some versions of gdb detect "popular prologue asm", and internally stop only after the prologue., when the begin line is 99% done. Then the values are correct, but you aren't really a the start of "begin".

440bx

  • Hero Member
  • *****
  • Posts: 4198
Re: FpDebug breakpoint on "begin"
« Reply #4 on: April 19, 2024, 11:28:09 pm »
Please report an issue (not fpdebug related) that the editor unnecessarily overlaps gutter icons.
Done.  Issue: 40914 link: https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/40914

Breakpoint on "begin" => I assume when you remove the breakpoint, then there is no blue dot on that line?    So the issue is that FPC does not generate code for that line.
You're right.  There is no blue dot on the line.

The reason why this works in gdb is, that gdb when given a line number will set the breakpoint at the next linenumber that has code (and stops at that next line...).
That's quite handy in the case of a breakpoint placed on a "begin".

GDB does that even if it is 1000 lines below.
I think that's way too many lines below.  IMO, if the line is not visible in the current editor window then it shouldn't be set.  That way there are no "surprise breakpoints".

Eventually FpDebug should have some smart way....
- a limit how many lines to look down
- determining if it is within the same function (though that will not work for the first line of a function)

For now, it has to be a line with code (actual asm statements attributed to the pascal statement on that line) in it (blue dot).
Actually, if possible, I think placing a breakpoint on a non-code line should be limited to the breakpoint being placed on a "begin" line.  In most cases, there will be a statement soon after the "begin".  The only thing that is a potential "gotcha" is a "begin end" function/procedure.  I suppose in that case the breakpoint can go on the "end" line (FPC does seem to put a blue dot for those lines.)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9991
  • Debugger - SynEdit - and more
    • wiki
Re: FpDebug breakpoint on "begin"
« Reply #5 on: April 20, 2024, 12:04:18 am »
It isn't that easy... of course not...

There are 2 possible approaches to solve it.

1) In the editor, based on knowledge the editor has
2) In the debugger, based on knowledge the debugger has

Well, mixes may be thinkable, but they are included...

1)  Editor.
The breakpoint can get set, at a time at which the debugger is not yet running, the editor does not have any info if that line will or will not get a blue dot.

- It would require an exchange when the debugger gets started.
- Breakpoints can exist in units currently not open in an editor. For those blue dots aren't loaded (and storage is bound to the editor).

So that is quite some extension. And it must all go through a generic interface that allows any backend to be bound to the IDE.

Given IFDEF and include files and macros and whatnot, finding the kind of line, and the owning procedure and all that will also need a deep dive into code tools. Though that could be omitted, just limiting it to "simple" cases.

2) The debugger
It doesn't have any source. It has to get it from the editor. But then the debugger would not go to codetools, it is not the job of the debugger to go parsing sources.






What I thing should happen

1) Very simple: Allow n lines below (n between 1 and 5 / maybe configurable)
But that could mean it goes into a different procedure. (if an "end" line has no code)

2)
When the debugger can't find line 100
- search for the next known line above, get the function name from the dwarf
- search for the next known line below, get the function name from the dwarf
- if both surrounding lines are in the same function => then use the "next known line below" (as already found).

That can still be limited by "up to max n lines".

The only disadvantage => it does not work, if the breakpoint is above the first known line of a function. E.g on the "procedure foo;" line itself.
Maybe the debugger can still see that the next found line is the first of the procedure, and take it if within a limit X (where X can be less or equal than the previous limit n)

That is
- "relatively simple"
- works for most cases
- can be done in the backend without interaction to the frontend




Backend and frontend both.

If sources are edited, the line movement is tracked "in the blue dots". Lines without them don't know if they moved. So adding a breakpoint there after editing will always be problematic. (That needs separate changes to the tracking...)





In the meantime, it might be possible to allow for "ONE line beneath".

That does only solve a subset of the issue, but it can't go very wrong either.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9991
  • Debugger - SynEdit - and more
    • wiki
Re: FpDebug breakpoint on "begin"
« Reply #6 on: April 20, 2024, 12:10:31 am »
Not tested, but this patch should hopefully do the "one line" (and if you can spot the "1", you can make it more)

Code: Diff  [Select][+][-]
  1. diff --git a/components/fpdebug/fpdbgclasses.pp b/components/fpdebug/fpdbgclasses.pp
  2. index 2008434e26..e4b28951a8 100644
  3. --- a/components/fpdebug/fpdbgclasses.pp
  4. +++ b/components/fpdebug/fpdbgclasses.pp
  5. @@ -739,7 +739,7 @@   TDbgInstance = class(TObject)
  6.      function GetOSDbgClasses: TOSDbgClasses;
  7.      function GetPointerSize: Integer;
  8.  
  9. -    function  GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray): Boolean;
  10. +    function  GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray; AMaxFindLineBelow: integer = 0): Boolean;
  11.      function FindProcSymbol(const AName: String; AIgnoreCase: Boolean = False): TFpSymbol; overload;
  12.      function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol; overload;
  13.    protected
  14. @@ -941,7 +941,7 @@   TDbgProcess = class(TDbgInstance)
  15.      function  FindSymbolScope(AThreadId, AStackFrame: Integer): TFpDbgSymbolScope;
  16.      function  FindProcStartEndPC(const AAdress: TDbgPtr; out AStartPC, AEndPC: TDBGPtr): boolean;
  17.  
  18. -    function  GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance = nil): Boolean;
  19. +    function  GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance = nil; AMaxFindLineBelow: integer = 0): Boolean;
  20.      //function  ContextFromProc(AThreadId, AStackFrame: Integer; AProcSym: TFpSymbol): TFpDbgLocationContext; inline; deprecated 'use TFpDbgSimpleLocationContext.Create';
  21.      function  GetLib(const AHandle: THandle; out ALib: TDbgLibrary): Boolean;
  22.      property  LibMap: TLibraryMap read FLibMap;
  23. @@ -2198,12 +2198,20 @@ destructor TDbgInstance.Destroy;
  24.    inherited;
  25.  end;
  26.  
  27. -function TDbgInstance.GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray): Boolean;
  28. +function TDbgInstance.GetLineAddresses(AFileName: String; ALine: Cardinal;
  29. +  var AResultList: TDBGPtrArray; AMaxFindLineBelow: integer): Boolean;
  30.  var
  31.    FoundLine: Integer;
  32.  begin
  33. -  if Assigned(DbgInfo) and DbgInfo.HasInfo then
  34. -    Result := DbgInfo.GetLineAddresses(AFileName, ALine, AResultList, fsNone, @FoundLine, @FLastLineAddressesFoundFile)
  35. +  if Assigned(DbgInfo) and DbgInfo.HasInfo then begin
  36. +    if AMaxFindLineBelow > 0 then begin
  37. +      Result := DbgInfo.GetLineAddresses(AFileName, ALine, AResultList, fsNext, @FoundLine, @FLastLineAddressesFoundFile);
  38. +      if Result then
  39. +        Result := (FoundLine >= ALine) and (FoundLine <= ALine + AMaxFindLineBelow);
  40. +    end
  41. +    else
  42. +      Result := DbgInfo.GetLineAddresses(AFileName, ALine, AResultList, fsNone, @FoundLine, @FLastLineAddressesFoundFile);
  43. +  end
  44.    else
  45.      Result := False;
  46.  end;
  47. @@ -2596,24 +2604,24 @@ function TDbgProcess.FindProcStartEndPC(const AAdress: TDbgPtr; out AStartPC,
  48.  end;
  49.  
  50.  function TDbgProcess.GetLineAddresses(AFileName: String; ALine: Cardinal;
  51. -  var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance): Boolean;
  52. +  var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance; AMaxFindLineBelow: integer): Boolean;
  53.  var
  54.    Lib: TDbgLibrary;
  55.  begin
  56.    if ASymInstance <> nil then begin
  57.      if ASymInstance = self then begin
  58. -      Result := inherited GetLineAddresses(AFileName, ALine, AResultList);
  59. +      Result := inherited GetLineAddresses(AFileName, ALine, AResultList, AMaxFindLineBelow);
  60.      end
  61.      else begin
  62. -      Result := ASymInstance.GetLineAddresses(AFileName, ALine, AResultList);
  63. +      Result := ASymInstance.GetLineAddresses(AFileName, ALine, AResultList, AMaxFindLineBelow);
  64.        FLastLineAddressesFoundFile := ASymInstance.FLastLineAddressesFoundFile;
  65.      end;
  66.      exit;
  67.    end;
  68.  
  69. -  Result := inherited GetLineAddresses(AFileName, ALine, AResultList);
  70. +  Result := inherited GetLineAddresses(AFileName, ALine, AResultList, AMaxFindLineBelow);
  71.    for Lib in FLibMap do begin
  72. -    if Lib.GetLineAddresses(AFileName, ALine, AResultList) then
  73. +    if Lib.GetLineAddresses(AFileName, ALine, AResultList, AMaxFindLineBelow) then
  74.        Result := True;
  75.      if Lib.FLastLineAddressesFoundFile then
  76.        FLastLineAddressesFoundFile := True;
  77. @@ -4187,7 +4195,7 @@ constructor TFpInternalBreakpointAtFileLine.Create(const AProcess: TDbgProcess;
  78.    FSymInstance := ASymInstance;
  79.  
  80.    addr := nil;
  81. -  AProcess.GetLineAddresses(AFileName, ALine, addr, ASymInstance);
  82. +  AProcess.GetLineAddresses(AFileName, ALine, addr, ASymInstance, 1);
  83.    FFoundFileWithoutLine := AProcess.FLastLineAddressesFoundFile and (Length(addr) = 0);
  84.    inherited Create(AProcess, addr, AnEnabled);
  85.  end;
  86.  
« Last Edit: April 20, 2024, 12:12:27 am by Martin_fr »

440bx

  • Hero Member
  • *****
  • Posts: 4198
Re: FpDebug breakpoint on "begin"
« Reply #7 on: April 20, 2024, 12:36:23 am »
I got my hands full... I'll wait until you've committed the solution you've chosen.   

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

YiannisKam

  • Full Member
  • ***
  • Posts: 106
Re: FpDebug breakpoint on "begin"
« Reply #8 on: April 20, 2024, 11:30:25 am »
Sorry for the off-topic 440bx, but may I ask which font family you use in your code editor?  They look very cool.

440bx

  • Hero Member
  • *****
  • Posts: 4198
Re: FpDebug breakpoint on "begin"
« Reply #9 on: April 20, 2024, 01:59:45 pm »
Sorry for the off-topic 440bx, but may I ask which font family you use in your code editor?  They look very cool.
No problem. 

I use the font that Borland distributed with Delphi 2 (and possibly some of the later versions.)  It's called "BorlandTE" (filename: BORTE.FON). Quite likely the best programming font ever designed.  Since its release I have not seen anything that matches it (though one font comes awfully close.)

I cannot share it because it is copyrighted but, there is a clone that is _almost_ identical that is a free download, it is "raize" font.  It so close that if you don't have them both, it's not likely you'd notice that one isn't the other (hint: the numeral "0" is where the difference between the two is more noticeable.)

I don't want to promote one site over another by offering a link.  Just do a search on "raize font".  There is one site where the font is rated at 4.9, I've used that site.  Any site you pick, be careful, they try to con you into clicking on something that is not the download button for the font but some junk they are peddling.

There is another clone called "Borlandte-cjm" (free with attribution), what's interesting about it is that it is a truetype font and works in Visual Studio (the reason I looked for it and found it, I wanted to use Borland's font in VS.)  It's a good effort and the fact that it works in VS gives it value but, it's noticeably not as good as Borland's raster font but, you may want to look at it.

Succinctly, first choice: BorlandTE, second (and close) choice: Raize, third choice (not as close as I'd like): Borlandte-cjm.

For more information about fonts, comments and screenshots, I recommend the easy to read article https://darinhiggins.com/2012/05/18/best-programming-font/

There about 4 additional alternatives that article mentions that I would consider if I didn't have Borland's font.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

YiannisKam

  • Full Member
  • ***
  • Posts: 106
Re: FpDebug breakpoint on "begin"
« Reply #10 on: April 20, 2024, 02:08:03 pm »
Thank you very much for the valuable information, I really appreciate it.

440bx

  • Hero Member
  • *****
  • Posts: 4198
Re: FpDebug breakpoint on "begin"
« Reply #11 on: April 20, 2024, 02:11:28 pm »
Thank you very much for the valuable information, I really appreciate it.
My pleasure.  You're welcome.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

VisualLab

  • Sr. Member
  • ****
  • Posts: 355
Re: FpDebug breakpoint on "begin"
« Reply #12 on: April 20, 2024, 02:30:31 pm »
Breakpoint on "begin" => I assume when you remove the breakpoint, then there is no blue dot on that line?    So the issue is that FPC does not generate code for that line.
You're right.  There is no blue dot on the line.

One thing I wonder: in Lazarus, blue dots appear in the editor gutter when debugging is started. They disappear when debugging is finished. In Delphi, blue dots appear after compilation/build is completed and remain after debugging is completed. What is the reason for this difference in the behavior of both IDEs?
« Last Edit: April 20, 2024, 02:32:10 pm by VisualLab »

VisualLab

  • Sr. Member
  • ****
  • Posts: 355
Re: FpDebug breakpoint on "begin"
« Reply #13 on: April 20, 2024, 02:39:28 pm »
At first sight it seems there is enough space to put the red breakpoint dot to the left of the little note bitmap.  Basically, if FpDebug could place its breakpoint indicator flush left there would be two (2) visible bitmaps at that location instead of just one.

Another possibility that does not entail moving the breakpoint indicator is to place the breakpoint indicator on top of of the Hint indicator (instead of having the Hint indicator on top as it is now.)  Personally, I think the breakpoint is a lot more important than the Hint.

I compared the location of the blue dots in Delphi and Lazarus. In Delphi, dots are placed near the left edge of the gutter. When debugging, they usually do not conflict with other icons. The dots in Lazarus are placed at the right edge of the gutter. As a result, they are often covered by other icons. Maybe it would be possible to separate vertical areas (stripes) in the gutter in which different types of icons would be displayed, so that they would not overlap? Additionally, divided into editor modes: editing and debugging. In each of these modes, the editor could display different icons in separate areas of the gutter.

440bx

  • Hero Member
  • *****
  • Posts: 4198
Re: FpDebug breakpoint on "begin"
« Reply #14 on: April 20, 2024, 02:59:22 pm »
Maybe it would be possible to separate vertical areas (stripes) in the gutter in which different types of icons would be displayed, so that they would not overlap? Additionally, divided into editor modes: editing and debugging. In each of these modes, the editor could display different icons in separate areas of the gutter.
I like the separate modes idea.  I think it makes sense to dedicate specific areas to specific purposes.

I think that's the direction this is going because in a previous post Martin made it clear that the two icons should not overlap and there is enough space for both icons to be displayed (thereby creating the separation you suggested.)

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018