Actual source code: adebug.c

petsc-main 2021-03-01
Report Typos and Errors
  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: {
 52:   PetscBool      xterm;

 55:   PetscStrncpy(DebugTerminal,terminal,sizeof(DebugTerminal));
 56:   PetscStrcmp(terminal,"xterm",&xterm);
 57:   if (xterm) {
 58:     PetscStrlcat(DebugTerminal," -e",sizeof(DebugTerminal));
 59:   }
 60:   return(0);
 61: }

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

 73: -  usedebugterminal - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
 74:             debugger should be started in a new terminal window) or PETSC_FALSE (to start debugger
 75:             in initial window (the option PETSC_FALSE makes no sense when using more
 76:             than one MPI process.)

 78:    Level: developer

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

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

 90:   if (debugger) {
 91:     PetscStrncpy(PetscDebugger,debugger,sizeof(PetscDebugger));
 92:   }
 93:   if (UseDebugTerminal) UseDebugTerminal = usedebugterminal;
 94:   return(0);
 95: }

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

100:    Not collective

102:     Level: developer

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

111: #if defined(PETSC_USE_DEBUGGER)
112:   PetscSetDebugger(PETSC_USE_DEBUGGER,PETSC_TRUE);
113: #endif
114: #if defined(__APPLE__)
115:   PetscSetDebugTerminal("Terminal");
116: #else
117:   PetscSetDebugTerminal("xterm");
118: #endif
119:   return(0);
120: }

123: {
124:   PetscBool      exists;
125:   char           *f;

129:   PetscStrstr(string, defaultDbg, &f);
130:   if (f) {
131:     PetscTestFile(string, 'x', &exists);
132:     if (exists) *debugger = string;
133:     else        *debugger = defaultDbg;
134:   }
135:   return(0);
136: }

138: /*@C
139:     PetscSetDebuggerFromString - Set the complete path for the
140:        debugger for PETSc to use.

142:    Not collective

144:    Level: developer

146: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
147: @*/
148: PetscErrorCode  PetscSetDebuggerFromString(const char *string)
149: {
150:   const char     *debugger = NULL;
151:   PetscBool      useterminal     = PETSC_TRUE;
152:   char           *f;

156:   PetscStrstr(string, "noxterm", &f);
157:   if (f) useterminal = PETSC_FALSE;
158:   PetscStrstr(string, "ddd", &f);
159:   if (f) useterminal = PETSC_FALSE;
160:   PetscStrstr(string, "noterminal", &f);
161:   if (f) useterminal = PETSC_FALSE;

177:   PetscSetDebugger(debugger, useterminal);
178:   return(0);
179: }

181: /*@
182:    PetscWaitOnError - If an error is detected and the process would normally exit the main program with MPI_Abort() sleep instead
183:                       of exiting.

185:    Not Collective

187:    Level: advanced

189:    Notes:
190:       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
191:       killing the user's debugging sessions.


194: .seealso: PetscSetDebugger(), PetscAttachDebugger()
195: @*/
196: PetscErrorCode  PetscWaitOnError()
197: {
198:   petscwaitonerrorflg  = PETSC_TRUE;
199:   return 0;
200: }

