Actual source code: adebug.c

petsc-3.3-p7 2013-05-11
  1: /*
  2:       Code to handle PETSc starting up in debuggers,etc.
  3: */

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

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

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

 26:    Not Collective

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

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

 35:    Level: developer

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

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

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

 47:    Concepts: debugger^setting

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

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

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

 65:    Not Collective

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

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

 77:    Level: developer

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

 82:   Concepts: debugger^setting

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

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

100: /*@
101:     PetscSetDefaultDebugger - Causes PETSc to use its default  debugger.

103:    Not collective

105:     Level: advanced

107: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
108: @*/
109: PetscErrorCode  PetscSetDefaultDebugger(void)
110: {

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

130: {
131:   PetscBool      exists;
132:   char           *f;

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

150: /*@C
151:     PetscSetDebuggerFromString - Set the complete path for the
152:        debugger for PETSc to use.

154:    Not collective
155:  
156:    Level: developer

158: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
159: @*/
160: PetscErrorCode  PetscSetDebuggerFromString(const char *string)
161: {
162:   const char     *debugger = PETSC_NULL;
163:   PetscBool      xterm    = PETSC_TRUE;
164:   char           *f;

168:   PetscStrstr(string, "noxterm", &f);
169:   if (f) xterm = PETSC_FALSE;
170:   PetscStrstr(string, "ddd", &f);
171:   if (f) xterm = PETSC_FALSE;

185:   PetscSetDebugger(debugger, xterm);
186:   return(0);
187: }


192: /*@
193:    PetscAttachDebugger - Attaches the debugger to the running process.

195:    Not Collective

197:    Level: advanced

199:    Concepts: debugger^starting from program

201:    Developer Notes: Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?

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


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

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

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;

251:     PetscGetHostName(hostname,64);
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(Debugger,"xxgdb",&isxxgdb);
262:     PetscStrcmp(Debugger,"ddd",&isddd);
263:     PetscStrcmp(Debugger,"kdbg",&iskdbg);
264:     PetscStrcmp(Debugger,"ups",&isups);
265:     PetscStrcmp(Debugger,"xldb",&isxldb);
266:     PetscStrcmp(Debugger,"xdb",&isxdb);
267:     PetscStrcmp(Debugger,"dbx",&isdbx);
268:     PetscStrcmp(Debugger,"idb",&isidb);
269:     PetscStrcmp(Debugger,"workshop",&isworkshop);

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

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

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

422:    Not Collective

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

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

439:    Level: developer

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

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

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

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

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

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

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

475:   PetscAttachDebugger();
476:   if (ierr) { /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
477:     abort();
478:   }
479:   return(0);
480: }

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:    Level: advanced

493:    Developer Notes: Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?

495:    Concepts: debugger^waiting for attachment

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

511: #if defined(PETSC_CANNOT_START_DEBUGGER) 
512:   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
513: #else
514:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
515:   if (ierr) rank = 0; /* ignore error since this may be already in error handler */
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:   fflush(stdout); /* ignore error because may already be in error handler */

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