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