About https://bugs.freepascal.org/view.php?id=34881

First of all, big thanks to Sven for the patch.
I had a look at it, I also looked through the alternatives again.

First of all the patch would need some tweaking (but that is to be expected), but I am not sure it is the best way to go.

Under gdb the issue is that there seems no way to access the data (added by the patch). And gdb itself does not seem to use it either (it does read the entries, but does not seem to further access them). Gdb actually does the same as the IDE does in none seh code. gdb sets breakpoints at "__cxa_begin_catch".

FpDebug of course could access the data, but I am not sure it is worth it (At least in the immediate future).

To access the data it is needed to unroll the stack, including through kernel and 3rd party code. Normal stack unrolling can fail in such cases. Of course it can be done with the help of the seh data itself. And that may be a path worth pursuing, even if only to get better stack traces. (Not sure yet what priority that may get...)

On win64 the unroll data can actually be captured by breaking on __FPC_specific_handler and using dispatch.ControlPc / So that might be easy (in fpdebug). On win32 this is not available. There is some dispatch argument, but I found no info what it contains.

------------------
I found some alternatives. (Comments welcome)
They do depend on implementation details, but so does having a breakpoint at fpc_raiseexception, fpc_catch...., or even __FPC_specific_handler.

*** Detecting on Win64
** Except
On win64, the address of except handlers can already be detected, by breaking on the kernel's RtlUnwindEx

** Finally
Breaking on __FPC_specific_handler the debugger can access "HandlerData" (a table with finally addresses for the  frame (on each call)) That works as long as those tables do not change in format. "HandlerData" is the only bit, that is compiler specific. The other structures are given by the OS.

The detected addresses can be verified, as they must have line info, and for finally blocks the function name must match .*fin\$.*
All this should work through gdb.

Not sure if it is worth writing dwarf info for __FPC_specific_handler  and its arguments. Then of course the arguments format could be checked, if they have the correct format.
At the moment, I am quite happy to access them without dbg info.


Alternative it is possible to use dispatch.ControlPc to find the function in which to look for finally handlers. FpDebug could use that to combine it with the dwarf from the patch. But since FpDebug knows the version of fpc that created the file, it also knows if it can trust the "HandlerData".


*** Detecting on Win32
The debugger can break on __FPC_finally_handler  and __FPC_except_handler
Both have frame.HandlerArg as argument which (depending on the other args) is the address of the next finally/except handler.

Again that relies on fpc not changing what HandlerArg contains.
But since it can be checked to be an address with line info, it should be use-able. (and should work through gdb)

*** Other OS ??
Are there any plans for such exception handling?

======================
About the patch. ...
The need to address the issues below, depends on the outcome of the above....

1)
program Project1;
begin
  try
    try
      writeln;
    except
      writeln;
    end;
  except
    writeln;
  end;
end.

gives
project1.lpr(2,6) Error: Internal error 2019102101

2)
The tag for a finally block point to the code in the function containing the try/finally. That is the asm instruction " call fin$1" However, in case of an exception this code is not executed. fin$1 is called from __FPC_specific_handler. So those addresses do not actually help.

The dwarf spec is not too specific, but I am not sure how good an idea it is to have the "catch" address range in a different function.

============
Something else / Stepping
Because finally is a subroutine, "step over / F8" does not enter it. That is not what the user expects.

In FpDebug that can be solved.
With GDB, that would require a lot of work, and probably slow down stepping quite a bit....

However gdb does check the function after a call statement.
program Project1;
label a,b;
begin
      writeln;
      asm
  call b
  jmp a
b:
  nop
  nop
  ret
a:
      end;
      writeln;
end.

And F8 will step into b (gdb 8.x). Because b is the same function. (and apparently gdb does some checks to distinguish this from a recursive call)

So if fpc would write dwarf info where the function includes the finally code, then stepping would work. Though with the finally code currently being in front of the function body, it would need an entry point. (not tested...). Or the finally code could be moved to the end.

Only tested with 64 bit.
I can do more tests, if it is considered worth the effort.


_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to