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