Recent

Author Topic: An instruction to pause the debugger. [SOLVED]  (Read 1977 times)

BrunoK

  • Hero Member
  • *****
  • Posts: 559
  • Retired programmer
An instruction to pause the debugger. [SOLVED]
« on: June 29, 2024, 05:16:28 pm »
Debugger : FpDebug, Lazarus 3.99

I have a pascal code generator and would like the generated code to be able to pause the execution with an instruction, like for the following code snippet from a CocoR grammar file :
Code: Pascal  [Select][+][-]
  1. SynchNext<const aCurrentInputSymbol: integer; const aAfterSymName, aAheadSymName: string>
  2.   (. var
  3.        lAfterSym,
  4.        lAheadSym: integer;
  5.      var
  6.        lNextSym,
  7.        lDefaultSym,
  8.        lPrevSym : integer;
  9.        lScanner: TRC5ExportScanner;
  10.   .)
  11.   = (. lScanner:=GetScanner;
  12.        lDefaultSym := identSym;
  13.        if not lScanner.fHashList.Hash(aAfterSymName, lAfterSym, lDefaultSym) then
  14.          Exit;
  15.        if not lScanner.fHashList.Hash(aAheadSymName, lAheadSym, lDefaultSym) then
  16.          Exit;
  17.        while fCurrentInputSymbol<>EOFSYMB do begin
  18.          if fCurrentInputSymbol=lAheadSym then begin
  19.            { Some checking about aAfterSymName preceding found aAheadSymName }
  20.            if lPrevSym<>lAfterSym then
  21.              { Scanner.pos}
  22. {PAUSE HERE >}    DebuggerPause; // <===== Programmed pause
  23.              lDefaultSym := lAfterSym;
  24.            Exit;
  25.          end;
  26.          lPrevSym := fCurrentInputSymbol;
  27.          Get;
  28.        end;
  29.     .)
  30.       .


At DebuggerPause is there an existing instruction that would put the debugger in pause on that line.
« Last Edit: June 29, 2024, 07:42:20 pm by BrunoK »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10222
  • Debugger - SynEdit - and more
    • wiki
Re: An instruction to pause the debugger.
« Reply #1 on: June 29, 2024, 05:23:14 pm »
yes, kinda....

On Windows:
Code: Pascal  [Select][+][-]
  1. DebugBreak
oder Win/Linux
Code: Pascal  [Select][+][-]
  1. asm
  2. int 3
  3. end;
(mind the space before the 3)

At least the latter, should probably be IFDEFed for debugging only. I.e., compile for debug with -dMY_DBG_DEFINE (which then goes into the ifdef)

Only, by default the debugger ignores both (the first one also ends on a "int 3")

In the Option, Debugger Backend, in the settings for FpDebug is "HandleDebugBreakInstruction", which is set to "IgnoreAll". Uncheck the IgnoreAll.

Downside: Other code (libraries) can also contain "int 3" => and then that will also enter debug pause.

BrunoK

  • Hero Member
  • *****
  • Posts: 559
  • Retired programmer
Re: An instruction to pause the debugger.
« Reply #2 on: June 29, 2024, 06:37:00 pm »
Uncheck'ed the IgnoreAll.

Put in my code
Code: Pascal  [Select][+][-]
  1.      if  lPrevSym=lAfterSym  then
  2.        {  Scanner.pos}
  3.        asm  int 3 end; // <- as suggested
  4.        lDefaultSym  :=  lAfterSym;
  5.      Exit;
  6.  
Raises
Quote
Code: Pascal  [Select][+][-]
  1. [Window Title]
  2.  
  3. prjR5DataReportToDB
  4.  
  5. [Content]
  6. Access violation.
  7.  
  8. Press OK to ignore and risk data corruption.
  9. Press Abort to kill the program.
  10.  
  11. [OK] [Abort]

What didn't I understand ?

MarkMLl

  • Hero Member
  • *****
  • Posts: 7419
Re: An instruction to pause the debugger.
« Reply #3 on: June 29, 2024, 06:44:01 pm »
Code: Pascal  [Select][+][-]
  1. asm
  2. int 3
  3. end;
(mind the space before the 3)

At least the latter, should probably be IFDEFed for debugging only. I.e., compile for debug with -dMY_DBG_DEFINE (which then goes into the ifdef)

Only, by default the debugger ignores both (the first one also ends on a "int 3")

In the Option, Debugger Backend, in the settings for FpDebug is "HandleDebugBreakInstruction", which is set to "IgnoreAll". Uncheck the IgnoreAll.

