xref: /petsc/src/sys/error/adebug.c (revision 5994c5adf5e28cb515faabacab9288947ca28f46)
1 /*
2       Code to handle PETSc starting up in debuggers,etc.
3 */
4 #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for fileno() */
5 #include <petscsys.h>                    /*I   "petscsys.h"   I*/
6 #include <signal.h>
7 #if defined(PETSC_HAVE_UNISTD_H)
8   #include <unistd.h>
9 #endif
10 
11 /*
12       These are the debugger and display used if the debugger is started up
13 */
14 static char      PetscDebugger[PETSC_MAX_PATH_LEN];
15 static char      DebugTerminal[PETSC_MAX_PATH_LEN];
16 static PetscBool UseDebugTerminal    = PETSC_TRUE;
17 PetscBool        petscwaitonerrorflg = PETSC_FALSE;
18 PetscBool        petscindebugger     = PETSC_FALSE;
19 
20 /*@C
21    PetscSetDebugTerminal - Sets the terminal to use for debugging.
22 
23    Not Collective; No Fortran Support
24 
25    Input Parameter:
26 .  terminal - name of terminal and any flags required to execute a program.
27               For example "xterm", "urxvt -e", "gnome-terminal -x".
28               On Apple macOS you can use "Terminal} (note the capital T)
29 
30    Options Database Key:
31 .  -debug_terminal terminal - use this terminal instead of the default
32 
33    Level: developer
34 
35    Notes:
36    You can start the debugger for all processes in the same GNU screen session.
37 
38 $     mpiexec -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"
39 
40    will open 4 windows in the session named "debug".
41 
42    The default on Apple is Terminal, on other systems the default is xterm
43 
44 .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
45 @*/
46 PetscErrorCode PetscSetDebugTerminal(const char terminal[])
47 {
48   PetscBool xterm;
49 
50   PetscFunctionBegin;
51   PetscCall(PetscStrncpy(DebugTerminal, terminal, sizeof(DebugTerminal)));
52   PetscCall(PetscStrcmp(terminal, "xterm", &xterm));
53   if (xterm) PetscCall(PetscStrlcat(DebugTerminal, " -e", sizeof(DebugTerminal)));
54   PetscFunctionReturn(PETSC_SUCCESS);
55 }
56 
57 /*@C
58    PetscSetDebugger - Sets options associated with the debugger.
59 
60    Not Collective; No Fortran Support
61 
62    Input Parameters:
63 +  debugger - name of debugger, which should be in your path,
64               usually "lldb", "dbx", "gdb", "cuda-gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
65               supports "xdb", and IBM rs6000 supports "xldb".
66 
67 -  usedebugterminal - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
68             debugger should be started in a new terminal window) or PETSC_FALSE (to start debugger
69             in initial window (the option PETSC_FALSE makes no sense when using more
70             than one MPI process.)
71 
72    Level: developer
73 
74 .seealso: `PetscAttachDebugger()`, `PetscAttachDebuggerErrorHandler()`, `PetscSetDebugTerminal()`
75 @*/
76 PetscErrorCode PetscSetDebugger(const char debugger[], PetscBool usedebugterminal)
77 {
78   PetscFunctionBegin;
79   if (debugger) PetscCall(PetscStrncpy(PetscDebugger, debugger, sizeof(PetscDebugger)));
80   if (UseDebugTerminal) UseDebugTerminal = usedebugterminal;
81   PetscFunctionReturn(PETSC_SUCCESS);
82 }
83 
84 /*@C
85     PetscSetDefaultDebugger - Causes PETSc to use its default debugger and output terminal
86 
87    Not Collective
88 
89     Level: developer
90 
91 .seealso: `PetscSetDebugger()`, `PetscSetDebuggerFromString()`, `PetscAttachDebugger()`
92 @*/
93 PetscErrorCode PetscSetDefaultDebugger(void)
94 {
95   PetscFunctionBegin;
96 #if defined(PETSC_USE_DEBUGGER)
97   PetscCall(PetscSetDebugger(PETSC_USE_DEBUGGER, PETSC_TRUE));
98 #endif
99 #if defined(__APPLE__)
100   PetscCall(PetscSetDebugTerminal("Terminal"));
101 #else
102   PetscCall(PetscSetDebugTerminal("xterm"));
103 #endif
104   PetscFunctionReturn(PETSC_SUCCESS);
105 }
106 
107 static PetscErrorCode PetscCheckDebugger_Private(const char defaultDbg[], const char string[], const char *debugger[])
108 {
109   char *f = NULL;
110 
111   PetscFunctionBegin;
112   PetscCall(PetscStrstr(string, defaultDbg, &f));
113   if (f) {
114     PetscBool exists;
115 
116     PetscCall(PetscTestFile(string, 'x', &exists));
117     if (exists) *debugger = string;
118     else *debugger = defaultDbg;
119   }
120   PetscFunctionReturn(PETSC_SUCCESS);
121 }
122 
123 /*@C
124     PetscSetDebuggerFromString - Set the complete path for the
125        debugger for PETSc to use.
126 
127    Not Collective
128 
129    Level: developer
130 
131 .seealso: `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscAttachDebugger()`
132 @*/
133 PetscErrorCode PetscSetDebuggerFromString(const char *string)
134 {
135   const char *debugger    = NULL;
136   PetscBool   useterminal = PETSC_TRUE;
137   char       *f           = NULL;
138 
139   PetscFunctionBegin;
140   PetscCall(PetscStrstr(string, "noxterm", &f));
141   if (f) useterminal = PETSC_FALSE;
142   PetscCall(PetscStrstr(string, "ddd", &f));
143   if (f) useterminal = PETSC_FALSE;
144   PetscCall(PetscStrstr(string, "noterminal", &f));
145   if (f) useterminal = PETSC_FALSE;
146   PetscCall(PetscCheckDebugger_Private("xdb", string, &debugger));
147   PetscCall(PetscCheckDebugger_Private("dbx", string, &debugger));
148   PetscCall(PetscCheckDebugger_Private("xldb", string, &debugger));
149   PetscCall(PetscCheckDebugger_Private("gdb", string, &debugger));
150   PetscCall(PetscCheckDebugger_Private("cuda-gdb", string, &debugger));
151   PetscCall(PetscCheckDebugger_Private("idb", string, &debugger));
152   PetscCall(PetscCheckDebugger_Private("xxgdb", string, &debugger));
153   PetscCall(PetscCheckDebugger_Private("ddd", string, &debugger));
154   PetscCall(PetscCheckDebugger_Private("kdbg", string, &debugger));
155   PetscCall(PetscCheckDebugger_Private("ups", string, &debugger));
156   PetscCall(PetscCheckDebugger_Private("workshop", string, &debugger));
157   PetscCall(PetscCheckDebugger_Private("pgdbg", string, &debugger));
158   PetscCall(PetscCheckDebugger_Private("pathdb", string, &debugger));
159   PetscCall(PetscCheckDebugger_Private("lldb", string, &debugger));
160   PetscCall(PetscSetDebugger(debugger, useterminal));
161   PetscFunctionReturn(PETSC_SUCCESS);
162 }
163 
164 /*@
165    PetscWaitOnError - If an error is detected and the process would normally exit the main program with `MPI_Abort()` sleep instead
166                       of exiting.
167 
168    Not Collective
169 
170    Level: advanced
171 
172    Note:
173       When `-start_in_debugger -debugger_ranks x,y,z` is used this prevents the processes NOT listed in x,y,z from calling `MPI_Abort()` and
174       killing the user's debugging sessions.
175 
176 .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
177 @*/
178 PetscErrorCode PetscWaitOnError(void)
179 {
180   petscwaitonerrorflg = PETSC_TRUE;
181   return PETSC_SUCCESS;
182 }
183 
184 /*@
185    PetscAttachDebugger - Attaches the debugger to the running process.
186 
187    Not Collective
188 
189    Options Database Keys:
190 +  -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n] -debug_terminal xterm or Terminal (for Apple)
191 .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
192 -  -stop_for_debugger - print a message on how to attach the process with a debugger and then wait for the user to attach
193 
194    Level: advanced
195 
196    Note:
197    If you get the message " stdin is not a tty, hence unable to attach debugger, see PetscAttachDebugger()", this means the application
198    is likely running in a batch system and you do not have terminal access to the process. You can try
199    running with `-start_in_debugger` without the `noxterm` argument or `-stop_for_debugger`
200 
201    Developer Note:
202     Since this can be called by the error handler, should it be calling `SETERRQ()` and `PetscCall()`?
203 
204 .seealso: `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscSetDebugTerminal()`, `PetscAttachDebuggerErrorHandler()`, `PetscStopForDebugger()`
205 @*/
206 PetscErrorCode PetscAttachDebugger(void)
207 {
208   PetscErrorCode PETSC_UNUSED ierr;
209 #if !defined(PETSC_CANNOT_START_DEBUGGER) && defined(PETSC_HAVE_FORK)
210   int       child     = 0;
211   PetscReal sleeptime = 0;
212   char      program[PETSC_MAX_PATH_LEN], display[256], hostname[64];
213 #endif
214 
215 #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
216   ierr = (*PetscErrorPrintf)("System cannot start debugger\n");
217   ierr = (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
218   ierr = (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
219   PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_SUP_SYS);
220 #else
221   if (PetscUnlikely(PetscGetDisplay(display, sizeof(display)))) {
222     ierr = (*PetscErrorPrintf)("PetscAttachDebugger: Cannot determine display\n");
223     return PETSC_ERR_SYS;
224   }
225   if (PetscUnlikely(PetscGetProgramName(program, sizeof(program)))) {
226     ierr = (*PetscErrorPrintf)("PetscAttachDebugger: Cannot determine program name needed to attach debugger\n");
227     return PETSC_ERR_SYS;
228   }
229   if (PetscUnlikely(!program[0])) {
230     ierr = (*PetscErrorPrintf)("PetscAttachDebugger: Cannot determine program name needed to attach debugger\n");
231     return PETSC_ERR_SYS;
232   }
233   if (PetscUnlikely(!isatty(fileno(stdin))) && !UseDebugTerminal) { printf("If the debugger exits immediately or hangs, this indicates you cannot use PetscAttachDebugger() in this situation\n\n"); }
234   child = (int)fork();
235   if (PetscUnlikely(child < 0)) {
236     ierr = (*PetscErrorPrintf)("PetscAttachDebugger: Error in fork() prior to attaching debugger\n");
237     return PETSC_ERR_SYS;
238   }
239   petscindebugger = PETSC_TRUE;
240 
241   /*
242       Swap role the parent and child. This is (I think) so that control c typed
243     in the debugger goes to the correct process.
244   */
245   #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
246   child = child ? 0 : (int)getppid();
247   #endif
248 
249   if (child) { /* I am the parent, will run the debugger */
250     const char *args[10];
251     char        pid[10];
252     PetscInt    j, jj;
253     PetscBool   isdbx, isidb, isxldb, isxxgdb, isups, isxdb, isworkshop, isddd, iskdbg, islldb;
254 
255     PetscCall(PetscGetHostName(hostname, sizeof(hostname)));
256     /*
257          We need to send a continue signal to the "child" process on the
258        alpha, otherwise it just stays off forever
259     */
260   #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
261     kill(child, SIGCONT);
262   #endif
263     PetscCall(PetscSNPrintf(pid, PETSC_STATIC_ARRAY_LENGTH(pid), "%d", child));
264 
265     PetscCall(PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb));
266     PetscCall(PetscStrcmp(PetscDebugger, "ddd", &isddd));
267     PetscCall(PetscStrcmp(PetscDebugger, "kdbg", &iskdbg));
268     PetscCall(PetscStrcmp(PetscDebugger, "ups", &isups));
269     PetscCall(PetscStrcmp(PetscDebugger, "xldb", &isxldb));
270     PetscCall(PetscStrcmp(PetscDebugger, "xdb", &isxdb));
271     PetscCall(PetscStrcmp(PetscDebugger, "dbx", &isdbx));
272     PetscCall(PetscStrcmp(PetscDebugger, "idb", &isidb));
273     PetscCall(PetscStrcmp(PetscDebugger, "workshop", &isworkshop));
274     PetscCall(PetscStrcmp(PetscDebugger, "lldb", &islldb));
275 
276     if (isxxgdb || isups || isddd) {
277       args[1] = program;
278       args[2] = pid;
279       args[3] = "-display";
280       args[0] = PetscDebugger;
281       args[4] = display;
282       args[5] = NULL;
283       printf("PETSC: Attaching %s to %s %s on %s\n", args[0], args[1], pid, hostname);
284       if (execvp(args[0], (char **)args) < 0) {
285         perror("Unable to start debugger");
286         exit(0);
287       }
288     } else if (iskdbg) {
289       args[1] = "-p";
290       args[2] = pid;
291       args[3] = program;
292       args[4] = "-display";
293       args[0] = PetscDebugger;
294       args[5] = display;
295       args[6] = NULL;
296       printf("PETSC: Attaching %s to %s %s on %s\n", args[0], args[3], pid, hostname);
297       if (execvp(args[0], (char **)args) < 0) {
298         perror("Unable to start debugger");
299         exit(0);
300       }
301     } else if (isxldb) {
302       args[1] = "-a";
303       args[2] = pid;
304       args[3] = program;
305       args[4] = "-display";
306       args[0] = PetscDebugger;
307       args[5] = display;
308       args[6] = NULL;
309       printf("PETSC: Attaching %s to %s %s on %s\n", args[0], args[1], pid, hostname);
310       if (execvp(args[0], (char **)args) < 0) {
311         perror("Unable to start debugger");
312         exit(0);
313       }
314     } else if (isworkshop) {
315       args[1] = "-s";
316       args[2] = pid;
317       args[3] = "-D";
318       args[4] = "-";
319       args[0] = PetscDebugger;
320       args[5] = pid;
321       args[6] = "-display";
322       args[7] = display;
323       args[8] = NULL;
324       printf("PETSC: Attaching %s to %s on %s\n", args[0], pid, hostname);
325       if (execvp(args[0], (char **)args) < 0) {
326         perror("Unable to start debugger");
327         exit(0);
328       }
329     } else {
330       j = 0;
331       if (UseDebugTerminal) {
332         PetscBool cmp;
333         char     *tmp, *tmp1 = NULL;
334         PetscCall(PetscStrncmp(DebugTerminal, "Terminal", 8, &cmp));
335         if (cmp) {
336           char command[1024];
337           if (islldb) PetscCall(PetscSNPrintf(command, sizeof(command), "osascript -e 'tell app \"Terminal\" to do script \"lldb  -p %s \"'\n", pid));
338           else {
339             char fullprogram[PETSC_MAX_PATH_LEN];
340             PetscCall(PetscGetFullPath(program, fullprogram, sizeof(fullprogram)));
341             PetscCall(PetscSNPrintf(command, sizeof(command), "osascript -e 'tell app \"Terminal\" to do script \"%s  %s %s \"'\n", PetscDebugger, fullprogram, pid));
342           }
343   #if defined(PETSC_HAVE_POPEN)
344           PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, command, "r", NULL));
345   #else
346           printf("-debug_terminal Terminal is not available on this system since PETSC_HAVE_POPEN is not defined in this configuration\n");
347   #endif
348           exit(0);
349         }
350 
351         PetscCall(PetscStrncmp(DebugTerminal, "screen", 6, &cmp));
352         if (!cmp) PetscCall(PetscStrncmp(DebugTerminal, "gnome-terminal", 6, &cmp));
353         if (cmp) display[0] = 0; /* when using screen, we never pass -display */
354         args[j++] = tmp = DebugTerminal;
355         if (display[0]) {
356           args[j++] = "-display";
357           args[j++] = display;
358         }
359         while (*tmp) {
360           PetscCall(PetscStrchr(tmp, ' ', &tmp1));
361           if (!tmp1) break;
362           *tmp1     = 0;
363           tmp       = tmp1 + 1;
364           args[j++] = tmp;
365         }
366       }
367       args[j++] = PetscDebugger;
368       jj        = j;
369       /* this is for default gdb */
370       args[j++] = program;
371       args[j++] = pid;
372       args[j++] = NULL;
373 
374       if (isidb) {
375         j         = jj;
376         args[j++] = "-pid";
377         args[j++] = pid;
378         args[j++] = "-gdb";
379         args[j++] = program;
380         args[j++] = NULL;
381       }
382       if (islldb) {
383         j         = jj;
384         args[j++] = "-p";
385         args[j++] = pid;
386         args[j++] = NULL;
387       }
388       if (isdbx) {
389         j         = jj;
390   #if defined(PETSC_USE_P_FOR_DEBUGGER)
391         args[j++] = "-p";
392         args[j++] = pid;
393         args[j++] = program;
394   #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
395         args[j++] = "-l";
396         args[j++] = "ALL";
397         args[j++] = "-P";
398         args[j++] = pid;
399         args[j++] = program;
400   #elif defined(PETSC_USE_A_FOR_DEBUGGER)
401         args[j++] = "-a";
402         args[j++] = pid;
403   #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
404         args[j++] = "-pid";
405         args[j++] = pid;
406         args[j++] = program;
407   #else
408         args[j++] = program;
409         args[j++] = pid;
410   #endif
411         args[j++] = NULL;
412       }
413       if (UseDebugTerminal) {
414         if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n", PetscDebugger, program, pid, display, hostname);
415         else printf("PETSC: Attaching %s to %s on pid %s on %s\n", PetscDebugger, program, pid, hostname);
416 
417         if (execvp(args[0], (char **)args) < 0) {
418           perror("Unable to start debugger in xterm");
419           exit(0);
420         }
421       } else {
422         printf("PETSC: Attaching %s to %s of pid %s on %s\n", PetscDebugger, program, pid, hostname);
423         if (execvp(args[0], (char **)args) < 0) {
424           perror("Unable to start debugger");
425           exit(0);
426         }
427       }
428     }
429   } else {          /* I am the child, continue with user code */
430     sleeptime = 10; /* default to sleep waiting for debugger */
431     PetscCall(PetscOptionsGetReal(NULL, NULL, "-debugger_pause", &sleeptime, NULL));
432     if (sleeptime < 0) sleeptime = -sleeptime;
433   #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
434     /*
435         HP cannot attach process to sleeping debugger, hence count instead
436     */
437     {
438       PetscReal x = 1.0;
439       int       i = 10000000;
440       while (i--) x++; /* cannot attach to sleeper */
441     }
442   #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
443     /*
444         IBM sleep may return at anytime, hence must see if there is more time to sleep
445     */
446     {
447       int left = sleeptime;
448       while (left > 0) left = PetscSleep(left) - 1;
449     }
450   #else
451     PetscCall(PetscSleep(sleeptime));
452   #endif
453   }
454 #endif
455   return PETSC_SUCCESS;
456 }
457 
458 /*@C
459    PetscAttachDebuggerErrorHandler - Error handler that attaches
460    a debugger to a running process when an error is detected.
461    This routine is useful for examining variables, etc.
462 
463    Not Collective
464 
465    Input Parameters:
466 +  comm - communicator over which error occurred
467 .  line - the line number of the error (indicated by `__LINE__`)
468 .  file - the file in which the error was detected (indicated by `__FILE__`)
469 .  message - an error text string, usually just printed to the screen
470 .  number - the generic error number
471 .  p - `PETSC_ERROR_INITIAL` if error just detected, otherwise `PETSC_ERROR_REPEAT`
472 -  ctx - error handler context
473 
474    Options Database Keys:
475 +  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
476 .  -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n]
477 -  -stop_for_debugger - prints a message on how to attach a debugger to the process and then waits for the attachment
478 
479    Level: developer
480 
481    Notes:
482    By default the Gnu debugger, gdb, is used.  Alternatives are cuda-gdb, lldb, dbx and
483    xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
484 
485    Most users need not directly employ this routine and the other error
486    handlers, but can instead use the simplified interface SETERR, which has
487    the calling sequence
488 $     SETERRQ(PETSC_COMM_SELF, number, p, message)
489 
490    Notes for experienced users:
491    Use `PetscPushErrorHandler()` to set the desired error handler.  The
492    currently available PETSc error handlers are
493 .vb
494     PetscTraceBackErrorHandler()
495     PetscAttachDebuggerErrorHandler()
496     PetscAbortErrorHandler()
497 .ve
498   or you may write your own.
499 
500    Developer Note:
501      This routine calls abort instead of returning because if it returned then `MPI_Abort()` would get called which can generate an exception
502      causing the debugger to be attached again in a cycle.
503 
504 .seealso: `PetscSetDebuggerFromString()`, `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscTraceBackErrorHandler()`,
505           `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscEmacsClientErrorHandler()`, `PetscReturnErrorHandler()`, `PetscSetDebugTermainal()`
506 @*/
507 PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode num, PetscErrorType p, const char *mess, void *ctx)
508 {
509   PetscErrorCode ierr;
510   if (!mess) mess = " ";
511 
512   if (fun) ierr = (*PetscErrorPrintf)("%s() at %s:%d %s\n", fun, file, line, mess);
513   else ierr = (*PetscErrorPrintf)("%s:%d %s\n", file, line, mess);
514 
515   ierr = PetscAttachDebugger();
516   (void)ierr;
517   abort(); /* call abort because don't want to kill other MPI ranks that may successfully attach to debugger */
518   PetscFunctionReturn(PETSC_SUCCESS);
519 }
520 
521 /*@C
522    PetscStopForDebugger - Prints a message to the screen indicating how to
523          attach to the process with the debugger and then waits for the
524          debugger to attach.
525 
526    Not Collective
527 
528    Options Database Key:
529 .   -stop_for_debugger - will stop for you to attach the debugger when PetscInitialize() is called
530 
531    Level: developer
532 
533    Note:
534     This is likely never needed since `PetscAttachDebugger()` is easier to use and seems to always work.
535 
536    Developer Note:
537     Since this can be called by the error handler, should it be calling `SETERRQ()` and `PetscCall()`?
538 
539 .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
540 @*/
541 PetscErrorCode PetscStopForDebugger(void)
542 {
543   PetscErrorCode ierr;
544   PetscInt       sleeptime = 0;
545 #if !defined(PETSC_CANNOT_START_DEBUGGER)
546   int         ppid;
547   PetscMPIInt rank;
548   char        program[PETSC_MAX_PATH_LEN], hostname[256];
549   PetscBool   isdbx, isxldb, isxxgdb, isddd, iskdbg, isups, isxdb, islldb;
550 #endif
551 
552   PetscFunctionBegin;
553 #if defined(PETSC_CANNOT_START_DEBUGGER)
554   PetscCall((*PetscErrorPrintf)("System cannot start debugger; just continuing program\n"));
555 #else
556   if (MPI_Comm_rank(PETSC_COMM_WORLD, &rank)) rank = 0; /* ignore error since this may be already in error handler */
557   ierr = PetscGetHostName(hostname, sizeof(hostname));
558   if (ierr) {
559     PetscCall((*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n"));
560     PetscFunctionReturn(PETSC_SUCCESS);
561   }
562 
563   ierr = PetscGetProgramName(program, sizeof(program));
564   if (ierr) {
565     PetscCall((*PetscErrorPrintf)("Cannot determine program name; just continuing program\n"));
566     PetscFunctionReturn(PETSC_SUCCESS);
567   }
568   if (!program[0]) {
569     PetscCall((*PetscErrorPrintf)("Cannot determine program name; just continuing program\n"));
570     PetscFunctionReturn(PETSC_SUCCESS);
571   }
572 
573   ppid = getpid();
574 
575   PetscCall(PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb));
576   PetscCall(PetscStrcmp(PetscDebugger, "ddd", &isddd));
577   PetscCall(PetscStrcmp(PetscDebugger, "kdbg", &iskdbg));
578   PetscCall(PetscStrcmp(PetscDebugger, "ups", &isups));
579   PetscCall(PetscStrcmp(PetscDebugger, "xldb", &isxldb));
580   PetscCall(PetscStrcmp(PetscDebugger, "xdb", &isxdb));
581   PetscCall(PetscStrcmp(PetscDebugger, "dbx", &isdbx));
582   PetscCall(PetscStrcmp(PetscDebugger, "lldb", &islldb));
583 
584   if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n", rank, hostname, PetscDebugger, program, ppid);
585   else if (isxldb) printf("[%d]%s>>%s -a %d %s\n", rank, hostname, PetscDebugger, ppid, program);
586   else if (islldb) printf("[%d]%s>>%s -p %d\n", rank, hostname, PetscDebugger, ppid);
587   else if (isdbx) {
588   #if defined(PETSC_USE_P_FOR_DEBUGGER)
589     printf("[%d]%s>>%s -p %d %s\n", rank, hostname, PetscDebugger, ppid, program);
590   #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
591     printf("[%d]%s>>%s -l ALL -P %d %s\n", rank, hostname, PetscDebugger, ppid, program);
592   #elif defined(PETSC_USE_A_FOR_DEBUGGER)
593     printf("[%d]%s>>%s -a %d\n", rank, hostname, PetscDebugger, ppid);
594   #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
595     printf("[%d]%s>>%s -pid %d %s\n", rank, hostname, PetscDebugger, ppid, program);
596   #else
597     printf("[%d]%s>>%s %s %d\n", rank, hostname, PetscDebugger, program, ppid);
598   #endif
599   }
600 #endif /* PETSC_CANNOT_START_DEBUGGER */
601 
602   fflush(stdout); /* ignore error because may already be in error handler */
603 
604   sleeptime = 25;                                                                         /* default to sleep waiting for debugger */
605   PetscCallContinue(PetscOptionsGetInt(NULL, NULL, "-debugger_pause", &sleeptime, NULL)); /* ignore error because may already be in error handler */
606   if (sleeptime < 0) sleeptime = -sleeptime;
607 #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
608   /*
609       HP cannot attach process to sleeping debugger, hence count instead
610   */
611   {
612     // this *will* get optimized away by any compiler known to man
613     PetscReal x = 1.0;
614     int       i = 10000000;
615     while (i--) x++; /* cannot attach to sleeper */
616   }
617 #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
618   /*
619       IBM sleep may return at anytime, hence must see if there is more time to sleep
620   */
621   {
622     int left = sleeptime;
623     while (left > 0) left = sleep(left) - 1;
624   }
625 #else
626   PetscCall(PetscSleep(sleeptime));
627 #endif
628   PetscFunctionReturn(PETSC_SUCCESS);
629 }
630