Actual source code: adebug.c
petsc-3.13.6 2020-09-29
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: .seealso: PetscSetDebugger()
43: @*/
44: PetscErrorCode PetscSetDebugTerminal(const char terminal[])
45: {
49: PetscStrcpy(DebugTerminal,terminal);
50: return(0);
51: }
53: /*@C
54: PetscSetDebugger - Sets options associated with the debugger.
56: Not Collective
58: Input Parameters:
59: + debugger - name of debugger, which should be in your path,
60: usually "lldb", "dbx", "gdb", "cuda-gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
61: supports "xdb", and IBM rs6000 supports "xldb".
63: - xterm - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
64: debugger should be started in a new xterm) or PETSC_FALSE (to start debugger
65: in initial window (the option PETSC_FALSE makes no sense when using more
66: than one MPI process.)
68: Level: developer
70: Fortran Note:
71: This routine is not supported in Fortran.
73: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
74: @*/
75: PetscErrorCode PetscSetDebugger(const char debugger[],PetscBool xterm)
76: {
80: if (debugger) {
81: PetscStrcpy(PetscDebugger,debugger);
82: }
83: Xterm = xterm;
84: return(0);
85: }
87: /*@C
88: PetscSetDefaultDebugger - Causes PETSc to use its default debugger.
90: Not collective
92: Level: developer
94: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
95: @*/
96: PetscErrorCode PetscSetDefaultDebugger(void)
97: {
101: #if defined(PETSC_USE_DEBUGGER)
102: PetscSetDebugger(PETSC_USE_DEBUGGER,PETSC_TRUE);
103: #endif
104: PetscSetDebugTerminal("xterm -e");
105: return(0);
106: }
109: {
110: PetscBool exists;
111: char *f;
115: PetscStrstr(string, defaultDbg, &f);
116: if (f) {
117: PetscTestFile(string, 'x', &exists);
118: if (exists) *debugger = string;
119: else *debugger = defaultDbg;
120: }
121: return(0);
122: }
124: /*@C
125: PetscSetDebuggerFromString - Set the complete path for the
126: debugger for PETSc to use.
128: Not collective
130: Level: developer
132: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
133: @*/
134: PetscErrorCode PetscSetDebuggerFromString(const char *string)
135: {
136: const char *debugger = NULL;
137: PetscBool xterm = PETSC_TRUE;
138: char *f;
142: PetscStrstr(string, "noxterm", &f);
143: if (f) xterm = PETSC_FALSE;
144: PetscStrstr(string, "ddd", &f);
145: if (f) xterm = PETSC_FALSE;
161: PetscSetDebugger(debugger, xterm);
162: return(0);
163: }
166: /*@
167: PetscAttachDebugger - Attaches the debugger to the running process.
169: Not Collective
171: Level: advanced
173: Developer Notes:
174: Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?
176: .seealso: PetscSetDebugger()
177: @*/
178: PetscErrorCode PetscAttachDebugger(void)
179: {
180: #if !defined(PETSC_CANNOT_START_DEBUGGER) && defined(PETSC_HAVE_FORK)
181: int child =0;
182: PetscReal sleeptime=0;
184: char program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
185: #endif
188: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
189: (*PetscErrorPrintf)("System cannot start debugger\n");
190: (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
191: (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
192: PETSCABORT(PETSC_COMM_WORLD,PETSC_ERR_SUP_SYS);
193: #else
194: PetscGetDisplay(display,128);
195: PetscGetProgramName(program,PETSC_MAX_PATH_LEN);
196: if (ierr) {
197: (*PetscErrorPrintf)("Cannot determine program name\n");
198: PetscFunctionReturn(1);
199: }
200: if (!program[0]) {
201: (*PetscErrorPrintf)("Cannot determine program name\n");
202: PetscFunctionReturn(1);
203: }
204: child = (int)fork();
205: if (child < 0) {
206: (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
207: PetscFunctionReturn(1);
208: }
210: /*
211: Swap role the parent and child. This is (I think) so that control c typed
212: in the debugger goes to the correct process.
213: */
214: #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
215: if (child) child = 0;
216: else child = (int)getppid();
217: #endif
219: if (child) { /* I am the parent, will run the debugger */
220: const char *args[10];
221: char pid[10];
222: PetscInt j,jj;
223: PetscBool isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;
225: PetscGetHostName(hostname,64);
226: /*
227: We need to send a continue signal to the "child" process on the
228: alpha, otherwise it just stays off forever
229: */
230: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
231: kill(child,SIGCONT);
232: #endif
233: sprintf(pid,"%d",child);
235: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
236: PetscStrcmp(PetscDebugger,"ddd",&isddd);
237: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
238: PetscStrcmp(PetscDebugger,"ups",&isups);
239: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
240: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
241: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
242: PetscStrcmp(PetscDebugger,"idb",&isidb);
243: PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
244: PetscStrcmp(PetscDebugger,"lldb",&islldb);
246: if (isxxgdb || isups || isddd) {
247: args[1] = program; args[2] = pid; args[3] = "-display";
248: args[0] = PetscDebugger; args[4] = display; args[5] = NULL;
249: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
250: if (execvp(args[0],(char**)args) < 0) {
251: perror("Unable to start debugger");
252: exit(0);
253: }
254: } else if (iskdbg) {
255: args[1] = "-p"; args[2] = pid; args[3] = program; args[4] = "-display";
256: args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
257: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
258: if (execvp(args[0],(char**)args) < 0) {
259: perror("Unable to start debugger");
260: exit(0);
261: }
262: } else if (isxldb) {
263: args[1] = "-a"; args[2] = pid; args[3] = program; args[4] = "-display";
264: args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
265: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
266: if (execvp(args[0],(char**)args) < 0) {
267: perror("Unable to start debugger");
268: exit(0);
269: }
270: } else if (isworkshop) {
271: args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
272: args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = NULL;
273: printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
274: if (execvp(args[0],(char**)args) < 0) {
275: perror("Unable to start debugger");
276: exit(0);
277: }
278: } else {
279: j = 0;
280: if (Xterm) {
281: PetscBool cmp;
282: char *tmp,*tmp1;
283: PetscStrncmp(DebugTerminal,"screen",6,&cmp);
284: if (!cmp) {PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);}
285: if (cmp) display[0] = 0; /* when using screen, we never pass -display */
286: args[j++] = tmp = DebugTerminal;
287: if (display[0]) {
288: args[j++] = "-display"; args[j++] = display;
289: }
290: while (*tmp) {
291: PetscStrchr(tmp,' ',&tmp1);
292: if (!tmp1) break;
293: *tmp1 = 0;
294: tmp = tmp1+1;
295: args[j++] = tmp;
296: }
297: }
298: args[j++] = PetscDebugger;
299: jj = j;
300: args[j++] = program; args[j++] = pid; args[j++] = NULL;
302: if (isidb) {
303: j = jj;
304: args[j++] = "-pid";
305: args[j++] = pid;
306: args[j++] = "-gdb";
307: args[j++] = program;
308: args[j++] = NULL;
309: }
310: if (islldb) {
311: j = jj;
312: args[j++] = "-p";
313: args[j++] = pid;
314: args[j++] = NULL;
315: }
316: if (isdbx) {
317: j = jj;
318: #if defined(PETSC_USE_P_FOR_DEBUGGER)
319: args[j++] = "-p";
320: args[j++] = pid;
321: args[j++] = program;
322: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
323: args[j++] = "-l";
324: args[j++] = "ALL";
325: args[j++] = "-P";
326: args[j++] = pid;
327: args[j++] = program;
328: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
329: args[j++] = "-a";
330: args[j++] = pid;
331: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
332: args[j++] = "-pid";
333: args[j++] = pid;
334: args[j++] = program;
335: #else
336: args[j++] = program;
337: args[j++] = pid;
338: #endif
339: args[j++] = NULL;
340: }
341: if (Xterm) {
342: if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
343: else printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);
345: if (execvp(args[0],(char**)args) < 0) {
346: perror("Unable to start debugger in xterm");
347: exit(0);
348: }
349: } else {
350: printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
351: if (execvp(args[0],(char**)args) < 0) {
352: perror("Unable to start debugger");
353: exit(0);
354: }
355: }
356: }
357: } else { /* I am the child, continue with user code */
358: sleeptime = 10; /* default to sleep waiting for debugger */
359: PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);
360: if (sleeptime < 0) sleeptime = -sleeptime;
361: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
362: /*
363: HP cannot attach process to sleeping debugger, hence count instead
364: */
365: {
366: PetscReal x = 1.0;
367: int i =10000000;
368: while (i--) x++; /* cannot attach to sleeper */
369: }
370: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
371: /*
372: IBM sleep may return at anytime, hence must see if there is more time to sleep
373: */
374: {
375: int left = sleeptime;
376: while (left > 0) left = PetscSleep(left) - 1;
377: }
378: #else
379: PetscSleep(sleeptime);
380: #endif
381: }
382: #endif
383: return(0);
384: }
386: /*@C
387: PetscAttachDebuggerErrorHandler - Error handler that attaches
388: a debugger to a running process when an error is detected.
389: This routine is useful for examining variables, etc.
391: Not Collective
393: Input Parameters:
394: + comm - communicator over which error occurred
395: . line - the line number of the error (indicated by __LINE__)
396: . file - the file in which the error was detected (indicated by __FILE__)
397: . message - an error text string, usually just printed to the screen
398: . number - the generic error number
399: . p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
400: - ctx - error handler context
402: Options Database Keys:
403: . -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
404: debugger attachment
406: Level: developer
408: Notes:
409: By default the GNU debugger, gdb, is used. Alternatives are cuda-gdb, lldb, dbx and
410: xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
412: Most users need not directly employ this routine and the other error
413: handlers, but can instead use the simplified interface SETERR, which has
414: the calling sequence
415: $ SETERRQ(PETSC_COMM_SELF,number,p,message)
417: Notes for experienced users:
418: Use PetscPushErrorHandler() to set the desired error handler. The
419: currently available PETSc error handlers are
420: $ PetscTraceBackErrorHandler()
421: $ PetscAttachDebuggerErrorHandler()
422: $ PetscAbortErrorHandler()
423: or you may write your own.
426: .seealso: PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
427: PetscAbortErrorHandler()
428: @*/
429: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
430: {
434: if (!fun) fun = "User provided function";
435: if (!mess) mess = " ";
437: (*PetscErrorPrintf)("%s() line %d in %s %s\n",fun,line,file,mess);
439: PetscAttachDebugger();
440: if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
441: return(0);
442: }
444: /*@C
445: PetscStopForDebugger - Prints a message to the screen indicating how to
446: attach to the process with the debugger and then waits for the
447: debugger to attach.
449: Not Collective
451: Level: developer
453: Notes:
454: This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.
456: Developer Notes:
457: Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()?
459: .seealso: PetscSetDebugger(), PetscAttachDebugger()
460: @*/
461: PetscErrorCode PetscStopForDebugger(void)
462: {
464: PetscInt sleeptime=0;
465: #if !defined(PETSC_CANNOT_START_DEBUGGER)
466: int ppid;
467: PetscMPIInt rank;
468: char program[PETSC_MAX_PATH_LEN],hostname[256];
469: PetscBool isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
470: #endif
473: #if defined(PETSC_CANNOT_START_DEBUGGER)
474: (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
475: #else
476: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
477: if (ierr) rank = 0; /* ignore error since this may be already in error handler */
478: PetscGetHostName(hostname,256);
479: if (ierr) {
480: (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
481: return(0);
482: }
484: PetscGetProgramName(program,256);
485: if (ierr) {
486: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
487: return(0);
488: }
489: if (!program[0]) {
490: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
491: return(0);
492: }
494: ppid = getpid();
496: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
497: PetscStrcmp(PetscDebugger,"ddd",&isddd);
498: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
499: PetscStrcmp(PetscDebugger,"ups",&isups);
500: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
501: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
502: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
503: PetscStrcmp(PetscDebugger,"lldb",&islldb);
505: if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
506: else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
507: else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
508: else if (isdbx) {
509: #if defined(PETSC_USE_P_FOR_DEBUGGER)
510: printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
511: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
512: printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
513: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
514: printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
515: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
516: printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
517: #else
518: printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
519: #endif
520: }
521: #endif /* PETSC_CANNOT_START_DEBUGGER */
523: fflush(stdout); /* ignore error because may already be in error handler */
525: sleeptime = 25; /* default to sleep waiting for debugger */
526: PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
527: if (sleeptime < 0) sleeptime = -sleeptime;
528: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
529: /*
530: HP cannot attach process to sleeping debugger, hence count instead
531: */
532: {
533: PetscReal x = 1.0;
534: int i =10000000;
535: while (i--) x++; /* cannot attach to sleeper */
536: }
537: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
538: /*
539: IBM sleep may return at anytime, hence must see if there is more time to sleep
540: */
541: {
542: int left = sleeptime;
543: while (left > 0) left = sleep(left) - 1;
544: }
545: #else
546: PetscSleep(sleeptime);
547: #endif
548: return(0);
549: }