Actual source code: adebug.c
petsc-3.11.4 2019-09-28
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 Xterm = PETSC_TRUE;
18: /*@C
19: PetscSetDebugTerminal - Sets the terminal to use (instead of xterm) for debugging.
21: Not Collective
23: Input Parameters:
24: + terminal - name of terminal and any flags required to execute a program.
25: For example "xterm -e", "urxvt -e", "gnome-terminal -x".
27: Options Database Keys:
28: -debug_terminal terminal - use this terminal instead of xterm
30: Level: developer
32: Notes:
33: You can start the debugger for all processes in the same GNU screen session.
35: mpiexec -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"
37: will open 4 windows in the session named "debug".
39: Fortran Note:
40: This routine is not supported in Fortran.
42: Concepts: debugger^setting
44: .seealso: PetscSetDebugger()
45: @*/
46: PetscErrorCode PetscSetDebugTerminal(const char terminal[])
47: {
51: PetscStrcpy(DebugTerminal,terminal);
52: return(0);
53: }
55: /*@C
56: PetscSetDebugger - Sets options associated with the debugger.
58: Not Collective
60: Input Parameters:
61: + debugger - name of debugger, which should be in your path,
62: usually "lldb", "dbx", "gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
63: supports "xdb", and IBM rs6000 supports "xldb".
65: - xterm - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
66: debugger should be started in a new xterm) or PETSC_FALSE (to start debugger
67: in initial window (the option PETSC_FALSE makes no sense when using more
68: than one MPI process.)
70: Level: developer
72: Fortran Note:
73: This routine is not supported in Fortran.
75: Concepts: debugger^setting
77: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
78: @*/
79: PetscErrorCode PetscSetDebugger(const char debugger[],PetscBool xterm)
80: {
84: if (debugger) {
85: PetscStrcpy(PetscDebugger,debugger);
86: }
87: Xterm = xterm;
88: return(0);
89: }
91: /*@C
92: PetscSetDefaultDebugger - Causes PETSc to use its default debugger.
94: Not collective
96: Level: developer
98: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
99: @*/
100: PetscErrorCode PetscSetDefaultDebugger(void)
101: {
105: #if defined(PETSC_USE_LLDB_DEBUGGER)
106: PetscSetDebugger("lldb",PETSC_TRUE);
107: #elif defined(PETSC_USE_DBX_DEBUGGER)
108: PetscSetDebugger("dbx",PETSC_TRUE);
109: #elif defined(PETSC_USE_XDB_DEBUGGER)
110: PetscSetDebugger("xdb",PETSC_TRUE);
111: #elif defined(PETSC_USE_IDB_DEBUGGER)
112: PetscSetDebugger("idb",PETSC_TRUE);
113: #else /* Default is gdb */
114: PetscSetDebugger("gdb",PETSC_TRUE);
115: #endif
116: PetscSetDebugTerminal("xterm -e");
117: return(0);
118: }
121: {
122: PetscBool exists;
123: char *f;
127: PetscStrstr(string, defaultDbg, &f);
128: if (f) {
129: PetscTestFile(string, 'x', &exists);
130: if (exists) *debugger = string;
131: else *debugger = defaultDbg;
132: }
133: return(0);
134: }
136: /*@C
137: PetscSetDebuggerFromString - Set the complete path for the
138: debugger for PETSc to use.
140: Not collective
142: Level: developer
144: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
145: @*/
146: PetscErrorCode PetscSetDebuggerFromString(const char *string)
147: {
148: const char *debugger = NULL;
149: PetscBool xterm = PETSC_TRUE;
150: char *f;
154: PetscStrstr(string, "noxterm", &f);
155: if (f) xterm = PETSC_FALSE;
156: PetscStrstr(string, "ddd", &f);
157: if (f) xterm = PETSC_FALSE;
172: PetscSetDebugger(debugger, xterm);
173: return(0);
174: }
177: /*@
178: PetscAttachDebugger - Attaches the debugger to the running process.
180: Not Collective
182: Level: advanced
184: Concepts: debugger^starting from program
186: Developer Notes:
187: Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?
189: .seealso: PetscSetDebugger()
190: @*/
191: PetscErrorCode PetscAttachDebugger(void)
192: {
193: #if !defined(PETSC_CANNOT_START_DEBUGGER)
194: int child =0;
195: PetscReal sleeptime=0;
197: char program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
198: #endif
201: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
202: (*PetscErrorPrintf)("System cannot start debugger\n");
203: (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
204: (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
205: MPI_Abort(PETSC_COMM_WORLD,1);
206: #else
207: PetscGetDisplay(display,128);
208: PetscGetProgramName(program,PETSC_MAX_PATH_LEN);
209: if (ierr) {
210: (*PetscErrorPrintf)("Cannot determine program name\n");
211: PetscFunctionReturn(1);
212: }
213: if (!program[0]) {
214: (*PetscErrorPrintf)("Cannot determine program name\n");
215: PetscFunctionReturn(1);
216: }
217: child = (int)fork();
218: if (child < 0) {
219: (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
220: PetscFunctionReturn(1);
221: }
223: /*
224: Swap role the parent and child. This is (I think) so that control c typed
225: in the debugger goes to the correct process.
226: */
227: if (child) child = 0;
228: else child = (int)getppid();
230: if (child) { /* I am the parent, will run the debugger */
231: const char *args[10];
232: char pid[10];
233: PetscInt j,jj;
234: PetscBool isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;
236: PetscGetHostName(hostname,64);
237: /*
238: We need to send a continue signal to the "child" process on the
239: alpha, otherwise it just stays off forever
240: */
241: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
242: kill(child,SIGCONT);
243: #endif
244: sprintf(pid,"%d",child);
246: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
247: PetscStrcmp(PetscDebugger,"ddd",&isddd);
248: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
249: PetscStrcmp(PetscDebugger,"ups",&isups);
250: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
251: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
252: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
253: PetscStrcmp(PetscDebugger,"idb",&isidb);
254: PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
255: PetscStrcmp(PetscDebugger,"lldb",&islldb);
257: if (isxxgdb || isups || isddd) {
258: args[1] = program; args[2] = pid; args[3] = "-display";
259: args[0] = PetscDebugger; args[4] = display; args[5] = 0;
260: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
261: if (execvp(args[0],(char**)args) < 0) {
262: perror("Unable to start debugger");
263: exit(0);
264: }
265: } else if (iskdbg) {
266: args[1] = "-p"; args[2] = pid; args[3] = program; args[4] = "-display";
267: args[0] = PetscDebugger; args[5] = display; args[6] = 0;
268: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
269: if (execvp(args[0],(char**)args) < 0) {
270: perror("Unable to start debugger");
271: exit(0);
272: }
273: } else if (isxldb) {
274: args[1] = "-a"; args[2] = pid; args[3] = program; args[4] = "-display";
275: args[0] = PetscDebugger; args[5] = display; args[6] = 0;
276: printf("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 (isworkshop) {
282: args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
283: args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = 0;
284: printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
285: if (execvp(args[0],(char**)args) < 0) {
286: perror("Unable to start debugger");
287: exit(0);
288: }
289: } else {
290: j = 0;
291: if (Xterm) {
292: PetscBool cmp;
293: char *tmp,*tmp1;
294: PetscStrncmp(DebugTerminal,"screen",6,&cmp);
295: if (!cmp) {PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);}
296: if (cmp) display[0] = 0; /* when using screen, we never pass -display */
297: args[j++] = tmp = DebugTerminal;
298: if (display[0]) {
299: args[j++] = "-display"; args[j++] = display;
300: }
301: while (*tmp) {
302: PetscStrchr(tmp,' ',&tmp1);
303: if (!tmp1) break;
304: *tmp1 = 0;
305: tmp = tmp1+1;
306: args[j++] = tmp;
307: }
308: }
309: args[j++] = PetscDebugger;
310: jj = j;
311: args[j++] = program; args[j++] = pid; args[j++] = 0;
313: if (isidb) {
314: j = jj;
315: args[j++] = "-pid";
316: args[j++] = pid;
317: args[j++] = "-gdb";
318: args[j++] = program;
319: args[j++] = 0;
320: }
321: if (islldb) {
322: j = jj;
323: args[j++] = "-p";
324: args[j++] = pid;
325: args[j++] = 0;
326: }
327: if (isdbx) {
328: j = jj;
329: #if defined(PETSC_USE_P_FOR_DEBUGGER)
330: args[j++] = "-p";
331: args[j++] = pid;
332: args[j++] = program;
333: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
334: args[j++] = "-l";
335: args[j++] = "ALL";
336: args[j++] = "-P";
337: args[j++] = pid;
338: args[j++] = program;
339: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
340: args[j++] = "-a";
341: args[j++] = pid;
342: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
343: args[j++] = "-pid";
344: args[j++] = pid;
345: args[j++] = program;
346: #else
347: args[j++] = program;
348: args[j++] = pid;
349: #endif
350: args[j++] = 0;
351: }
352: if (Xterm) {
353: if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
354: else printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);
356: if (execvp(args[0],(char**)args) < 0) {
357: perror("Unable to start debugger in xterm");
358: exit(0);
359: }
360: } else {
361: printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
362: if (execvp(args[0],(char**)args) < 0) {
363: perror("Unable to start debugger");
364: exit(0);
365: }
366: }
367: }
368: } else { /* I am the child, continue with user code */
369: sleeptime = 10; /* default to sleep waiting for debugger */
370: PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);
371: if (sleeptime < 0) sleeptime = -sleeptime;
372: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
373: /*
374: HP cannot attach process to sleeping debugger, hence count instead
375: */
376: {
377: PetscReal x = 1.0;
378: int i =10000000;
379: while (i--) x++; /* cannot attach to sleeper */
380: }
381: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
382: /*
383: IBM sleep may return at anytime, hence must see if there is more time to sleep
384: */
385: {
386: int left = sleeptime;
387: while (left > 0) left = PetscSleep(left) - 1;
388: }
389: #else
390: PetscSleep(sleeptime);
391: #endif
392: }
393: #endif
394: return(0);
395: }
397: /*@C
398: PetscAttachDebuggerErrorHandler - Error handler that attaches
399: a debugger to a running process when an error is detected.
400: This routine is useful for examining variables, etc.
402: Not Collective
404: Input Parameters:
405: + comm - communicator over which error occurred
406: . line - the line number of the error (indicated by __LINE__)
407: . file - the file in which the error was detected (indicated by __FILE__)
408: . message - an error text string, usually just printed to the screen
409: . number - the generic error number
410: . p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
411: - ctx - error handler context
413: Options Database Keys:
414: . -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
415: debugger attachment
417: Level: developer
419: Notes:
420: By default the GNU debugger, gdb, is used. Alternatives are lldb, dbx and
421: xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
423: Most users need not directly employ this routine and the other error
424: handlers, but can instead use the simplified interface SETERR, which has
425: the calling sequence
426: $ SETERRQ(PETSC_COMM_SELF,number,p,message)
428: Notes for experienced users:
429: Use PetscPushErrorHandler() to set the desired error handler. The
430: currently available PETSc error handlers are
431: $ PetscTraceBackErrorHandler()
432: $ PetscAttachDebuggerErrorHandler()
433: $ PetscAbortErrorHandler()
434: or you may write your own.
436: Concepts: debugger^error handler
437: Concepts: error handler^attach debugger
439: .seealso: PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
440: PetscAbortErrorHandler()
441: @*/
442: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
443: {
447: if (!fun) fun = "User provided function";
448: if (!mess) mess = " ";
450: (*PetscErrorPrintf)("%s() line %d in %s %s\n",fun,line,file,mess);
452: PetscAttachDebugger();
453: if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
454: return(0);
455: }
457: /*@C
458: PetscStopForDebugger - Prints a message to the screen indicating how to
459: attach to the process with the debugger and then waits for the
460: debugger to attach.
462: Not Collective
464: Level: developer
466: Notes:
467: This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.
469: Developer Notes:
470: Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()?
472: Concepts: debugger^waiting for attachment
474: .seealso: PetscSetDebugger(), PetscAttachDebugger()
475: @*/
476: PetscErrorCode PetscStopForDebugger(void)
477: {
479: PetscInt sleeptime=0;
480: #if !defined(PETSC_CANNOT_START_DEBUGGER)
481: int ppid;
482: PetscMPIInt rank;
483: char program[PETSC_MAX_PATH_LEN],hostname[256];
484: PetscBool isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
485: #endif
488: #if defined(PETSC_CANNOT_START_DEBUGGER)
489: (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
490: #else
491: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
492: if (ierr) rank = 0; /* ignore error since this may be already in error handler */
493: PetscGetHostName(hostname,256);
494: if (ierr) {
495: (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
496: return(0);
497: }
499: PetscGetProgramName(program,256);
500: if (ierr) {
501: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
502: return(0);
503: }
504: if (!program[0]) {
505: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
506: return(0);
507: }
509: ppid = getpid();
511: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
512: PetscStrcmp(PetscDebugger,"ddd",&isddd);
513: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
514: PetscStrcmp(PetscDebugger,"ups",&isups);
515: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
516: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
517: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
518: PetscStrcmp(PetscDebugger,"lldb",&islldb);
520: if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
521: else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
522: else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
523: else if (isdbx) {
524: #if defined(PETSC_USE_P_FOR_DEBUGGER)
525: printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
526: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
527: printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
528: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
529: printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
530: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
531: printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
532: #else
533: printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
534: #endif
535: }
536: #endif /* PETSC_CANNOT_START_DEBUGGER */
538: fflush(stdout); /* ignore error because may already be in error handler */
540: sleeptime = 25; /* default to sleep waiting for debugger */
541: PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
542: if (sleeptime < 0) sleeptime = -sleeptime;
543: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
544: /*
545: HP cannot attach process to sleeping debugger, hence count instead
546: */
547: {
548: PetscReal x = 1.0;
549: int i =10000000;
550: while (i--) x++; /* cannot attach to sleeper */
551: }
552: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
553: /*
554: IBM sleep may return at anytime, hence must see if there is more time to sleep
555: */
556: {
557: int left = sleeptime;
558: while (left > 0) left = sleep(left) - 1;
559: }
560: #else
561: PetscSleep(sleeptime);
562: #endif
563: return(0);
564: }