Recent

Author Topic: How to Debug and Step into Assert() Function in Lazarus?  (Read 3268 times)

PascalDragon

  • Hero Member
  • *****
  • Posts: 5823
  • Compiler Developer
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #30 on: October 26, 2024, 03:40:05 pm »
It is in system.inc
Code: Pascal  [Select][+][-]
  1. Procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;
  2.    ErrorAddr:Pointer); [Public,Alias : 'FPC_ASSERT']; compilerproc;
  3. begin
  4.   if codepointer(AssertErrorProc)<>nil then
  5.     AssertErrorProc(Msg,FName,LineNo,ErrorAddr)
  6.   else
  7.     HandleErrorAddrFrameInd(227,get_pc_addr,get_frame);
  8. end;
  9.  

Mind that this is an intrinsic. As you can see the boolean result of the condition is not in the parameters => that code is inlined into your calling procedure. So the above is only called, if the condition fails.

Afaik it then depends. If any unit in your app (including recursively any unit you used) uses "SysUtils then it throws an exception.

And if you want you can catch that exception.

And as one might also conclude from that code: one can replace AssertErrorProc if one wants. For example the mentioned throwing of an exception is accomplished by the SysUtils unit setting AssertErrorProc in its initialization section.

Aruna

  • Hero Member
  • *****
  • Posts: 568
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #31 on: October 27, 2024, 02:39:20 am »
https://wiki.freepascal.org/Debugger_Status
Many thanks for the link..

LLDB like GDB is a command line debugger, that you can download. It supports Linux, Win and Mac.
Ok..

In the IDE it was added as "LLDB with FpDebug" for Mac, since the pure "FpDebug" does not work for Mac.
Ah, I see now..

"LLDB (Alpha)" without FpDebug was just a by product. It exists, but has no support. (hence Alpha).
Hmm.. interesting.

FpDebug only supports the Intel/Amd architecture, so for other targets other debuggers are needed. And also for cross debugging and embedded other debuggers are needed. (though there is an FpDebug based debugger for some avr embedded...)
Thank you for taking the time to explain all this, very much appreciated.


On Windows, gdb is still shipped with the IDE => so that can be used. However it delivers a significantly lesser experience. There are a very few edge cases where it still may be useful. (like in some scenarios, when debugging inside the windows kernel, it gives longer stack traces // or cross debugging from a 32bit IDE to a 64bit project -> really should use the 64bit IDE instead)
Your joking right? 'Who' debuuged from a 32bit IDE into a 64bit project that is not going to end well as MarkMLI would say. You have to be insane to do something like that or simply did not know better?

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10690
  • Debugger - SynEdit - and more
    • wiki
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #32 on: October 27, 2024, 11:17:33 am »
Your joking right? 'Who' debuuged from a 32bit IDE into a 64bit project that is not going to end well as MarkMLI would say. You have to be insane to do something like that or simply did not know better?

Over the years I have learned that some of the things I take for granted (as in "how else could you possible do that") are anything but that. And that there are other ways to it. Even if those other ways don't work for me, they still make sense.

Maybe someone has some IDE add on, that only comes for 32bit (e.g. requires a dll that only exists in 32bit)? That can happen if you write software to control external legacy hardware (and you need it to work in the designer too), and the drivers are 32bit. If that is industrial, then new hardware may cost 5 or 6 digits figures.

Aruna

  • Hero Member
  • *****
  • Posts: 568
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #33 on: October 27, 2024, 11:21:33 am »
It is in system.inc
Code: Pascal  [Select][+][-]
  1. Procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;
  2.    ErrorAddr:Pointer); [Public,Alias : 'FPC_ASSERT']; compilerproc;
  3. begin
  4.   if codepointer(AssertErrorProc)<>nil then
  5.     AssertErrorProc(Msg,FName,LineNo,ErrorAddr)
  6.   else
  7.     HandleErrorAddrFrameInd(227,get_pc_addr,get_frame);
  8. end;
  9.  

Mind that this is an intrinsic. As you can see the boolean result of the condition is not in the parameters => that code is inlined into your calling procedure. So the above is only called, if the condition fails.

Afaik it then depends. If any unit in your app (including recursively any unit you used) uses "SysUtils then it throws an exception.

And if you want you can catch that exception.

And as one might also conclude from that code: one can replace AssertErrorProc if one wants. For example the mentioned throwing of an exception is accomplished by the SysUtils unit setting AssertErrorProc in its initialization section.

Hi @PascalDragon. I am yet very new to all this and trying to teach myself how things work under the hood. So, The fpc_assert procedure checks whether a custom error handler (AssertErrorProc) is set? If it is, it uses it to handle the assertion. Otherwise, it uses a default handler (HandleErrorAddrFrameInd) ? Is that the way things work?

I also ran the code snippet above throughchatGPT as it has many times helped me to break down things and understand how the code works. This is what chatGPT said when I asked it to give me a heavily commented breakdown and explanation:

