Recent

Author Topic: existing variables unavailable when exception happens  (Read 1585 times)

NightSky

  • New Member
  • *
  • Posts: 20
existing variables unavailable when exception happens
« on: May 29, 2023, 03:11:25 am »
I'm sure that this has been mentioned before, but a cursory search of topics seems to miss this.

I'm debugging a relatively complex program.  I get an FPC exception, generall because of an invalid argument to a number conversion routine.  Still debugging stuff.

When I try to find the string that caused the error, to see what it was, while I do find the "error", I cannot look at any of the variables.  I cannot trace back up a chain to see what the variables are, I only get an error "$" is not a valid number.  (which when you realize it was supposed to be a $nnnn where nnnn is a hex number, I understand).  However, trying to look at the variables gives me a "name = ???" which says that the crash happens in such a way to destroy the variables, which is of no great help.

Is this a "standard behavior" or a bug?   

Is there a workaround for this?

Handoko

  • Hero Member
  • *****
  • Posts: 5122
  • My goal: build my own game engine using Lazarus
Re: existing variables unavailable when exception happens
« Reply #1 on: May 29, 2023, 04:20:44 am »
Use Try-Except statement and write code to log the variable to screen/file in On Except block.
https://wiki.freepascal.org/Try

Or you can simply send the value to Form.Caption, like the code below:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   Test, i: Integer;
  4. begin
  5.   i := 123;
  6.   repeat
  7.     Test := Random(10);
  8.     Caption := Test.ToString;
  9.     Application.ProcessMessages;
  10.     i := i div Test;
  11.   until False;
  12. end;

Line #10 is where the error happens. So you need to put Line #8 and #9 right above it.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9754
  • Debugger - SynEdit - and more
    • wiki
Re: existing variables unavailable when exception happens
« Reply #2 on: May 29, 2023, 11:16:57 am »
I can't tell for sure from your description what the issue is....

1) First of all, I assume Lazarus 2.2.6 ? (or 2.2.n)

2) Your OS?

3) Project Options > Debugging
 a) Generate info for debugger enabled?
 b) Type of debug info? (Dwarf ....?)
     Should be
     For GDB based debugger : Dwarf with sets
     For FpDebug: Dwarf-3 or Dwarf with sets (chose the latter, if you may switch back to gdb at some point)

4) Tools > Options > Debugger Backend 
Which debugger is selected? "GNU Debugger (gdb)" or "FpDebug (...)"

If not "FpDebug" => try FpDebug.

5)
Have you got the "Stack Window" open?  Menu: View > Debug Windows > Call Stack
If so, what does it show?

If it does show function names, which one is active (little green arrow in the left-most column)
Maybe you need to select a difference line? (select line, click "green arrow" tool button)

6)
Quote
"$" is not a valid number.
- What is the exact term you are looking at?
- Are you hovering the mouse?
- Can you copy the term to the "Watches" window?

7)
Quote
I get an FPC exception
I.e., "Run time error"?
Or "The project raised an exception ..." ?

If the first, and if "sysutils" is used, then if you continue (F9) you should get the "raised an exception" => Do you get different info then (see your code in the stacktrace, in case it had not been there before)



If you do get an "Access violation" or "Sigfault" then that is different.

E.g. if you get stack corruption, then the assemble window may open, and show you code at adress 0x0000000 (which does not exist).
Or it may show you code at a random address which may or may not be in your exe.

If your stack got corrupted, then getting data may or may not be possible. Because if the stack is corrupted, it is possible that all and any info where your code is/was has been lost.
« Last Edit: May 29, 2023, 11:20:46 am by Martin_fr »

NightSky

  • New Member
  • *
  • Posts: 20
Re: existing variables unavailable when exception happens
« Reply #3 on: May 29, 2023, 05:37:48 pm »
I can't tell for sure from your description what the issue is....

1) First of all, I assume Lazarus 2.2.6 ? (or 2.2.n)

2.2.2

2) Your OS?

Windows 10, 64 bit


3) Project Options > Debugging
 a) Generate info for debugger enabled?

Yes.
 b) Type of debug info? (Dwarf ....?)
     Should be
     For GDB based debugger : Dwarf with sets
     For FpDebug: Dwarf-3 or Dwarf with sets (chose the latter, if you may switch back to gdb at some point)

Dwarf with sets

4) Tools > Options > Debugger Backend 
Which debugger is selected? "GNU Debugger (gdb)" or "FpDebug (...)"

FPdebug


If not "FpDebug" => try FpDebug.

