Actual source code: adebug.c
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 UseDebugTerminal = PETSC_TRUE;
17: PetscBool petscwaitonerrorflg = PETSC_FALSE;
18: PetscBool petscindebugger = PETSC_FALSE;
20: /*@C
21: PetscSetDebugTerminal - Sets the terminal to use 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, "urxvt -e", "gnome-terminal -x".
28: On Apple MacOS you can use Terminal (note the capital T)
30: Options Database Keys:
31: -debug_terminal terminal - use this terminal instead of the default
33: Level: developer
35: Notes:
36: You can start the debugger for all processes in the same GNU screen session.
38: mpiexec -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"
40: will open 4 windows in the session named "debug".
42: The default on Apple is Terminal, on other systems the default is xterm
44: Fortran Note:
45: This routine is not supported in Fortran.
47: .seealso: PetscSetDebugger()
48: @*/
49: PetscErrorCode PetscSetDebugTerminal(const char terminal[])
50: {
51: PetscBool xterm;
53: PetscStrncpy(DebugTerminal,terminal,sizeof(DebugTerminal));
54: PetscStrcmp(terminal,"xterm",&xterm);
55: if (xterm) PetscStrlcat(DebugTerminal," -e",sizeof(DebugTerminal));
56: return 0;
57: }
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", "cuda-gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
67: supports "xdb", and IBM rs6000 supports "xldb".
69: - usedebugterminal - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
70: debugger should be started in a new terminal window) 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: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler(), PetscSetDebugTerminal()
80: @*/
81: PetscErrorCode PetscSetDebugger(const char debugger[], PetscBool usedebugterminal)
82: {
83: if (debugger) PetscStrncpy(PetscDebugger,debugger,sizeof(PetscDebugger));
84: if (UseDebugTerminal) UseDebugTerminal = usedebugterminal;
85: return 0;
86: }
88: /*@C
89: PetscSetDefaultDebugger - Causes PETSc to use its default debugger and output terminal
91: Not collective
93: Level: developer
95: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
96: @*/
97: PetscErrorCode PetscSetDefaultDebugger(void)
98: {
99: #if defined(PETSC_USE_DEBUGGER)
100: PetscSetDebugger(PETSC_USE_DEBUGGER,PETSC_TRUE);
101: #endif
102: #if defined(__APPLE__)
103: PetscSetDebugTerminal("Terminal");
104: #else
105: PetscSetDebugTerminal("xterm");
106: #endif
107: return 0;
108: }
111: {
112: PetscBool exists;
113: 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 useterminal = PETSC_TRUE;
138: char *f;
140: PetscStrstr(string, "noxterm", &f);
141: if (f) useterminal = PETSC_FALSE;
142: PetscStrstr(string, "ddd", &f);
143: if (f) useterminal = PETSC_FALSE;
144: PetscStrstr(string, "noterminal", &f);
145: if (f) useterminal = PETSC_FALSE;
160: PetscSetDebugger(debugger, useterminal);
161: return 0;
162: }
164: /*@
165: PetscWaitOnError - If an error is detected and the process would normally exit the main program with MPI_Abort() sleep instead
166: of exiting.
168: Not Collective
170: Level: advanced
172: Notes:
173: 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
174: killing the user's debugging sessions.
176: .seealso: PetscSetDebugger(), PetscAttachDebugger()
177: @*/
178: PetscErrorCode PetscWaitOnError()
179: {
180: petscwaitonerrorflg = PETSC_TRUE;
181: return 0;
182: }
184: /*@
185: PetscAttachDebugger - Attaches the debugger to the running process.
187: Not Collective
189: Options Database Keys:
190: - -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n] -debug_terminal xterm or Terminal (for Apple)
191: . -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
193: Level: advanced
195: Developer Notes:
196: Since this can be called by the error handler should it be calling SETERRQ() and PetscCall()?
198: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger(), PetscSetDebugTerminal(), PetscAttachDebuggerErrorHandler(), PetscStopForDebugger()
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
209: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
210: (*PetscErrorPrintf)("System cannot start debugger\n");
211: (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
212: (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
213: PETSCABORT(PETSC_COMM_WORLD,PETSC_ERR_SUP_SYS);
214: #else
215: PetscGetDisplay(display,sizeof(display));
216: if (PetscUnlikely(ierr)) {
217: (*PetscErrorPrintf)("Cannot determine display\n");
218: return PETSC_ERR_SYS;
219: }
220: PetscGetProgramName(program,sizeof(program));
221: if (PetscUnlikely(ierr)) {
222: (*PetscErrorPrintf)("Cannot determine program name\n");
223: return PETSC_ERR_SYS;
224: }
225: if (PetscUnlikely(!program[0])) {
226: (*PetscErrorPrintf)("Cannot determine program name\n");
227: return PETSC_ERR_SYS;
228: }
229: child = (int)fork();
230: if (PetscUnlikely(child < 0)) {
231: (*PetscErrorPrintf)("Error in fork() prior to attaching debugger\n");
232: return PETSC_ERR_SYS;
233: }
234: petscindebugger = PETSC_TRUE;
236: /*
237: Swap role the parent and child. This is (I think) so that control c typed
238: in the debugger goes to the correct process.
239: */
240: #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
241: if (child) child = 0;
242: else child = (int)getppid();
243: #endif
245: if (child) { /* I am the parent, will run the debugger */
246: const char *args[10];
247: char pid[10];
248: PetscInt j,jj;
249: PetscBool isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;
251: PetscGetHostName(hostname,sizeof(hostname));
252: /*
253: We need to send a continue signal to the "child" process on the
254: alpha, otherwise it just stays off forever
255: */
256: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
257: kill(child,SIGCONT);
258: #endif
259: sprintf(pid,"%d",child);
261: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
262: PetscStrcmp(PetscDebugger,"ddd",&isddd);
263: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
264: PetscStrcmp(PetscDebugger,"ups",&isups);
265: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
266: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
267: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
268: PetscStrcmp(PetscDebugger,"idb",&isidb);
269: PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
270: PetscStrcmp(PetscDebugger,"lldb",&islldb);
272: if (isxxgdb || isups || isddd) {
273: args[1] = program; args[2] = pid; args[3] = "-display";
274: args[0] = PetscDebugger; args[4] = display; args[5] = NULL;
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 (iskdbg) {
281: args[1] = "-p"; args[2] = pid; args[3] = program; args[4] = "-display";
282: args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
283: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
284: if (execvp(args[0],(char**)args) < 0) {
285: perror("Unable to start debugger");
286: exit(0);
287: }
288: } else if (isxldb) {
289: args[1] = "-a"; args[2] = pid; args[3] = program; args[4] = "-display";
290: args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
291: printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
292: if (execvp(args[0],(char**)args) < 0) {
293: perror("Unable to start debugger");
294: exit(0);
295: }
296: } else if (isworkshop) {
297: args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
298: args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = NULL;
299: printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
300: if (execvp(args[0],(char**)args) < 0) {
301: perror("Unable to start debugger");
302: exit(0);
303: }
304: } else {
305: j = 0;
306: if (UseDebugTerminal) {
307: PetscBool cmp;
308: char *tmp,*tmp1;
309: PetscStrncmp(DebugTerminal,"Terminal",8,&cmp);
310: if (cmp) {
311: char command[1024];
312: if (islldb) PetscSNPrintf(command,sizeof(command),"osascript -e 'tell app \"Terminal\" to do script \"lldb -p %s \"'\n",pid);
313: else {
314: char fullprogram[PETSC_MAX_PATH_LEN];
315: PetscGetFullPath(program,fullprogram,sizeof(fullprogram));
316: PetscSNPrintf(command,sizeof(command),"osascript -e 'tell app \"Terminal\" to do script \"%s %s %s \"'\n",PetscDebugger,fullprogram,pid);
317: }
318: PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",NULL);
319: exit(0);
320: }
322: PetscStrncmp(DebugTerminal,"screen",6,&cmp);
323: if (!cmp) PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);
324: if (cmp) display[0] = 0; /* when using screen, we never pass -display */
325: args[j++] = tmp = DebugTerminal;
326: if (display[0]) {
327: args[j++] = "-display"; args[j++] = display;
328: }
329: while (*tmp) {
330: PetscStrchr(tmp,' ',&tmp1);
331: if (!tmp1) break;
332: *tmp1 = 0;
333: tmp = tmp1+1;
334: args[j++] = tmp;
335: }
336: }
337: args[j++] = PetscDebugger;
338: jj = j;
339: /* this is for default gdb */
340: args[j++] = program;
341: args[j++] = pid;
342: args[j++] = NULL;
344: if (isidb) {
345: j = jj;
346: args[j++] = "-pid";
347: args[j++] = pid;
348: args[j++] = "-gdb";
349: args[j++] = program;
350: args[j++] = NULL;
351: }
352: if (islldb) {
353: j = jj;
354: args[j++] = "-p";
355: args[j++] = pid;
356: args[j++] = NULL;
357: }
358: if (isdbx) {
359: j = jj;
360: #if defined(PETSC_USE_P_FOR_DEBUGGER)
361: args[j++] = "-p";
362: args[j++] = pid;
363: args[j++] = program;
364: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
365: args[j++] = "-l";
366: args[j++] = "ALL";
367: args[j++] = "-P";
368: args[j++] = pid;
369: args[j++] = program;
370: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
371: args[j++] = "-a";
372: args[j++] = pid;
373: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
374: args[j++] = "-pid";
375: args[j++] = pid;
376: args[j++] = program;
377: #else
378: args[j++] = program;
379: args[j++] = pid;
380: #endif
381: args[j++] = NULL;
382: }
383: if (UseDebugTerminal) {
384: if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
385: else printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);
387: if (execvp(args[0],(char**)args) < 0) {
388: perror("Unable to start debugger in xterm");
389: exit(0);
390: }
391: } else {
392: printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
393: if (execvp(args[0],(char**)args) < 0) {
394: perror("Unable to start debugger");
395: exit(0);
396: }
397: }
398: }
399: } else { /* I am the child, continue with user code */
400: sleeptime = 10; /* default to sleep waiting for debugger */
401: PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);
402: if (sleeptime < 0) sleeptime = -sleeptime;
403: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
404: /*
405: HP cannot attach process to sleeping debugger, hence count instead
406: */
407: {
408: PetscReal x = 1.0;
409: int i =10000000;
410: while (i--) x++; /* cannot attach to sleeper */
411: }
412: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
413: /*
414: IBM sleep may return at anytime, hence must see if there is more time to sleep
415: */
416: {
417: int left = sleeptime;
418: while (left > 0) left = PetscSleep(left) - 1;
419: }
420: #else
421: PetscSleep(sleeptime);
422: #endif
423: }
424: #endif
425: return 0;
426: }
428: /*@C
429: PetscAttachDebuggerErrorHandler - Error handler that attaches
430: a debugger to a running process when an error is detected.
431: This routine is useful for examining variables, etc.
433: Not Collective
435: Input Parameters:
436: + comm - communicator over which error occurred
437: . line - the line number of the error (indicated by __LINE__)
438: . file - the file in which the error was detected (indicated by __FILE__)
439: . message - an error text string, usually just printed to the screen
440: . number - the generic error number
441: . p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
442: - ctx - error handler context
444: Options Database Keys:
445: + -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
446: - -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n]
448: Level: developer
450: Notes:
451: By default the GNU debugger, gdb, is used. Alternatives are cuda-gdb, lldb, dbx and
452: xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
454: Most users need not directly employ this routine and the other error
455: handlers, but can instead use the simplified interface SETERR, which has
456: the calling sequence
457: $ SETERRQ(PETSC_COMM_SELF,number,p,message)
459: Notes for experienced users:
460: Use PetscPushErrorHandler() to set the desired error handler. The
461: currently available PETSc error handlers are
462: $ PetscTraceBackErrorHandler()
463: $ PetscAttachDebuggerErrorHandler()
464: $ PetscAbortErrorHandler()
465: or you may write your own.
467: .seealso: PetscSetDebuggerFromString(), PetscSetDebugger(), PetscSetDefaultDebugger(), PetscError(), PetscPushErrorHandler(), PetscPopErrorHandler(), PetscTraceBackErrorHandler(),
468: PetscAbortErrorHandler(), PetscMPIAbortErrorHandler(), PetscEmacsClientErrorHandler(), PetscReturnErrorHandler(), PetscSetDebugTermainal()
469: @*/
470: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
471: {
474: if (!fun) fun = "User provided function";
475: if (!mess) mess = " ";
477: (*PetscErrorPrintf)("%s() at %s:%d %s\n",fun,file,line,mess);
479: PetscAttachDebugger();
480: if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
481: return 0;
482: }
484: /*@C
485: PetscStopForDebugger - Prints a message to the screen indicating how to
486: attach to the process with the debugger and then waits for the
487: debugger to attach.
489: Not Collective
491: Options Database:
492: . -stop_for_debugger - will stop for you to attach the debugger when PetscInitialize() is called
494: Level: developer
496: Notes:
497: This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.
499: Developer Notes:
500: Since this can be called by the error handler, should it be calling SETERRQ() and PetscCall()?
502: .seealso: PetscSetDebugger(), PetscAttachDebugger()
503: @*/
504: PetscErrorCode PetscStopForDebugger(void)
505: {
507: PetscInt sleeptime=0;
508: #if !defined(PETSC_CANNOT_START_DEBUGGER)
509: int ppid;
510: PetscMPIInt rank;
511: char program[PETSC_MAX_PATH_LEN],hostname[256];
512: PetscBool isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
513: #endif
515: #if defined(PETSC_CANNOT_START_DEBUGGER)
516: (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
517: #else
518: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
519: if (ierr) rank = 0; /* ignore error since this may be already in error handler */
520: PetscGetHostName(hostname,sizeof(hostname));
521: if (ierr) {
522: (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
523: return 0;
524: }
526: PetscGetProgramName(program,sizeof(program));
527: if (ierr) {
528: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
529: return 0;
530: }
531: if (!program[0]) {
532: (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
533: return 0;
534: }
536: ppid = getpid();
538: PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
539: PetscStrcmp(PetscDebugger,"ddd",&isddd);
540: PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
541: PetscStrcmp(PetscDebugger,"ups",&isups);
542: PetscStrcmp(PetscDebugger,"xldb",&isxldb);
543: PetscStrcmp(PetscDebugger,"xdb",&isxdb);
544: PetscStrcmp(PetscDebugger,"dbx",&isdbx);
545: PetscStrcmp(PetscDebugger,"lldb",&islldb);
547: if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
548: else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
549: else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
550: else if (isdbx) {
551: #if defined(PETSC_USE_P_FOR_DEBUGGER)
552: printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
553: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
554: printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
555: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
556: printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
557: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
558: printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
559: #else
560: printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
561: #endif
562: }
563: #endif /* PETSC_CANNOT_START_DEBUGGER */
565: fflush(stdout); /* ignore error because may already be in error handler */
567: sleeptime = 25; /* default to sleep waiting for debugger */
568: PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
569: if (sleeptime < 0) sleeptime = -sleeptime;
570: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
571: /*
572: HP cannot attach process to sleeping debugger, hence count instead
573: */
574: {
575: PetscReal x = 1.0;
576: int i =10000000;
577: while (i--) x++; /* cannot attach to sleeper */
578: }
579: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
580: /*
581: IBM sleep may return at anytime, hence must see if there is more time to sleep
582: */
583: {
584: int left = sleeptime;
585: while (left > 0) left = sleep(left) - 1;
586: }
587: #else
588: PetscSleep(sleeptime);
589: #endif
590: return 0;
591: }