Actual source code: adebug.c

petsc-3.6.4 2016-04-12
Report Typos and Errors
  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

 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;

 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".

 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:      mpirun -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:    Concepts: debugger^setting

 46: .seealso: PetscSetDebugger()
 47: @*/
 48: PetscErrorCode  PetscSetDebugTerminal(const char terminal[])
 49: {

 53:   PetscStrcpy(DebugTerminal,terminal);
 54:   return(0);
 55: }

 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", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
 67:               supports "xdb", and IBM rs6000 supports "xldb".

 69: -  xterm - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
 70:             debugger should be started in a new xterm) 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:   Concepts: debugger^setting

 81: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
 82: @*/
 83: PetscErrorCode  PetscSetDebugger(const char debugger[],PetscBool xterm)
 84: {

 88:   if (debugger) {
 89:     PetscStrcpy(PetscDebugger,debugger);
 90:   }
 91:   Xterm = xterm;
 92:   return(0);
 93: }

 97: /*@C
 98:     PetscSetDefaultDebugger - Causes PETSc to use its default  debugger.

100:    Not collective

102:     Level: developer

104: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
105: @*/
106: PetscErrorCode  PetscSetDefaultDebugger(void)
107: {

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

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

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

146: /*@C
147:     PetscSetDebuggerFromString - Set the complete path for the
148:        debugger for PETSc to use.

150:    Not collective

152:    Level: developer

154: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
155: @*/
156: PetscErrorCode  PetscSetDebuggerFromString(const char *string)
157: {
158:   const char     *debugger = NULL;
159:   PetscBool      xterm     = PETSC_TRUE;
160:   char           *f;

164:   PetscStrstr(string, "noxterm", &f);
165:   if (f) xterm = PETSC_FALSE;
166:   PetscStrstr(string, "ddd", &f);
167:   if (f) xterm = PETSC_FALSE;

182:   PetscSetDebugger(debugger, xterm);
183:   return(0);
184: }


189: /*@
190:    PetscAttachDebugger - Attaches the debugger to the running process.

192:    Not Collective

194:    Level: advanced

196:    Concepts: debugger^starting from program

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

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

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

234:   /*
235:       Swap role the parent and child. This is (I think) so that control c typed
236:     in the debugger goes to the correct process.
237:   */
238:   if (child) child = 0;
239:   else       child = (int)getppid();

241:   if (child) { /* I am the parent, will run the debugger */
242:     const char *args[10];
243:     char       pid[10];
244:     PetscInt   j,jj;
245:     PetscBool  isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;

247:     PetscGetHostName(hostname,64);
248:     /*
249:          We need to send a continue signal to the "child" process on the
250:        alpha, otherwise it just stays off forever
251:     */
252: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
253:     kill(child,SIGCONT);
254: #endif
255:     sprintf(pid,"%d",child);

257:     PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
258:     PetscStrcmp(PetscDebugger,"ddd",&isddd);
259:     PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
260:     PetscStrcmp(PetscDebugger,"ups",&isups);
261:     PetscStrcmp(PetscDebugger,"xldb",&isxldb);
262:     PetscStrcmp(PetscDebugger,"xdb",&isxdb);
263:     PetscStrcmp(PetscDebugger,"dbx",&isdbx);
264:     PetscStrcmp(PetscDebugger,"idb",&isidb);
265:     PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
266:     PetscStrcmp(PetscDebugger,"lldb",&islldb);

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

323:       if (isidb) {
324:         j = jj;
325:         args[j++] = "-pid";
326:         args[j++] = pid;
327:         args[j++] = "-gdb";
328:         args[j++] = program;
329:         args[j++] = 0;
330:       }
331:       if (islldb) {
332:         j = jj;
333:         args[j++] = "-p";
334:         args[j++] = pid;
335:         args[j++] = 0;
336:       }
337:       if (isdbx) {
338:         j = jj;
339: #if defined(PETSC_USE_P_FOR_DEBUGGER)
340:         args[j++] = "-p";
341:         args[j++] = pid;
342:         args[j++] = program;
343: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
344:         args[j++] = "-l";
345:         args[j++] = "ALL";
346:         args[j++] = "-P";
347:         args[j++] = pid;
348:         args[j++] = program;
349: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
350:         args[j++] = "-a";
351:         args[j++] = pid;
352: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
353:         args[j++] = "-pid";
354:         args[j++] = pid;
355:         args[j++] = program;
356: #endif
357:         args[j++] = 0;
358:       }
359:       if (Xterm) {
360:         if (display[0]) (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
361:         else            (*PetscErrorPrintf)("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);

363:         if (execvp(args[0],(char**)args)  < 0) {
364:           perror("Unable to start debugger in xterm");
365:           exit(0);
366:         }
367:       } else {
368:         (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
369:         if (execvp(args[0],(char**)args)  < 0) {
370:           perror("Unable to start debugger");
371:           exit(0);
372:         }
373:       }
374:     }
375:   } else {   /* I am the child, continue with user code */
376:     sleeptime = 10; /* default to sleep waiting for debugger */
377:     PetscOptionsGetReal(NULL,"-debugger_pause",&sleeptime,NULL);
378:     if (sleeptime < 0) sleeptime = -sleeptime;
379: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
380:     /*
381:         HP cannot attach process to sleeping debugger, hence count instead
382:     */
383:     {
384:       PetscReal x = 1.0;
385:       int       i =10000000;
386:       while (i--) x++;  /* cannot attach to sleeper */
387:     }
388: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
389:     /*
390:         IBM sleep may return at anytime, hence must see if there is more time to sleep
391:     */
392:     {
393:       int left = sleeptime;
394:       while (left > 0) left = PetscSleep(left) - 1;
395:     }
396: #else
397:     PetscSleep(sleeptime);
398: #endif
399:   }
400: #endif
401:   return(0);
402: }

406: /*@C
407:    PetscAttachDebuggerErrorHandler - Error handler that attaches
408:    a debugger to a running process when an error is detected.
409:    This routine is useful for examining variables, etc.

411:    Not Collective

413:    Input Parameters:
414: +  comm - communicator over which error occurred
415: .  line - the line number of the error (indicated by __LINE__)
416: .  fun - function where error occured (indicated by __FUNCT__)
417: .  file - the file in which the error was detected (indicated by __FILE__)
418: .  message - an error text string, usually just printed to the screen
419: .  number - the generic error number
420: .  p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
421: -  ctx - error handler context

423:    Options Database Keys:
424: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
425:    debugger attachment

427:    Level: developer

429:    Notes:
430:    By default the GNU debugger, gdb, is used.  Alternatives are lldb, dbx and
431:    xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).

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

438:    Notes for experienced users:
439:    Use PetscPushErrorHandler() to set the desired error handler.  The
440:    currently available PETSc error handlers are
441: $    PetscTraceBackErrorHandler()
442: $    PetscAttachDebuggerErrorHandler()
443: $    PetscAbortErrorHandler()
444:    or you may write your own.

446:    Concepts: debugger^error handler
447:    Concepts: error handler^attach debugger

449: .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
450:            PetscAbortErrorHandler()
451: @*/
452: PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
453: {

457:   if (!fun) fun = "User provided function";
458:   if (!mess) mess = " ";

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

462:   PetscAttachDebugger();
463:   if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
464:   return(0);
465: }

469: /*@C
470:    PetscStopForDebugger - Prints a message to the screen indicating how to
471:          attach to the process with the debugger and then waits for the
472:          debugger to attach.

474:    Not Collective

476:    Level: developer

478:    Notes: This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.

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

482:    Concepts: debugger^waiting for attachment

484: .seealso: PetscSetDebugger(), PetscAttachDebugger()
485: @*/
486: PetscErrorCode  PetscStopForDebugger(void)
487: {
489:   PetscInt       sleeptime=0;
490: #if !defined(PETSC_CANNOT_START_DEBUGGER)
491:   int            ppid;
492:   PetscMPIInt    rank;
493:   char           program[PETSC_MAX_PATH_LEN],hostname[256];
494:   PetscBool      isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
495: #endif

498: #if defined(PETSC_CANNOT_START_DEBUGGER)
499:   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
500: #else
501:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
502:   if (ierr) rank = 0; /* ignore error since this may be already in error handler */
503:   PetscGetHostName(hostname,256);
504:   if (ierr) {
505:     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
506:     return(0);
507:   }

509:   PetscGetProgramName(program,256);
510:   if (ierr) {
511:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
512:     return(0);
513:   }
514:   if (!program[0]) {
515:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
516:     return(0);
517:   }

519:   ppid = getpid();

521:   PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
522:   PetscStrcmp(PetscDebugger,"ddd",&isddd);
523:   PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
524:   PetscStrcmp(PetscDebugger,"ups",&isups);
525:   PetscStrcmp(PetscDebugger,"xldb",&isxldb);
526:   PetscStrcmp(PetscDebugger,"xdb",&isxdb);
527:   PetscStrcmp(PetscDebugger,"dbx",&isdbx);
528:   PetscStrcmp(PetscDebugger,"lldb",&islldb);

530:   if (isxxgdb || isups || isddd || iskdbg) (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
531:   else if (isxldb) (*PetscErrorPrintf)("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
532:   else if (islldb) (*PetscErrorPrintf)("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
533:   else if (isdbx) {
534: #if defined(PETSC_USE_P_FOR_DEBUGGER)
535:      (*PetscErrorPrintf)("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
536: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
537:      (*PetscErrorPrintf)("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
538: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
539:      (*PetscErrorPrintf)("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
540: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
541:      (*PetscErrorPrintf)("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
542: #else
543:      (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
544: #endif
545:   }
546: #endif /* PETSC_CANNOT_START_DEBUGGER */

548:   fflush(stdout); /* ignore error because may already be in error handler */

550:   sleeptime = 25; /* default to sleep waiting for debugger */
551:   PetscOptionsGetInt(NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
552:   if (sleeptime < 0) sleeptime = -sleeptime;
553: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
554:   /*
555:       HP cannot attach process to sleeping debugger, hence count instead
556:   */
557:   {
558:     PetscReal x = 1.0;
559:     int       i =10000000;
560:     while (i--) x++;  /* cannot attach to sleeper */
561:   }
562: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
563:   /*
564:       IBM sleep may return at anytime, hence must see if there is more time to sleep
565:   */
566:   {
567:     int left = sleeptime;
568:     while (left > 0) left = sleep(left) - 1;
569:   }
570: #else
571:   PetscSleep(sleeptime);
572: #endif
573:   return(0);
574: }