Actual source code: adebug.c
petsc-3.9.4 2018-09-11
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".
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: Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?
188: .seealso: PetscSetDebugger()
189: @*/
190: PetscErrorCode PetscAttachDebugger(void)
191: {
192: #if !defined(PETSC_CANNOT_START_DEBUGGER)
193: int child =0;
194: PetscReal sleeptime=0;
196: char program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
197: #endif
200: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
201: (*PetscErrorPrintf)("System cannot start debugger\n");
202: (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
203: (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
204: MPI_Abort(PETSC_COMM_WORLD,1);
205: #else
206: PetscGetDisplay(display,128);
207: PetscGetProgramName(program,PETSC_MAX_PATH_LEN);
208: if (ierr) {
209: (*PetscErrorPrintf)("Cannot determine program name\n");
210: PetscFunctionReturn(1);
211: }
212: if (!program[0]) {
213: (*PetscErrorPrintf)("Cannot determine program name\n");
214: PetscFunctionReturn(1);
215: }
216: child = (int)fork();
217: if (child < 0) {
218: (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
219: PetscFunctionReturn(1);
220: }
222: /*
223: Swap role the parent and child. This is (I think) so that control c typed
224: in the debugger goes to the correct process.
225: */
226: if (child) child = 0;
227: else child = (int)getppid();
229: if (child) { /* I am the parent, will run the debugger */
230: const char *args[10];
231: char pid[10];
232: PetscInt j,jj;
233: PetscBool isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;
235: PetscGetHostName(hostname,64);
236: /*
237: We need to send a continue signal to the "child" process on the
238: alpha, otherwise it just stays off forever
239: */
240: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
241: kill(child,SIGCONT);
242: #endif
243: sprintf(pid,"%d",child);
245: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
246: PetscStrcmp(PetscDebugger,"ddd",&isddd);
247: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
248: PetscStrcmp(PetscDebugger,"ups",&isups);
249: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
250: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
251: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
252: PetscStrcmp(PetscDebugger,"idb",&isidb);
253: PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
254: PetscStrcmp(PetscDebugger,"lldb",&islldb);
256: if (isxxgdb || isups || isddd) {
257: args[1] = program; args[2] = pid; args[3] = "-display";
258: args[0] = PetscDebugger; args[4] = display; args[5] = 0;
259: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
260: if (execvp(args[0],(char**)args) < 0) {
261: perror("Unable to start debugger");
262: exit(0);
263: }
264: } else if (iskdbg) {
265: args[1] = "-p"; args[2] = pid; args[3] = program; args[4] = "-display";
266: args[0] = PetscDebugger; args[5] = display; args[6] = 0;
267: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
268: if (execvp(args[0],(char**)args) < 0) {
269: perror("Unable to start debugger");
270: exit(0);
271: }
272: } else if (isxldb) {
273: args[1] = "-a"; args[2] = pid; args[3] = program; args[4] = "-display";
274: args[0] = PetscDebugger; args[5] = display; args[6] = 0;
275: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
276: if (execvp(args[0],(char**)args) < 0) {
277: perror("Unable to start debugger");
278: exit(0);
279: }
280: } else if (isworkshop) {
281: args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
282: args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = 0;
283: printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
284: if (execvp(args[0],(char**)args) < 0) {
285: perror("Unable to start debugger");
286: exit(0);
287: }
288: } else {
289: j = 0;
290: if (Xterm) {
291: PetscBool cmp;
292: char *tmp,*tmp1;
293: PetscStrncmp(DebugTerminal,"screen",6,&cmp);
294: if (cmp) display[0] = 0; /* when using screen, we never pass -display */
295: args[j++] = tmp = DebugTerminal;
296: if (display[0]) {
297: args[j++] = "-display"; args[j++] = display;
298: }
299: while (*tmp) {
300: PetscStrchr(tmp,' ',&tmp1);
301: if (!tmp1) break;
302: *tmp1 = 0;
303: tmp = tmp1+1;
304: args[j++] = tmp;
305: }
306: }
307: args[j++] = PetscDebugger;
308: jj = j;
309: args[j++] = program; args[j++] = pid; args[j++] = 0;
311: if (isidb) {
312: j = jj;
313: args[j++] = "-pid";
314: args[j++] = pid;
315: args[j++] = "-gdb";
316: args[j++] = program;
317: args[j++] = 0;
318: }
319: if (islldb) {
320: j = jj;
321: args[j++] = "-p";
322: args[j++] = pid;
323: args[j++] = 0;
324: }
325: if (isdbx) {
326: j = jj;
327: #if defined(PETSC_USE_P_FOR_DEBUGGER)
328: args[j++] = "-p";
329: args[j++] = pid;
330: args[j++] = program;
331: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
332: args[j++] = "-l";
333: args[j++] = "ALL";
334: args[j++] = "-P";
335: args[j++] = pid;
336: args[j++] = program;
337: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
338: args[j++] = "-a";
339: args[j++] = pid;
340: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
341: args[j++] = "-pid";
342: args[j++] = pid;
343: args[j++] = program;
344: #else
345: args[j++] = program;
346: args[j++] = pid;
347: #endif
348: args[j++] = 0;
349: }
350: if (Xterm) {
351: if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
352: else printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);
354: if (execvp(args[0],(char**)args) < 0) {
355: perror("Unable to start debugger in xterm");
356: exit(0);
357: }
358: } else {
359: printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
360: if (execvp(args[0],(char**)args) < 0) {
361: perror("Unable to start debugger");
362: exit(0);
363: }
364: }
365: }
366: } else { /* I am the child, continue with user code */
367: sleeptime = 10; /* default to sleep waiting for debugger */
368: PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);
369: if (sleeptime < 0) sleeptime = -sleeptime;
370: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
371: /*
372: HP cannot attach process to sleeping debugger, hence count instead
373: */
374: {
375: PetscReal x = 1.0;
376: int i =10000000;
377: while (i--) x++; /* cannot attach to sleeper */
378: }
379: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
380: /*
381: IBM sleep may return at anytime, hence must see if there is more time to sleep
382: */
383: {
384: int left = sleeptime;
385: while (left > 0) left = PetscSleep(left) - 1;
386: }
387: #else
388: PetscSleep(sleeptime);
389: #endif
390: }
391: #endif
392: return(0);
393: }
395: /*@C
396: PetscAttachDebuggerErrorHandler - Error handler that attaches
397: a debugger to a running process when an error is detected.
398: This routine is useful for examining variables, etc.
400: Not Collective
402: Input Parameters:
403: + comm - communicator over which error occurred
404: . line - the line number of the error (indicated by __LINE__)
405: . file - the file in which the error was detected (indicated by __FILE__)
406: . message - an error text string, usually just printed to the screen
407: . number - the generic error number
408: . p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
409: - ctx - error handler context
411: Options Database Keys:
412: . -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
413: debugger attachment
415: Level: developer
417: Notes:
418: By default the GNU debugger, gdb, is used. Alternatives are lldb, dbx and
419: xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
421: Most users need not directly employ this routine and the other error
422: handlers, but can instead use the simplified interface SETERR, which has
423: the calling sequence
424: $ SETERRQ(PETSC_COMM_SELF,number,p,message)
426: Notes for experienced users:
427: Use PetscPushErrorHandler() to set the desired error handler. The
428: currently available PETSc error handlers are
429: $ PetscTraceBackErrorHandler()
430: $ PetscAttachDebuggerErrorHandler()
431: $ PetscAbortErrorHandler()
432: or you may write your own.
434: Concepts: debugger^error handler
435: Concepts: error handler^attach debugger
437: .seealso: PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
438: PetscAbortErrorHandler()
439: @*/
440: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
441: {
445: if (!fun) fun = "User provided function";
446: if (!mess) mess = " ";
448: (*PetscErrorPrintf)("%s() line %d in %s %s\n",fun,line,file,mess);
450: PetscAttachDebugger();
451: if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
452: return(0);
453: }
455: /*@C
456: PetscStopForDebugger - Prints a message to the screen indicating how to
457: attach to the process with the debugger and then waits for the
458: debugger to attach.
460: Not Collective
462: Level: developer
464: Notes: This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.
466: Developer Notes: Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()?
468: Concepts: debugger^waiting for attachment
470: .seealso: PetscSetDebugger(), PetscAttachDebugger()
471: @*/
472: PetscErrorCode PetscStopForDebugger(void)
473: {
475: PetscInt sleeptime=0;
476: #if !defined(PETSC_CANNOT_START_DEBUGGER)
477: int ppid;
478: PetscMPIInt rank;
479: char program[PETSC_MAX_PATH_LEN],hostname[256];
480: PetscBool isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
481: #endif
484: #if defined(PETSC_CANNOT_START_DEBUGGER)
485: (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
486: #else
487: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
488: if (ierr) rank = 0; /* ignore error since this may be already in error handler */
489: PetscGetHostName(hostname,256);
490: if (ierr) {
491: (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
492: return(0);
493: }
495: PetscGetProgramName(program,256);
496: if (ierr) {
497: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
498: return(0);
499: }
500: if (!program[0]) {
501: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
502: return(0);
503: }
505: ppid = getpid();
507: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
508: PetscStrcmp(PetscDebugger,"ddd",&isddd);
509: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
510: PetscStrcmp(PetscDebugger,"ups",&isups);
511: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
512: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
513: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
514: PetscStrcmp(PetscDebugger,"lldb",&islldb);
516: if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
517: else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
518: else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
519: else if (isdbx) {
520: #if defined(PETSC_USE_P_FOR_DEBUGGER)
521: printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
522: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
523: printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
524: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
525: printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
526: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
527: printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
528: #else
529: printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
530: #endif
531: }
532: #endif /* PETSC_CANNOT_START_DEBUGGER */
534: fflush(stdout); /* ignore error because may already be in error handler */
536: sleeptime = 25; /* default to sleep waiting for debugger */
537: PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
538: if (sleeptime < 0) sleeptime = -sleeptime;
539: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
540: /*
541: HP cannot attach process to sleeping debugger, hence count instead
542: */
543: {
544: PetscReal x = 1.0;
545: int i =10000000;
546: while (i--) x++; /* cannot attach to sleeper */
547: }
548: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
549: /*
550: IBM sleep may return at anytime, hence must see if there is more time to sleep
551: */
552: {
553: int left = sleeptime;
554: while (left > 0) left = sleep(left) - 1;
555: }
556: #else
557: PetscSleep(sleeptime);
558: #endif
559: return(0);
560: }