202: /*@
203:    PetscAttachDebugger - Attaches the debugger to the running process.

205:    Not Collective

207:    Options Database Keys:
208: -  -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n] -debug_terminal xterm or Terminal (for Apple)
209: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment

211:    Level: advanced

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

216: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger(), PetscSetDebugTerminal(), PetscAttachDebuggerErrorHandler(), PetscStopForDebugger()
217: @*/
218: PetscErrorCode  PetscAttachDebugger(void)
219: {
220: #if !defined(PETSC_CANNOT_START_DEBUGGER) && defined(PETSC_HAVE_FORK)
221:   int            child    =0;
222:   PetscReal      sleeptime=0;
224:   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
225: #endif

228: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
229:   (*PetscErrorPrintf)("System cannot start debugger\n");
230:   (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
231:   (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
232:   PETSCABORT(PETSC_COMM_WORLD,PETSC_ERR_SUP_SYS);
233: #else
234:   PetscGetDisplay(display,sizeof(display));
235:   PetscGetProgramName(program,sizeof(program));
236:   if (ierr) {
237:     (*PetscErrorPrintf)("Cannot determine program name\n");
238:     PetscFunctionReturn(PETSC_ERR_SYS);
239:   }
240:   if (!program[0]) {
241:     (*PetscErrorPrintf)("Cannot determine program name\n");
242:     PetscFunctionReturn(PETSC_ERR_SYS);
243:   }
244:   child = (int)fork();
245:   if (child < 0) {
246:     (*PetscErrorPrintf)("Error in fork() prior to attaching debugger\n");
247:     PetscFunctionReturn(PETSC_ERR_SYS);
248:   }
249:   petscindebugger = PETSC_TRUE;

251:   /*
252:       Swap role the parent and child. This is (I think) so that control c typed
253:     in the debugger goes to the correct process.
254:   */
255: #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
256:   if (child) child = 0;
257:   else       child = (int)getppid();
258: #endif

260:   if (child) { /* I am the parent, will run the debugger */
261:     const char *args[10];
262:     char       pid[10];
263:     PetscInt   j,jj;
264:     PetscBool  isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;

266:     PetscGetHostName(hostname,sizeof(hostname));
267:     /*
268:          We need to send a continue signal to the "child" process on the
269:        alpha, otherwise it just stays off forever
270:     */
271: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
272:     kill(child,SIGCONT);
273: #endif
274:     sprintf(pid,"%d",child);

276:     PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
277:     PetscStrcmp(PetscDebugger,"ddd",&isddd);
278:     PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
279:     PetscStrcmp(PetscDebugger,"ups",&isups);
280:     PetscStrcmp(PetscDebugger,"xldb",&isxldb);
281:     PetscStrcmp(PetscDebugger,"xdb",&isxdb);
282:     PetscStrcmp(PetscDebugger,"dbx",&isdbx);
283:     PetscStrcmp(PetscDebugger,"idb",&isidb);
284:     PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
285:     PetscStrcmp(PetscDebugger,"lldb",&islldb);

287:     if (isxxgdb || isups || isddd) {
288:       args[1] = program; args[2] = pid; args[3] = "-display";
289:       args[0] = PetscDebugger; args[4] = display; args[5] = NULL;
290:       printf("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 (iskdbg) {
296:       args[1] = "-p"; args[2] = pid; args[3] = program;  args[4] = "-display";
297:       args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
298:       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
299:       if (execvp(args[0],(char**)args)  < 0) {
300:         perror("Unable to start debugger");
301:         exit(0);
302:       }
303:     } else if (isxldb) {
304:       args[1] = "-a"; args[2] = pid; args[3] = program;  args[4] = "-display";
305:       args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
306:       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
307:       if (execvp(args[0],(char**)args)  < 0) {
308:         perror("Unable to start debugger");
309:         exit(0);
310:       }
311:     } else if (isworkshop) {
312:       args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
313:       args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = NULL;
314:       printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
315:       if (execvp(args[0],(char**)args)  < 0) {
316:         perror("Unable to start debugger");
317:         exit(0);
318:       }
319:     } else {
320:       j = 0;
321:       if (UseDebugTerminal) {
322:         PetscBool cmp;
323:         char      *tmp,*tmp1;
324:         PetscStrncmp(DebugTerminal,"Terminal",8,&cmp);
325:         if (cmp) {
326:           char command[1024];
327:           PetscSNPrintf(command,sizeof(command),"osascript -e 'tell app \"Terminal\" to do script \"lldb  -p %s  %s \"'\n",pid,program);
328:           PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",NULL);
329:           exit(0);
330:         }

332:         PetscStrncmp(DebugTerminal,"screen",6,&cmp);
333:         if (!cmp) {PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);}
334:         if (cmp) display[0] = 0; /* when using screen, we never pass -display */
335:         args[j++] = tmp = DebugTerminal;
336:         if (display[0]) {
337:           args[j++] = "-display"; args[j++] = display;
338:         }
339:         while (*tmp) {
340:           PetscStrchr(tmp,' ',&tmp1);
341:           if (!tmp1) break;
342:           *tmp1     = 0;
343:           tmp       = tmp1+1;
344:           args[j++] = tmp;
345:         }
346:       }
347:       args[j++] = PetscDebugger;
348:       jj = j;
349:       /* this is for default gdb */
350:       args[j++] = program;
351:       args[j++] = pid;
352:       args[j++] = NULL;

354:       if (isidb) {
355:         j = jj;
356:         args[j++] = "-pid";
357:         args[j++] = pid;
358:         args[j++] = "-gdb";
359:         args[j++] = program;
360:         args[j++] = NULL;
361:       }
362:       if (islldb) {
363:         j = jj;
364:         args[j++] = "-p";
365:         args[j++] = pid;
366:         args[j++] = NULL;
367:       }
368:       if (isdbx) {
369:         j = jj;
370: #if defined(PETSC_USE_P_FOR_DEBUGGER)
371:         args[j++] = "-p";
372:         args[j++] = pid;
373:         args[j++] = program;
374: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
375:         args[j++] = "-l";
376:         args[j++] = "ALL";
377:         args[j++] = "-P";
378:         args[j++] = pid;
379:         args[j++] = program;
380: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
381:         args[j++] = "-a";
382:         args[j++] = pid;
383: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
384:         args[j++] = "-pid";
385:         args[j++] = pid;
386:         args[j++] = program;
387: #else
388:         args[j++] = program;
389:         args[j++] = pid;
390: #endif
391:         args[j++] = NULL;
392:       }
393:       if (UseDebugTerminal) {
394:         if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
395:         else            printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);

397:         if (execvp(args[0],(char**)args)  < 0) {
398:           perror("Unable to start debugger in xterm");
399:           exit(0);
400:         }
401:       } else {
402:         printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
403:         if (execvp(args[0],(char**)args)  < 0) {
404:           perror("Unable to start debugger");
405:           exit(0);
406:         }
407:       }
408:     }
409:   } else {   /* I am the child, continue with user code */
410:     sleeptime = 10; /* default to sleep waiting for debugger */
411:     PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);
412:     if (sleeptime < 0) sleeptime = -sleeptime;
413: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
414:     /*
415:         HP cannot attach process to sleeping debugger, hence count instead
416:     */
417:     {
418:       PetscReal x = 1.0;
419:       int       i =10000000;
420:       while (i--) x++;  /* cannot attach to sleeper */
421:     }
422: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
423:     /*
424:         IBM sleep may return at anytime, hence must see if there is more time to sleep
425:     */
426:     {
427:       int left = sleeptime;
428:       while (left > 0) left = PetscSleep(left) - 1;
429:     }
430: #else
431:     PetscSleep(sleeptime);
432: #endif
433:   }
434: #endif
435:   return(0);
436: }