Downside: Other code (libraries) can also contain "int 3" => and then that will also enter debug pause.

Thanks very much for that Martin. I admit to fairly regularly having an Assert(false,... if I want to be alerted that a program has got itself into a thoroughly discombobulated state.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 4471
Re: An instruction to pause the debugger.
« Reply #4 on: June 29, 2024, 06:57:23 pm »
Uncheck'ed the IgnoreAll.

What didn't I understand ?
I just tried the "asm int 3 end;" and it didn't work.  The program execution got messed up.

If you are using Windows, use DebugBreak(), that one works.  I use it all the time.

HTH.

ETA:

using "asm int 3 end;" does work with GDB.  I know because that's what I used all the time before FpDebug supported DebugBreak();

Because of Martin's answer to you, I'm guessing that FpDebug now is supposed to support "asm int 3 end;" too but, as I mentioned above, I tried it and execution got messed up.  IOW, "asm int 3 end;" isn't working quite right at this time.

« Last Edit: June 29, 2024, 07:03:17 pm by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

BrunoK

  • Hero Member
  • *****
  • Posts: 559
  • Retired programmer
Re: An instruction to pause the debugger.
« Reply #5 on: June 29, 2024, 07:41:33 pm »
Marking discussion as SOLVED.

If you are using Windows, use DebugBreak(), that one works.  I use it all the time.
Thank you very much, this works on Windows with FPDebugger provided the Uncheck'ed  IgnoreAll as indicated by Martin.

No need of USES Windows ...

 The bit of code (CocoR) ends up being :
 
Code: Pascal  [Select][+][-]
  1.       while fCurrentInputSymbol<>EOFSYMB do begin
  2.          if fCurrentInputSymbol=lAheadSym then begin
  3.            DebugBreak;
  4.            { Some checking about aAfterSymName preceding found aAheadSymName }
  5.            if lPrevSym<>lAfterSym then
  6.              DebugBreak;
  7.              lDefaultSym := lAfterSym;
  8.            Exit;
  9.          end;
  10.          lPrevSym := fCurrentInputSymbol;
  11.          Get;
  12.        end;
  13.  
That pop's up the Call Stack when reaching one the DebugBreak instructions, then one F7 single step places you on the next executable line.

Maybe, just maybe, a feature would be the debugger poping the source at the DebugBreak instruction as if a Break point had been set there.

This is very useful and I should have asked many months/year ago.

440bx

  • Hero Member
  • *****
  • Posts: 4471
Re: An instruction to pause the debugger.
« Reply #6 on: June 29, 2024, 07:54:36 pm »
This is very useful and I should have asked many months/year ago.
Just in case you might find this useful, this is what I do:
Code: Pascal  [Select][+][-]
  1.       if IsDebuggerPresent() then
  2.       begin
  3.         DebugBreak();
  4.       end;
  5.  
Checking if the debugger is present before calling DebugBreak() allows leaving the debugging code in the executable.  This makes removing the DebugBreak() in the release version unnecessary.  Without the check for the Debugger presence then the calls to DebugBreak() have to be removed or placed in a {$ifdef } conditional compilation because if a DebugBreak() occurs without a debugger to catch it, Windows will report it as an unhandled exception and terminate the program (usually not a desirable outcome ;) )

Activating the DebugBreak() only if a debugger is present is a very convenient and practical solution.  The cost is a slight increase in code size (I think about 8 bytes total per instance... that's nothing in today's machines.)

