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