Actual source code: adebug.c
1: #define PETSC_DLL
2: /*
3: Code to handle PETSc starting up in debuggers,etc.
4: */
6: #include petsc.h
7: #include <signal.h>
8: #include petscsys.h
9: #if defined(PETSC_HAVE_UNISTD_H)
10: #include <unistd.h>
11: #endif
12: #if defined(PETSC_HAVE_STDLIB_H)
13: #include <stdlib.h>
14: #endif
15: #include "petscfix.h"
17: /*
18: These are the debugger and display used if the debugger is started up
19: */
20: static char Debugger[PETSC_MAX_PATH_LEN];
21: static char DebugTerminal[PETSC_MAX_PATH_LEN];
22: static PetscTruth Xterm = PETSC_TRUE;
26: /*@C
27: PetscSetDebugTerminal - Sets the terminal to use (instead of xterm) for debugging.
29: Not Collective
31: Input Parameters:
32: + terminal - name of terminal and any flags required to execute a program.
33: For example "xterm -e", "urxvt -e".
35: Options Database Keys:
36: -debug_terminal terminal - use this terminal instead of xterm
38: Level: developer
40: Notes:
41: You can start the debugger for all processes in the same GNU screen session.
43: mpirun -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"
45: will open 4 windows in the session named "debug".
46:
47: Fortran Note:
48: This routine is not supported in Fortran.
50: Concepts: debugger^setting
52: .seealso: PetscSetDebugger()
53: @*/
54: PetscErrorCode PetscSetDebugTerminal(const char terminal[])
55: {
59: PetscStrcpy(DebugTerminal,terminal);
60: return(0);
61: }
65: /*@C
66: PetscSetDebugger - Sets options associated with the debugger.
68: Not Collective
70: Input Parameters:
71: + debugger - name of debugger, which should be in your path,
72: usually "dbx", "gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
73: supports "xdb", and IBM rs6000 supports "xldb".
75: - xterm - flag to indicate debugger window, set to either 1 (to indicate
76: debugger should be started in a new xterm) or 0 (to start debugger
77: in initial window (the option 0 makes no sense when using more
78: than one processor.)
80: Level: developer
82: Fortran Note:
83: This routine is not supported in Fortran.
85: Concepts: debugger^setting
87: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
88: @*/
89: PetscErrorCode PetscSetDebugger(const char debugger[],PetscTruth xterm)
90: {
94: if (debugger) {
95: PetscStrcpy(Debugger,debugger);
96: }
97: Xterm = xterm;
99: return(0);
100: }
104: /*@
105: PetscSetDefaultDebugger - Causes PETSc to use its default
106: debugger.
108: Not collective
110: Level: advanced
112: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
113: @*/
114: PetscErrorCode PetscSetDefaultDebugger(void)
115: {
119: #if defined(PETSC_USE_DBX_DEBUGGER)
120: PetscSetDebugger("dbx",PETSC_TRUE);
121: #elif defined(PETSC_USE_XDB_DEBUGGER)
122: PetscSetDebugger("xdb",PETSC_TRUE);
123: #elif defined(PETSC_USE_IDB_DEBUGGER)
124: PetscSetDebugger("idb",PETSC_TRUE);
125: #else /* Default is gdb */
126: PetscSetDebugger("gdb",PETSC_TRUE);
127: #endif
128: PetscSetDebugTerminal("xterm -e");
129: return(0);
130: }
135: {
136: PetscTruth exists;
137: char *f;
141: PetscStrstr(string, defaultDbg, &f);
142: if (f) {
143: PetscTestFile(string, 'x', &exists);
144: if (exists) {
145: *debugger = string;
146: } else {
147: *debugger = defaultDbg;
148: }
149: }
150: return(0);
151: }
155: /*@C
156: PetscSetDebuggerFromString - Set the complete path for the
157: debugger for PETSc to use.
159: Not collective
160:
161: Level: advanced
163: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
164: @*/
165: PetscErrorCode PetscSetDebuggerFromString(char *string)
166: {
167: const char *debugger = PETSC_NULL;
168: PetscTruth xterm = PETSC_TRUE;
169: char *f;
173: PetscStrstr(string, "noxterm", &f);
174: if (f) xterm = PETSC_FALSE;
175: PetscStrstr(string, "ddd", &f);
176: if (f) xterm = PETSC_FALSE;
190: PetscSetDebugger(debugger, xterm);
191: return(0);
192: }
197: /*@
198: PetscAttachDebugger - Attaches the debugger to the running process.
200: Not Collective
202: Level: advanced
204: Concepts: debugger^starting from program
206: .seealso: PetscSetDebugger()
207: @*/
208: PetscErrorCode PetscAttachDebugger(void)
209: {
210: #if !defined(PETSC_CANNOT_START_DEBUGGER)
211: int child=0;
212: PetscInt sleeptime=0;
214: char program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
215: #endif
219: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
220: (*PetscErrorPrintf)("System cannot start debugger\n");
221: (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
222: (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
223: MPI_Finalize();
224: exit(0);
225: #else
226: PetscGetDisplay(display,128);
227: PetscGetProgramName(program,PETSC_MAX_PATH_LEN);
228: if (ierr) {
229: (*PetscErrorPrintf)("Cannot determine program name\n");
230: PetscFunctionReturn(1);
231: }
232: if (!program[0]) {
233: (*PetscErrorPrintf)("Cannot determine program name\n");
234: PetscFunctionReturn(1);
235: }
236: child = (int)fork();
237: if (child < 0) {
238: (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
239: PetscFunctionReturn(1);
240: }
242: /*
243: Swap role the parent and child. This is (I think) so that control c typed
244: in the debugger goes to the correct process.
245: */
246: if (child) { child = 0; }
247: else { child = (int)getppid(); }
249: if (child) { /* I am the parent, will run the debugger */
250: const char *args[10];
251: char pid[10];
252: PetscInt j,jj;
253: PetscTruth isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg;
255: PetscGetHostName(hostname,64);
256: /*
257: We need to send a continue signal to the "child" process on the
258: alpha, otherwise it just stays off forever
259: */
260: #if defined (PETSC_NEED_KILL_FOR_DEBUGGER)
261: kill(child,SIGCONT);
262: #endif
263: sprintf(pid,"%d",child);
265: PetscStrcmp(Debugger,"xxgdb",&isxxgdb);
266: PetscStrcmp(Debugger,"ddd",&isddd);
267: PetscStrcmp(Debugger,"kdbg",&iskdbg);
268: PetscStrcmp(Debugger,"ups",&isups);
269: PetscStrcmp(Debugger,"xldb",&isxldb);
270: PetscStrcmp(Debugger,"xdb",&isxdb);
271: PetscStrcmp(Debugger,"dbx",&isdbx);
272: PetscStrcmp(Debugger,"idb",&isidb);
273: PetscStrcmp(Debugger,"workshop",&isworkshop);
275: if (isxxgdb || isups || isddd ) {
276: args[1] = program; args[2] = pid; args[3] = "-display";
277: args[0] = Debugger; args[4] = display; args[5] = 0;
278: (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
279: if (execvp(args[0],(char**)args) < 0) {
280: perror("Unable to start debugger");
281: exit(0);
282: }
283: } else if (iskdbg) {
284: args[1] = "-p"; args[2] = pid; args[3] = program; args[4] = "-display";
285: args[0] = Debugger; args[5] = display; args[6] = 0;
286: (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
287: if (execvp(args[0],(char**)args) < 0) {
288: perror("Unable to start debugger");
289: exit(0);
290: }
291: } else if (isxldb) {
292: args[1] = "-a"; args[2] = pid; args[3] = program; args[4] = "-display";
293: args[0] = Debugger; args[5] = display; args[6] = 0;
294: (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
295: if (execvp(args[0],(char**)args) < 0) {
296: perror("Unable to start debugger");
297: exit(0);
298: }
299: } else if (isworkshop) {
300: args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
301: args[0] = Debugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = 0;
302: (*PetscErrorPrintf)("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
303: if (execvp(args[0],(char**)args) < 0) {
304: perror("Unable to start debugger");
305: exit(0);
306: }
307: } else {
308: j = 0;
309: if (Xterm) {
310: PetscTruth cmp;
311: char *tmp,*tmp1;
312: PetscStrncmp(DebugTerminal,"screen",6,&cmp);
313: if (cmp) display[0] = 0; /* when using screen, we never pass -display */
314: args[j++] = tmp = DebugTerminal;
315: if (display[0]) {
316: args[j++] = "-display"; args[j++] = display;
317: }
318: while (*tmp) {
319: PetscStrchr(tmp,' ',&tmp1);
320: if (!tmp1) break;
321: *tmp1 = 0;
322: tmp = tmp1+1;
323: args[j++] = tmp;
324: }
325: }
326: args[j++] = Debugger;
327: jj = j;
328: args[j++] = program; args[j++] = pid; args[j++] = 0;
330: if (isidb) {
331: j = jj;
332: args[j++] = "-pid";
333: args[j++] = pid;
334: args[j++] = "-gdb";
335: args[j++] = program;
336: args[j++] = 0;
337: }
338: #if defined(PETSC_USE_P_FOR_DEBUGGER)
339: if (isdbx) {
340: j = jj;
341: args[j++] = "-p";
342: args[j++] = pid;
343: args[j++] = program;
344: args[j++] = 0;
345: }
346: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
347: if (isxdb) {
348: j = jj;
349: args[j++] = "-l";
350: args[j++] = "ALL";
351: args[j++] = "-P";
352: args[j++] = pid;
353: args[j++] = program;
354: args[j++] = 0;
355: }
356: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
357: if (isdbx) {
358: j = jj;
359: args[j++] = "-a";
360: args[j++] = pid;
361: args[j++] = 0;
362: }
363: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
364: if (isdbx) {
365: j = jj;
366: args[j++] = "-pid";
367: args[j++] = pid;
368: args[j++] = program;
369: args[j++] = 0;
370: }
371: #endif
372: if (Xterm) {
373: if (display[0]) {
374: (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",Debugger,program,pid,display,hostname);
375: } else {
376: (*PetscErrorPrintf)("PETSC: Attaching %s to %s on pid %s on %s\n",Debugger,program,pid,hostname);
377: }
378: if (execvp(args[0],(char**)args) < 0) {
379: perror("Unable to start debugger in xterm");
380: exit(0);
381: }
382: } else {
383: (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on %s\n",Debugger,program,pid,hostname);
384: if (execvp(args[0],(char**)args) < 0) {
385: perror("Unable to start debugger");
386: exit(0);
387: }
388: }
389: }
390: } else { /* I am the child, continue with user code */
391: sleeptime = 10; /* default to sleep waiting for debugger */
392: PetscOptionsGetInt(PETSC_NULL,"-debugger_pause",&sleeptime,PETSC_NULL);
393: if (sleeptime < 0) sleeptime = -sleeptime;
394: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
395: /*
396: HP cannot attach process to sleeping debugger, hence count instead
397: */
398: {
399: PetscReal x = 1.0;
400: int i=10000000;
401: while (i--) x++ ; /* cannot attach to sleeper */
402: }
403: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
404: /*
405: IBM sleep may return at anytime, hence must see if there is more time to sleep
406: */
407: {
408: int left = sleeptime;
409: while (left > 0) {left = PetscSleep(left) - 1;}
410: }
411: #else
412: PetscSleep(sleeptime);
413: #endif
414: }
415: #endif
416: return(0);
417: }
421: /*@C
422: PetscAttachDebuggerErrorHandler - Error handler that attaches
423: a debugger to a running process when an error is detected.
424: This routine is useful for examining variables, etc.
426: Not Collective
428: Input Parameters:
429: + line - the line number of the error (indicated by __LINE__)
430: . fun - function where error occured (indicated by __FUNCT__)
431: . file - the file in which the error was detected (indicated by __FILE__)
432: . dir - the directory of the file (indicated by __SDIR__)
433: . message - an error text string, usually just printed to the screen
434: . number - the generic error number
435: . p - the specific error number
436: - ctx - error handler context
438: Options Database Keys:
439: . -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
440: debugger attachment
442: Level: developer
444: Notes:
445: By default the GNU debugger, gdb, is used. Alternatives are dbx and
446: xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
448: Most users need not directly employ this routine and the other error
449: handlers, but can instead use the simplified interface SETERR, which has
450: the calling sequence
451: $ SETERRQ(number,p,message)
453: Notes for experienced users:
454: Use PetscPushErrorHandler() to set the desired error handler. The
455: currently available PETSc error handlers are
456: $ PetscTraceBackErrorHandler()
457: $ PetscAttachDebuggerErrorHandler()
458: $ PetscAbortErrorHandler()
459: or you may write your own.
461: Concepts: debugger^error handler
462: Concepts: error handler^attach debugger
464: .seealso: PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
465: PetscAbortErrorHandler()
466: @*/
467: PetscErrorCode PetscAttachDebuggerErrorHandler(int line,const char* fun,const char *file,const char* dir,int num,int p,const char* mess,void *ctx)
468: {
472: if (!fun) fun = "User provided function";
473: if (!dir) dir = " ";
474: if (!mess) mess = " ";
476: (*PetscErrorPrintf)("%s() line %d in %s%s %s\n",fun,line,dir,file,mess);
478: PetscAttachDebugger();
479: if (ierr) { /* hopeless so get out */
480: MPI_Finalize();
481: exit(num);
482: }
483: return(0);
484: }
488: /*@C
489: PetscStopForDebugger - Prints a message to the screen indicating how to
490: attach to the process with the debugger and then waits for the
491: debugger to attach.
493: Not Collective
495: Level: advanced
497: Concepts: debugger^waiting for attachment
499: .seealso: PetscSetDebugger(), PetscAttachDebugger()
500: @*/
501: PetscErrorCode PetscStopForDebugger(void)
502: {
504: PetscInt sleeptime=0;
505: int err;
506: #if !defined(PETSC_CANNOT_START_DEBUGGER)
507: int ppid;
508: PetscMPIInt rank;
509: char program[PETSC_MAX_PATH_LEN],hostname[256];
510: PetscTruth isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb;
511: #endif
514: #if defined(PETSC_CANNOT_START_DEBUGGER)
515: (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
516: #else
517: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
518: PetscGetHostName(hostname,256);
519: if (ierr) {
520: (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
521: return(0);
522: }
524: PetscGetProgramName(program,256);
525: if (ierr) {
526: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
527: return(0);
528: }
529: if (!program[0]) {
530: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
531: return(0);
532: }
534: ppid = getpid();
536: PetscStrcmp(Debugger,"xxgdb",&isxxgdb);
537: PetscStrcmp(Debugger,"ddd",&isddd);
538: PetscStrcmp(Debugger,"kdbg",&iskdbg);
539: PetscStrcmp(Debugger,"ups",&isups);
540: PetscStrcmp(Debugger,"xldb",&isxldb);
541: PetscStrcmp(Debugger,"xdb",&isxdb);
542: PetscStrcmp(Debugger,"dbx",&isdbx);
544: if (isxxgdb || isups || isddd || iskdbg ) {
545: (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,Debugger,program,ppid);
546: }
547: #if defined(PETSC_USE_A_FOR_DEBUGGER)
548: else if (isxldb) {
549: (*PetscErrorPrintf)("{%d]%s>>%s -a %d %s\n",rank,hostname,Debugger,ppid,program);
550: }
551: #endif
552: #if defined(PETSC_USE_P_FOR_DEBUGGER)
553: else if (isdbx) {
554: (*PetscErrorPrintf)("[%d]%s>>%s -p %d %s\n",rank,hostname,Debugger,ppid,program);
555: }
556: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
557: else if (isxdb) {
558: (*PetscErrorPrintf)("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,Debugger,ppid,program);
559: }
560: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
561: else if (isdbx) {
562: (*PetscErrorPrintf)("[%d]%s>>%s -a %d\n",rank,hostname,Debugger,ppid);
563: }
564: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
565: else if (isdbx) {
566: (*PetscErrorPrintf)("[%d]%s>>%s -pid %d %s\n",rank,hostname,Debugger,ppid,program);
567: }
568: #else
569: else {
570: (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,Debugger,program,ppid);
571: }
572: #endif
573: #endif /* PETSC_CANNOT_START_DEBUGGER */
575: err = fflush(stdout);
576: if (err) SETERRQ(PETSC_ERR_SYS,"fflush() failed on stdout");
578: sleeptime = 25; /* default to sleep waiting for debugger */
579: PetscOptionsGetInt(PETSC_NULL,"-debugger_pause",&sleeptime,PETSC_NULL);
580: if (sleeptime < 0) sleeptime = -sleeptime;
581: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
582: /*
583: HP cannot attach process to sleeping debugger, hence count instead
584: */
585: {
586: PetscReal x = 1.0;
587: int i=10000000;
588: while (i--) x++ ; /* cannot attach to sleeper */
589: }
590: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
591: /*
592: IBM sleep may return at anytime, hence must see if there is more time to sleep
593: */
594: {
595: int left = sleeptime;
596: while (left > 0) {left = sleep(left) - 1;}
597: }
598: #else
599: PetscSleep(sleeptime);
600: #endif
601: return(0);
602: }