5)
Have you got the "Stack Window" open?  Menu: View > Debug Windows > Call Stack
If so, what does it show?

I did.  This is a aperiodic error.  There is a remote application sending ascii encoded binary data over a serial line.  The packet when generated has a checksum and is discarded when the checksum is bad. 

What I see in the stack window (by memory) is messaging, then further up, the error determination, then a raise exception (I think), then two calls to internal machine language.

If it does show function names, which one is active (little green arrow in the left-most column)
Maybe you need to select a difference line? (select line, click "green arrow" tool button)

The exception is thrown by HEX2DEC, which apparently doesn't like a single "$" for an input string, (trapping out either '' for a string or '$' for a string seems to avoid this)
That is an error message in one of the windows after the program is allowed to continue.

My original comment was that if I try to hover over the input variable to the function, I get a value of ???.

6)
Quote
"$" is not a valid number.
- What is the exact term you are looking at?
- Are you hovering the mouse?
- Can you copy the term to the "Watches" window?

I think I've tried copying the variable to the watches window, and IIRC, none of the watches give valid values (not bad values, '???' values, IIRC).


7)
Quote
I get an FPC exception
I.e., "Run time error"?
Or "The project raised an exception ..." ?

I actually get both, which ought to have been caught, but I suspect my code is faulty.  (which will be later in this)

If the first, and if "sysutils" is used, then if you continue (F9) you should get the "raised an exception" => Do you get different info then (see your code in the stacktrace, in case it had not been there before)

Can't answer that.  Program is currently running properly (of course)




If you do get an "Access violation" or "Sigfault" then that is different.

Nope, not that.  Not a bad pointer.  Had that, familiar with it.  This is one of the system routines reporting an input value violation.

E.g. if you get stack corruption, then the assemble window may open, and show you code at adress 0x0000000 (which does not exist).
Or it may show you code at a random address which may or may not be in your exe.

Don't think that happened.  If part of HEX2DEC can do that, then I'd suspect insufficient paranoia in the programmers who wrote that routine.

If your stack got corrupted, then getting data may or may not be possible. Because if the stack is corrupted, it is possible that all and any info where your code is/was has been lost.

Been there, done that in C++ code on an STM32 processor running FreeRTOS.  Don't think that the stack is corrupted since I can go up and down the call stack (with the exception of the machine language calls at the very last) and find where the program did calls.



Still puzzled a bit, but perhaps I've given you enough information to help out.

For a second (and related), topic, I suspect that my use of try/except seems to be flawed.

From what I see, the following code ought to work properly, with some questions.

