Actual source code: adebug.c

petsc-master 2019-06-15
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:   PetscStrcpy(DebugTerminal,terminal);
 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", "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:     PetscStrcpy(PetscDebugger,debugger);
 82:   }
 83:   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_LLDB_DEBUGGER)
102:   PetscSetDebugger("lldb",PETSC_TRUE);
103: #elif defined(PETSC_USE_DBX_DEBUGGER)
104:   PetscSetDebugger("dbx",PETSC_TRUE);
105: #elif defined(PETSC_USE_XDB_DEBUGGER)
106:   PetscSetDebugger("xdb",PETSC_TRUE);
107: #elif defined(PETSC_USE_IDB_DEBUGGER)
108:   PetscSetDebugger("idb",PETSC_TRUE);
109: #else  /* Default is gdb */
110:   PetscSetDebugger("gdb",PETSC_TRUE);
111: #endif
112:   PetscSetDebugTerminal("xterm -e");
113:   return(0);
114: }

117: {
118:   PetscBool      exists;
119:   char           *f;

123:   PetscStrstr(string, defaultDbg, &f);
124:   if (f) {
125:     PetscTestFile(string, 'x', &exists);
126:     if (exists) *debugger = string;
127:     else        *debugger = defaultDbg;
128:   }
129:   return(0);
130: }

132: /*@C
133:     PetscSetDebuggerFromString - Set the complete path for the
134:        debugger for PETSc to use.

136:    Not collective

138:    Level: developer

140: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
141: @*/
142: PetscErrorCode  PetscSetDebuggerFromString(const char *string)
143: {
144:   const char     *debugger = NULL;
145:   PetscBool      xterm     = PETSC_TRUE;
146:   char           *f;

150:   PetscStrstr(string, "noxterm", &f);
151:   if (f) xterm = PETSC_FALSE;
152:   PetscStrstr(string, "ddd", &f);
153:   if (f) xterm = PETSC_FALSE;

168:   PetscSetDebugger(debugger, xterm);
169:   return(0);
170: }


173: /*@
174:    PetscAttachDebugger - Attaches the debugger to the running process.

176:    Not Collective

178:    Level: advanced

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

183: .seealso: PetscSetDebugger()
184: @*/
185: PetscErrorCode  PetscAttachDebugger(void)
186: {
187: #if !defined(PETSC_CANNOT_START_DEBUGGER)
188:   int            child    =0;
189:   PetscReal      sleeptime=0;
191:   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
192: #endif

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

217:   /*
218:       Swap role the parent and child. This is (I think) so that control c typed
219:     in the debugger goes to the correct process.
220:   */
221:   if (child) child = 0;
222:   else       child = (int)getppid();

224:   if (child) { /* I am the parent, will run the debugger */
225:     const char *args[10];
226:     char       pid[10];
227:     PetscInt   j,jj;
228:     PetscBool  isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;

230:     PetscGetHostName(hostname,64);
231:     /*
232:          We need to send a continue signal to the "child" process on the
233:        alpha, otherwise it just stays off forever
234:     */
235: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
236:     kill(child,SIGCONT);
237: #endif
238:     sprintf(pid,"%d",child);

240:     PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
241:     PetscStrcmp(PetscDebugger,"ddd",&isddd);
242:     PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
243:     PetscStrcmp(PetscDebugger,"ups",&isups);
244:     PetscStrcmp(PetscDebugger,"xldb",&isxldb);
245:     PetscStrcmp(PetscDebugger,"xdb",&isxdb);
246:     PetscStrcmp(PetscDebugger,"dbx",&isdbx);
247:     PetscStrcmp(PetscDebugger,"idb",&isidb);
248:     PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
249:     PetscStrcmp(PetscDebugger,"lldb",&islldb);

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

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

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

391: /*@C
392:    PetscAttachDebuggerErrorHandler - Error handler that attaches
393:    a debugger to a running process when an error is detected.
394:    This routine is useful for examining variables, etc.

396:    Not Collective

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

407:    Options Database Keys:
408: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
409:    debugger attachment

411:    Level: developer

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

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

422:    Notes for experienced users:
423:    Use PetscPushErrorHandler() to set the desired error handler.  The
424:    currently available PETSc error handlers are
425: $    PetscTraceBackErrorHandler()
426: $    PetscAttachDebuggerErrorHandler()
427: $    PetscAbortErrorHandler()
428:    or you may write your own.


431: .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
432:            PetscAbortErrorHandler()
433: @*/
434: PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
435: {

439:   if (!fun) fun = "User provided function";
440:   if (!mess) mess = " ";

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

444:   PetscAttachDebugger();
445:   if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
446:   return(0);
447: }

449: /*@C
450:    PetscStopForDebugger - Prints a message to the screen indicating how to
451:          attach to the process with the debugger and then waits for the
452:          debugger to attach.

454:    Not Collective

456:    Level: developer

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

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

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

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

489:   PetscGetProgramName(program,256);
490:   if (ierr) {
491:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
492:     return(0);
493:   }
494:   if (!program[0]) {
495:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
496:     return(0);
497:   }

499:   ppid = getpid();

501:   PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
502:   PetscStrcmp(PetscDebugger,"ddd",&isddd);
503:   PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
504:   PetscStrcmp(PetscDebugger,"ups",&isups);
505:   PetscStrcmp(PetscDebugger,"xldb",&isxldb);
506:   PetscStrcmp(PetscDebugger,"xdb",&isxdb);
507:   PetscStrcmp(PetscDebugger,"dbx",&isdbx);
508:   PetscStrcmp(PetscDebugger,"lldb",&islldb);

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

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

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