xref: /petsc/src/sys/error/adebug.c (revision 0528010d2e36fd843091ae68bca6200af44882d4)
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)))) {
234     ierr = (*PetscErrorPrintf)("PetscAttachDebugger: stdin is not a tty, hence unable to attach debugger, see PetscAttachDebugger()\n");
235     return PETSC_ERR_SYS;
236   }
237   child = (int)fork();
238   if (PetscUnlikely(child < 0)) {
239     ierr = (*PetscErrorPrintf)("PetscAttachDebugger: Error in fork() prior to attaching debugger\n");
240     return PETSC_ERR_SYS;
241   }
242   petscindebugger = PETSC_TRUE;
243 
244   /*
245       Swap role the parent and child. This is (I think) so that control c typed
246     in the debugger goes to the correct process.
247   */
248   #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
249   child = child ? 0 : (int)getppid();
250   #endif
251 
252   if (child) { /* I am the parent, will run the debugger */
253     const char *args[10];
254     char        pid[10];
255     PetscInt    j, jj;
256     PetscBool   isdbx, isidb, isxldb, isxxgdb, isups, isxdb, isworkshop, isddd, iskdbg, islldb;
257 
258     PetscCall(PetscGetHostName(hostname, sizeof(hostname)));
259     /*
260          We need to send a continue signal to the "child" process on the
261        alpha, otherwise it just stays off forever
262     */
263   #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
264     kill(child, SIGCONT);
265   #endif
266     PetscCall(PetscSNPrintf(pid, PETSC_STATIC_ARRAY_LENGTH(pid), "%d", child));
267 
268     PetscCall(PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb));
269     PetscCall(PetscStrcmp(PetscDebugger, "ddd", &isddd));
270     PetscCall(PetscStrcmp(PetscDebugger, "kdbg", &iskdbg));
271     PetscCall(PetscStrcmp(PetscDebugger, "ups", &isups));
272     PetscCall(PetscStrcmp(PetscDebugger, "xldb", &isxldb));
273     PetscCall(PetscStrcmp(PetscDebugger, "xdb", &isxdb));
274     PetscCall(PetscStrcmp(PetscDebugger, "dbx", &isdbx));
275     PetscCall(PetscStrcmp(PetscDebugger, "idb", &isidb));
276     PetscCall(PetscStrcmp(PetscDebugger, "workshop", &isworkshop));
277     PetscCall(PetscStrcmp(PetscDebugger, "lldb", &islldb));
278 
279     if (isxxgdb || isups || isddd) {
280       args[1] = program;
281       args[2] = pid;
282       args[3] = "-display";
283       args[0] = PetscDebugger;
284       args[4] = display;
285       args[5] = NULL;
286       printf("PETSC: Attaching %s to %s %s on %s\n", args[0], args[1], pid, hostname);
287       if (execvp(args[0], (char **)args) < 0) {
288         perror("Unable to start debugger");
289         exit(0);
290       }
291     } else if (iskdbg) {
292       args[1] = "-p";
293       args[2] = pid;
294       args[3] = program;
295       args[4] = "-display";
296       args[0] = PetscDebugger;
297       args[5] = display;
298       args[6] = NULL;
299       printf("PETSC: Attaching %s to %s %s on %s\n", args[0], args[3], pid, hostname);
300       if (execvp(args[0], (char **)args) < 0) {
301         perror("Unable to start debugger");
302         exit(0);
303       }
304     } else if (isxldb) {
305       args[1] = "-a";
306       args[2] = pid;
307       args[3] = program;
308       args[4] = "-display";
309       args[0] = PetscDebugger;
310       args[5] = display;
311       args[6] = NULL;
312       printf("PETSC: Attaching %s to %s %s on %s\n", args[0], args[1], pid, hostname);
313       if (execvp(args[0], (char **)args) < 0) {
314         perror("Unable to start debugger");
315         exit(0);
316       }
317     } else if (isworkshop) {
318       args[1] = "-s";
319       args[2] = pid;
320       args[3] = "-D";
321       args[4] = "-";
322       args[0] = PetscDebugger;
323       args[5] = pid;
324       args[6] = "-display";
325       args[7] = display;
326       args[8] = NULL;
327       printf("PETSC: Attaching %s to %s on %s\n", args[0], pid, hostname);
328       if (execvp(args[0], (char **)args) < 0) {
329         perror("Unable to start debugger");
330         exit(0);
331       }
332     } else {
333       j = 0;
334       if (UseDebugTerminal) {
335         PetscBool cmp;
336         char     *tmp, *tmp1 = NULL;
337         PetscCall(PetscStrncmp(DebugTerminal, "Terminal", 8, &cmp));
338         if (cmp) {
339           char command[1024];
340           if (islldb) PetscCall(PetscSNPrintf(command, sizeof(command), "osascript -e 'tell app \"Terminal\" to do script \"lldb  -p %s \"'\n", pid));
341           else {
342             char fullprogram[PETSC_MAX_PATH_LEN];
343             PetscCall(PetscGetFullPath(program, fullprogram, sizeof(fullprogram)));
344             PetscCall(PetscSNPrintf(command, sizeof(command), "osascript -e 'tell app \"Terminal\" to do script \"%s  %s %s \"'\n", PetscDebugger, fullprogram, pid));
345           }
346   #if defined(PETSC_HAVE_POPEN)
347           PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, command, "r", NULL));
348   #else
349           printf("-debug_terminal Terminal is not available on this system since PETSC_HAVE_POPEN is not defined in this configuration\n");
350   #endif
351           exit(0);
352         }
353 
354         PetscCall(PetscStrncmp(DebugTerminal, "screen", 6, &cmp));
355         if (!cmp) PetscCall(PetscStrncmp(DebugTerminal, "gnome-terminal", 6, &cmp));
356         if (cmp) display[0] = 0; /* when using screen, we never pass -display */
357         args[j++] = tmp = DebugTerminal;
358         if (display[0]) {
359           args[j++] = "-display";
360           args[j++] = display;
361         }
362         while (*tmp) {
363           PetscCall(PetscStrchr(tmp, ' ', &tmp1));
364           if (!tmp1) break;
365           *tmp1     = 0;
366           tmp       = tmp1 + 1;
367           args[j++] = tmp;
368         }
369       }
370       args[j++] = PetscDebugger;
371       jj        = j;
372       /* this is for default gdb */
373       args[j++] = program;
374       args[j++] = pid;
375       args[j++] = NULL;
376 
377       if (isidb) {
378         j         = jj;
379         args[j++] = "-pid";
380         args[j++] = pid;
381         args[j++] = "-gdb";
382         args[j++] = program;
383         args[j++] = NULL;
384       }
385       if (islldb) {
386         j         = jj;
387         args[j++] = "-p";
388         args[j++] = pid;
389         args[j++] = NULL;
390       }
391       if (isdbx) {
392         j         = jj;
393   #if defined(PETSC_USE_P_FOR_DEBUGGER)
394         args[j++] = "-p";
395         args[j++] = pid;
396         args[j++] = program;
397   #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
398         args[j++] = "-l";
399         args[j++] = "ALL";
400         args[j++] = "-P";
401         args[j++] = pid;
402         args[j++] = program;
403   #elif defined(PETSC_USE_A_FOR_DEBUGGER)
404         args[j++] = "-a";
405         args[j++] = pid;
406   #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
407         args[j++] = "-pid";
408         args[j++] = pid;
409         args[j++] = program;
410   #else
411         args[j++] = program;
412         args[j++] = pid;
413   #endif
414         args[j++] = NULL;
415       }
416       if (UseDebugTerminal) {
417         if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n", PetscDebugger, program, pid, display, hostname);
418         else printf("PETSC: Attaching %s to %s on pid %s on %s\n", PetscDebugger, program, pid, hostname);
419 
420         if (execvp(args[0], (char **)args) < 0) {
421           perror("Unable to start debugger in xterm");
422           exit(0);
423         }
424       } else {
425         printf("PETSC: Attaching %s to %s of pid %s on %s\n", PetscDebugger, program, pid, hostname);
426         if (execvp(args[0], (char **)args) < 0) {
427           perror("Unable to start debugger");
428           exit(0);
429         }
430       }
431     }
432   } else {          /* I am the child, continue with user code */
433     sleeptime = 10; /* default to sleep waiting for debugger */
434     PetscCall(PetscOptionsGetReal(NULL, NULL, "-debugger_pause", &sleeptime, NULL));
435     if (sleeptime < 0) sleeptime = -sleeptime;
436   #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
437     /*
438         HP cannot attach process to sleeping debugger, hence count instead
439     */
440     {
441       PetscReal x = 1.0;
442       int       i = 10000000;
443       while (i--) x++; /* cannot attach to sleeper */
444     }
445   #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
446     /*
447         IBM sleep may return at anytime, hence must see if there is more time to sleep
448     */
449     {
450       int left = sleeptime;
451       while (left > 0) left = PetscSleep(left) - 1;
452     }
453   #else
454     PetscCall(PetscSleep(sleeptime));
455   #endif
456   }
457 #endif
458   return PETSC_SUCCESS;
459 }
460 
461 /*@C
462    PetscAttachDebuggerErrorHandler - Error handler that attaches
463    a debugger to a running process when an error is detected.
464    This routine is useful for examining variables, etc.
465 
466    Not Collective
467 
468    Input Parameters:
469 +  comm - communicator over which error occurred
470 .  line - the line number of the error (indicated by `__LINE__`)
471 .  file - the file in which the error was detected (indicated by `__FILE__`)
472 .  message - an error text string, usually just printed to the screen
473 .  number - the generic error number
474 .  p - `PETSC_ERROR_INITIAL` if error just detected, otherwise `PETSC_ERROR_REPEAT`
475 -  ctx - error handler context
476 
477    Options Database Keys:
478 +  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
479 .  -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n]
480 -  -stop_for_debugger - prints a message on how to attach a debugger to the process and then waits for the attachment
481 
482    Level: developer
483 
484    Notes:
485    By default the Gnu debugger, gdb, is used.  Alternatives are cuda-gdb, lldb, dbx and
486    xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
487 
488    Most users need not directly employ this routine and the other error
489    handlers, but can instead use the simplified interface SETERR, which has
490    the calling sequence
491 $     SETERRQ(PETSC_COMM_SELF, number, p, message)
492 
493    Notes for experienced users:
494    Use `PetscPushErrorHandler()` to set the desired error handler.  The
495    currently available PETSc error handlers are
496 .vb
497     PetscTraceBackErrorHandler()
498     PetscAttachDebuggerErrorHandler()
499     PetscAbortErrorHandler()
500 .ve
501   or you may write your own.
502 
503    Developer Note:
504      This routine calls abort instead of returning because if it returned then `MPI_Abort()` would get called which can generate an exception
505      causing the debugger to be attached again in a cycle.
506 
507 .seealso: `PetscSetDebuggerFromString()`, `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscTraceBackErrorHandler()`,
508           `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscEmacsClientErrorHandler()`, `PetscReturnErrorHandler()`, `PetscSetDebugTermainal()`
509 @*/
510 PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode num, PetscErrorType p, const char *mess, void *ctx)
511 {
512   PetscErrorCode ierr;
513   if (!mess) mess = " ";
514 
515   if (fun) ierr = (*PetscErrorPrintf)("%s() at %s:%d %s\n", fun, file, line, mess);
516   else ierr = (*PetscErrorPrintf)("%s:%d %s\n", file, line, mess);
517 
518   ierr = PetscAttachDebugger();
519   (void)ierr;
520   abort(); /* call abort because don't want to kill other MPI ranks that may successfully attach to debugger */
521   PetscFunctionReturn(PETSC_SUCCESS);
522 }
523 
524 /*@C
525    PetscStopForDebugger - Prints a message to the screen indicating how to
526          attach to the process with the debugger and then waits for the
527          debugger to attach.
528 
529    Not Collective
530 
531    Options Database Key:
532 .   -stop_for_debugger - will stop for you to attach the debugger when PetscInitialize() is called
533 
534    Level: developer
535 
536    Note:
537     This is likely never needed since `PetscAttachDebugger()` is easier to use and seems to always work.
538 
539    Developer Note:
540     Since this can be called by the error handler, should it be calling `SETERRQ()` and `PetscCall()`?
541 
542 .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
543 @*/
544 PetscErrorCode PetscStopForDebugger(void)
545 {
546   PetscErrorCode ierr;
547   PetscInt       sleeptime = 0;
548 #if !defined(PETSC_CANNOT_START_DEBUGGER)
549   int         ppid;
550   PetscMPIInt rank;
551   char        program[PETSC_MAX_PATH_LEN], hostname[256];
552   PetscBool   isdbx, isxldb, isxxgdb, isddd, iskdbg, isups, isxdb, islldb;
553 #endif
554 
555   PetscFunctionBegin;
556 #if defined(PETSC_CANNOT_START_DEBUGGER)
557   PetscCall((*PetscErrorPrintf)("System cannot start debugger; just continuing program\n"));
558 #else
559   if (MPI_Comm_rank(PETSC_COMM_WORLD, &rank)) rank = 0; /* ignore error since this may be already in error handler */
560   ierr = PetscGetHostName(hostname, sizeof(hostname));
561   if (ierr) {
562     PetscCall((*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n"));
563     PetscFunctionReturn(PETSC_SUCCESS);
564   }
565 
566   ierr = PetscGetProgramName(program, sizeof(program));
567   if (ierr) {
568     PetscCall((*PetscErrorPrintf)("Cannot determine program name; just continuing program\n"));
569     PetscFunctionReturn(PETSC_SUCCESS);
570   }
571   if (!program[0]) {
572     PetscCall((*PetscErrorPrintf)("Cannot determine program name; just continuing program\n"));
573     PetscFunctionReturn(PETSC_SUCCESS);
574   }
575 
576   ppid = getpid();
577 
578   PetscCall(PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb));
579   PetscCall(PetscStrcmp(PetscDebugger, "ddd", &isddd));
580   PetscCall(PetscStrcmp(PetscDebugger, "kdbg", &iskdbg));
581   PetscCall(PetscStrcmp(PetscDebugger, "ups", &isups));
582   PetscCall(PetscStrcmp(PetscDebugger, "xldb", &isxldb));
583   PetscCall(PetscStrcmp(PetscDebugger, "xdb", &isxdb));
584   PetscCall(PetscStrcmp(PetscDebugger, "dbx", &isdbx));
585   PetscCall(PetscStrcmp(PetscDebugger, "lldb", &islldb));
586 
587   if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n", rank, hostname, PetscDebugger, program, ppid);
588   else if (isxldb) printf("[%d]%s>>%s -a %d %s\n", rank, hostname, PetscDebugger, ppid, program);
589   else if (islldb) printf("[%d]%s>>%s -p %d\n", rank, hostname, PetscDebugger, ppid);
590   else if (isdbx) {
591   #if defined(PETSC_USE_P_FOR_DEBUGGER)
592     printf("[%d]%s>>%s -p %d %s\n", rank, hostname, PetscDebugger, ppid, program);
593   #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
594     printf("[%d]%s>>%s -l ALL -P %d %s\n", rank, hostname, PetscDebugger, ppid, program);
595   #elif defined(PETSC_USE_A_FOR_DEBUGGER)
596     printf("[%d]%s>>%s -a %d\n", rank, hostname, PetscDebugger, ppid);
597   #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
598     printf("[%d]%s>>%s -pid %d %s\n", rank, hostname, PetscDebugger, ppid, program);
599   #else
600     printf("[%d]%s>>%s %s %d\n", rank, hostname, PetscDebugger, program, ppid);
601   #endif
602   }
603 #endif /* PETSC_CANNOT_START_DEBUGGER */
604 
605   fflush(stdout); /* ignore error because may already be in error handler */
606 
607   sleeptime = 25;                                                                         /* default to sleep waiting for debugger */
608   PetscCallContinue(PetscOptionsGetInt(NULL, NULL, "-debugger_pause", &sleeptime, NULL)); /* ignore error because may already be in error handler */
609   if (sleeptime < 0) sleeptime = -sleeptime;
610 #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
611   /*
612       HP cannot attach process to sleeping debugger, hence count instead
613   */
614   {
615     // this *will* get optimized away by any compiler known to man
616     PetscReal x = 1.0;
617     int       i = 10000000;
618     while (i--) x++; /* cannot attach to sleeper */
619   }
620 #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
621   /*
622       IBM sleep may return at anytime, hence must see if there is more time to sleep
623   */
624   {
625     int left = sleeptime;
626     while (left > 0) left = sleep(left) - 1;
627   }
628 #else
629   PetscCall(PetscSleep(sleeptime));
630 #endif
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633