Code: Pascal  [Select][+][-]
  1.  
  2. function convert_field(data: string): word;
  3. var
  4.   tempstr:                string;
  5.   i:                      integer;
  6.   value:                  word;
  7.  
  8. begin
  9.   tempstr :=  trim(data);
  10.   if (tempstr = '$') or (tempstr = '') then
  11.   begin
  12.     convert_field := 0;
  13.     exit;
  14.   end;
  15.  
  16.   try
  17.     try
  18.       value := HEX2DEC(tempstr);
  19.     except
  20.       // will only be executed in case of an exception
  21.       //on E: EDatabaseError do
  22.       //  ShowMessage( 'Database error: '+ E.ClassName + #13#10 + E.Message );
  23.       on E: Exception do
  24.       begin
  25.         ShowMessage( 'Error: '+ E.ClassName + #13#10 + E.Message );
  26.         value := 0;
  27.       end;
  28.   end;
  29. finally
  30.   convert_field := value;
  31. end;
  32.  
  33. end;
  34.  
  35.  
  36.  

Should I remove the trap lines, I get the error from HEX2DEC.  My questions about this particular code are:
  • I don't think I can have a single structure of try/except/finally, it seems to have to be nested.
    The documentation is a bit vague about the exception code:  the documentation says "the code will be exeuted", the examples give ON exception, and hint that the specific type of exception needs to be trapped here.  seems to be a conflict. 

I seem to be missing something.

Thanks

NightSky

  • New Member
  • *
  • Posts: 20
Re: existing variables unavailable when exception happens
« Reply #4 on: May 29, 2023, 06:04:38 pm »
     NOTE: if your login expires, you can't post a reply, and get the error message "you're not allowed to do this"
Logging in gives you a wonderful, pristine blank box in which you can put your thoughts.....

Not special at all




NightSky

  • New Member
  • *
  • Posts: 20
Re: existing variables unavailable when exception happens
« Reply #5 on: May 29, 2023, 06:07:38 pm »
Rewrite:

Got the glitch

stack is:

#0 FPC_RAISEEXCEPTION at :0
#1 SYSUTILS_$$_STRTOINT$ANSISTRING$$LONGINT+120 at :0
#2 STRUTILS_$$_HEX2DEC$ANSISTRING$$LONGINT+94 at :0
#3 CONVERT_FIELD($0000000007A13848^: '0 '#$03'E') at D:\Documents\Projects\Lazarus Delphi\TRACE ANALYZER 2\main.pas:1003
#4 TFORM1.DECODE_INCOMING(TFORM1($00000000060EB090), SYSTEM_SUPERUSER_PACKET (SYSTEM_SUPERUSER_PACKET_TYPE (#$01; ('3', '4', '7', {5 more elements}); #$02; SUPERUSER_BLOCK (NRF_BLOCK (({4 elements}); ({4 elements}); ({4 elements}); ({2 elements}); ({2 elements}); ({2 elements})); COMMAND_BLOCK (({4 elements}); STRING_BLOCK (({60 elements})); NRF_BLOCK (({4 elements}); ({4 elements}); ({4 elements}); ({2 elements}); ({2 elements}); ({2 elements})))); #$00; (#$00, #$00, #$00, {1 more elements}); #$00; #$00; #$00); (#$01, '3', '4', '7', '3', '4', '6', '1', ' ', #$02, {54 more elements})), 1) at D:\Documents\Projects\Lazarus Delphi\TRACE ANALYZER 2\main.pas:2115
#5 TFORM1.LAZSERIAL1RXDATA(TFORM1($00000000060EB090), TOBJECT($00000000016104B0)) at D:\Documents\Projects\Lazarus Delphi\TRACE ANALYZER 2\main.pas:1443
#6 TCOMPORTREADTHREAD.CALLEVENT(TCOMPORTREADTHREAD($0000000007990FC0)) at D:\Documents\Projects\Lazarus Delphi\Components\TLazSerial-master\lazserial.pas:492
#7 CLASSES$_$TTHREAD_$__$$_AFTERCONSTRUCTION+68 at :0
#8 TWINDOWPROCHELPER.DOWINDOWPROC(TWINDOWPROCHELPER (856864; 0; 0; 0; TMESSAGE (0; 0; 0; 0; 0; 0; TDWORDFILLER (({4 elements})); 0; 0; TDWORDFILLER (({4 elements})); 0; 0; TDWORDFILLER (({4 elements}))); $00000000013FF7C8; nil; True; False; $00000000016381D0; TDOUBLEBUFFER (0; 0; 0; 0); 0; 0; TLMPAINT (0; 0; 0; nil; 0); False; 0; TLMSCROLL (0; 0; 0; 0; 0; 0; 0; 0); TLMKEY (0; 0; 0; 0; 0; 0; 0); TLMKEY (0; 0; 0; 0; 0; 0; 0); TLMMOUSE (0; 0; 0; 0; TSMALLPOINT (0; 0); 0; 0); TLMCONTEXTMENU (0; 0; 0; 0; 0; TSMALLPOINT (0; 0); 0; 0); TLMMOUSE (0; 0; 0; 0; TSMALLPOINT (0; 0); 0; 0); TLMMOUSEEVENT (0; 0; 0; 0; 0; 0; 0; 0; 0; nil; []); TLMMOVE (0; 0; 0; 0; 0; TSMALLPOINT (0; 0); 0; 0); TLMNOTIFY (0; 0; 0; nil; 0); TDRAWLISTITEMSTRUCT (0; TRECT (0; 0; 0; 0; TPOINT (0; 0); TPOINT (0; 0); TARRAY4INTEGERTYPE({4 elements})); 0; []); nil; nil)) at C:\lazarus\lcl\interfaces\win32\win32callback.inc:2055
#9 WINDOWPROC(856864, 0, 0, 0) at C:\lazarus\lcl\interfaces\win32\win32callback.inc:2772
#10 user32:CallWindowProcW+1016 at :0
#11 TAPPLICATION.HANDLEMESSAGE(TAPPLICATION($00000000015C0BF0)) at C:\lazarus\lcl\include\application.inc:1264
#12 TAPPLICATION.RUNLOOP(TAPPLICATION($00000000015C0BF0)) at C:\lazarus\lcl\include\application.inc:1383
#13 TWIDGETSET.APPRUN(TWIDGETSET($0000000001618400), TAPPLICATIONMAINLOOP ($000000010002C530 = TAPPLICATION.RUNLOOP: TAPPLICATIONMAINLOOP; TOBJECT($00000000015C0BF0))) at C:\lazarus\lcl\include\interfacebase.inc:54
#14 TAPPLICATION.RUN(TAPPLICATION($00000000015C0BF0)) at C:\lazarus\lcl\include\application.inc:1371
#15 main at D:\Documents\Projects\Lazarus Delphi\TRACE ANALYZER 2\TRACE_ANALYZER_2.lpr:23
#16 DEBUGEND_$P$TRACE_ANALYZER_2+6 at :0


hovering mouse over variable gives '???' for value

Variable watch shows "variable not found"

Exception was lost in the great rewrite, but made sense (bad number/invalid number)

did "break" rather than "continue"


Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9754
  • Debugger - SynEdit - and more
    • wiki
Re: existing variables unavailable when exception happens
« Reply #6 on: May 29, 2023, 07:56:34 pm »
Quote
The exception is thrown by HEX2DEC, which apparently doesn't like a single "$" for an input string, (trapping out either '' for a string or '$' for a string seems to avoid this)
That is an error message in one of the windows after the program is allowed to continue.

HEX2DEC is in StrUtils => and that is in the RTL. The RTL usually does not have debug info. So, yes indeed - by design - you can't debug there. (function names are sometimes avail, due to left overs from the linker).

If you need to debug in the RTL, then you need to rebuild fpc.

Similar restrictions are true for packages. Only many of the packages in Lazarus have debug info by default.


Quote
I don't think I can have a single structure of try/except/finally, it seems to have to be nested.
Yes they need to be nested.

Except: You don't (re-)raise the exception. So the code always continues after the "except ... end" block. In that case you don't need a "try finally". Of course if you remove it, you have to remember to add it again, if you make changes (remove the except, or re-raise).
Well, the finally still covers, if any error happens inside the "except" block. If that is a concern.


Quote
Should I remove the trap lines,
Lost in translation? Not sure what you mean.


Quote
NOTE: if your login expires, you can't post a reply, and get the error message "you're not allowed to do this"
Logging in gives you a wonderful, pristine blank box in which you can put your thoughts.....
The forum software isn't written by us, so unfortunately we can't do much about it. Unless they fixed it, and then when our admin eventually has the time and upgrades.... (That is planed / Has been planed for some time...)

Quote
Code: Pascal  [Select][+][-]
  1. Got the glitch
  2.  
  3. stack is:
  4.  
  5. #0 FPC_RAISEEXCEPTION at :0
  6. #1 SYSUTILS_$$_STRTOINT$ANSISTRING$$LONGINT+120 at :0
  7. #2 STRUTILS_$$_HEX2DEC$ANSISTRING$$LONGINT+94 at :0

Both RTL. You can select frames further down, and if they are in your code they should have debug info.

Unfortunately (as far as I am aware) there is no pre-build RTL with debug info available. If needed, the best option may be FpcUpDeluxe.




Ps, please use "preview" to check if you got Quote and Code tags correct... Or edit your posts. Thanks.


NightSky

  • New Member
  • *
  • Posts: 20
Re: existing variables unavailable when exception happens
« Reply #7 on: May 29, 2023, 08:07:50 pm »
OK, I can see the lack of debug information, so that explains why, when halted, all the variables are "???" in value?
Even the ones that are NOT part of the RTL?

Oh, just different nomenclature, the trap lines are the lines of code used to "trap" the empty string or just a "$" formatting errors, rather than relying on the HEX2DEC routine and the try/exception to catch them.

On the site, well, that's awkward, but best that can be done.

Did preview it, but the quote key quoted the entire message, and not the part I had highlighted.  Will do better next time

We're getting somewhere (just need to make sure that the valid hex number routine works).

Thanks

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9754
  • Debugger - SynEdit - and more
    • wiki
Re: existing variables unavailable when exception happens
« Reply #8 on: May 29, 2023, 09:40:00 pm »
OK, I can see the lack of debug information, so that explains why, when halted, all the variables are "???" in value?
Even the ones that are NOT part of the RTL?

I don't know how/which "are NOT part of the RTL" you were accessing.

If you access global vars, from a unit of your project (or a package that has debug info), then they should work.

If you access locals, you need to select (and "set as current" with green-arrow-tool-button) the correct frame from the stack window.
E.g. If you just hover over some text in a function, it will take the text from the editor, but look in the "current function". (Not the function in which the word occurs in the editor).
That is because the function in the editor, may be recursive, and then it would not even be able to tell which "stack" should be current. You have to be explicit.

* "Has debug info" => such units will show blue dots in the gutter, next to the code.

 

TinyPortal © 2005-2018