Actual source code: adebug.c

petsc-3.11.4 2019-09-28
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:    Concepts: debugger^setting

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

 51:   PetscStrcpy(DebugTerminal,terminal);
 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", "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:   Concepts: debugger^setting

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

 84:   if (debugger) {
 85:     PetscStrcpy(PetscDebugger,debugger);
 86:   }
 87:   Xterm = xterm;
 88:   return(0);
 89: }

 91: /*@C
 92:     PetscSetDefaultDebugger - Causes PETSc to use its default  debugger.

 94:    Not collective

 96:     Level: developer

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

105: #if defined(PETSC_USE_LLDB_DEBUGGER)
106:   PetscSetDebugger("lldb",PETSC_TRUE);
107: #elif defined(PETSC_USE_DBX_DEBUGGER)
108:   PetscSetDebugger("dbx",PETSC_TRUE);
109: #elif defined(PETSC_USE_XDB_DEBUGGER)
110:   PetscSetDebugger("xdb",PETSC_TRUE);
111: #elif defined(PETSC_USE_IDB_DEBUGGER)
112:   PetscSetDebugger("idb",PETSC_TRUE);
113: #else  /* Default is gdb */
114:   PetscSetDebugger("gdb",PETSC_TRUE);
115: #endif
116:   PetscSetDebugTerminal("xterm -e");
117:   return(0);
118: }

121: {
122:   PetscBool      exists;
123:   char           *f;

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

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

140:    Not collective

142:    Level: developer

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

154:   PetscStrstr(string, "noxterm", &f);
155:   if (f) xterm = PETSC_FALSE;
156:   PetscStrstr(string, "ddd", &f);
157:   if (f) xterm = PETSC_FALSE;

172:   PetscSetDebugger(debugger, xterm);
173:   return(0);
174: }


