Date: 2015-10-02T21:59:31+00:00

Actual source code: adebug.c
petsc-3.6.2 2015-10-02
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:      mpirun -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:       (*PetscErrorPrintf)("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:       (*PetscErrorPrintf)("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:       (*PetscErrorPrintf)("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:       (*PetscErrorPrintf)("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: #endif
    357:         args[j++] = 0;
    358:       }
    359:       if (Xterm) {
    360:         if (display[0]) (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
    361:         else            (*PetscErrorPrintf)("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);

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

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

    411:    Not Collective

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

    423:    Options Database Keys:
    424: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
    425:    debugger attachment

    427:    Level: developer

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

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

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

    446:    Concepts: debugger^error handler
    447:    Concepts: error handler^attach debugger

    449: .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
    450:            PetscAbortErrorHandler()
    451: @*/
    452: PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
    453: {

    457:   if (!fun) fun = "User provided function";
    458:   if (!mess) mess = " ";

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

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

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

    474:    Not Collective

    476:    Level: developer

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

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

    482:    Concepts: debugger^waiting for attachment

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

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

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

    519:   ppid = getpid();

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

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

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

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