Actual source code: adebug.c
petsc-3.6.4 2016-04-12
1: /*
2: Code to handle PETSc starting up in debuggers,etc.
3: */
5: #include <petscsys.h> /*I "petscsys.h" I*/
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 Xterm = PETSC_TRUE;
20: /*@C
21: PetscSetDebugTerminal - Sets the terminal to use (instead of xterm) 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 -e", "urxvt -e".
29: Options Database Keys:
30: -debug_terminal terminal - use this terminal instead of xterm
32: Level: developer
34: Notes:
35: You can start the debugger for all processes in the same GNU screen session.
37: mpirun -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"
39: will open 4 windows in the session named "debug".
41: Fortran Note:
42: This routine is not supported in Fortran.
44: Concepts: debugger^setting
46: .seealso: PetscSetDebugger()
47: @*/
48: PetscErrorCode PetscSetDebugTerminal(const char terminal[])
49: {
53: PetscStrcpy(DebugTerminal,terminal);
54: return(0);
55: }
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", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
67: supports "xdb", and IBM rs6000 supports "xldb".
69: - xterm - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
70: debugger should be started in a new xterm) 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: Concepts: debugger^setting
81: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
82: @*/
83: PetscErrorCode PetscSetDebugger(const char debugger[],PetscBool xterm)
84: {
88: if (debugger) {
89: PetscStrcpy(PetscDebugger,debugger);
90: }
91: Xterm = xterm;
92: return(0);
93: }
97: /*@C
98: PetscSetDefaultDebugger - Causes PETSc to use its default debugger.
100: Not collective
102: Level: developer
104: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
105: @*/
106: PetscErrorCode PetscSetDefaultDebugger(void)
107: {
111: #if defined(PETSC_USE_LLDB_DEBUGGER)
112: PetscSetDebugger("lldb",PETSC_TRUE);
113: #elif defined(PETSC_USE_DBX_DEBUGGER)
114: PetscSetDebugger("dbx",PETSC_TRUE);
115: #elif defined(PETSC_USE_XDB_DEBUGGER)
116: PetscSetDebugger("xdb",PETSC_TRUE);
117: #elif defined(PETSC_USE_IDB_DEBUGGER)
118: PetscSetDebugger("idb",PETSC_TRUE);
119: #else /* Default is gdb */
120: PetscSetDebugger("gdb",PETSC_TRUE);
121: #endif
122: PetscSetDebugTerminal("xterm -e");
123: return(0);
124: }
129: {
130: PetscBool exists;
131: char *f;
135: PetscStrstr(string, defaultDbg, &f);
136: if (f) {
137: PetscTestFile(string, 'x', &exists);
138: if (exists) *debugger = string;
139: else *debugger = defaultDbg;
140: }
141: return(0);
142: }
146: /*@C
147: PetscSetDebuggerFromString - Set the complete path for the
148: debugger for PETSc to use.
150: Not collective
152: Level: developer
154: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
155: @*/
156: PetscErrorCode PetscSetDebuggerFromString(const char *string)
157: {
158: const char *debugger = NULL;
159: PetscBool xterm = PETSC_TRUE;
160: char *f;
164: PetscStrstr(string, "noxterm", &f);
165: if (f) xterm = PETSC_FALSE;
166: PetscStrstr(string, "ddd", &f);
167: if (f) xterm = PETSC_FALSE;
182: PetscSetDebugger(debugger, xterm);
183: return(0);
184: }
189: /*@
190: PetscAttachDebugger - Attaches the debugger to the running process.
192: Not Collective
194: Level: advanced
196: Concepts: debugger^starting from program
198: Developer Notes: Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?
200: .seealso: PetscSetDebugger()
201: @*/
202: PetscErrorCode PetscAttachDebugger(void)
203: {
204: #if !defined(PETSC_CANNOT_START_DEBUGGER)
205: int child =0;
206: PetscReal sleeptime=0;
208: char program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
209: #endif
212: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
213: (*PetscErrorPrintf)("System cannot start debugger\n");
214: (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
215: (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
216: MPI_Abort(PETSC_COMM_WORLD,1);
217: #else
218: PetscGetDisplay(display,128);
219: PetscGetProgramName(program,PETSC_MAX_PATH_LEN);
220: if (ierr) {
221: (*PetscErrorPrintf)("Cannot determine program name\n");
222: PetscFunctionReturn(1);
223: }
224: if (!program[0]) {
225: (*PetscErrorPrintf)("Cannot determine program name\n");
226: PetscFunctionReturn(1);
227: }
228: child = (int)fork();
229: if (child < 0) {
230: (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
231: PetscFunctionReturn(1);
232: }
234: /*
235: Swap role the parent and child. This is (I think) so that control c typed
236: in the debugger goes to the correct process.
237: */
238: if (child) child = 0;
239: else child = (int)getppid();
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,64);
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; args[2] = pid; args[3] = "-display";
270: args[0] = PetscDebugger; args[4] = display; args[5] = 0;
271: (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
272: if (execvp(args[0],(char**)args) < 0) {
273: perror("Unable to start debugger");
274: exit(0);
275: }
276: } else if (iskdbg) {
277: args[1] = "-p"; args[2] = pid; args[3] = program; args[4] = "-display";
278: args[0] = PetscDebugger; args[5] = display; args[6] = 0;
279: (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
280: if (execvp(args[0],(char**)args) < 0) {
281: perror("Unable to start debugger");
282: exit(0);
283: }
284: } else if (isxldb) {
285: args[1] = "-a"; args[2] = pid; args[3] = program; args[4] = "-display";
286: args[0] = PetscDebugger; args[5] = display; args[6] = 0;
287: (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
288: if (execvp(args[0],(char**)args) < 0) {
289: perror("Unable to start debugger");
290: exit(0);
291: }
292: } else if (isworkshop) {
293: args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
294: args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = 0;
295: (*PetscErrorPrintf)("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
296: if (execvp(args[0],(char**)args) < 0) {
297: perror("Unable to start debugger");
298: exit(0);
299: }
300: } else {
301: j = 0;
302: if (Xterm) {
303: PetscBool cmp;
304: char *tmp,*tmp1;
305: PetscStrncmp(DebugTerminal,"screen",6,&cmp);
306: if (cmp) display[0] = 0; /* when using screen, we never pass -display */
307: args[j++] = tmp = DebugTerminal;
308: if (display[0]) {
309: args[j++] = "-display"; args[j++] = display;
310: }
311: while (*tmp) {
312: PetscStrchr(tmp,' ',&tmp1);
313: if (!tmp1) break;
314: *tmp1 = 0;
315: tmp = tmp1+1;
316: args[j++] = tmp;
317: }
318: }
319: args[j++] = PetscDebugger;
320: jj = j;
321: args[j++] = program; args[j++] = pid; args[j++] = 0;
323: if (isidb) {
324: j = jj;
325: args[j++] = "-pid";
326: args[j++] = pid;
327: args[j++] = "-gdb";
328: args[j++] = program;
329: args[j++] = 0;
330: }
331: if (islldb) {
332: j = jj;
333: args[j++] = "-p";
334: args[j++] = pid;
335: args[j++] = 0;
336: }
337: if (isdbx) {
338: j = jj;
339: #if defined(PETSC_USE_P_FOR_DEBUGGER)
340: args[j++] = "-p";
341: args[j++] = pid;
342: args[j++] = program;
343: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
344: args[j++] = "-l";
345: args[j++] = "ALL";
346: args[j++] = "-P";
347: args[j++] = pid;
348: args[j++] = program;
349: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
350: args[j++] = "-a";
351: args[j++] = pid;
352: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
353: args[j++] = "-pid";
354: args[j++] = pid;
355: args[j++] = program;
356: #endif
357: args[j++] = 0;
358: }
359: if (Xterm) {
360: if (display[0]) (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
361: else (*PetscErrorPrintf)("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);
363: if (execvp(args[0],(char**)args) < 0) {
364: perror("Unable to start debugger in xterm");
365: exit(0);
366: }
367: } else {
368: (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
369: if (execvp(args[0],(char**)args) < 0) {
370: perror("Unable to start debugger");
371: exit(0);
372: }
373: }
374: }
375: } else { /* I am the child, continue with user code */
376: sleeptime = 10; /* default to sleep waiting for debugger */
377: PetscOptionsGetReal(NULL,"-debugger_pause",&sleeptime,NULL);
378: if (sleeptime < 0) sleeptime = -sleeptime;
379: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
380: /*
381: HP cannot attach process to sleeping debugger, hence count instead
382: */
383: {
384: PetscReal x = 1.0;
385: int i =10000000;
386: while (i--) x++; /* cannot attach to sleeper */
387: }
388: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
389: /*
390: IBM sleep may return at anytime, hence must see if there is more time to sleep
391: */
392: {
393: int left = sleeptime;
394: while (left > 0) left = PetscSleep(left) - 1;
395: }
396: #else
397: PetscSleep(sleeptime);
398: #endif
399: }
400: #endif
401: return(0);
402: }
406: /*@C
407: PetscAttachDebuggerErrorHandler - Error handler that attaches
408: a debugger to a running process when an error is detected.
409: This routine is useful for examining variables, etc.
411: Not Collective
413: Input Parameters:
414: + comm - communicator over which error occurred
415: . line - the line number of the error (indicated by __LINE__)
416: . fun - function where error occured (indicated by __FUNCT__)
417: . file - the file in which the error was detected (indicated by __FILE__)
418: . message - an error text string, usually just printed to the screen
419: . number - the generic error number
420: . p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
421: - ctx - error handler context
423: Options Database Keys:
424: . -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
425: debugger attachment
427: Level: developer
429: Notes:
430: By default the GNU debugger, gdb, is used. Alternatives are lldb, dbx and
431: xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
433: Most users need not directly employ this routine and the other error
434: handlers, but can instead use the simplified interface SETERR, which has
435: the calling sequence
436: $ SETERRQ(PETSC_COMM_SELF,number,p,message)
438: Notes for experienced users:
439: Use PetscPushErrorHandler() to set the desired error handler. The
440: currently available PETSc error handlers are
441: $ PetscTraceBackErrorHandler()
442: $ PetscAttachDebuggerErrorHandler()
443: $ PetscAbortErrorHandler()
444: or you may write your own.
446: Concepts: debugger^error handler
447: Concepts: error handler^attach debugger
449: .seealso: PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
450: PetscAbortErrorHandler()
451: @*/
452: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
453: {
457: if (!fun) fun = "User provided function";
458: if (!mess) mess = " ";
460: (*PetscErrorPrintf)("%s() line %d in %s %s\n",fun,line,file,mess);
462: PetscAttachDebugger();
463: if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
464: return(0);
465: }
469: /*@C
470: PetscStopForDebugger - Prints a message to the screen indicating how to
471: attach to the process with the debugger and then waits for the
472: debugger to attach.
474: Not Collective
476: Level: developer
478: Notes: This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.
480: Developer Notes: Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()?
482: Concepts: debugger^waiting for attachment
484: .seealso: PetscSetDebugger(), PetscAttachDebugger()
485: @*/
486: PetscErrorCode PetscStopForDebugger(void)
487: {
489: PetscInt sleeptime=0;
490: #if !defined(PETSC_CANNOT_START_DEBUGGER)
491: int ppid;
492: PetscMPIInt rank;
493: char program[PETSC_MAX_PATH_LEN],hostname[256];
494: PetscBool isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
495: #endif
498: #if defined(PETSC_CANNOT_START_DEBUGGER)
499: (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
500: #else
501: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
502: if (ierr) rank = 0; /* ignore error since this may be already in error handler */
503: PetscGetHostName(hostname,256);
504: if (ierr) {
505: (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
506: return(0);
507: }
509: PetscGetProgramName(program,256);
510: if (ierr) {
511: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
512: return(0);
513: }
514: if (!program[0]) {
515: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
516: return(0);
517: }
519: ppid = getpid();
521: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
522: PetscStrcmp(PetscDebugger,"ddd",&isddd);
523: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
524: PetscStrcmp(PetscDebugger,"ups",&isups);
525: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
526: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
527: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
528: PetscStrcmp(PetscDebugger,"lldb",&islldb);
530: if (isxxgdb || isups || isddd || iskdbg) (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
531: else if (isxldb) (*PetscErrorPrintf)("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
532: else if (islldb) (*PetscErrorPrintf)("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
533: else if (isdbx) {
534: #if defined(PETSC_USE_P_FOR_DEBUGGER)
535: (*PetscErrorPrintf)("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
536: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
537: (*PetscErrorPrintf)("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
538: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
539: (*PetscErrorPrintf)("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
540: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
541: (*PetscErrorPrintf)("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
542: #else
543: (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
544: #endif
545: }
546: #endif /* PETSC_CANNOT_START_DEBUGGER */
548: fflush(stdout); /* ignore error because may already be in error handler */
550: sleeptime = 25; /* default to sleep waiting for debugger */
551: PetscOptionsGetInt(NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
552: if (sleeptime < 0) sleeptime = -sleeptime;
553: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
554: /*
555: HP cannot attach process to sleeping debugger, hence count instead
556: */
557: {
558: PetscReal x = 1.0;
559: int i =10000000;
560: while (i--) x++; /* cannot attach to sleeper */
561: }
562: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
563: /*
564: IBM sleep may return at anytime, hence must see if there is more time to sleep
565: */
566: {
567: int left = sleeptime;
568: while (left > 0) left = sleep(left) - 1;
569: }
570: #else
571: PetscSleep(sleeptime);
572: #endif
573: return(0);
574: }