Actual source code: adebug.c

petsc-3.14.6 2021-03-30
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 Xterm = PETSC_TRUE;
 17: PetscBool        petscwaitonerrorflg = PETSC_FALSE;
 18: PetscBool        petscindebugger  = PETSC_FALSE;

 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", "gnome-terminal -x".

 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:      mpiexec -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: .seealso: PetscSetDebugger()
 45: @*/
 46: PetscErrorCode  PetscSetDebugTerminal(const char terminal[])
 47: {

 51:   PetscStrncpy(DebugTerminal,terminal,sizeof(DebugTerminal));
 52:   return(0);
 53: }

 55: /*@C
 56:    PetscSetDebugger - Sets options associated with the debugger.

 58:    Not Collective

 60:    Input Parameters:
 61: +  debugger - name of debugger, which should be in your path,
 62:               usually "lldb", "dbx", "gdb", "cuda-gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
 63:               supports "xdb", and IBM rs6000 supports "xldb".

 65: -  xterm - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
 66:             debugger should be started in a new xterm) or PETSC_FALSE (to start debugger
 67:             in initial window (the option PETSC_FALSE makes no sense when using more
 68:             than one MPI process.)

 70:    Level: developer

 72:    Fortran Note:
 73:    This routine is not supported in Fortran.

 75: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
 76: @*/
 77: PetscErrorCode  PetscSetDebugger(const char debugger[],PetscBool xterm)
 78: {

 82:   if (debugger) {
 83:     PetscStrncpy(PetscDebugger,debugger,sizeof(PetscDebugger));
 84:   }
 85:   if (Xterm) Xterm = xterm;
 86:   return(0);
 87: }

 89: /*@C
 90:     PetscSetDefaultDebugger - Causes PETSc to use its default  debugger.

 92:    Not collective

 94:     Level: developer

 96: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
 97: @*/
 98: PetscErrorCode  PetscSetDefaultDebugger(void)
 99: {

103: #if defined(PETSC_USE_DEBUGGER)
104:   PetscSetDebugger(PETSC_USE_DEBUGGER,PETSC_TRUE);
105: #endif
106:   PetscSetDebugTerminal("xterm -e");
107:   return(0);
108: }

111: {
112:   PetscBool      exists;
113:   char           *f;

117:   PetscStrstr(string, defaultDbg, &f);
118:   if (f) {
119:     PetscTestFile(string, 'x', &exists);
120:     if (exists) *debugger = string;
121:     else        *debugger = defaultDbg;
122:   }
123:   return(0);
124: }

126: /*@C
127:     PetscSetDebuggerFromString - Set the complete path for the
128:        debugger for PETSc to use.

130:    Not collective

132:    Level: developer

134: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
135: @*/
136: PetscErrorCode  PetscSetDebuggerFromString(const char *string)
137: {
138:   const char     *debugger = NULL;
139:   PetscBool      xterm     = PETSC_TRUE;
140:   char           *f;

144:   PetscStrstr(string, "noxterm", &f);
145:   if (f) xterm = PETSC_FALSE;
146:   PetscStrstr(string, "ddd", &f);
147:   if (f) xterm = PETSC_FALSE;

163:   PetscSetDebugger(debugger, xterm);
164:   return(0);
165: }

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

171:    Not Collective

173:    Level: advanced

175:    Notes:
176:       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
177:       killing the user's debugging sessions.


180: .seealso: PetscSetDebugger(), PetscAttachDebugger()
181: @*/
182: PetscErrorCode  PetscWaitOnError()
183: {
184:   petscwaitonerrorflg  = PETSC_TRUE;
185:   return 0;
186: }

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

191:    Not Collective

193:    Level: advanced

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

198: .seealso: PetscSetDebugger()
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

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

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

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

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

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

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

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++] = NULL;
335:       }
336:       if (islldb) {
337:         j = jj;
338:         args[j++] = "-p";
339:         args[j++] = pid;
340:         args[j++] = NULL;
341:       }
342:       if (isdbx) {
343:         j = jj;
344: #if defined(PETSC_USE_P_FOR_DEBUGGER)
345:         args[j++] = "-p";
346:         args[j++] = pid;
347:         args[j++] = program;
348: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
349:         args[j++] = "-l";
350:         args[j++] = "ALL";
351:         args[j++] = "-P";
352:         args[j++] = pid;
353:         args[j++] = program;
354: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
355:         args[j++] = "-a";
356:         args[j++] = pid;
357: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
358:         args[j++] = "-pid";
359:         args[j++] = pid;
360:         args[j++] = program;
361: #else
362:         args[j++] = program;
363:         args[j++] = pid;
364: #endif
365:         args[j++] = NULL;
366:       }
367:       if (Xterm) {
368:         if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
369:         else            printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);

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

412: /*@C
413:    PetscAttachDebuggerErrorHandler - Error handler that attaches
414:    a debugger to a running process when an error is detected.
415:    This routine is useful for examining variables, etc.

417:    Not Collective

419:    Input Parameters:
420: +  comm - communicator over which error occurred
421: .  line - the line number of the error (indicated by __LINE__)
422: .  file - the file in which the error was detected (indicated by __FILE__)
423: .  message - an error text string, usually just printed to the screen
424: .  number - the generic error number
425: .  p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
426: -  ctx - error handler context

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

432:    Level: developer

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

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

443:    Notes for experienced users:
444:    Use PetscPushErrorHandler() to set the desired error handler.  The
445:    currently available PETSc error handlers are
446: $    PetscTraceBackErrorHandler()
447: $    PetscAttachDebuggerErrorHandler()
448: $    PetscAbortErrorHandler()
449:    or you may write your own.


452: .seealso:  PetscSetDebuggerFromString(), PetscSetDebugger(), PetscSetDefaultDebugger(), PetscError(), PetscPushErrorHandler(), PetscPopErrorHandler(), PetscTraceBackErrorHandler(),
453:            PetscAbortErrorHandler(), PetscMPIAbortErrorHandler(), PetscEmacsClientErrorHandler(), PetscReturnErrorHandler()
454: @*/
455: PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
456: {

460:   if (!fun) fun = "User provided function";
461:   if (!mess) mess = " ";

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

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

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

475:    Not Collective

477:    Level: developer

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

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

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

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

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

520:   ppid = getpid();

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

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

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

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