Actual source code: adebug.c
petsc-3.10.5 2019-03-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: }