glib/glib/gwin32-private.c
Руслан Ижбулатов 025a346728 W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.

This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.

The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.

The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.

The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.

There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.

The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.

The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.

[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-03-06 11:41:56 +00:00

78 lines
2.5 KiB
C

/* gwin32-private.c - private glib functions for gwin32.c
*
* Copyright 2019 Руслан Ижбулатов
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/* Copy @cmdline into @debugger, and substitute @pid for `%p`
* and @event for `%e`.
* If @debugger_size (in bytes) is overflowed, return %FALSE.
* Also returns %FALSE when `%` is followed by anything other
* than `e` or `p`.
*/
static gboolean
_g_win32_subst_pid_and_event (char *debugger,
gsize debugger_size,
const char *cmdline,
DWORD pid,
guintptr event)
{
gsize i = 0, dbg_i = 0;
/* These are integers, and they can't be longer than 20 characters
* even when they are 64-bit and in decimal notation.
* Use 30 just to be sure.
*/
#define STR_BUFFER_SIZE 30
char pid_str[STR_BUFFER_SIZE] = {0};
gsize pid_str_len;
char event_str[STR_BUFFER_SIZE] = {0};
gsize event_str_len;
#undef STR_BUFFER_SIZE
snprintf (pid_str, G_N_ELEMENTS (pid_str), "%lu", pid);
pid_str[G_N_ELEMENTS (pid_str) - 1] = 0;
pid_str_len = strlen (pid_str);
snprintf (event_str, G_N_ELEMENTS (pid_str), "%Iu", event);
event_str[G_N_ELEMENTS (pid_str) - 1] = 0;
event_str_len = strlen (event_str);
while (cmdline[i] != 0 && dbg_i < debugger_size)
{
if (cmdline[i] != '%')
debugger[dbg_i++] = cmdline[i++];
else if (cmdline[i + 1] == 'p')
{
gsize j = 0;
while (j < pid_str_len && dbg_i < debugger_size)
debugger[dbg_i++] = pid_str[j++];
i += 2;
}
else if (cmdline[i + 1] == 'e')
{
gsize j = 0;
while (j < event_str_len && dbg_i < debugger_size)
debugger[dbg_i++] = event_str[j++];
i += 2;
}
else
return FALSE;
}
if (dbg_i < debugger_size)
debugger[dbg_i] = 0;
else
return FALSE;
return TRUE;
}