libgimp, devel-docs: enhance GIMP-PLUGIN-DEBUG backtrace

This commit is contained in:
bootchk 2020-11-21 14:08:36 -05:00 committed by Jehan
parent c10ffd4f38
commit 59f2ba44c7
4 changed files with 531 additions and 224 deletions

View File

@ -2,74 +2,104 @@ Debugging Plug-ins
==================
Eeek! The plug-in you're working on has a bug in it! And the fix isn't
completely obvious, so you want to use debugger to see what is going on.
completely obvious, so you want to use a debugger to see what is going on.
But hmm, how does one start a plug-in under a debugger if GIMP is the one
who is starting the plug-in...
To address this issue, libgimp has some hooks controlled by the
GIMP_PLUGIN_DEBUG environment variable. The idea is that you can attach
a debugger to the pid of the plug-in you want to debug. The format is as
follows:
GIMP_PLUGIN_DEBUG environment variable at runtime.
GIMP_PLUGIN_DEBUG lets you arrange that a plug-in suspends when it starts,
and then you can start a debugger and attach the debugger to the pid of the
plug-in.
GIMP_PLUGIN_DEBUG also lets you arrange for log messages of levels WARNING,
CRITICAL, and ERROR (from the plug-in, GIMP libraries, and GLib libraries)
to be fatal and generate a backtrace at that point (also called
a stack trace, similar to that generated in a debugger using the 'bt' command.)
When GIMP_PLUGIN_DEBUG is not defined, depending on how other GLib environment
variables are defined, a plug-in may quietly execute past
warning and critical logged events, and only terminate on a ERROR logged event
(without a backtrace), or on a soft or hard fault such as a memory exception
(possibly producing a core dump that you can examine using a debugger.)
Format of GIMP_PLUGIN_DEBUG:
----------------------------
GIMP_PLUGIN_DEBUG=name<,options>
"name" refers to the name of the plug-in binary that you wish to debug.
"name" specifies the name of the plug-in that you wish to debug,
or "all" to debug every plug-in. See below "Plug-in names".
"options" is one or more of the following options, separated by :'s
"options" is zero or more of the following options, separated by :'s
run: suspend the plug-in when its run_proc is called.
query: suspend the plug-in when its query_proc is called.
init: suspend the plug-in when its init_proc is called.
pid: just print the pid of the plug-in on run_proc.
fatal-warnings: emulate passing --g-fatal-warnings on the command line.
fw: shorthand for above.
on: shorthand for run:fatal-warnings. This is also the default
in the absence of an options string.
run: suspend the plug-in when its run func is called.
query: suspend the plug-in when its query func is called.
init: suspend the plug-in when its init func is called.
quit: suspend the plug-in when its quit func is called.
pid: just print the pid of the plug-in on run_proc.
fatal-warnings: similar to "gimp --g-fatal-warnings" on the command line,
but for the plugin process
fw: shorthand for above.
fatal-criticals: make CRITICAL level messages fatal (but not WARNING)
In the absence of an options string, only ERRORs are fatal and generate
a backtrace according to stack-trace-mode
The steps to debug a plug-in are as follows:
To use a debugger on a C-language plug-in:
------------------------------
0. Make sure GIMP is built with debugging information (gcc -g)
0. Ensure GIMP was built with debugging information (gcc -g)
1. Start GIMP with the appropriate debugging environment variables
1. In a terminal, start GIMP with the environment variable GIMP_PLUGIN_DEBUG set
( e.g. ">GIMP_PLUGIN_DEBUG=blur,on gimp" )
2. Load the standalone plug-in program in the debugger (gdb or
the ddd frontend to gdb)
2. In another terminal, start a debugger (gdb, lldb, or other) and load the plug-in
program into the debugger. Loading only loads the debug symbols.
( e.g. ">gdb blur" )
3. Invoke the plug-in procedure in GIMP. GIMP will start the plug-in
process, then send a STOP signal to it and then print a message with
the pid of the plug-in process to the terminal.
process, then suspend it and print the pid of the plug-in process
to the terminal where you started GIMP.
4. Attach to the pid of the plug-in process in the debugger
5. Set breakpoints where you want the plug-in to stop in the debugger
6. Send the CONT signal (kill -CONT <pid>) to the plug-in process
(When compiled with Windows, resume the plug-in process with
gimp-debug-resume.exe <pid>)
7. Enter "continue" in the debugger. The plug-in will then continue
and break at the breakpoints.
4. In the debugger, attach to the pid of the plug-in process.
(e.g. "gdb> attach <pid>")
Expect the debugger to say where the plug-in is suspended.
Examples:
5. In the debugger, set breakpoints (or examine memory, or step, etc.)
6. Windows: resume the plug-in process with "gimp-debug-resume.exe <pid>"
(On Linux, the gdb continue command resumes the attached process.)
7. In the debugger, enter "continue". Expect the plug-in to resume under
control of the debugger and pause at breakpoints.
(e.g. "gdb> continue")
Examples using a debugger:
--------------------------
GIMP_PLUGIN_DEBUG=blur
When the blur plug-in is called to perform an action, it is suspended
and the following is printed to the console:
When the blur plug-in's run func is called (the run phase),
GIMP suspends it and prints to the console:
(blur:9000): LibGimp-DEBUG: Waiting for debugger...
9000 is the pid of the new plug-in process. You can start your debugger,
attach to it, set breakpoints/watches/etc. and continue from there.
In case of the gdb typing "continue" will start the plugin.
attach to the plug-in, set breakpoints/watches/etc. and continue from there.
Using gdb command "continue" will resume the plugin.
Expect the plugin to execute until it hits a breakpoint or until a WARNING
or worse event is logged or until a hard fault such as a memory violation.
Then the debugger will be back in control.
GIMP_PLUGIN_DEBUG=blur,on
Same effect as above.
GIMP_PLUGIN_DEBUG=blur,run:fatal-warnings
Same effect as above.
@ -80,20 +110,177 @@ GIMP_PLUGIN_DEBUG=blur,pid
(blur:9000): LibGimp-DEBUG: Here I am!
This simply prints the pid but doesn't halt the plug-in. It is simply
convenience, since if your plug-in has a GUI, the GUI can start up
and you can attach to it there while it is waiting for user input.
This simply prints the pid but doesn't suspend the plug-in. It is a
convenience for a plug-in having a GUI. The GUI starts up and waits
for user input. When you attach, you will find the plug-in waiting
in the event loop.
GIMP_PLUGIN_DEBUG=blur,query
Same effect as if you did run, but instead suspends when the plug-in
is queried on GIMP startup.
GIMP_PLUGIN_DEBUG=blur,init
GIMP_PLUGIN_DEBUG=blur,quit
Same as above, but in the init phase of startup.
Same effect as for "run", but instead libgimp suspends the plug-in before
one of a plugin's phases: query, init, run, quit
E.G. when it is queried or init'ed on GIMP startup.
To get a backtrace for a plug-in in any language:
-------------------------------------------------
0. Ensure GIMP (and all libraries you want details for)
were built with debugging information (gcc -g)
1. In a terminal, start GIMP with the environment variable GIMP_PLUGIN_DEBUG set
( e.g. ">GIMP_PLUGIN_DEBUG=all,fatal-criticals gimp" )
Expect GIMP to start normally.
2. In GIMP, do somthing that would invoke a plugin.
Whenever the specified plug-in processes generate log events of
the specified levels or worse, libgimp will print or offer to print
(depends on stack-trace-mode) a backtrace, and then terminate the plug-in.
The GIMP app will usually continue to run.
For interpreted language plug-ins, the backtrace will include many frames
from the interpreter and modules such as PyGObject. Exceptions in the
interpreted language may print on their own and not generate log events
to be caught by GIMP_PLUGIN_DEBUG. But log events from the interpreter
calling out (to LibGimp and GLib) can generate backtraces.
GIMP_PLUGIN_DEBUG and stack-trace-mode
--------------------------------------
GIMP_PLUGIN_DEBUG=all,fatal-warning only makes the machinery *consider*
generating a backtrace, for more log events. The 'stack-trace-mode' pertains.
The GIMP app on the command line takes a flag:
--stack-trace-mode [never, query, always]
When the GIMP app forks a plugin process, it passes that arg to the plugin,
and the arg controls how a backtrace is printed.
The default is "query", which means libgimp will ask you:
"[E]xit [S]tacktrace [P]roceed"
(similar to the GLib default handler for ERROR log events.)
"always" means libgimp prints a backtrace (and then the plugin terminates.)
"never" means libgimp does not print a backtrace, only a message. But for
GIMP_PLUGIN_DEBUG=all,fatal-warning, the plugin terminates on the first WARNING.
Examples getting a backtrace on logged events:
--------------------------------------------
GIMP_PLUGIN_DEBUG=blur,fatal-warnings
The blur plug-in will run until the first logged WARNING or worse,
from the plug-in, GIMP libraries, or GLib libraries.
Then a backtrace can print to the console and the blur plug-in terminate.
Usually you will also see a message from the main GIMP app
saying the plugin aborted without returning a value.
GIMP_PLUGIN_DEBUG=all,fatal-criticals
Every plug-in (whether you invoked it from the GIMP GUI or it was called
by another plug-in) will run until the first logged CRITICAL or worse,
from the plug-in, GIMP libraries, or GLib libraries.
Then, as above, a backtrace can print etc.
GIMP_PLUGIN_DEBUG=all
As above, for all plugins, but only for a logged ERROR.
Quality of a backtrace
----------------------
A detailed backtrace depends on:
1) building GIMP and dependencies with debug info enabled
2) having a debugger installed
When a debugger is not installed, a backtrace may lack details such as
function names and line numbers.
More about logging levels
-------------------------
See https://developer.gnome.org/glib/stable/glib-Message-Logging.html
Level Engendered by
-----------------------
WARNING g_warning().
CRITICAL g_return_value_if_fail() or g_return_if_fail().
ERROR g_assert() or g_error().
Use of logging levels is by convention, and libraries that GIMP uses may not
follow conventions.
Generally speaking...
WARNINGs are common but don't signify much. They might mean that your plug-in
code does not understand, or is sloppy with, the GIMP API.
CRITICALs are rare but more significant. They usually mean that GIMP will
attempt to continue past an errant condition. The GLib function
g_return_value_if_fail() is often used in GIMP code as a precondition,
required to succeed before a GIMP function executes its body,
the function returning early when the precondition fails.
ERRORs are usually dire. They always terminate a plug-in.
Plug-in names
-------------
A plug-in may register many PDB procedures. Use the plug-in name, not a
procedure-name, e.g. "file-psd" not "file-psd-save". When a plug-in is "run",
one of its PDB procedures is run, and all of its PDB procedures
are covered by a GIMP_PLUGIN_DEBUG definition.
A name is usually the name of the executable file, including any suffix.
Examples: "file-psd" or "foggify.py" or on some platforms "foo.exe."
Usually an interpreted plug-in has a hashbang on the first line
e.g. "#!/usr/bin/env python3" in the first line of foo.py.
Then the file is executable, GIMP forks that file, and the Linux loader
invokes the interpreter.
However, GIMP still allows a plug-in source
to lack a hashbang (and it is not technically "an executable")
but then GIMP forks the interpreter, passing the script filename.
In this case, you must still use the name of the script file e.g. "foo.py"
in GIMP_PLUGIN_DEBUG.
(Since forever, GIMP does not understand Python packages.
GIMP only installs Python plugins from directories named like foo/foo.py.
A directory that is a Python package (having an __init__.py file)
will be read by GIMP at startup, but GIMP will only install one plugin
from that directory, and only if the .py file is named like the directory.)
Finding plug-in source by name
------------------------------
A GIMP supported C language plug-in's source should be in a similar-named
directory in the GIMP repository. For example, "file-psd" is a directory
(but there is no "file-psd.c".)
An interpreted plug-in is *installed* in a directory of a similar name
e.g. "plug-ins/foggify/foggify.py".
But in the GIMP repository, foggify.py does not live at foggify/foggify.py
but at plug-ins/python/foggify.py .
Examples using other debug tools:
---------------------------------
Hmm, but what about memory debuggers such as valgrind or purify? For those
you can set the following:
@ -108,7 +295,11 @@ GIMP_PLUGIN_DEBUG_WRAPPER=debugger
put command line options here too, they will be parsed like they do
in the shell.
When compiled with Windows, the plug-in process is halted by Windows functions.
Windows:
--------
When compiled with Windows, a plug-in process is halted by Windows functions.
It must be resumed externally by invoking gimp-debug-resume.exe <pid>
The plug-ins pid can be found out by invoking gimp-debug-resume.exe
The plug-ins pid can be found out by invoking gimp-debug-resume.exe
without parameters. It shows the pid of all running processes.

