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