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