Actual source code: adebug.c

petsc-master 2020-07-13
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;

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

 21:    Not Collective

 23:    Input Parameters:
 24: .  terminal - name of terminal and any flags required to execute a program.
 25:               For example "xterm -e", "urxvt -e", "gnome-terminal -x".

 27:    Options Database Keys:
 28:    -debug_terminal terminal - use this terminal instead of xterm

 30:    Level: developer

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

 35:      mpiexec -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"

 37:    will open 4 windows in the session named "debug".

 39:    Fortran Note:
 40:    This routine is not supported in Fortran.

 42: .seealso: PetscSetDebugger()
 43: @*/
 44: PetscErrorCode  PetscSetDebugTerminal(const char terminal[])
 45: {

 49:   PetscStrncpy(DebugTerminal,terminal,sizeof(DebugTerminal));
 50:   return(0);
 51: }

 53: /*@C
 54:    PetscSetDebugger - Sets options associated with the debugger.

 56:    Not Collective

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

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

 68:    Level: developer

 70:    Fortran Note:
 71:    This routine is not supported in Fortran.

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

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

 87: /*@C
 88:     PetscSetDefaultDebugger - Causes PETSc to use its default  debugger.

 90:    Not collective

 92:     Level: developer

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

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

109: {
110:   PetscBool      exists;
111:   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      xterm     = PETSC_TRUE;
138:   char           *f;

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

161:   PetscSetDebugger(debugger, xterm);
162:   return(0);
163: }


166: /*@
167:    PetscAttachDebugger - Attaches the debugger to the running process.

169:    Not Collective

171:    Level: advanced

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

176: .seealso: PetscSetDebugger()
177: @*/
178: PetscErrorCode  PetscAttachDebugger(void)
179: {
180: #if !defined(PETSC_CANNOT_START_DEBUGGER) && defined(PETSC_HAVE_FORK)
181:   int            child    =0;
182:   PetscReal      sleeptime=0;
184:   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
185: #endif

188: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
189:   (*PetscErrorPrintf)("System cannot start debugger\n");
190:   (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
191:   (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
192:   PETSCABORT(PETSC_COMM_WORLD,PETSC_ERR_SUP_SYS);
193: #else
194:   PetscGetDisplay(display,sizeof(display));
195:   PetscGetProgramName(program,sizeof(program));
196:   if (ierr) {
197:     (*PetscErrorPrintf)("Cannot determine program name\n");
198:     PetscFunctionReturn(1);
199:   }
200:   if (!program[0]) {
201:     (*PetscErrorPrintf)("Cannot determine program name\n");
202:     PetscFunctionReturn(1);
203:   }
204:   child = (int)fork();
205:   if (child < 0) {
206:     (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
207:     PetscFunctionReturn(1);
208:   }

210:   /*
211:       Swap role the parent and child. This is (I think) so that control c typed
212:     in the debugger goes to the correct process.
213:   */
214: #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
215:   if (child) child = 0;
216:   else       child = (int)getppid();
217: #endif

219:   if (child) { /* I am the parent, will run the debugger */
220:     const char *args[10];
221:     char       pid[10];
222:     PetscInt   j,jj;
223:     PetscBool  isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;

225:     PetscGetHostName(hostname,sizeof(hostname));
226:     /*
227:          We need to send a continue signal to the "child" process on the
228:        alpha, otherwise it just stays off forever
229:     */
230: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
231:     kill(child,SIGCONT);
232: #endif
233:     sprintf(pid,"%d",child);

235:     PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
236:     PetscStrcmp(PetscDebugger,"ddd",&isddd);
237:     PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
238:     PetscStrcmp(PetscDebugger,"ups",&isups);
239:     PetscStrcmp(PetscDebugger,"xldb",&isxldb);
240:     PetscStrcmp(PetscDebugger,"xdb",&isxdb);
241:     PetscStrcmp(PetscDebugger,"dbx",&isdbx);
242:     PetscStrcmp(PetscDebugger,"idb",&isidb);
243:     PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
244:     PetscStrcmp(PetscDebugger,"lldb",&islldb);

246:     if (isxxgdb || isups || isddd) {
247:       args[1] = program; args[2] = pid; args[3] = "-display";
248:       args[0] = PetscDebugger; args[4] = display; args[5] = NULL;
249:       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
250:       if (execvp(args[0],(char**)args)  < 0) {
251:         perror("Unable to start debugger");
252:         exit(0);
253:       }
254:     } else if (iskdbg) {
255:       args[1] = "-p"; args[2] = pid; args[3] = program;  args[4] = "-display";
256:       args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
257:       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
258:       if (execvp(args[0],(char**)args)  < 0) {
259:         perror("Unable to start debugger");
260:         exit(0);
261:       }
262:     } else if (isxldb) {
263:       args[1] = "-a"; args[2] = pid; args[3] = program;  args[4] = "-display";
264:       args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
265:       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
266:       if (execvp(args[0],(char**)args)  < 0) {
267:         perror("Unable to start debugger");
268:         exit(0);
269:       }
270:     } else if (isworkshop) {
271:       args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
272:       args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = NULL;
273:       printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
274:       if (execvp(args[0],(char**)args)  < 0) {
275:         perror("Unable to start debugger");
276:         exit(0);
277:       }
278:     } else {
279:       j = 0;
280:       if (Xterm) {
281:         PetscBool cmp;
282:         char      *tmp,*tmp1;
283:         PetscStrncmp(DebugTerminal,"screen",6,&cmp);
284:         if (!cmp) {PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);}
285:         if (cmp) display[0] = 0; /* when using screen, we never pass -display */
286:         args[j++] = tmp = DebugTerminal;
287:         if (display[0]) {
288:           args[j++] = "-display"; args[j++] = display;
289:         }
290:         while (*tmp) {
291:           PetscStrchr(tmp,' ',&tmp1);
292:           if (!tmp1) break;
293:           *tmp1     = 0;
294:           tmp       = tmp1+1;
295:           args[j++] = tmp;
296:         }
297:       }
298:       args[j++] = PetscDebugger;
299:       jj = j;
300:       args[j++] = program; args[j++] = pid; args[j++] = NULL;

302:       if (isidb) {
303:         j = jj;
304:         args[j++] = "-pid";
305:         args[j++] = pid;
306:         args[j++] = "-gdb";
307:         args[j++] = program;
308:         args[j++] = NULL;
309:       }
310:       if (islldb) {
311:         j = jj;
312:         args[j++] = "-p";
313:         args[j++] = pid;
314:         args[j++] = NULL;
315:       }
316:       if (isdbx) {
317:         j = jj;
318: #if defined(PETSC_USE_P_FOR_DEBUGGER)
319:         args[j++] = "-p";
320:         args[j++] = pid;
321:         args[j++] = program;
322: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
323:         args[j++] = "-l";
324:         args[j++] = "ALL";
325:         args[j++] = "-P";
326:         args[j++] = pid;
327:         args[j++] = program;
328: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
329:         args[j++] = "-a";
330:         args[j++] = pid;
331: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
332:         args[j++] = "-pid";
333:         args[j++] = pid;
334:         args[j++] = program;
335: #else
336:         args[j++] = program;
337:         args[j++] = pid;
338: #endif
339:         args[j++] = NULL;
340:       }
341:       if (Xterm) {
342:         if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
343:         else            printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);

345:         if (execvp(args[0],(char**)args)  < 0) {
346:           perror("Unable to start debugger in xterm");
347:           exit(0);
348:         }
349:       } else {
350:         printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
351:         if (execvp(args[0],(char**)args)  < 0) {
352:           perror("Unable to start debugger");
353:           exit(0);
354:         }
355:       }
356:     }
357:   } else {   /* I am the child, continue with user code */
358:     sleeptime = 10; /* default to sleep waiting for debugger */
359:     PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);
360:     if (sleeptime < 0) sleeptime = -sleeptime;
361: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
362:     /*
363:         HP cannot attach process to sleeping debugger, hence count instead
364:     */
365:     {
366:       PetscReal x = 1.0;
367:       int       i =10000000;
368:       while (i--) x++;  /* cannot attach to sleeper */
369:     }
370: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
371:     /*
372:         IBM sleep may return at anytime, hence must see if there is more time to sleep
373:     */
374:     {
375:       int left = sleeptime;
376:       while (left > 0) left = PetscSleep(left) - 1;
377:     }
378: #else
379:     PetscSleep(sleeptime);
380: #endif
381:   }
382: #endif
383:   return(0);
384: }