HTH.
(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: 10222
  • Debugger - SynEdit - and more
    • wiki
Re: An instruction to pause the debugger.
« Reply #7 on: June 29, 2024, 08:38:24 pm »
Maybe, just maybe, a feature would be the debugger poping the source at the DebugBreak instruction as if a Break point had been set there.

There are a lot of refinements this could get. But, even though I do note that there is more interest than was originally anticipated, it will have to wait. Too many other things on my list.

BrunoK

  • Hero Member
  • *****
  • Posts: 559
  • Retired programmer
Re: An instruction to pause the debugger.
« Reply #8 on: June 29, 2024, 11:39:53 pm »
Just in case you might find this useful, this is what I do:
Code: Pascal  [Select][+][-]
  1.       if IsDebuggerPresent() then
  2.       begin
  3.         DebugBreak();
  4.       end;
  5.  
Noted, thank you.

440bx

  • Hero Member
  • *****
  • Posts: 4471
Re: An instruction to pause the debugger. [SOLVED]
« Reply #9 on: June 30, 2024, 03:19:50 am »
You're welcome Bruno.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 15487
  • Censorship about opinions does not belong here.
Re: An instruction to pause the debugger. [SOLVED]
« Reply #10 on: June 30, 2024, 10:12:06 pm »
May I suggest a codeless solution?
Code: Pascal  [Select][+][-]
  1. {$ifopt D+}DebugBreak();{$endif}
In effect about the same as assertions, the code does not end up in a release compile.
IsDebuggerPresent was nice in the days but not always reliable.
« Last Edit: June 30, 2024, 10:17:20 pm by Thaddy »
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.

440bx

  • Hero Member
  • *****
  • Posts: 4471
Re: An instruction to pause the debugger. [SOLVED]
« Reply #11 on: June 30, 2024, 11:23:42 pm »
May I suggest a codeless solution?
Code: Pascal  [Select][+][-]
  1. {$ifopt D+}DebugBreak();{$endif}
In effect about the same as assertions, the code does not end up in a release compile.
IsDebuggerPresent was nice in the days but not always reliable.
IsDebuggerPresent() is _completely_ reliable except in one case, which is, when a cracker wants to hide the fact that he/she is running the app under a debugger (it's very easy to make IsDebuggerPresent() return false but, only with malice)

Other than that exception which occurs as a result of malice, IsDebuggerPresent() is rock solid.

Your suggestion still has merit but, if I were going that route, I'd make it a macro.

Another reason I prefer IsDebuggerPresent() is because I can add ad-hoc code between the begin/end to debug a particular situation.  begin/end space... the ultimate frontier.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

BrunoK

  • Hero Member
  • *****
  • Posts: 559
  • Retired programmer
Re: An instruction to pause the debugger. [SOLVED]
« Reply #12 on: July 01, 2024, 02:52:12 pm »
Quote
Code: Pascal  [Select][+][-]
  1. {$ifopt D+}DebugBreak();{$endif}
Seems not to work in Windows, ifopt is always true.

My current version is, in the program where I want to put the DebugBreak :

Code: Pascal  [Select][+][-]
  1. function DebugBreak: boolean; inline;
  2. begin
  3.   {$ifdef windows}
  4.   Result := Windows.IsDebuggerPresent();
  5.   if Result then
  6.     Windows.DebugBreak;
  7.   {$else}
  8.     Result := False;
  9.   {$endif}
  10.   (* Testing
  11.   if Result then
  12.     WriteLn('{Has debug}')
  13.   else
  14.     WriteLn('{Doesn''''t have debug}');
  15.   *)
  16. end;
The DebugBreak function inlines well.

440bx

  • Hero Member
  • *****
  • Posts: 4471
Re: An instruction to pause the debugger. [SOLVED]
« Reply #13 on: July 01, 2024, 03:15:35 pm »
Just a very minor thing... in that code I don't think you need the {$else} part because result will already be set by IsDebuggerPresent();

Another thing you may want to consider, if you change it to a procedure then you can make it use zero bytes if you don't need the DebugBreak facility.  Something like this:
Code: Pascal  [Select][+][-]
  1. procedure DebugBreak(); inline;
  2. begin
  3.   {$if defined(USE_DEBUGBREAK)}
  4.     {$ifdef windows}
  5.     if Windows.IsDebuggerPresent() then
  6.        Windows.DebugBreak;
  7.     {$endif}
  8.   {$endif}
  9. end;

the net effect of doing it that way is that if USE_DEBUGBREAK is not defined then the DebugBreak procedure is empty and since it is inlined, the compiler entirely omits the call.  IOW, it takes _zero_ bytes.  Basically, you can have your cake and eat it too whenever convenient.

HTH.
(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: 10222
  • Debugger - SynEdit - and more
    • wiki
Re: An instruction to pause the debugger. [SOLVED]
« Reply #14 on: July 01, 2024, 03:16:04 pm »
If you write your own wrapper function, you can just fill it with
Code: Pascal  [Select][+][-]
  1. asm
  2.   nop
  3. end;
and set a breakpoint there.

Unless, you have multiple binaries (such as lots of dll, in each of which you want such a function).


EDIT:
if the function is "inline" then you can't set a breakpoint, as fpc does not provide line info for that.

But if you IFDEF, then you can IFnDEF the "inline".
« Last Edit: July 01, 2024, 03:18:07 pm by Martin_fr »

 

TinyPortal © 2005-2018