Actual source code: adebug.c
petsc-3.7.1 2016-05-15
Report Typos and Errors

      1: /*
      2:       Code to handle PETSc starting up in debuggers,etc.
      3: */

      5: #include <petscsys.h>               /*I   "petscsys.h"   I*/
      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;

     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".

     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:    Concepts: debugger^setting

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

     53:   PetscStrcpy(DebugTerminal,terminal);
     54:   return(0);
     55: }

     59: /*@C
     60:    PetscSetDebugger - Sets options associated with the debugger.

     62:    Not Collective

     64:    Input Parameters:
     65: +  debugger - name of debugger, which should be in your path,
     66:               usually "lldb", "dbx", "gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
     67:               supports "xdb", and IBM rs6000 supports "xldb".

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

     74:    Level: developer

     76:    Fortran Note:
     77:    This routine is not supported in Fortran.

     79:   Concepts: debugger^setting

     81: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
     82: @*/
     83: PetscErrorCode  PetscSetDebugger(const char debugger[],PetscBool xterm)
     84: {

     88:   if (debugger) {
     89:     PetscStrcpy(PetscDebugger,debugger);
     90:   }
     91:   Xterm = xterm;
     92:   return(0);
     93: }

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

    100:    Not collective

    102:     Level: developer

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

    111: #if defined(PETSC_USE_LLDB_DEBUGGER)
    112:   PetscSetDebugger("lldb",PETSC_TRUE);
    113: #elif defined(PETSC_USE_DBX_DEBUGGER)
    114:   PetscSetDebugger("dbx",PETSC_TRUE);
    115: #elif defined(PETSC_USE_XDB_DEBUGGER)
    116:   PetscSetDebugger("xdb",PETSC_TRUE);
    117: #elif defined(PETSC_USE_IDB_DEBUGGER)
    118:   PetscSetDebugger("idb",PETSC_TRUE);
    119: #else  /* Default is gdb */
    120:   PetscSetDebugger("gdb",PETSC_TRUE);
    121: #endif
    122:   PetscSetDebugTerminal("xterm -e");
    123:   return(0);
    124: }

    129: {
    130:   PetscBool      exists;
    131:   char           *f;

    135:   PetscStrstr(string, defaultDbg, &f);
    136:   if (f) {
    137:     PetscTestFile(string, 'x', &exists);
    138:     if (exists) *debugger = string;
    139:     else        *debugger = defaultDbg;
    140:   }
    141:   return(0);
    142: }

    146: /*@C
    147:     PetscSetDebuggerFromString - Set the complete path for the
    148:        debugger for PETSc to use.

    150:    Not collective

    152:    Level: developer

    154: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
    155: @*/
    156: PetscErrorCode  PetscSetDebuggerFromString(const char *string)
    157: {
    158:   const char     *debugger = NULL;
    159:   PetscBool      xterm     = PETSC_TRUE;
    160:   char           *f;

    164:   PetscStrstr(string, "noxterm", &f);
    165:   if (f) xterm = PETSC_FALSE;
    166:   PetscStrstr(string, "ddd", &f);
    167:   if (f) xterm = PETSC_FALSE;

    182:   PetscSetDebugger(debugger, xterm);
    183:   return(0);
    184: }

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

    192:    Not Collective

    194:    Level: advanced

    196:    Concepts: debugger^starting from program

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

    200: .seealso: PetscSetDebugger()
    201: @*/
    202: PetscErrorCode  PetscAttachDebugger(void)
    203: {
    204: #if !defined(PETSC_CANNOT_START_DEBUGGER)
    205:   int            child    =0;
    206:   PetscReal      sleeptime=0;
    208:   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
    209: #endif

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

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

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

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

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

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

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

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

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

    414:    Not Collective

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

    426:    Options Database Keys:
    427: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
    428:    debugger attachment

    430:    Level: developer

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

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

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

    449:    Concepts: debugger^error handler
    450:    Concepts: error handler^attach debugger

    452: .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
    453:            PetscAbortErrorHandler()
    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: }

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

    477:    Not Collective

    479:    Level: developer

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

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

    485:    Concepts: debugger^waiting for attachment

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

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

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

    522:   ppid = getpid();

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

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

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

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