Re: [fpc-devel] 034881: Request debug info for SEH (finally/except) to prevent regression when win32 switches to SEH

2019-10-29 Thread Sven Barth via fpc-devel
Martin Frb  schrieb am Di., 29. Okt. 2019, 20:08:

> 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".
>

When implementing the patch I saw a bug report on GDB regarding the
exception blocks (that's how I learned that ICC generates them), so it
seems that it does handle them in some case... (at least to get the C++
exception variable that has been caught).

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

FPC trunk now supports PSABIEH on i386 and x86_64 linux. You need to
recompile the compiler with -dPSABIEH as well as the library path set to
wherever libgcc.a resides (of course RTL and packages need to be recompiled
as well).


> ==
> 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
>

Yes, I didn't test nested blocks, because I wasn't yet sure whether there
debug information should be siblings or nested as well.


> 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.
>

Yeah, I noticed that as well, but at least it could be used to set a
breakpoint at the called function inside that range...


> 
> 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.
>

For the compiler the finally code is generated essentially as a nested
function. It does not know the concept of a function following immediately
afterwards.

So that would be a rather complex undertaking that I don't believe is worth
the effort.

Regards,
Sven

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


[fpc-devel] 034881: Request debug info for SEH (finally/except) to prevent regression when win32 switches to SEH

2019-10-29 Thread Martin Frb

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