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