---
Code: Pascal  [Select][+][-]
  1. Procedure fpc_assert(Const Msg, FName: Shortstring; LineNo: Longint; ErrorAddr: Pointer);
  2.   // Declares the procedure 'fpc_assert', which is used to handle assertion errors.
  3.   // Parameters:
  4.   //   - Msg: A message string that provides details about the assertion error.
  5.   //   - FName: The name of the file in which the assertion failed.
  6.   //   - LineNo: The line number in the file where the assertion failure occurred.
  7.   //   - ErrorAddr: A pointer to the address where the error occurred, which can
  8.   //     help in debugging the issue by showing the memory location.
  9.  
  10.   [Public, Alias : 'FPC_ASSERT'];  // The procedure is public and has an alias 'FPC_ASSERT'.
  11.                                    // This means it can be called using 'FPC_ASSERT' as an alternative name.
  12.   compilerproc;  // This attribute specifies that it is a compiler-provided procedure
  13.                  // and can only be used internally by the compiler.
  14.  
  15. begin
  16.   if codepointer(AssertErrorProc) <> nil then
  17.     // Check if 'AssertErrorProc' (a custom assertion error handler) is set.
  18.     // 'codepointer' is used to obtain the code pointer of 'AssertErrorProc' and check if it's not nil.
  19.     // If it's nil, no custom error handler is defined, so we use a default handler instead.
  20.  
  21.     AssertErrorProc(Msg, FName, LineNo, ErrorAddr)
  22.     // If 'AssertErrorProc' is not nil, call it with the provided assertion details (Msg, FName, LineNo, ErrorAddr).
  23.     // This allows the custom handler to process the assertion failure as needed.
  24.  
  25.   else
  26.     HandleErrorAddrFrameInd(227, get_pc_addr, get_frame);
  27.     // If 'AssertErrorProc' is nil, use the default error handler 'HandleErrorAddrFrameInd'.
  28.     // Parameters for 'HandleErrorAddrFrameInd':
  29.     //   - 227: Likely a specific error code indicating an assertion failure.
  30.     //   - get_pc_addr: Function to get the program counter (PC) address where the error occurred.
  31.     //   - get_frame: Function to get the current stack frame, which helps in tracing the error context.
  32. end;

It also gave me this:
Code: Text  [Select][+][-]
  1. Key Points Explained
  2.  
  3.     Parameters:
  4.         Msg: A short string with the error message for the assertion. This message usually describes what the assertion expected to be true.
  5.         FName: The file name where the assertion failed, which aids in debugging by showing the source location.
  6.         LineNo: The line number in the file where the failure happened, which helps pinpoint the exact location in the source code.
  7.         ErrorAddr: The memory address where the error occurred, useful for lower-level debugging.
  8.  
  9.     Error Handling Logic:
  10.         Custom Handler (AssertErrorProc):
  11.             AssertErrorProc is checked first. If it’s not nil, it means a custom error-handling procedure is set, and it will be used to handle the assertion.
  12.            This is useful if developers want to customize how assertions are reported or handled.
  13.         Default Handler (HandleErrorAddrFrameInd):
  14.             If AssertErrorProc is nil (no custom handler is provided), it falls back on a default handler, HandleErrorAddrFrameInd. This function uses
  15.             hardcoded values and system functions (get_pc_addr and get_frame) to identify the program counter and stack frame, aiding in debugging
  16.            by showing the context of the assertion failure.
  17.  
  18. This setup allows the fpc_assert procedure to either use custom handling or revert to a default approach, ensuring assertions are managed consistently,
  19. even if a custom handler is absent.

Is the above correct? The reason I ask is when I run anything through chatGPT I usually get myself in a lot of trouble with the community or end up being told not to use generated AI nonsense. But to me, chatGPT is simply another 'tool' that has helped me understand code which at first was way over my head. I decided to share this in the hope if the breakdown is correct and accurate it can help others who are newbies like myself.

 

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1294
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #34 on: October 27, 2024, 12:14:47 pm »
Quote
Is the above correct?
You could ask chat gpt  :D
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Aruna

  • Hero Member
  • *****
  • Posts: 568
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #35 on: October 27, 2024, 01:07:04 pm »
Quote
Is the above correct?
You could ask chat gpt  :D
I did ask and chatGPT said please go ask the gods. So I did :)
PascalDragon = One of the Pascal Gods!
Soo.. HA!  :P

Aruna

  • Hero Member
  • *****
  • Posts: 568
Re: How to Debug and Step into Assert() Function in Lazarus?
« Reply #36 on: October 27, 2024, 01:13:30 pm »
Over the years I have learned that some of the things I take for granted (as in "how else could you possible do that") are anything but that. And that there are other ways to it. Even if those other ways don't work for me, they still make sense.
True... been there, done that :) recently with a Arduino Nano and getting Laz-IDE to talk to it ( bi-directional) and MarkMLI freaked out and wanted to know "why are you using file operations on a serial comm port"  and he was right to ask but I could not for the life of me get Synapse to be my friend or suss out how Synapse wants things done so I went old school and the thing is my file operations worked!

Maybe someone has some IDE add on, that only comes for 32bit (e.g. requires a dll that only exists in 32bit)? That can happen if you write software to control external legacy hardware (and you need it to work in the designer too), and the drivers are 32bit. If that is industrial, then new hardware may cost 5 or 6 digits figures.
Oh yes that... I totally forgot the rather pricey industrial aspect!

 

TinyPortal © 2005-2018