Actual source code: adebug.c

  1: #define PETSC_DLL
  2: /*
  3:       Code to handle PETSc starting up in debuggers,etc.
  4: */

 6:  #include petsc.h
  7: #include <signal.h> 
 8:  #include petscsys.h
  9: #if defined(PETSC_HAVE_UNISTD_H)
 10: #include <unistd.h>
 11: #endif 
 12: #if defined(PETSC_HAVE_STDLIB_H)
 13: #include <stdlib.h>
 14: #endif
 15: #include "petscfix.h"

 17: /*
 18:       These are the debugger and display used if the debugger is started up
 19: */
 20: static char       Debugger[PETSC_MAX_PATH_LEN];
 21: static char       DebugTerminal[PETSC_MAX_PATH_LEN];
 22: static PetscTruth Xterm = PETSC_TRUE;

 26: /*@C
 27:    PetscSetDebugTerminal - Sets the terminal to use (instead of xterm) for debugging.

 29:    Not Collective

 31:    Input Parameters:
 32: +  terminal - name of terminal and any flags required to execute a program.
 33:               For example "xterm -e", "urxvt -e".

 35:    Options Database Keys:
 36:    -debug_terminal terminal - use this terminal instead of xterm

 38:    Level: developer

 40:    Notes:
 41:    You can start the debugger for all processes in the same GNU screen session.

 43:      mpirun -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"

 45:    will open 4 windows in the session named "debug".
 46:      
 47:    Fortran Note:
 48:    This routine is not supported in Fortran.

 50:    Concepts: debugger^setting

 52: .seealso: PetscSetDebugger()
 53: @*/
 54: PetscErrorCode  PetscSetDebugTerminal(const char terminal[])
 55: {

 59:   PetscStrcpy(DebugTerminal,terminal);
 60:   return(0);
 61: }

 65: /*@C
 66:    PetscSetDebugger - Sets options associated with the debugger.

 68:    Not Collective

 70:    Input Parameters:
 71: +  debugger - name of debugger, which should be in your path,
 72:               usually "dbx", "gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
 73:               supports "xdb", and IBM rs6000 supports "xldb".

 75: -  xterm - flag to indicate debugger window, set to either 1 (to indicate
 76:             debugger should be started in a new xterm) or 0 (to start debugger
 77:             in initial window (the option 0 makes no sense when using more
 78:             than one processor.)

 80:    Level: developer

 82:    Fortran Note:
 83:    This routine is not supported in Fortran.

 85:   Concepts: debugger^setting

 87: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
 88: @*/
 89: PetscErrorCode  PetscSetDebugger(const char debugger[],PetscTruth xterm)
 90: {

 94:   if (debugger) {
 95:     PetscStrcpy(Debugger,debugger);
 96:   }
 97:   Xterm = xterm;

 99:   return(0);
100: }

104: /*@
105:     PetscSetDefaultDebugger - Causes PETSc to use its default 
106:           debugger.

108:    Not collective

110:     Level: advanced

112: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
113: @*/
114: PetscErrorCode  PetscSetDefaultDebugger(void)
115: {

119: #if defined(PETSC_USE_DBX_DEBUGGER)
120:   PetscSetDebugger("dbx",PETSC_TRUE);
121: #elif defined(PETSC_USE_XDB_DEBUGGER) 
122:   PetscSetDebugger("xdb",PETSC_TRUE);
123: #elif defined(PETSC_USE_IDB_DEBUGGER) 
124:   PetscSetDebugger("idb",PETSC_TRUE);
125: #else  /* Default is gdb */
126:   PetscSetDebugger("gdb",PETSC_TRUE);
127: #endif
128:   PetscSetDebugTerminal("xterm -e");
129:   return(0);
130: }

135: {
136:   PetscTruth exists;
137:   char      *f;

141:   PetscStrstr(string, defaultDbg, &f);
142:   if (f) {
143:     PetscTestFile(string, 'x', &exists);
144:     if (exists) {
145:       *debugger = string;
146:     } else {
147:       *debugger = defaultDbg;
148:     }
149:   }
150:   return(0);
151: }

155: /*@C
156:     PetscSetDebuggerFromString - Set the complete path for the
157:        debugger for PETSc to use.

159:    Not collective
160:  
161:    Level: advanced

163: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
164: @*/
165: PetscErrorCode  PetscSetDebuggerFromString(char *string)
166: {
167:   const char *debugger = PETSC_NULL;
168:   PetscTruth  xterm    = PETSC_TRUE;
169:   char       *f;

173:   PetscStrstr(string, "noxterm", &f);
174:   if (f) xterm = PETSC_FALSE;
175:   PetscStrstr(string, "ddd", &f);
176:   if (f) xterm = PETSC_FALSE;

190:   PetscSetDebugger(debugger, xterm);
191:   return(0);
192: }