438: /*@C
439:    PetscAttachDebuggerErrorHandler - Error handler that attaches
440:    a debugger to a running process when an error is detected.
441:    This routine is useful for examining variables, etc.

443:    Not Collective

445:    Input Parameters:
446: +  comm - communicator over which error occurred
447: .  line - the line number of the error (indicated by __LINE__)
448: .  file - the file in which the error was detected (indicated by __FILE__)
449: .  message - an error text string, usually just printed to the screen
450: .  number - the generic error number
451: .  p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
452: -  ctx - error handler context

454:    Options Database Keys:
455: +  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
456: -  -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n]

458:    Level: developer

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

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

469:    Notes for experienced users:
470:    Use PetscPushErrorHandler() to set the desired error handler.  The
471:    currently available PETSc error handlers are
472: $    PetscTraceBackErrorHandler()
473: $    PetscAttachDebuggerErrorHandler()
474: $    PetscAbortErrorHandler()
475:    or you may write your own.


478: .seealso:  PetscSetDebuggerFromString(), PetscSetDebugger(), PetscSetDefaultDebugger(), PetscError(), PetscPushErrorHandler(), PetscPopErrorHandler(), PetscTraceBackErrorHandler(),
479:            PetscAbortErrorHandler(), PetscMPIAbortErrorHandler(), PetscEmacsClientErrorHandler(), PetscReturnErrorHandler(), PetscSetDebugTermainal()
480: @*/
481: PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
482: {

486:   if (!fun) fun = "User provided function";
487:   if (!mess) mess = " ";

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

491:   PetscAttachDebugger();
492:   if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
493:   return(0);
494: }

496: /*@C
497:    PetscStopForDebugger - Prints a message to the screen indicating how to
498:          attach to the process with the debugger and then waits for the
499:          debugger to attach.

501:    Not Collective

503:    Options Database:
504: .   -stop_for_debugger - will stop for you to attach the debugger when PetscInitialize() is called

506:    Level: developer

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

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

514: .seealso: PetscSetDebugger(), PetscAttachDebugger()
515: @*/
516: PetscErrorCode  PetscStopForDebugger(void)
517: {
519:   PetscInt       sleeptime=0;
520: #if !defined(PETSC_CANNOT_START_DEBUGGER)
521:   int            ppid;
522:   PetscMPIInt    rank;
523:   char           program[PETSC_MAX_PATH_LEN],hostname[256];
524:   PetscBool      isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
525: #endif

528: #if defined(PETSC_CANNOT_START_DEBUGGER)
529:   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
530: #else
531:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
532:   if (ierr) rank = 0; /* ignore error since this may be already in error handler */
533:   PetscGetHostName(hostname,sizeof(hostname));
534:   if (ierr) {
535:     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
536:     return(0);
537:   }

539:   PetscGetProgramName(program,sizeof(program));
540:   if (ierr) {
541:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
542:     return(0);
543:   }
544:   if (!program[0]) {
545:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
546:     return(0);
547:   }

549:   ppid = getpid();

551:   PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
552:   PetscStrcmp(PetscDebugger,"ddd",&isddd);
553:   PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
554:   PetscStrcmp(PetscDebugger,"ups",&isups);
555:   PetscStrcmp(PetscDebugger,"xldb",&isxldb);
556:   PetscStrcmp(PetscDebugger,"xdb",&isxdb);
557:   PetscStrcmp(PetscDebugger,"dbx",&isdbx);
558:   PetscStrcmp(PetscDebugger,"lldb",&islldb);

560:   if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
561:   else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
562:   else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
563:   else if (isdbx) {
564: #if defined(PETSC_USE_P_FOR_DEBUGGER)
565:      printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
566: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
567:      printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
568: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
569:      printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
570: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
571:      printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
572: #else
573:      printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
574: #endif
575:   }
576: #endif /* PETSC_CANNOT_START_DEBUGGER */

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

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