386: /*@C
387:    PetscAttachDebuggerErrorHandler - Error handler that attaches
388:    a debugger to a running process when an error is detected.
389:    This routine is useful for examining variables, etc.

391:    Not Collective

393:    Input Parameters:
394: +  comm - communicator over which error occurred
395: .  line - the line number of the error (indicated by __LINE__)
396: .  file - the file in which the error was detected (indicated by __FILE__)
397: .  message - an error text string, usually just printed to the screen
398: .  number - the generic error number
399: .  p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
400: -  ctx - error handler context

402:    Options Database Keys:
403: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
404:    debugger attachment

406:    Level: developer

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

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

417:    Notes for experienced users:
418:    Use PetscPushErrorHandler() to set the desired error handler.  The
419:    currently available PETSc error handlers are
420: $    PetscTraceBackErrorHandler()
421: $    PetscAttachDebuggerErrorHandler()
422: $    PetscAbortErrorHandler()
423:    or you may write your own.


426: .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
427:            PetscAbortErrorHandler()
428: @*/
429: PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
430: {

434:   if (!fun) fun = "User provided function";
435:   if (!mess) mess = " ";

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

439:   PetscAttachDebugger();
440:   if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */    
441:   return(0);
442: }

444: /*@C
445:    PetscStopForDebugger - Prints a message to the screen indicating how to
446:          attach to the process with the debugger and then waits for the
447:          debugger to attach.

449:    Not Collective

451:    Level: developer

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

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

459: .seealso: PetscSetDebugger(), PetscAttachDebugger()
460: @*/
461: PetscErrorCode  PetscStopForDebugger(void)
462: {
464:   PetscInt       sleeptime=0;
465: #if !defined(PETSC_CANNOT_START_DEBUGGER)
466:   int            ppid;
467:   PetscMPIInt    rank;
468:   char           program[PETSC_MAX_PATH_LEN],hostname[256];
469:   PetscBool      isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
470: #endif

473: #if defined(PETSC_CANNOT_START_DEBUGGER)
474:   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
475: #else
476:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
477:   if (ierr) rank = 0; /* ignore error since this may be already in error handler */
478:   PetscGetHostName(hostname,sizeof(hostname));
479:   if (ierr) {
480:     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
481:     return(0);
482:   }

484:   PetscGetProgramName(program,sizeof(program));
485:   if (ierr) {
486:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
487:     return(0);
488:   }
489:   if (!program[0]) {
490:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
491:     return(0);
492:   }

494:   ppid = getpid();

496:   PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
497:   PetscStrcmp(PetscDebugger,"ddd",&isddd);
498:   PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
499:   PetscStrcmp(PetscDebugger,"ups",&isups);
500:   PetscStrcmp(PetscDebugger,"xldb",&isxldb);
501:   PetscStrcmp(PetscDebugger,"xdb",&isxdb);
502:   PetscStrcmp(PetscDebugger,"dbx",&isdbx);
503:   PetscStrcmp(PetscDebugger,"lldb",&islldb);

505:   if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
506:   else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
507:   else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
508:   else if (isdbx) {
509: #if defined(PETSC_USE_P_FOR_DEBUGGER)
510:      printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
511: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
512:      printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
513: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
514:      printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
515: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
516:      printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
517: #else
518:      printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
519: #endif
520:   }
521: #endif /* PETSC_CANNOT_START_DEBUGGER */

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

525:   sleeptime = 25; /* default to sleep waiting for debugger */
526:   PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
527:   if (sleeptime < 0) sleeptime = -sleeptime;
528: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
529:   /*
530:       HP cannot attach process to sleeping debugger, hence count instead
531:   */
532:   {
533:     PetscReal x = 1.0;
534:     int       i =10000000;
535:     while (i--) x++;  /* cannot attach to sleeper */
536:   }
537: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
538:   /*
539:       IBM sleep may return at anytime, hence must see if there is more time to sleep
540:   */
541:   {
542:     int left = sleeptime;
543:     while (left > 0) left = sleep(left) - 1;
544:   }
545: #else
546:   PetscSleep(sleeptime);
547: #endif
548:   return(0);
549: }