www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.debugger - Catching excecptions in the MSVC debugger when running Win64

reply Lewis <musicaljelly gmail.com> writes:
I can't seem to catch a D exception on win64 in the Visual Studio 
debugger. I'm using:

- DMD compiler (2.094.2)
- VisualD 1.1.0
- Visual Studio 2019
- Building a Win64 executable
- Debugger set to Visual Studio
- All Win32 and D exceptions enabled in the Exception Settings 
window in VS

Test code:

```
import std.file : copy;
int main()
{
     copy("filethatdoesnotexist.bla", "othernonexistentfile.bla");
     return 0;
}
```

I've tried manually rebuilding phobos in debug so I can see 
inside it. I can step into the copy(), all the way until the 
point where it constructs the FileException object. But the 
debugger never seems to catch the exception.

Instead the debugger breaks in deh_win64_posix.d:493 on the call 
to terminate() at the end of _d_throwc(). But this just causes 
the debugger to catch *0xC0000096: Privileged instruction* 
(presumably due to the hlt instruction inside terminate()), 
instead of actually understanding the D FileException that got 
thrown. Nothing is printed to the output window regarding the D 
exception

Is this the expected behaviour? If not, how to I get visual 
studio to properly catch D exceptions for a win64 executable?
Apr 26 2021
next sibling parent Lewis <musicaljelly gmail.com> writes:
Clearly I don't know how to spell exception :P
Apr 26 2021
prev sibling parent reply Lewis <musicaljelly gmail.com> writes:
Okay, I was able to get the VS debugger to catch exceptions in 
win64 by adding a hack to deh_win64_posix.d so that it mimics 
deh_win32.d.

I added the following code above the definition of _d_throwc():

```
import core.sys.windows.windef : DWORD;
extern(Windows)
{
     void RaiseException(DWORD, DWORD, DWORD, void*);
}
```

...and I added the following to _d_throwc() itself, right after 
it calls _d_createTrace():

```
template MAKE_EXCEPTION_CODE(int severity, int facility, int 
exception)
{
    enum int MAKE_EXCEPTION_CODE = (((severity) << 30) | (1 << 29) 
| (0 << 28) | ((facility) << 16) | (exception));
}
enum int STATUS_DIGITAL_MARS_D_EXCEPTION = 
MAKE_EXCEPTION_CODE!(3,'D',1);
enum DWORD EXCEPTION_NONCONTINUABLE = 1;
RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION, 
EXCEPTION_NONCONTINUABLE, 1, cast(void*)&h);
```

With this, the debugger catches exceptions again.

This feels like a total hack though. Presumably I'm missing an 
obvious better solution?
Apr 26 2021
parent Rainer Schuetze <r.sagitario gmx.de> writes:
On 27/04/2021 07:43, Lewis wrote:
 Okay, I was able to get the VS debugger to catch exceptions in win64 by
 adding a hack to deh_win64_posix.d so that it mimics deh_win32.d.
 
 I added the following code above the definition of _d_throwc():
 
 ```
 import core.sys.windows.windef : DWORD;
 extern(Windows)
 {
    void RaiseException(DWORD, DWORD, DWORD, void*);
 }
 ```
 
 ...and I added the following to _d_throwc() itself, right after it calls
 _d_createTrace():
 
 ```
 template MAKE_EXCEPTION_CODE(int severity, int facility, int exception)
 {
   enum int MAKE_EXCEPTION_CODE = (((severity) << 30) | (1 << 29) | (0 <<
 28) | ((facility) << 16) | (exception));
 }
 enum int STATUS_DIGITAL_MARS_D_EXCEPTION = MAKE_EXCEPTION_CODE!(3,'D',1);
 enum DWORD EXCEPTION_NONCONTINUABLE = 1;
 RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION,
 EXCEPTION_NONCONTINUABLE, 1, cast(void*)&h);
 ```
 
 With this, the debugger catches exceptions again.
 
 This feels like a total hack though. Presumably I'm missing an obvious
 better solution?
Unfortunately, the dmd backend does not use the standard exception mechanism for win64, but some homegrown one adapted from the linux exception handling. That's why the debugger does not recognize the exceptions. Your solution works for catching exceptions, but catch statements will not work with RaiseException. I guess the best option is to set a breakpoint in _d_throwc. LDC uses C++ exceptions, so your debugger should behave as expected when building with LDC.
Apr 26 2021