View File

@ -57,74 +57,164 @@
#include "gimp.h"
#include "gimp-debug.h"
static GLogLevelFlags create_log_level_flags (void);
static void make_visible_libgimp_messages (void);
static void gimp_message_func (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer data);
static void gimp_fatal_func (const gchar *log_domain,
GLogLevelFlags flags,
const gchar *message,
gpointer data);
static const GDebugKey gimp_debug_keys[] =
{
{ "pid", GIMP_DEBUG_PID },
{ "fatal-warnings", GIMP_DEBUG_FATAL_WARNINGS },
{ "fatal-criticals", GIMP_DEBUG_FATAL_CRITICALS },
{ "fw", GIMP_DEBUG_FATAL_WARNINGS },
{ "query", GIMP_DEBUG_QUERY },
{ "init", GIMP_DEBUG_INIT },
{ "run", GIMP_DEBUG_RUN },
{ "quit", GIMP_DEBUG_QUIT },
{ "on", GIMP_DEBUG_DEFAULT }
{ "quit", GIMP_DEBUG_QUIT }
};
static guint gimp_debug_flags = 0;
/* Set by gimp_debug_configure() to partial parameterize gimp_fatal_handler(). */
static GimpStackTraceMode _stack_trace_mode = GIMP_STACK_TRACE_NEVER;
/* Set by _gimp_debug_init(). Exported by _gimp_get_debug_flags() */
static guint _gimp_debug_flags = 0;
/*
* Set _gimp_debug_flags, from env var GIMP_PLUGIN_DEBUG if it exists.
* Also ensure GLib default handler prints all log messages for domain LibGimp.
*/
void
_gimp_debug_init (const gchar *basename)
{
const gchar *env_string = g_getenv ("GIMP_PLUGIN_DEBUG");
const gchar *debug_options;
gint plugin_name_len;
gboolean is_debug_name_match_basename;
if (env_string)
if (!env_string) return;
debug_options = strchr (env_string, ',');
/* Does name match basename or name match "all"
* Use strlen to allow basename to have prefix "all" without matching.
*/
/* Safe subtraction of pointers into the same string. */
plugin_name_len = debug_options - env_string;
is_debug_name_match_basename = (
((strlen (basename) == plugin_name_len) &&
(strncmp (basename, env_string, plugin_name_len) == 0)) ||
(strncmp (env_string, "all", plugin_name_len) == 0)
);
if (is_debug_name_match_basename && debug_options)
{
gchar *debug_string;
const gchar *debug_messages;
debug_string = strchr (env_string, ',');
if (debug_string)
{
gint len = debug_string - env_string;
if ((strlen (basename) == len) &&
(strncmp (basename, env_string, len) == 0))
{
gimp_debug_flags =
g_parse_debug_string (debug_string + 1,
gimp_debug_keys,
G_N_ELEMENTS (gimp_debug_keys));
}
}
else if (strcmp (env_string, basename) == 0)
{
gimp_debug_flags = GIMP_DEBUG_DEFAULT;
}
/* make debug output visible by setting G_MESSAGES_DEBUG */
debug_messages = g_getenv ("G_MESSAGES_DEBUG");
if (debug_messages)
{
gchar *tmp = g_strconcat (debug_messages, ",LibGimp", NULL);
g_setenv ("G_MESSAGES_DEBUG", tmp, TRUE);
g_free (tmp);
}
else
{
g_setenv ("G_MESSAGES_DEBUG", "LibGimp", TRUE);
}
_gimp_debug_flags =
g_parse_debug_string (debug_options + 1,
gimp_debug_keys,
G_N_ELEMENTS (gimp_debug_keys));
}
/* Else assert _gimp_debug_flags==0 .
* Only ERROR will be fatal, and fatal handler installed
* (to print according to stack-trace-mode)
*/
make_visible_libgimp_messages();
}
guint
_gimp_debug_flags (void)
_gimp_get_debug_flags (void)
{
return gimp_debug_flags;
return _gimp_debug_flags;
}
/*
* Configure GLib logging according to GIMP_PLUGIN_DEBUG
*/
void
_gimp_debug_configure (GimpStackTraceMode stack_trace_mode)
{
const gchar * const gimp_log_domains[] =
{
"LibGimp",
"LibGimpBase",
"LibGimpColor",
"LibGimpConfig",
"LibGimpMath",
"LibGimpModule",
"LibGimpThumb",
"LibGimpWidgets"
};
const gchar * const glib_log_domains[] =
{
"GLib",
"GLib-GObject",
"GLib-GIO",
};
gint i;
GLogLevelFlags fatal_mask;
_stack_trace_mode = stack_trace_mode;
/* Set handler for Gimp domains, for MESSAGE level.
* i.e. from g_message(), but not from g_info() (rarely used?).
*/
for (i = 0; i < G_N_ELEMENTS (gimp_log_domains); i++)
g_log_set_handler (gimp_log_domains[i],
G_LOG_LEVEL_MESSAGE,
gimp_message_func,
NULL);
/* Also set handler for "" i.e. app domain. */
g_log_set_handler (NULL,
G_LOG_LEVEL_MESSAGE,
gimp_message_func,
NULL);
/* Make fatal a subset of log levels (ERROR is always fatal)
* as specified by GIMP_PLUGIN_DEBUG now in _gimp_debug_flags
*/
fatal_mask = create_log_level_flags();
g_log_set_always_fatal (fatal_mask);
/* set our custom handler for fatal messages, for many domains. */
/* For the null i.e. "" i.e. app i.e. plugin domain */
g_log_set_handler (NULL,
fatal_mask,
gimp_fatal_func,
NULL);
for (i = 0; i < G_N_ELEMENTS (gimp_log_domains); i++)
g_log_set_handler (gimp_log_domains[i],
fatal_mask,
gimp_fatal_func,
NULL);
for (i = 0; i < G_N_ELEMENTS (glib_log_domains); i++)
g_log_set_handler (glib_log_domains[i],
fatal_mask,
gimp_fatal_func,
NULL);
}
/*
* Suspend i.e. pause the plugin process.
*/
void
_gimp_debug_stop (void)
{
@ -176,3 +266,152 @@ _gimp_debug_stop (void)
#endif
}
/* private functions */
/*
* Append domain LibGimp to env var G_MESSAGES_DEBUG.
* Per GLib docs, that makes default handler print all levels of log messages,
* from domain LibGimp.
* We may yet install non-default handler gimp_fatal_func(), for some levels,
* which prints the message and also may generate stack trace.
*
* This does not depend on GIMP_PLUGIN_DEBUG or any plugin names therein.
* This does not affect the Gimp app, whose environment is distinct.
* This does not make a plugin's own logged messages visible,
* since the plugin is in a distinct domain.
*/
static void
make_visible_libgimp_messages (void)
{
const gchar *debug_messages = g_getenv ("G_MESSAGES_DEBUG");
if (debug_messages)
{
gchar *tmp = g_strconcat (debug_messages, ",LibGimp", NULL);
g_setenv ("G_MESSAGES_DEBUG", tmp, TRUE);
g_free (tmp);
}
else
{
g_setenv ("G_MESSAGES_DEBUG", "LibGimp", TRUE);
}
}
/* Create GLogLevelFlags for fatal,
* from current fatal flags and from GIMP_PLUGIN_DEBUG env var.
*/
static GLogLevelFlags
create_log_level_flags(void)
{
GLogLevelFlags result;
result = g_log_set_always_fatal (G_LOG_FATAL_MASK);
/* result is the old one, and may have flags set already
* via the GLib G_DEBUG environment variable.
*/
/* Ensure ERROR remains fatal.
* Even if GIMP_PLUGIN_DEBUG is not defined, or defined "=run"
* we install fatal handler for ERROR for all plugins.
*/
result |= G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL;
if (_gimp_debug_flags & GIMP_DEBUG_FATAL_WARNINGS)
result |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
if (_gimp_debug_flags & GIMP_DEBUG_FATAL_CRITICALS)
result |= G_LOG_LEVEL_CRITICAL;
return result;
}
/*
* Handler for GLib log events of MESSAGE level.
* Signature is GLogFunc
*/
static void
gimp_message_func (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer data)
{
gimp_message (message);
}
/*
* Handler for fatal GLib logging events.
* Signature is GLogFunc
*/
static void
gimp_fatal_func (const gchar *log_domain,
GLogLevelFlags flags,
const gchar *message,
gpointer data)
{
const gchar *level;
switch (flags & G_LOG_LEVEL_MASK)
{
case G_LOG_LEVEL_WARNING:
level = "WARNING";
break;
case G_LOG_LEVEL_CRITICAL:
level = "CRITICAL";
break;
case G_LOG_LEVEL_ERROR:
level = "ERROR";
break;
default:
level = "FATAL";
break;
}
/* Earlier, gimp.c g_set_prgname to short basename; progname is full path. */
/*
* Print message canonical to what GLib's default handler would.
* Except prefix with which plugin using short name i.e. basename
* so reader can distinguish interleaved messages from plugin or app process.
* The log_domain is which library logged the event.
*/
g_printerr ("Plugin %s: %s: %s: %s\n",
g_get_prgname(), log_domain, level, message);
#ifndef G_OS_WIN32
switch (_stack_trace_mode)
{
case GIMP_STACK_TRACE_NEVER:
break;
case GIMP_STACK_TRACE_QUERY:
{
sigset_t sigset;
sigemptyset (&sigset);
sigprocmask (SIG_SETMASK, &sigset, NULL);
gimp_stack_trace_query (log_domain);
}
break;
case GIMP_STACK_TRACE_ALWAYS:
{
sigset_t sigset;
sigemptyset (&sigset);
sigprocmask (SIG_SETMASK, &sigset, NULL);
gimp_stack_trace_print (log_domain, stdout, NULL);
}
break;
}
#endif /* ! G_OS_WIN32 */
/* Do not end with gimp_quit().
* We want the plug-in to continue its normal crash course, otherwise
* we won't get the "Plug-in crashed" error in GIMP.
*/
exit (EXIT_FAILURE);
}

