diff --git a/devel-docs/debug-plug-ins.txt b/devel-docs/debug-plug-ins.txt index 3e8befa952..101eeca081 100644 --- a/devel-docs/debug-plug-ins.txt +++ b/devel-docs/debug-plug-ins.txt @@ -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 ) to the plug-in process - (When compiled with Windows, resume the plug-in process with - gimp-debug-resume.exe ) - - 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 ") + 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 " + (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 -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. diff --git a/libgimp/gimp-debug.c b/libgimp/gimp-debug.c index 4caaccf6aa..34b7a101f5 100644 --- a/libgimp/gimp-debug.c +++ b/libgimp/gimp-debug.c @@ -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); +} diff --git a/libgimp/gimp-debug.h b/libgimp/gimp-debug.h index db5e07af8b..e5fd4b5b4d 100644 --- a/libgimp/gimp-debug.h +++ b/libgimp/gimp-debug.h @@ -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); diff --git a/libgimp/gimp.c b/libgimp/gimp.c index 25500c72d0..f14fbadd4f 100644 --- a/libgimp/gimp.c +++ b/libgimp/gimp.c @@ -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);