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: }