Actual source code: adebug.c
1: /*
2: Code to handle PETSc starting up in debuggers,etc.
3: */
5: #include <petscsys.h>
6: #include <signal.h>
7: #if defined(PETSC_HAVE_UNISTD_H)
8: #include <unistd.h>
9: #endif
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;
20: /*@C
21: PetscSetDebugTerminal - Sets the terminal to use for debugging.
23: Not Collective
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)
30: Options Database Key:
31: -debug_terminal terminal - use this terminal instead of the default
33: Level: developer
35: Notes:
36: You can start the debugger for all processes in the same GNU screen session.
38: mpiexec -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"
40: will open 4 windows in the session named "debug".
42: The default on Apple is Terminal, on other systems the default is xterm
44: Fortran Note:
45: This routine is not supported in Fortran.
47: .seealso: `PetscSetDebugger()`
48: @*/
49: PetscErrorCode PetscSetDebugTerminal(const char terminal[])
50: {
51: PetscBool xterm;
53: PetscStrncpy(DebugTerminal, terminal, sizeof(DebugTerminal));
54: PetscStrcmp(terminal, "xterm", &xterm);
55: if (xterm) PetscStrlcat(DebugTerminal, " -e", sizeof(DebugTerminal));
56: return 0;
57: }
59: /*@C
60: PetscSetDebugger - Sets options associated with the debugger.
62: Not Collective
64: Input Parameters:
65: + debugger - name of debugger, which should be in your path,
66: usually "lldb", "dbx", "gdb", "cuda-gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
67: supports "xdb", and IBM rs6000 supports "xldb".
69: - usedebugterminal - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
70: debugger should be started in a new terminal window) or PETSC_FALSE (to start debugger
71: in initial window (the option PETSC_FALSE makes no sense when using more
72: than one MPI process.)
74: Level: developer
76: Fortran Note:
77: This routine is not supported in Fortran.
79: .seealso: `PetscAttachDebugger()`, `PetscAttachDebuggerErrorHandler()`, `PetscSetDebugTerminal()`
80: @*/
81: PetscErrorCode PetscSetDebugger(const char debugger[], PetscBool usedebugterminal)
82: {
83: if (debugger) PetscStrncpy(PetscDebugger, debugger, sizeof(PetscDebugger));
84: if (UseDebugTerminal) UseDebugTerminal = usedebugterminal;
85: return 0;
86: }
88: /*@C
89: PetscSetDefaultDebugger - Causes PETSc to use its default debugger and output terminal
91: Not collective
93: Level: developer
95: .seealso: `PetscSetDebugger()`, `PetscSetDebuggerFromString()`
96: @*/
97: PetscErrorCode PetscSetDefaultDebugger(void)
98: {
99: #if defined(PETSC_USE_DEBUGGER)
100: PetscSetDebugger(PETSC_USE_DEBUGGER, PETSC_TRUE);
101: #endif
102: #if defined(__APPLE__)
103: PetscSetDebugTerminal("Terminal");
104: #else
105: PetscSetDebugTerminal("xterm");
106: #endif
107: return 0;
108: }
111: {
112: PetscBool exists;
113: char *f;
115: PetscStrstr(string, defaultDbg, &f);
116: if (f) {
117: PetscTestFile(string, 'x', &exists);
118: if (exists) *debugger = string;
119: else *debugger = defaultDbg;
120: }
121: return 0;
122: }
124: /*@C
125: PetscSetDebuggerFromString - Set the complete path for the
126: debugger for PETSc to use.
128: Not collective
130: Level: developer
132: .seealso: `PetscSetDebugger()`, `PetscSetDefaultDebugger()`
133: @*/
134: PetscErrorCode PetscSetDebuggerFromString(const char *string)
135: {
136: const char *debugger = NULL;
137: PetscBool useterminal = PETSC_TRUE;
138: char *f;
140: PetscStrstr(string, "noxterm", &f);
141: if (f) useterminal = PETSC_FALSE;
142: PetscStrstr(string, "ddd", &f);
143: if (f) useterminal = PETSC_FALSE;
144: PetscStrstr(string, "noterminal", &f);
145: if (f) useterminal = PETSC_FALSE;
160: PetscSetDebugger(debugger, useterminal);
161: return 0;
162: }
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.
168: Not Collective
170: Level: advanced
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.
176: .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
177: @*/
178: PetscErrorCode PetscWaitOnError()
179: {
180: petscwaitonerrorflg = PETSC_TRUE;
181: return 0;
182: }
184: /*@
185: PetscAttachDebugger - Attaches the debugger to the running process.
187: Not Collective
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
193: Level: advanced
195: Developer Note:
196: Since this can be called by the error handler should it be calling `SETERRQ()` and `PetscCall()`?
198: .seealso: `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscSetDebugTerminal()`, `PetscAttachDebuggerErrorHandler()`, `PetscStopForDebugger()`
199: @*/
200: PetscErrorCode PetscAttachDebugger(void)
201: {
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
208: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
209: (*PetscErrorPrintf)("System cannot start debugger\n");
210: (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
211: (*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: (*PetscErrorPrintf)("Cannot determine display\n");
216: return PETSC_ERR_SYS;
217: }
218: if (PetscUnlikely(PetscGetProgramName(program, sizeof(program)))) {
219: (*PetscErrorPrintf)("Cannot determine program name needed to attach debugger\n");
220: return PETSC_ERR_SYS;
221: }
222: if (PetscUnlikely(!program[0])) {
223: (*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: (*PetscErrorPrintf)("Error in fork() prior to attaching debugger\n");
229: return PETSC_ERR_SYS;
230: }
231: petscindebugger = PETSC_TRUE;
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
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;
247: 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: sprintf(pid, "%d", child);
257: PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb);
258: PetscStrcmp(PetscDebugger, "ddd", &isddd);
259: PetscStrcmp(PetscDebugger, "kdbg", &iskdbg);
260: PetscStrcmp(PetscDebugger, "ups", &isups);
261: PetscStrcmp(PetscDebugger, "xldb", &isxldb);
262: PetscStrcmp(PetscDebugger, "xdb", &isxdb);
263: PetscStrcmp(PetscDebugger, "dbx", &isdbx);
264: PetscStrcmp(PetscDebugger, "idb", &isidb);
265: PetscStrcmp(PetscDebugger, "workshop", &isworkshop);
266: PetscStrcmp(PetscDebugger, "lldb", &islldb);
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: PetscStrncmp(DebugTerminal, "Terminal", 8, &cmp);
327: if (cmp) {
328: char command[1024];
329: if (islldb) 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: PetscGetFullPath(program, fullprogram, sizeof(fullprogram));
333: PetscSNPrintf(command, sizeof(command), "osascript -e 'tell app \"Terminal\" to do script \"%s %s %s \"'\n", PetscDebugger, fullprogram, pid);
334: }
335: PetscPOpen(PETSC_COMM_SELF, NULL, command, "r", NULL);
336: exit(0);
337: }
339: PetscStrncmp(DebugTerminal, "screen", 6, &cmp);
340: if (!cmp) PetscStrncmp(DebugTerminal, "gnome-terminal", 6, &cmp);
341: if (cmp) display[0] = 0; /* when using screen, we never pass -display */
342: args[j++] = tmp = DebugTerminal;
343: if (display[0]) {
344: args[j++] = "-display";
345: args[j++] = display;
346: }
347: while (*tmp) {
348: PetscStrchr(tmp, ' ', &tmp1);
349: if (!tmp1) break;
350: *tmp1 = 0;
351: tmp = tmp1 + 1;
352: args[j++] = tmp;
353: }
354: }
355: args[j++] = PetscDebugger;
356: jj = j;
357: /* this is for default gdb */
358: args[j++] = program;
359: args[j++] = pid;
360: args[j++] = NULL;
362: if (isidb) {
363: j = jj;
364: args[j++] = "-pid";
365: args[j++] = pid;
366: args[j++] = "-gdb";
367: args[j++] = program;
368: args[j++] = NULL;
369: }
370: if (islldb) {
371: j = jj;
372: args[j++] = "-p";
373: args[j++] = pid;
374: args[j++] = NULL;
375: }
376: if (isdbx) {
377: j = jj;
378: #if defined(PETSC_USE_P_FOR_DEBUGGER)
379: args[j++] = "-p";
380: args[j++] = pid;
381: args[j++] = program;
382: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
383: args[j++] = "-l";
384: args[j++] = "ALL";
385: args[j++] = "-P";
386: args[j++] = pid;
387: args[j++] = program;
388: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
389: args[j++] = "-a";
390: args[j++] = pid;
391: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
392: args[j++] = "-pid";
393: args[j++] = pid;
394: args[j++] = program;
395: #else
396: args[j++] = program;
397: args[j++] = pid;
398: #endif
399: args[j++] = NULL;
400: }
401: if (UseDebugTerminal) {
402: if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n", PetscDebugger, program, pid, display, hostname);
403: else printf("PETSC: Attaching %s to %s on pid %s on %s\n", PetscDebugger, program, pid, hostname);
405: if (execvp(args[0], (char **)args) < 0) {
406: perror("Unable to start debugger in xterm");
407: exit(0);
408: }
409: } else {
410: printf("PETSC: Attaching %s to %s of pid %s on %s\n", PetscDebugger, program, pid, hostname);
411: if (execvp(args[0], (char **)args) < 0) {
412: perror("Unable to start debugger");
413: exit(0);
414: }
415: }
416: }
417: } else { /* I am the child, continue with user code */
418: sleeptime = 10; /* default to sleep waiting for debugger */
419: PetscOptionsGetReal(NULL, NULL, "-debugger_pause", &sleeptime, NULL);
420: if (sleeptime < 0) sleeptime = -sleeptime;
421: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
422: /*
423: HP cannot attach process to sleeping debugger, hence count instead
424: */
425: {
426: PetscReal x = 1.0;
427: int i = 10000000;
428: while (i--) x++; /* cannot attach to sleeper */
429: }
430: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
431: /*
432: IBM sleep may return at anytime, hence must see if there is more time to sleep
433: */
434: {
435: int left = sleeptime;
436: while (left > 0) left = PetscSleep(left) - 1;
437: }
438: #else
439: PetscSleep(sleeptime);
440: #endif
441: }
442: #endif
443: return 0;
444: }
446: /*@C
447: PetscAttachDebuggerErrorHandler - Error handler that attaches
448: a debugger to a running process when an error is detected.
449: This routine is useful for examining variables, etc.
451: Not Collective
453: Input Parameters:
454: + comm - communicator over which error occurred
455: . line - the line number of the error (indicated by __LINE__)
456: . file - the file in which the error was detected (indicated by __FILE__)
457: . message - an error text string, usually just printed to the screen
458: . number - the generic error number
459: . p - `PETSC_ERROR_INITIAL` if error just detected, otherwise `PETSC_ERROR_REPEAT`
460: - ctx - error handler context
462: Options Database Keys:
463: + -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
464: - -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n]
466: Level: developer
468: Notes:
469: By default the GNU debugger, gdb, is used. Alternatives are cuda-gdb, lldb, dbx and
470: xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
472: Most users need not directly employ this routine and the other error
473: handlers, but can instead use the simplified interface SETERR, which has
474: the calling sequence
475: $ SETERRQ(PETSC_COMM_SELF,number,p,message)
477: Notes for experienced users:
478: Use `PetscPushErrorHandler()` to set the desired error handler. The
479: currently available PETSc error handlers are
480: $ PetscTraceBackErrorHandler()
481: $ PetscAttachDebuggerErrorHandler()
482: $ PetscAbortErrorHandler()
483: or you may write your own.
485: Developer Note:
486: This routine calls abort instead of returning because if it returned then `MPI_Abort()` would get called which can generate an exception
487: causing the debugger to be attached again in a cycle.
489: .seealso: `PetscSetDebuggerFromString()`, `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscTraceBackErrorHandler()`,
490: `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscEmacsClientErrorHandler()`, `PetscReturnErrorHandler()`, `PetscSetDebugTermainal()`
491: @*/
492: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode num, PetscErrorType p, const char *mess, void *ctx)
493: {
494: if (!mess) mess = " ";
496: if (fun) (*PetscErrorPrintf)("%s() at %s:%d %s\n", fun, file, line, mess);
497: else (*PetscErrorPrintf)("%s:%d %s\n", file, line, mess);
499: PetscAttachDebugger();
500: abort(); /* call abort because don't want to kill other MPI ranks that may successfully attach to debugger */
501: return 0;
502: }
504: /*@C
505: PetscStopForDebugger - Prints a message to the screen indicating how to
506: attach to the process with the debugger and then waits for the
507: debugger to attach.
509: Not Collective
511: Options Database Key:
512: . -stop_for_debugger - will stop for you to attach the debugger when PetscInitialize() is called
514: Level: developer
516: Note:
517: This is likely never needed since `PetscAttachDebugger()` is easier to use and seems to always work.
519: Developer Note:
520: Since this can be called by the error handler, should it be calling `SETERRQ()` and `PetscCall()`?
522: .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
523: @*/
524: PetscErrorCode PetscStopForDebugger(void)
525: {
527: PetscInt sleeptime = 0;
528: #if !defined(PETSC_CANNOT_START_DEBUGGER)
529: int ppid;
530: PetscMPIInt rank;
531: char program[PETSC_MAX_PATH_LEN], hostname[256];
532: PetscBool isdbx, isxldb, isxxgdb, isddd, iskdbg, isups, isxdb, islldb;
533: #endif
535: #if defined(PETSC_CANNOT_START_DEBUGGER)
536: (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
537: #else
538: MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
539: if (ierr) rank = 0; /* ignore error since this may be already in error handler */
540: PetscGetHostName(hostname, sizeof(hostname));
541: if (ierr) {
542: (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
543: return 0;
544: }
546: PetscGetProgramName(program, sizeof(program));
547: if (ierr) {
548: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
549: return 0;
550: }
551: if (!program[0]) {
552: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
553: return 0;
554: }
556: ppid = getpid();
558: PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb);
559: PetscStrcmp(PetscDebugger, "ddd", &isddd);
560: PetscStrcmp(PetscDebugger, "kdbg", &iskdbg);
561: PetscStrcmp(PetscDebugger, "ups", &isups);
562: PetscStrcmp(PetscDebugger, "xldb", &isxldb);
563: PetscStrcmp(PetscDebugger, "xdb", &isxdb);
564: PetscStrcmp(PetscDebugger, "dbx", &isdbx);
565: PetscStrcmp(PetscDebugger, "lldb", &islldb);
567: if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n", rank, hostname, PetscDebugger, program, ppid);
568: else if (isxldb) printf("[%d]%s>>%s -a %d %s\n", rank, hostname, PetscDebugger, ppid, program);
569: else if (islldb) printf("[%d]%s>>%s -p %d\n", rank, hostname, PetscDebugger, ppid);
570: else if (isdbx) {
571: #if defined(PETSC_USE_P_FOR_DEBUGGER)
572: printf("[%d]%s>>%s -p %d %s\n", rank, hostname, PetscDebugger, ppid, program);
573: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
574: printf("[%d]%s>>%s -l ALL -P %d %s\n", rank, hostname, PetscDebugger, ppid, program);
575: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
576: printf("[%d]%s>>%s -a %d\n", rank, hostname, PetscDebugger, ppid);
577: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
578: printf("[%d]%s>>%s -pid %d %s\n", rank, hostname, PetscDebugger, ppid, program);
579: #else
580: printf("[%d]%s>>%s %s %d\n", rank, hostname, PetscDebugger, program, ppid);
581: #endif
582: }
583: #endif /* PETSC_CANNOT_START_DEBUGGER */
585: fflush(stdout); /* ignore error because may already be in error handler */
587: sleeptime = 25; /* default to sleep waiting for debugger */
588: PetscOptionsGetInt(NULL, NULL, "-debugger_pause", &sleeptime, NULL); /* ignore error because may already be in error handler */
589: if (sleeptime < 0) sleeptime = -sleeptime;
590: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
591: /*
592: HP cannot attach process to sleeping debugger, hence count instead
593: */
594: {
595: PetscReal x = 1.0;
596: int i = 10000000;
597: while (i--) x++; /* cannot attach to sleeper */
598: }
599: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
600: /*
601: IBM sleep may return at anytime, hence must see if there is more time to sleep
602: */
603: {
604: int left = sleeptime;
605: while (left > 0) left = sleep(left) - 1;
606: }
607: #else
608: PetscSleep(sleeptime);
609: #endif
610: return 0;
611: }