Actual source code: adebug.c
petsc-3.14.6 2021-03-30
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;
17: PetscBool petscwaitonerrorflg = PETSC_FALSE;
18: PetscBool petscindebugger = PETSC_FALSE;
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", "gnome-terminal -x".
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: mpiexec -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: .seealso: PetscSetDebugger()
45: @*/
46: PetscErrorCode PetscSetDebugTerminal(const char terminal[])
47: {
51: PetscStrncpy(DebugTerminal,terminal,sizeof(DebugTerminal));
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", "cuda-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: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
76: @*/
77: PetscErrorCode PetscSetDebugger(const char debugger[],PetscBool xterm)
78: {
82: if (debugger) {
83: PetscStrncpy(PetscDebugger,debugger,sizeof(PetscDebugger));
84: }
85: if (Xterm) Xterm = xterm;
86: return(0);
87: }
89: /*@C
90: PetscSetDefaultDebugger - Causes PETSc to use its default debugger.
92: Not collective
94: Level: developer
96: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
97: @*/
98: PetscErrorCode PetscSetDefaultDebugger(void)
99: {
103: #if defined(PETSC_USE_DEBUGGER)
104: PetscSetDebugger(PETSC_USE_DEBUGGER,PETSC_TRUE);
105: #endif
106: PetscSetDebugTerminal("xterm -e");
107: return(0);
108: }
111: {
112: PetscBool exists;
113: char *f;
117: PetscStrstr(string, defaultDbg, &f);
118: if (f) {
119: PetscTestFile(string, 'x', &exists);
120: if (exists) *debugger = string;
121: else *debugger = defaultDbg;
122: }
123: return(0);
124: }
126: /*@C
127: PetscSetDebuggerFromString - Set the complete path for the
128: debugger for PETSc to use.
130: Not collective
132: Level: developer
134: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
135: @*/
136: PetscErrorCode PetscSetDebuggerFromString(const char *string)
137: {
138: const char *debugger = NULL;
139: PetscBool xterm = PETSC_TRUE;
140: char *f;
144: PetscStrstr(string, "noxterm", &f);
145: if (f) xterm = PETSC_FALSE;
146: PetscStrstr(string, "ddd", &f);
147: if (f) xterm = PETSC_FALSE;
163: PetscSetDebugger(debugger, xterm);
164: return(0);
165: }
167: /*@
168: PetscWaitOnError - If an error is detected and the process would normally exit the main program with MPI_Abort() sleep instead
169: of exiting.
171: Not Collective
173: Level: advanced
175: Notes:
176: When -start_in_debugger -debugger_ranks x,y,z is used this prevents the processes NOT listed in x,y,z from calling MPI_Abort and
177: killing the user's debugging sessions.
180: .seealso: PetscSetDebugger(), PetscAttachDebugger()
181: @*/
182: PetscErrorCode PetscWaitOnError()
183: {
184: petscwaitonerrorflg = PETSC_TRUE;
185: return 0;
186: }
188: /*@
189: PetscAttachDebugger - Attaches the debugger to the running process.
191: Not Collective
193: Level: advanced
195: Developer Notes:
196: Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?
198: .seealso: PetscSetDebugger()
199: @*/
200: PetscErrorCode PetscAttachDebugger(void)
201: {
202: #if !defined(PETSC_CANNOT_START_DEBUGGER) && defined(PETSC_HAVE_FORK)
203: int child =0;
204: PetscReal sleeptime=0;
206: char program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
207: #endif
210: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
211: (*PetscErrorPrintf)("System cannot start debugger\n");
212: (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
213: (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
214: PETSCABORT(PETSC_COMM_WORLD,PETSC_ERR_SUP_SYS);
215: #else
216: PetscGetDisplay(display,sizeof(display));
217: PetscGetProgramName(program,sizeof(program));
218: if (ierr) {
219: (*PetscErrorPrintf)("Cannot determine program name\n");
220: PetscFunctionReturn(1);
221: }
222: if (!program[0]) {
223: (*PetscErrorPrintf)("Cannot determine program name\n");
224: PetscFunctionReturn(1);
225: }
226: child = (int)fork();
227: if (child < 0) {
228: (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
229: PetscFunctionReturn(1);
230: }
231: petscindebugger = PETSC_TRUE;
233: /*
234: Swap role the parent and child. This is (I think) so that control c typed
235: in the debugger goes to the correct process.
236: */
237: #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
238: if (child) child = 0;
239: else child = (int)getppid();
240: #endif
242: if (child) { /* I am the parent, will run the debugger */
243: const char *args[10];
244: char pid[10];
245: PetscInt j,jj;
246: PetscBool isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;
248: PetscGetHostName(hostname,sizeof(hostname));
249: /*
250: We need to send a continue signal to the "child" process on the
251: alpha, otherwise it just stays off forever
252: */
253: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
254: kill(child,SIGCONT);
255: #endif
256: sprintf(pid,"%d",child);
258: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
259: PetscStrcmp(PetscDebugger,"ddd",&isddd);
260: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
261: PetscStrcmp(PetscDebugger,"ups",&isups);
262: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
263: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
264: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
265: PetscStrcmp(PetscDebugger,"idb",&isidb);
266: PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
267: PetscStrcmp(PetscDebugger,"lldb",&islldb);
269: if (isxxgdb || isups || isddd) {
270: args[1] = program; args[2] = pid; args[3] = "-display";
271: args[0] = PetscDebugger; args[4] = display; args[5] = NULL;
272: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
273: if (execvp(args[0],(char**)args) < 0) {
274: perror("Unable to start debugger");
275: exit(0);
276: }
277: } else if (iskdbg) {
278: args[1] = "-p"; args[2] = pid; args[3] = program; args[4] = "-display";
279: args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
280: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
281: if (execvp(args[0],(char**)args) < 0) {
282: perror("Unable to start debugger");
283: exit(0);
284: }
285: } else if (isxldb) {
286: args[1] = "-a"; args[2] = pid; args[3] = program; args[4] = "-display";
287: args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
288: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
289: if (execvp(args[0],(char**)args) < 0) {
290: perror("Unable to start debugger");
291: exit(0);
292: }
293: } else if (isworkshop) {
294: args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
295: args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = NULL;
296: printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
297: if (execvp(args[0],(char**)args) < 0) {
298: perror("Unable to start debugger");
299: exit(0);
300: }
301: } else {
302: j = 0;
303: if (Xterm) {
304: PetscBool cmp;
305: char *tmp,*tmp1;
306: PetscStrncmp(DebugTerminal,"screen",6,&cmp);
307: if (!cmp) {PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);}
308: if (cmp) display[0] = 0; /* when using screen, we never pass -display */
309: args[j++] = tmp = DebugTerminal;
310: if (display[0]) {
311: args[j++] = "-display"; args[j++] = display;
312: }
313: while (*tmp) {
314: PetscStrchr(tmp,' ',&tmp1);
315: if (!tmp1) break;
316: *tmp1 = 0;
317: tmp = tmp1+1;
318: args[j++] = tmp;
319: }
320: }
321: args[j++] = PetscDebugger;
322: jj = j;
323: /* this is for default gdb */
324: args[j++] = program;
325: args[j++] = pid;
326: args[j++] = NULL;
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++] = NULL;
335: }
336: if (islldb) {
337: j = jj;
338: args[j++] = "-p";
339: args[j++] = pid;
340: args[j++] = NULL;
341: }
342: if (isdbx) {
343: j = jj;
344: #if defined(PETSC_USE_P_FOR_DEBUGGER)
345: args[j++] = "-p";
346: args[j++] = pid;
347: args[j++] = program;
348: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
349: args[j++] = "-l";
350: args[j++] = "ALL";
351: args[j++] = "-P";
352: args[j++] = pid;
353: args[j++] = program;
354: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
355: args[j++] = "-a";
356: args[j++] = pid;
357: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
358: args[j++] = "-pid";
359: args[j++] = pid;
360: args[j++] = program;
361: #else
362: args[j++] = program;
363: args[j++] = pid;
364: #endif
365: args[j++] = NULL;
366: }
367: if (Xterm) {
368: if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
369: else printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);
371: if (execvp(args[0],(char**)args) < 0) {
372: perror("Unable to start debugger in xterm");
373: exit(0);
374: }
375: } else {
376: printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
377: if (execvp(args[0],(char**)args) < 0) {
378: perror("Unable to start debugger");
379: exit(0);
380: }
381: }
382: }
383: } else { /* I am the child, continue with user code */
384: sleeptime = 10; /* default to sleep waiting for debugger */
385: PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);
386: if (sleeptime < 0) sleeptime = -sleeptime;
387: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
388: /*
389: HP cannot attach process to sleeping debugger, hence count instead
390: */
391: {
392: PetscReal x = 1.0;
393: int i =10000000;
394: while (i--) x++; /* cannot attach to sleeper */
395: }
396: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
397: /*
398: IBM sleep may return at anytime, hence must see if there is more time to sleep
399: */
400: {
401: int left = sleeptime;
402: while (left > 0) left = PetscSleep(left) - 1;
403: }
404: #else
405: PetscSleep(sleeptime);
406: #endif
407: }
408: #endif
409: return(0);
410: }
412: /*@C
413: PetscAttachDebuggerErrorHandler - Error handler that attaches
414: a debugger to a running process when an error is detected.
415: This routine is useful for examining variables, etc.
417: Not Collective
419: Input Parameters:
420: + comm - communicator over which error occurred
421: . line - the line number of the error (indicated by __LINE__)
422: . file - the file in which the error was detected (indicated by __FILE__)
423: . message - an error text string, usually just printed to the screen
424: . number - the generic error number
425: . p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
426: - ctx - error handler context
428: Options Database Keys:
429: + -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
430: - -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n]
432: Level: developer
434: Notes:
435: By default the GNU debugger, gdb, is used. Alternatives are cuda-gdb, lldb, dbx and
436: xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
438: Most users need not directly employ this routine and the other error
439: handlers, but can instead use the simplified interface SETERR, which has
440: the calling sequence
441: $ SETERRQ(PETSC_COMM_SELF,number,p,message)
443: Notes for experienced users:
444: Use PetscPushErrorHandler() to set the desired error handler. The
445: currently available PETSc error handlers are
446: $ PetscTraceBackErrorHandler()
447: $ PetscAttachDebuggerErrorHandler()
448: $ PetscAbortErrorHandler()
449: or you may write your own.
452: .seealso: PetscSetDebuggerFromString(), PetscSetDebugger(), PetscSetDefaultDebugger(), PetscError(), PetscPushErrorHandler(), PetscPopErrorHandler(), PetscTraceBackErrorHandler(),
453: PetscAbortErrorHandler(), PetscMPIAbortErrorHandler(), PetscEmacsClientErrorHandler(), PetscReturnErrorHandler()
454: @*/
455: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
456: {
460: if (!fun) fun = "User provided function";
461: if (!mess) mess = " ";
463: (*PetscErrorPrintf)("%s() line %d in %s %s\n",fun,line,file,mess);
465: PetscAttachDebugger();
466: if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
467: return(0);
468: }
470: /*@C
471: PetscStopForDebugger - Prints a message to the screen indicating how to
472: attach to the process with the debugger and then waits for the
473: debugger to attach.
475: Not Collective
477: Level: developer
479: Notes:
480: This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.
482: Developer Notes:
483: Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()?
485: .seealso: PetscSetDebugger(), PetscAttachDebugger()
486: @*/
487: PetscErrorCode PetscStopForDebugger(void)
488: {
490: PetscInt sleeptime=0;
491: #if !defined(PETSC_CANNOT_START_DEBUGGER)
492: int ppid;
493: PetscMPIInt rank;
494: char program[PETSC_MAX_PATH_LEN],hostname[256];
495: PetscBool isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
496: #endif
499: #if defined(PETSC_CANNOT_START_DEBUGGER)
500: (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
501: #else
502: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
503: if (ierr) rank = 0; /* ignore error since this may be already in error handler */
504: PetscGetHostName(hostname,sizeof(hostname));
505: if (ierr) {
506: (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
507: return(0);
508: }
510: PetscGetProgramName(program,sizeof(program));
511: if (ierr) {
512: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
513: return(0);
514: }
515: if (!program[0]) {
516: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
517: return(0);
518: }
520: ppid = getpid();
522: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
523: PetscStrcmp(PetscDebugger,"ddd",&isddd);
524: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
525: PetscStrcmp(PetscDebugger,"ups",&isups);
526: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
527: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
528: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
529: PetscStrcmp(PetscDebugger,"lldb",&islldb);
531: if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
532: else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
533: else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
534: else if (isdbx) {
535: #if defined(PETSC_USE_P_FOR_DEBUGGER)
536: printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
537: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
538: printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
539: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
540: printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
541: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
542: printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
543: #else
544: printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
545: #endif
546: }
547: #endif /* PETSC_CANNOT_START_DEBUGGER */
549: fflush(stdout); /* ignore error because may already be in error handler */
551: sleeptime = 25; /* default to sleep waiting for debugger */
552: PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
553: if (sleeptime < 0) sleeptime = -sleeptime;
554: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
555: /*
556: HP cannot attach process to sleeping debugger, hence count instead
557: */
558: {
559: PetscReal x = 1.0;
560: int i =10000000;
561: while (i--) x++; /* cannot attach to sleeper */
562: }
563: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
564: /*
565: IBM sleep may return at anytime, hence must see if there is more time to sleep
566: */
567: {
568: int left = sleeptime;
569: while (left > 0) left = sleep(left) - 1;
570: }
571: #else
572: PetscSleep(sleeptime);
573: #endif
574: return(0);
575: }