View File

@ -32,14 +32,14 @@ typedef enum
GIMP_DEBUG_INIT = 1 << 3,
GIMP_DEBUG_RUN = 1 << 4,
GIMP_DEBUG_QUIT = 1 << 5,
GIMP_DEBUG_FATAL_CRITICALS = 1 << 6,
GIMP_DEBUG_DEFAULT = (GIMP_DEBUG_RUN | GIMP_DEBUG_FATAL_WARNINGS)
} GimpDebugFlag;
void _gimp_debug_init (const gchar *basename);
guint _gimp_debug_flags (void);
void _gimp_debug_configure (GimpStackTraceMode stack_trace_mode);
guint _gimp_get_debug_flags (void);
void _gimp_debug_stop (void);

View File

@ -108,14 +108,6 @@
static void gimp_close (void);
static void gimp_message_func (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer data);
static void gimp_fatal_func (const gchar *log_domain,
GLogLevelFlags flags,
const gchar *message,
gpointer data);
#ifdef G_OS_WIN32
@ -506,54 +498,7 @@ gimp_main (GType plug_in_type,
bind_textdomain_codeset (GETTEXT_PACKAGE"-libgimp", "UTF-8");
#endif
/* set handler both for the "LibGimp" and "" domains */
{
const gchar * const log_domains[] =
{
"LibGimp",
"LibGimpBase",
"LibGimpColor",
"LibGimpConfig",
"LibGimpMath",
"LibGimpModule",
"LibGimpThumb",
"LibGimpWidgets"
};
gint i;
for (i = 0; i < G_N_ELEMENTS (log_domains); i++)
g_log_set_handler (log_domains[i],
G_LOG_LEVEL_MESSAGE,
gimp_message_func,
NULL);
g_log_set_handler (NULL,
G_LOG_LEVEL_MESSAGE,
gimp_message_func,
NULL);
}
if (_gimp_debug_flags () & GIMP_DEBUG_FATAL_WARNINGS)
{
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
g_log_set_handler (NULL,
G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL |
G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL,
gimp_fatal_func,
NULL);
}
else
{
g_log_set_handler (NULL,
G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL,
gimp_fatal_func,
NULL);
}
_gimp_debug_configure (stack_trace_mode);
PLUG_IN = g_object_new (plug_in_type,
"read-channel", read_channel,
@ -564,7 +509,7 @@ gimp_main (GType plug_in_type,
if (strcmp (argv[ARG_MODE], "-query") == 0)
{
if (_gimp_debug_flags () & GIMP_DEBUG_QUERY)
if (_gimp_get_debug_flags () & GIMP_DEBUG_QUERY)
_gimp_debug_stop ();
_gimp_plug_in_query (PLUG_IN);
@ -576,7 +521,7 @@ gimp_main (GType plug_in_type,
if (strcmp (argv[ARG_MODE], "-init") == 0)
{
if (_gimp_debug_flags () & GIMP_DEBUG_INIT)
if (_gimp_get_debug_flags () & GIMP_DEBUG_INIT)
_gimp_debug_stop ();
_gimp_plug_in_init (PLUG_IN);
@ -586,9 +531,9 @@ gimp_main (GType plug_in_type,
return EXIT_SUCCESS;
}
if (_gimp_debug_flags () & GIMP_DEBUG_RUN)
if (_gimp_get_debug_flags () & GIMP_DEBUG_RUN)
_gimp_debug_stop ();
else if (_gimp_debug_flags () & GIMP_DEBUG_PID)
else if (_gimp_get_debug_flags () & GIMP_DEBUG_PID)
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Here I am!");
_gimp_plug_in_run (PLUG_IN);
@ -953,7 +898,7 @@ gimp_get_progname (void)
static void
gimp_close (void)
{
if (_gimp_debug_flags () & GIMP_DEBUG_QUIT)
if (_gimp_get_debug_flags () & GIMP_DEBUG_QUIT)
_gimp_debug_stop ();
_gimp_plug_in_quit (PLUG_IN);
@ -966,76 +911,8 @@ gimp_close (void)
g_clear_object (&PLUG_IN);
}
static void
gimp_message_func (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer data)
{
gimp_message (message);
}
static void
gimp_fatal_func (const gchar *log_domain,
GLogLevelFlags flags,
const gchar *message,
gpointer data)
{
const gchar *level;
switch (flags & G_LOG_LEVEL_MASK)
{
case G_LOG_LEVEL_WARNING:
level = "WARNING";
break;
case G_LOG_LEVEL_CRITICAL:
level = "CRITICAL";
break;
case G_LOG_LEVEL_ERROR:
level = "ERROR";
break;
default:
level = "FATAL";
break;
}
g_printerr ("%s: %s: %s\n",
progname, level, message);
#ifndef G_OS_WIN32
switch (stack_trace_mode)
{
case GIMP_STACK_TRACE_NEVER:
break;
case GIMP_STACK_TRACE_QUERY:
{
sigset_t sigset;
sigemptyset (&sigset);
sigprocmask (SIG_SETMASK, &sigset, NULL);
gimp_stack_trace_query (progname);
}
break;
case GIMP_STACK_TRACE_ALWAYS:
{
sigset_t sigset;
sigemptyset (&sigset);
sigprocmask (SIG_SETMASK, &sigset, NULL);
gimp_stack_trace_print (progname, stdout, NULL);
}
break;
}
#endif /* ! G_OS_WIN32 */
/* Do not end with gimp_quit().
* We want the plug-in to continue its normal crash course, otherwise
* we won't get the "Plug-in crashed" error in GIMP.
*/
exit (EXIT_FAILURE);
}
#ifdef G_OS_WIN32
@ -1043,7 +920,7 @@ gimp_fatal_func (const gchar *log_domain,
static LONG WINAPI
gimp_plugin_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo)
{
g_printerr ("%s: fatal error\n", progname);
g_printerr ("Plugin signal handler: %s: fatal error\n", progname);
SetUnhandledExceptionFilter (_prevExceptionFilter);