197: /*@
198:    PetscAttachDebugger - Attaches the debugger to the running process.

200:    Not Collective

202:    Level: advanced

204:    Concepts: debugger^starting from program

206: .seealso: PetscSetDebugger()
207: @*/
208: PetscErrorCode  PetscAttachDebugger(void)
209: {
210: #if !defined(PETSC_CANNOT_START_DEBUGGER) 
211:   int            child=0;
212:   PetscInt       sleeptime=0;
214:   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
215: #endif


219: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
220:   (*PetscErrorPrintf)("System cannot start debugger\n");
221:   (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
222:   (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
223:   MPI_Finalize();
224:   exit(0);
225: #else
226:   PetscGetDisplay(display,128);
227:   PetscGetProgramName(program,PETSC_MAX_PATH_LEN);
228:   if (ierr) {
229:     (*PetscErrorPrintf)("Cannot determine program name\n");
230:     PetscFunctionReturn(1);
231:   }
232:   if (!program[0]) {
233:     (*PetscErrorPrintf)("Cannot determine program name\n");
234:     PetscFunctionReturn(1);
235:   }
236:   child = (int)fork();
237:   if (child < 0) {
238:     (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
239:     PetscFunctionReturn(1);
240:   }

242:   /*
243:       Swap role the parent and child. This is (I think) so that control c typed
244:     in the debugger goes to the correct process.
245:   */
246:   if (child) { child = 0; }
247:   else       { child = (int)getppid(); }

249:   if (child) { /* I am the parent, will run the debugger */
250:     const char *args[10];
251:     char       pid[10];
252:     PetscInt   j,jj;
253:     PetscTruth isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg;

255:     PetscGetHostName(hostname,64);
256:     /*
257:          We need to send a continue signal to the "child" process on the 
258:        alpha, otherwise it just stays off forever
259:     */
260: #if defined (PETSC_NEED_KILL_FOR_DEBUGGER)
261:     kill(child,SIGCONT);
262: #endif
263:     sprintf(pid,"%d",child);

265:     PetscStrcmp(Debugger,"xxgdb",&isxxgdb);
266:     PetscStrcmp(Debugger,"ddd",&isddd);
267:     PetscStrcmp(Debugger,"kdbg",&iskdbg);
268:     PetscStrcmp(Debugger,"ups",&isups);
269:     PetscStrcmp(Debugger,"xldb",&isxldb);
270:     PetscStrcmp(Debugger,"xdb",&isxdb);
271:     PetscStrcmp(Debugger,"dbx",&isdbx);
272:     PetscStrcmp(Debugger,"idb",&isidb);
273:     PetscStrcmp(Debugger,"workshop",&isworkshop);

275:     if (isxxgdb || isups || isddd ) {
276:       args[1] = program; args[2] = pid; args[3] = "-display";
277:       args[0] = Debugger; args[4] = display; args[5] = 0;
278:       (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
279:       if (execvp(args[0],(char**)args)  < 0) {
280:         perror("Unable to start debugger");
281:         exit(0);
282:       }
283:     } else if (iskdbg) {
284:       args[1] = "-p"; args[2] = pid; args[3] = program;  args[4] = "-display";
285:       args[0] = Debugger; args[5] = display; args[6] = 0;
286:       (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
287:       if (execvp(args[0],(char**)args)  < 0) {
288:         perror("Unable to start debugger");
289:         exit(0);
290:       }
291:     } else if (isxldb) {
292:       args[1] = "-a"; args[2] = pid; args[3] = program;  args[4] = "-display";
293:       args[0] = Debugger; args[5] = display; args[6] = 0;
294:       (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
295:       if (execvp(args[0],(char**)args)  < 0) {
296:         perror("Unable to start debugger");
297:         exit(0);
298:       }
299:     } else if (isworkshop) {
300:       args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
301:       args[0] = Debugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = 0;
302:       (*PetscErrorPrintf)("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
303:       if (execvp(args[0],(char**)args)  < 0) {
304:         perror("Unable to start debugger");
305:         exit(0);
306:       }
307:     } else {
308:       j = 0;
309:       if (Xterm) {
310:         PetscTruth cmp;
311:         char *tmp,*tmp1;
312:         PetscStrncmp(DebugTerminal,"screen",6,&cmp);
313:         if (cmp) display[0] = 0; /* when using screen, we never pass -display */
314:         args[j++] = tmp = DebugTerminal;
315:         if (display[0]) {
316:           args[j++] = "-display"; args[j++] = display;
317:         }
318:         while (*tmp) {
319:           PetscStrchr(tmp,' ',&tmp1);
320:           if (!tmp1) break;
321:           *tmp1 = 0;
322:           tmp = tmp1+1;
323:           args[j++] = tmp;
324:         }
325:       }
326:       args[j++] = Debugger;
327:       jj = j;
328:       args[j++] = program; args[j++] = pid; args[j++] = 0;

330:       if (isidb) {
331:         j = jj;
332:         args[j++] = "-pid";
333:         args[j++] = pid;
334:         args[j++] = "-gdb";
335:         args[j++] = program;
336:         args[j++] = 0;
337:       }
338: #if defined(PETSC_USE_P_FOR_DEBUGGER)
339:       if (isdbx) {
340:         j = jj;
341:         args[j++] = "-p";
342:         args[j++] = pid;
343:         args[j++] = program;
344:         args[j++] = 0;
345:       }
346: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
347:       if (isxdb) {
348:         j = jj;
349:         args[j++] = "-l";
350:         args[j++] = "ALL";
351:         args[j++] = "-P";
352:         args[j++] = pid;
353:         args[j++] = program;
354:         args[j++] = 0;
355:       }
356: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
357:       if (isdbx) {
358:         j = jj;
359:         args[j++] = "-a";
360:         args[j++] = pid;
361:         args[j++] = 0;
362:       }
363: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
364:       if (isdbx) {
365:         j = jj;
366:         args[j++] = "-pid";
367:         args[j++] = pid;
368:         args[j++] = program;
369:         args[j++] = 0;
370:       }
371: #endif
372:       if (Xterm) {
373:         if (display[0]) {
374:           (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",Debugger,program,pid,display,hostname);
375:         } else {
376:           (*PetscErrorPrintf)("PETSC: Attaching %s to %s on pid %s on %s\n",Debugger,program,pid,hostname);
377:         }
378:         if (execvp(args[0],(char**)args)  < 0) {
379:           perror("Unable to start debugger in xterm");
380:           exit(0);
381:         }
382:       } else {
383:         (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on %s\n",Debugger,program,pid,hostname);
384:         if (execvp(args[0],(char**)args)  < 0) {
385:           perror("Unable to start debugger");
386:           exit(0);
387:         }
388:       }
389:     }
390:   } else {   /* I am the child, continue with user code */
391:     sleeptime = 10; /* default to sleep waiting for debugger */
392:     PetscOptionsGetInt(PETSC_NULL,"-debugger_pause",&sleeptime,PETSC_NULL);
393:     if (sleeptime < 0) sleeptime = -sleeptime;
394: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
395:     /*
396:         HP cannot attach process to sleeping debugger, hence count instead
397:     */
398:     {
399:       PetscReal x = 1.0;
400:       int i=10000000;
401:       while (i--) x++ ; /* cannot attach to sleeper */
402:     }
403: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
404:     /*
405:         IBM sleep may return at anytime, hence must see if there is more time to sleep
406:     */
407:     {
408:       int left = sleeptime;
409:       while (left > 0) {left = PetscSleep(left) - 1;}
410:     }
411: #else
412:     PetscSleep(sleeptime);
413: #endif
414:   }
415: #endif
416:   return(0);
417: }

421: /*@C
422:    PetscAttachDebuggerErrorHandler - Error handler that attaches
423:    a debugger to a running process when an error is detected.
424:    This routine is useful for examining variables, etc. 

426:    Not Collective

428:    Input Parameters:
429: +  line - the line number of the error (indicated by __LINE__)
430: .  fun - function where error occured (indicated by __FUNCT__)
431: .  file - the file in which the error was detected (indicated by __FILE__)
432: .  dir - the directory of the file (indicated by __SDIR__)
433: .  message - an error text string, usually just printed to the screen
434: .  number - the generic error number
435: .  p - the specific error number
436: -  ctx - error handler context

438:    Options Database Keys:
439: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
440:    debugger attachment

442:    Level: developer

444:    Notes:
445:    By default the GNU debugger, gdb, is used.  Alternatives are dbx and
446:    xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).

448:    Most users need not directly employ this routine and the other error 
449:    handlers, but can instead use the simplified interface SETERR, which has 
450:    the calling sequence
451: $     SETERRQ(number,p,message)

453:    Notes for experienced users:
454:    Use PetscPushErrorHandler() to set the desired error handler.  The
455:    currently available PETSc error handlers are
456: $    PetscTraceBackErrorHandler()
457: $    PetscAttachDebuggerErrorHandler()
458: $    PetscAbortErrorHandler()
459:    or you may write your own.

461:    Concepts: debugger^error handler
462:    Concepts: error handler^attach debugger

464: .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(), 
465:            PetscAbortErrorHandler()
466: @*/
467: PetscErrorCode  PetscAttachDebuggerErrorHandler(int line,const char* fun,const char *file,const char* dir,int num,int p,const char* mess,void *ctx)
468: {

472:   if (!fun)  fun = "User provided function";
473:   if (!dir)  dir = " ";
474:   if (!mess) mess = " ";

476:   (*PetscErrorPrintf)("%s() line %d in %s%s %s\n",fun,line,dir,file,mess);

478:   PetscAttachDebugger();
479:   if (ierr) { /* hopeless so get out */
480:     MPI_Finalize();
481:     exit(num);
482:   }
483:   return(0);
484: }

488: /*@C
489:    PetscStopForDebugger - Prints a message to the screen indicating how to
490:          attach to the process with the debugger and then waits for the 
491:          debugger to attach.

493:    Not Collective

495:    Level: advanced

497:    Concepts: debugger^waiting for attachment

499: .seealso: PetscSetDebugger(), PetscAttachDebugger()
500: @*/
501: PetscErrorCode  PetscStopForDebugger(void)
502: {
504:   PetscInt       sleeptime=0;
505:   int            err;
506: #if !defined(PETSC_CANNOT_START_DEBUGGER) 
507:   int            ppid;
508:   PetscMPIInt    rank;
509:   char           program[PETSC_MAX_PATH_LEN],hostname[256];
510:   PetscTruth     isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb;
511: #endif

514: #if defined(PETSC_CANNOT_START_DEBUGGER) 
515:   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
516: #else
517:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
518:   PetscGetHostName(hostname,256);
519:   if (ierr) {
520:     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
521:     return(0);
522:   }

524:   PetscGetProgramName(program,256);
525:   if (ierr) {
526:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
527:     return(0);
528:   }
529:   if (!program[0]) {
530:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
531:     return(0);
532:   }

534:   ppid = getpid();

536:   PetscStrcmp(Debugger,"xxgdb",&isxxgdb);
537:   PetscStrcmp(Debugger,"ddd",&isddd);
538:   PetscStrcmp(Debugger,"kdbg",&iskdbg);
539:   PetscStrcmp(Debugger,"ups",&isups);
540:   PetscStrcmp(Debugger,"xldb",&isxldb);
541:   PetscStrcmp(Debugger,"xdb",&isxdb);
542:   PetscStrcmp(Debugger,"dbx",&isdbx);

544:   if (isxxgdb || isups || isddd || iskdbg ) {
545:     (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,Debugger,program,ppid);
546:   }
547: #if defined(PETSC_USE_A_FOR_DEBUGGER)
548:   else if (isxldb) {
549:     (*PetscErrorPrintf)("{%d]%s>>%s -a %d %s\n",rank,hostname,Debugger,ppid,program);
550:   }
551: #endif
552: #if defined(PETSC_USE_P_FOR_DEBUGGER)
553:   else if (isdbx) {
554:     (*PetscErrorPrintf)("[%d]%s>>%s -p %d %s\n",rank,hostname,Debugger,ppid,program);
555:   }
556: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
557:   else if (isxdb) {
558:     (*PetscErrorPrintf)("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,Debugger,ppid,program);
559:   }
560: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
561:   else if (isdbx) {
562:     (*PetscErrorPrintf)("[%d]%s>>%s -a %d\n",rank,hostname,Debugger,ppid);
563:   }
564: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
565:   else if (isdbx) {
566:     (*PetscErrorPrintf)("[%d]%s>>%s -pid %d %s\n",rank,hostname,Debugger,ppid,program);
567:   }
568: #else 
569:   else {
570:     (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,Debugger,program,ppid);
571:   }
572: #endif
573: #endif /* PETSC_CANNOT_START_DEBUGGER */

575:   err = fflush(stdout);
576:   if (err) SETERRQ(PETSC_ERR_SYS,"fflush() failed on stdout");

578:   sleeptime = 25; /* default to sleep waiting for debugger */
579:   PetscOptionsGetInt(PETSC_NULL,"-debugger_pause",&sleeptime,PETSC_NULL);
580:   if (sleeptime < 0) sleeptime = -sleeptime;
581: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
582:   /*
583:       HP cannot attach process to sleeping debugger, hence count instead
584:   */
585:   {
586:     PetscReal x = 1.0;
587:     int i=10000000;
588:     while (i--) x++ ; /* cannot attach to sleeper */
589:   }
590: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
591:   /*
592:       IBM sleep may return at anytime, hence must see if there is more time to sleep
593:   */
594:   {
595:     int left = sleeptime;
596:     while (left > 0) {left = sleep(left) - 1;}
597:   }
598: #else
599:   PetscSleep(sleeptime);
600: #endif
601:   return(0);
602: }