Actual source code: adebug.c

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

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

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

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

 27:    Not Collective

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

 33:    Options Database Keys:
 34:    -debug_terminal terminal - use this terminal instead of xterm

 36:    Level: developer

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

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

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

 48:    Concepts: debugger^setting

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

 57:   PetscStrcpy(DebugTerminal,terminal);
 58:   return(0);
 59: }

 63: /*@C
 64:    PetscSetDebugger - Sets options associated with the debugger.

 66:    Not Collective

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

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

 78:    Level: developer

 80:    Fortran Note:
 81:    This routine is not supported in Fortran.

 83:   Concepts: debugger^setting

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

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

 97:   return(0);
 98: }

102: /*@
103:     PetscSetDefaultDebugger - Causes PETSc to use its default 
104:           debugger.

106:    Not collective

108:     Level: advanced

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

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

133: {
134:   PetscTruth exists;
135:   char      *f;

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

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

157:    Not collective
158:  
159:    Level: advanced

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

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

188:   PetscSetDebugger(debugger, xterm);
189:   return(0);
190: }


195: /*@
196:    PetscAttachDebugger - Attaches the debugger to the running process.

198:    Not Collective

200:    Level: advanced

202:    Concepts: debugger^starting from program

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


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

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

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

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

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

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

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

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

424:    Not Collective

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

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

440:    Level: developer

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

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

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

459:    Concepts: debugger^error handler
460:    Concepts: error handler^attach debugger

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

470:   if (!fun)  fun = "User provided function";
471:   if (!dir)  dir = " ";
472:   if (!mess) mess = " ";

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

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

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

491:    Not Collective

493:    Level: advanced

495:    Concepts: debugger^waiting for attachment

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

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

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

532:   ppid = getpid();

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

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

573:   err = fflush(stdout);
574:   if (err) SETERRQ(PETSC_ERR_SYS,"fflush() failed on stdout");

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