1 /* 2 Code to handle PETSc starting up in debuggers,etc. 3 */ 4 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 10 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; 17 18 /*@C 19 PetscSetDebugTerminal - Sets the terminal to use (instead of xterm) for debugging. 20 21 Not Collective 22 23 Input Parameters: 24 + terminal - name of terminal and any flags required to execute a program. 25 For example "xterm -e", "urxvt -e". 26 27 Options Database Keys: 28 -debug_terminal terminal - use this terminal instead of xterm 29 30 Level: developer 31 32 Notes: 33 You can start the debugger for all processes in the same GNU screen session. 34 35 mpiexec -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen" 36 37 will open 4 windows in the session named "debug". 38 39 Fortran Note: 40 This routine is not supported in Fortran. 41 42 Concepts: debugger^setting 43 44 .seealso: PetscSetDebugger() 45 @*/ 46 PetscErrorCode PetscSetDebugTerminal(const char terminal[]) 47 { 48 PetscErrorCode ierr; 49 50 PetscFunctionBegin; 51 ierr = PetscStrcpy(DebugTerminal,terminal);CHKERRQ(ierr); 52 PetscFunctionReturn(0); 53 } 54 55 /*@C 56 PetscSetDebugger - Sets options associated with the debugger. 57 58 Not Collective 59 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". 64 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.) 69 70 Level: developer 71 72 Fortran Note: 73 This routine is not supported in Fortran. 74 75 Concepts: debugger^setting 76 77 .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler() 78 @*/ 79 PetscErrorCode PetscSetDebugger(const char debugger[],PetscBool xterm) 80 { 81 PetscErrorCode ierr; 82 83 PetscFunctionBegin; 84 if (debugger) { 85 ierr = PetscStrcpy(PetscDebugger,debugger);CHKERRQ(ierr); 86 } 87 Xterm = xterm; 88 PetscFunctionReturn(0); 89 } 90 91 /*@C 92 PetscSetDefaultDebugger - Causes PETSc to use its default debugger. 93 94 Not collective 95 96 Level: developer 97 98 .seealso: PetscSetDebugger(), PetscSetDebuggerFromString() 99 @*/ 100 PetscErrorCode PetscSetDefaultDebugger(void) 101 { 102 PetscErrorCode ierr; 103 104 PetscFunctionBegin; 105 #if defined(PETSC_USE_LLDB_DEBUGGER) 106 ierr = PetscSetDebugger("lldb",PETSC_TRUE);CHKERRQ(ierr); 107 #elif defined(PETSC_USE_DBX_DEBUGGER) 108 ierr = PetscSetDebugger("dbx",PETSC_TRUE);CHKERRQ(ierr); 109 #elif defined(PETSC_USE_XDB_DEBUGGER) 110 ierr = PetscSetDebugger("xdb",PETSC_TRUE);CHKERRQ(ierr); 111 #elif defined(PETSC_USE_IDB_DEBUGGER) 112 ierr = PetscSetDebugger("idb",PETSC_TRUE);CHKERRQ(ierr); 113 #else /* Default is gdb */ 114 ierr = PetscSetDebugger("gdb",PETSC_TRUE);CHKERRQ(ierr); 115 #endif 116 ierr = PetscSetDebugTerminal("xterm -e");CHKERRQ(ierr); 117 PetscFunctionReturn(0); 118 } 119 120 static PetscErrorCode PetscCheckDebugger_Private(const char defaultDbg[], const char string[], const char *debugger[]) 121 { 122 PetscBool exists; 123 char *f; 124 PetscErrorCode ierr; 125 126 PetscFunctionBegin; 127 ierr = PetscStrstr(string, defaultDbg, &f);CHKERRQ(ierr); 128 if (f) { 129 ierr = PetscTestFile(string, 'x', &exists);CHKERRQ(ierr); 130 if (exists) *debugger = string; 131 else *debugger = defaultDbg; 132 } 133 PetscFunctionReturn(0); 134 } 135 136 /*@C 137 PetscSetDebuggerFromString - Set the complete path for the 138 debugger for PETSc to use. 139 140 Not collective 141 142 Level: developer 143 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; 151 PetscErrorCode ierr; 152 153 PetscFunctionBegin; 154 ierr = PetscStrstr(string, "noxterm", &f);CHKERRQ(ierr); 155 if (f) xterm = PETSC_FALSE; 156 ierr = PetscStrstr(string, "ddd", &f);CHKERRQ(ierr); 157 if (f) xterm = PETSC_FALSE; 158 ierr = PetscCheckDebugger_Private("xdb", string, &debugger);CHKERRQ(ierr); 159 ierr = PetscCheckDebugger_Private("dbx", string, &debugger);CHKERRQ(ierr); 160 ierr = PetscCheckDebugger_Private("xldb", string, &debugger);CHKERRQ(ierr); 161 ierr = PetscCheckDebugger_Private("gdb", string, &debugger);CHKERRQ(ierr); 162 ierr = PetscCheckDebugger_Private("idb", string, &debugger);CHKERRQ(ierr); 163 ierr = PetscCheckDebugger_Private("xxgdb", string, &debugger);CHKERRQ(ierr); 164 ierr = PetscCheckDebugger_Private("ddd", string, &debugger);CHKERRQ(ierr); 165 ierr = PetscCheckDebugger_Private("kdbg", string, &debugger);CHKERRQ(ierr); 166 ierr = PetscCheckDebugger_Private("ups", string, &debugger);CHKERRQ(ierr); 167 ierr = PetscCheckDebugger_Private("workshop", string, &debugger);CHKERRQ(ierr); 168 ierr = PetscCheckDebugger_Private("pgdbg", string, &debugger);CHKERRQ(ierr); 169 ierr = PetscCheckDebugger_Private("pathdb", string, &debugger);CHKERRQ(ierr); 170 ierr = PetscCheckDebugger_Private("lldb", string, &debugger);CHKERRQ(ierr); 171 172 ierr = PetscSetDebugger(debugger, xterm);CHKERRQ(ierr); 173 PetscFunctionReturn(0); 174 } 175 176 177 /*@ 178 PetscAttachDebugger - Attaches the debugger to the running process. 179 180 Not Collective 181 182 Level: advanced 183 184 Concepts: debugger^starting from program 185 186 Developer Notes: Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()? 187 188 .seealso: PetscSetDebugger() 189 @*/ 190 PetscErrorCode PetscAttachDebugger(void) 191 { 192 #if !defined(PETSC_CANNOT_START_DEBUGGER) 193 int child =0; 194 PetscReal sleeptime=0; 195 PetscErrorCode ierr; 196 char program[PETSC_MAX_PATH_LEN],display[256],hostname[64]; 197 #endif 198 199 PetscFunctionBegin; 200 #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK) 201 (*PetscErrorPrintf)("System cannot start debugger\n"); 202 (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n"); 203 (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n"); 204 MPI_Abort(PETSC_COMM_WORLD,1); 205 #else 206 ierr = PetscGetDisplay(display,128);CHKERRQ(ierr); 207 ierr = PetscGetProgramName(program,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 208 if (ierr) { 209 (*PetscErrorPrintf)("Cannot determine program name\n"); 210 PetscFunctionReturn(1); 211 } 212 if (!program[0]) { 213 (*PetscErrorPrintf)("Cannot determine program name\n"); 214 PetscFunctionReturn(1); 215 } 216 child = (int)fork(); 217 if (child < 0) { 218 (*PetscErrorPrintf)("Error in fork() attaching debugger\n"); 219 PetscFunctionReturn(1); 220 } 221 222 /* 223 Swap role the parent and child. This is (I think) so that control c typed 224 in the debugger goes to the correct process. 225 */ 226 if (child) child = 0; 227 else child = (int)getppid(); 228 229 if (child) { /* I am the parent, will run the debugger */ 230 const char *args[10]; 231 char pid[10]; 232 PetscInt j,jj; 233 PetscBool isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb; 234 235 ierr = PetscGetHostName(hostname,64);CHKERRQ(ierr); 236 /* 237 We need to send a continue signal to the "child" process on the 238 alpha, otherwise it just stays off forever 239 */ 240 #if defined(PETSC_NEED_KILL_FOR_DEBUGGER) 241 kill(child,SIGCONT); 242 #endif 243 sprintf(pid,"%d",child); 244 245 ierr = PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);CHKERRQ(ierr); 246 ierr = PetscStrcmp(PetscDebugger,"ddd",&isddd);CHKERRQ(ierr); 247 ierr = PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);CHKERRQ(ierr); 248 ierr = PetscStrcmp(PetscDebugger,"ups",&isups);CHKERRQ(ierr); 249 ierr = PetscStrcmp(PetscDebugger,"xldb",&isxldb);CHKERRQ(ierr); 250 ierr = PetscStrcmp(PetscDebugger,"xdb",&isxdb);CHKERRQ(ierr); 251 ierr = PetscStrcmp(PetscDebugger,"dbx",&isdbx);CHKERRQ(ierr); 252 ierr = PetscStrcmp(PetscDebugger,"idb",&isidb);CHKERRQ(ierr); 253 ierr = PetscStrcmp(PetscDebugger,"workshop",&isworkshop);CHKERRQ(ierr); 254 ierr = PetscStrcmp(PetscDebugger,"lldb",&islldb);CHKERRQ(ierr); 255 256 if (isxxgdb || isups || isddd) { 257 args[1] = program; args[2] = pid; args[3] = "-display"; 258 args[0] = PetscDebugger; args[4] = display; args[5] = 0; 259 printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname); 260 if (execvp(args[0],(char**)args) < 0) { 261 perror("Unable to start debugger"); 262 exit(0); 263 } 264 } else if (iskdbg) { 265 args[1] = "-p"; args[2] = pid; args[3] = program; args[4] = "-display"; 266 args[0] = PetscDebugger; args[5] = display; args[6] = 0; 267 printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname); 268 if (execvp(args[0],(char**)args) < 0) { 269 perror("Unable to start debugger"); 270 exit(0); 271 } 272 } else if (isxldb) { 273 args[1] = "-a"; args[2] = pid; args[3] = program; args[4] = "-display"; 274 args[0] = PetscDebugger; args[5] = display; args[6] = 0; 275 printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname); 276 if (execvp(args[0],(char**)args) < 0) { 277 perror("Unable to start debugger"); 278 exit(0); 279 } 280 } else if (isworkshop) { 281 args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-"; 282 args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = 0; 283 printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname); 284 if (execvp(args[0],(char**)args) < 0) { 285 perror("Unable to start debugger"); 286 exit(0); 287 } 288 } else { 289 j = 0; 290 if (Xterm) { 291 PetscBool cmp; 292 char *tmp,*tmp1; 293 ierr = PetscStrncmp(DebugTerminal,"screen",6,&cmp);CHKERRQ(ierr); 294 if (cmp) display[0] = 0; /* when using screen, we never pass -display */ 295 args[j++] = tmp = DebugTerminal; 296 if (display[0]) { 297 args[j++] = "-display"; args[j++] = display; 298 } 299 while (*tmp) { 300 ierr = PetscStrchr(tmp,' ',&tmp1);CHKERRQ(ierr); 301 if (!tmp1) break; 302 *tmp1 = 0; 303 tmp = tmp1+1; 304 args[j++] = tmp; 305 } 306 } 307 args[j++] = PetscDebugger; 308 jj = j; 309 args[j++] = program; args[j++] = pid; args[j++] = 0; 310 311 if (isidb) { 312 j = jj; 313 args[j++] = "-pid"; 314 args[j++] = pid; 315 args[j++] = "-gdb"; 316 args[j++] = program; 317 args[j++] = 0; 318 } 319 if (islldb) { 320 j = jj; 321 args[j++] = "-p"; 322 args[j++] = pid; 323 args[j++] = 0; 324 } 325 if (isdbx) { 326 j = jj; 327 #if defined(PETSC_USE_P_FOR_DEBUGGER) 328 args[j++] = "-p"; 329 args[j++] = pid; 330 args[j++] = program; 331 #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER) 332 args[j++] = "-l"; 333 args[j++] = "ALL"; 334 args[j++] = "-P"; 335 args[j++] = pid; 336 args[j++] = program; 337 #elif defined(PETSC_USE_A_FOR_DEBUGGER) 338 args[j++] = "-a"; 339 args[j++] = pid; 340 #elif defined(PETSC_USE_PID_FOR_DEBUGGER) 341 args[j++] = "-pid"; 342 args[j++] = pid; 343 args[j++] = program; 344 #else 345 args[j++] = program; 346 args[j++] = pid; 347 #endif 348 args[j++] = 0; 349 } 350 if (Xterm) { 351 if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname); 352 else printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname); 353 354 if (execvp(args[0],(char**)args) < 0) { 355 perror("Unable to start debugger in xterm"); 356 exit(0); 357 } 358 } else { 359 printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname); 360 if (execvp(args[0],(char**)args) < 0) { 361 perror("Unable to start debugger"); 362 exit(0); 363 } 364 } 365 } 366 } else { /* I am the child, continue with user code */ 367 sleeptime = 10; /* default to sleep waiting for debugger */ 368 ierr = PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);CHKERRQ(ierr); 369 if (sleeptime < 0) sleeptime = -sleeptime; 370 #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP) 371 /* 372 HP cannot attach process to sleeping debugger, hence count instead 373 */ 374 { 375 PetscReal x = 1.0; 376 int i =10000000; 377 while (i--) x++; /* cannot attach to sleeper */ 378 } 379 #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY) 380 /* 381 IBM sleep may return at anytime, hence must see if there is more time to sleep 382 */ 383 { 384 int left = sleeptime; 385 while (left > 0) left = PetscSleep(left) - 1; 386 } 387 #else 388 PetscSleep(sleeptime); 389 #endif 390 } 391 #endif 392 PetscFunctionReturn(0); 393 } 394 395 /*@C 396 PetscAttachDebuggerErrorHandler - Error handler that attaches 397 a debugger to a running process when an error is detected. 398 This routine is useful for examining variables, etc. 399 400 Not Collective 401 402 Input Parameters: 403 + comm - communicator over which error occurred 404 . line - the line number of the error (indicated by __LINE__) 405 . file - the file in which the error was detected (indicated by __FILE__) 406 . message - an error text string, usually just printed to the screen 407 . number - the generic error number 408 . p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT 409 - ctx - error handler context 410 411 Options Database Keys: 412 . -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates 413 debugger attachment 414 415 Level: developer 416 417 Notes: 418 By default the GNU debugger, gdb, is used. Alternatives are lldb, dbx and 419 xxgdb,xldb (on IBM rs6000), xdb (on HP-UX). 420 421 Most users need not directly employ this routine and the other error 422 handlers, but can instead use the simplified interface SETERR, which has 423 the calling sequence 424 $ SETERRQ(PETSC_COMM_SELF,number,p,message) 425 426 Notes for experienced users: 427 Use PetscPushErrorHandler() to set the desired error handler. The 428 currently available PETSc error handlers are 429 $ PetscTraceBackErrorHandler() 430 $ PetscAttachDebuggerErrorHandler() 431 $ PetscAbortErrorHandler() 432 or you may write your own. 433 434 Concepts: debugger^error handler 435 Concepts: error handler^attach debugger 436 437 .seealso: PetscPushErrorHandler(), PetscTraceBackErrorHandler(), 438 PetscAbortErrorHandler() 439 @*/ 440 PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx) 441 { 442 PetscErrorCode ierr; 443 444 PetscFunctionBegin; 445 if (!fun) fun = "User provided function"; 446 if (!mess) mess = " "; 447 448 (*PetscErrorPrintf)("%s() line %d in %s %s\n",fun,line,file,mess); 449 450 ierr = PetscAttachDebugger(); 451 if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */ 452 PetscFunctionReturn(0); 453 } 454 455 /*@C 456 PetscStopForDebugger - Prints a message to the screen indicating how to 457 attach to the process with the debugger and then waits for the 458 debugger to attach. 459 460 Not Collective 461 462 Level: developer 463 464 Notes: This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work. 465 466 Developer Notes: Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()? 467 468 Concepts: debugger^waiting for attachment 469 470 .seealso: PetscSetDebugger(), PetscAttachDebugger() 471 @*/ 472 PetscErrorCode PetscStopForDebugger(void) 473 { 474 PetscErrorCode ierr; 475 PetscInt sleeptime=0; 476 #if !defined(PETSC_CANNOT_START_DEBUGGER) 477 int ppid; 478 PetscMPIInt rank; 479 char program[PETSC_MAX_PATH_LEN],hostname[256]; 480 PetscBool isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb; 481 #endif 482 483 PetscFunctionBegin; 484 #if defined(PETSC_CANNOT_START_DEBUGGER) 485 (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n"); 486 #else 487 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); 488 if (ierr) rank = 0; /* ignore error since this may be already in error handler */ 489 ierr = PetscGetHostName(hostname,256); 490 if (ierr) { 491 (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n"); 492 PetscFunctionReturn(0); 493 } 494 495 ierr = PetscGetProgramName(program,256); 496 if (ierr) { 497 (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n"); 498 PetscFunctionReturn(0); 499 } 500 if (!program[0]) { 501 (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n"); 502 PetscFunctionReturn(0); 503 } 504 505 ppid = getpid(); 506 507 ierr = PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);CHKERRQ(ierr); 508 ierr = PetscStrcmp(PetscDebugger,"ddd",&isddd);CHKERRQ(ierr); 509 ierr = PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);CHKERRQ(ierr); 510 ierr = PetscStrcmp(PetscDebugger,"ups",&isups);CHKERRQ(ierr); 511 ierr = PetscStrcmp(PetscDebugger,"xldb",&isxldb);CHKERRQ(ierr); 512 ierr = PetscStrcmp(PetscDebugger,"xdb",&isxdb);CHKERRQ(ierr); 513 ierr = PetscStrcmp(PetscDebugger,"dbx",&isdbx);CHKERRQ(ierr); 514 ierr = PetscStrcmp(PetscDebugger,"lldb",&islldb);CHKERRQ(ierr); 515 516 if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid); 517 else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program); 518 else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid); 519 else if (isdbx) { 520 #if defined(PETSC_USE_P_FOR_DEBUGGER) 521 printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program); 522 #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER) 523 printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program); 524 #elif defined(PETSC_USE_A_FOR_DEBUGGER) 525 printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid); 526 #elif defined(PETSC_USE_PID_FOR_DEBUGGER) 527 printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program); 528 #else 529 printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid); 530 #endif 531 } 532 #endif /* PETSC_CANNOT_START_DEBUGGER */ 533 534 fflush(stdout); /* ignore error because may already be in error handler */ 535 536 sleeptime = 25; /* default to sleep waiting for debugger */ 537 PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */ 538 if (sleeptime < 0) sleeptime = -sleeptime; 539 #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP) 540 /* 541 HP cannot attach process to sleeping debugger, hence count instead 542 */ 543 { 544 PetscReal x = 1.0; 545 int i =10000000; 546 while (i--) x++; /* cannot attach to sleeper */ 547 } 548 #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY) 549 /* 550 IBM sleep may return at anytime, hence must see if there is more time to sleep 551 */ 552 { 553 int left = sleeptime; 554 while (left > 0) left = sleep(left) - 1; 555 } 556 #else 557 PetscSleep(sleeptime); 558 #endif 559 PetscFunctionReturn(0); 560 } 561 562 563 564