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