177: /*@
178:    PetscAttachDebugger - Attaches the debugger to the running process.

180:    Not Collective

182:    Level: advanced

184:    Concepts: debugger^starting from program

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

189: .seealso: PetscSetDebugger()
190: @*/
191: PetscErrorCode  PetscAttachDebugger(void)
192: {
193: #if !defined(PETSC_CANNOT_START_DEBUGGER)
194:   int            child    =0;
195:   PetscReal      sleeptime=0;
197:   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
198: #endif

201: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
202:   (*PetscErrorPrintf)("System cannot start debugger\n");
203:   (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
204:   (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
205:   MPI_Abort(PETSC_COMM_WORLD,1);
206: #else
207:   PetscGetDisplay(display,128);
208:   PetscGetProgramName(program,PETSC_MAX_PATH_LEN);
209:   if (ierr) {
210:     (*PetscErrorPrintf)("Cannot determine program name\n");
211:     PetscFunctionReturn(1);
212:   }
213:   if (!program[0]) {
214:     (*PetscErrorPrintf)("Cannot determine program name\n");
215:     PetscFunctionReturn(1);
216:   }
217:   child = (int)fork();
218:   if (child < 0) {
219:     (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
220:     PetscFunctionReturn(1);
221:   }

223:   /*
224:       Swap role the parent and child. This is (I think) so that control c typed
225:     in the debugger goes to the correct process.
226:   */
227:   if (child) child = 0;
228:   else       child = (int)getppid();

230:   if (child) { /* I am the parent, will run the debugger */
231:     const char *args[10];
232:     char       pid[10];
233:     PetscInt   j,jj;
234:     PetscBool  isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;

236:     PetscGetHostName(hostname,64);
237:     /*
238:          We need to send a continue signal to the "child" process on the
239:        alpha, otherwise it just stays off forever
240:     */
241: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
242:     kill(child,SIGCONT);
243: #endif
244:     sprintf(pid,"%d",child);

246:     PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
247:     PetscStrcmp(PetscDebugger,"ddd",&isddd);
248:     PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
249:     PetscStrcmp(PetscDebugger,"ups",&isups);
250:     PetscStrcmp(PetscDebugger,"xldb",&isxldb);
251:     PetscStrcmp(PetscDebugger,"xdb",&isxdb);
252:     PetscStrcmp(PetscDebugger,"dbx",&isdbx);
253:     PetscStrcmp(PetscDebugger,"idb",&isidb);
254:     PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
255:     PetscStrcmp(PetscDebugger,"lldb",&islldb);

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

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

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

397: /*@C
398:    PetscAttachDebuggerErrorHandler - Error handler that attaches
399:    a debugger to a running process when an error is detected.
400:    This routine is useful for examining variables, etc.

402:    Not Collective

404:    Input Parameters:
405: +  comm - communicator over which error occurred
406: .  line - the line number of the error (indicated by __LINE__)
407: .  file - the file in which the error was detected (indicated by __FILE__)
408: .  message - an error text string, usually just printed to the screen
409: .  number - the generic error number
410: .  p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
411: -  ctx - error handler context

413:    Options Database Keys:
414: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
415:    debugger attachment

417:    Level: developer

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

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

428:    Notes for experienced users:
429:    Use PetscPushErrorHandler() to set the desired error handler.  The
430:    currently available PETSc error handlers are
431: $    PetscTraceBackErrorHandler()
432: $    PetscAttachDebuggerErrorHandler()
433: $    PetscAbortErrorHandler()
434:    or you may write your own.

436:    Concepts: debugger^error handler
437:    Concepts: error handler^attach debugger

439: .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
440:            PetscAbortErrorHandler()
441: @*/
442: PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
443: {

447:   if (!fun) fun = "User provided function";
448:   if (!mess) mess = " ";

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

452:   PetscAttachDebugger();
453:   if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
454:   return(0);
455: }

457: /*@C
458:    PetscStopForDebugger - Prints a message to the screen indicating how to
459:          attach to the process with the debugger and then waits for the
460:          debugger to attach.

462:    Not Collective

464:    Level: developer

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

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

472:    Concepts: debugger^waiting for attachment

474: .seealso: PetscSetDebugger(), PetscAttachDebugger()
475: @*/
476: PetscErrorCode  PetscStopForDebugger(void)
477: {
479:   PetscInt       sleeptime=0;
480: #if !defined(PETSC_CANNOT_START_DEBUGGER)
481:   int            ppid;
482:   PetscMPIInt    rank;
483:   char           program[PETSC_MAX_PATH_LEN],hostname[256];
484:   PetscBool      isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
485: #endif

488: #if defined(PETSC_CANNOT_START_DEBUGGER)
489:   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
490: #else
491:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
492:   if (ierr) rank = 0; /* ignore error since this may be already in error handler */
493:   PetscGetHostName(hostname,256);
494:   if (ierr) {
495:     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
496:     return(0);
497:   }

499:   PetscGetProgramName(program,256);
500:   if (ierr) {
501:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
502:     return(0);
503:   }
504:   if (!program[0]) {
505:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
506:     return(0);
507:   }

509:   ppid = getpid();

511:   PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
512:   PetscStrcmp(PetscDebugger,"ddd",&isddd);
513:   PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
514:   PetscStrcmp(PetscDebugger,"ups",&isups);
515:   PetscStrcmp(PetscDebugger,"xldb",&isxldb);
516:   PetscStrcmp(PetscDebugger,"xdb",&isxdb);
517:   PetscStrcmp(PetscDebugger,"dbx",&isdbx);
518:   PetscStrcmp(PetscDebugger,"lldb",&islldb);

520:   if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
521:   else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
522:   else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
523:   else if (isdbx) {
524: #if defined(PETSC_USE_P_FOR_DEBUGGER)
525:      printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
526: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
527:      printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
528: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
529:      printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
530: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
531:      printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
532: #else
533:      printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
534: #endif
535:   }
536: #endif /* PETSC_CANNOT_START_DEBUGGER */

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

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