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