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 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: 187 Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()? 188 189 .seealso: PetscSetDebugger() 190 @*/ 191 PetscErrorCode PetscAttachDebugger(void) 192 { 193 #if !defined(PETSC_CANNOT_START_DEBUGGER) 194 int child =0; 195 PetscReal sleeptime=0; 196 PetscErrorCode ierr; 197 char program[PETSC_MAX_PATH_LEN],display[256],hostname[64]; 198 #endif 199 200 PetscFunctionBegin; 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 ierr = PetscGetDisplay(display,128);CHKERRQ(ierr); 208 ierr = PetscGetProgramName(program,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 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 } 222 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(); 229 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; 235 236 ierr = PetscGetHostName(hostname,64);CHKERRQ(ierr); 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); 245 246 ierr = PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);CHKERRQ(ierr); 247 ierr = PetscStrcmp(PetscDebugger,"ddd",&isddd);CHKERRQ(ierr); 248 ierr = PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);CHKERRQ(ierr); 249 ierr = PetscStrcmp(PetscDebugger,"ups",&isups);CHKERRQ(ierr); 250 ierr = PetscStrcmp(PetscDebugger,"xldb",&isxldb);CHKERRQ(ierr); 251 ierr = PetscStrcmp(PetscDebugger,"xdb",&isxdb);CHKERRQ(ierr); 252 ierr = PetscStrcmp(PetscDebugger,"dbx",&isdbx);CHKERRQ(ierr); 253 ierr = PetscStrcmp(PetscDebugger,"idb",&isidb);CHKERRQ(ierr); 254 ierr = PetscStrcmp(PetscDebugger,"workshop",&isworkshop);CHKERRQ(ierr); 255 ierr = PetscStrcmp(PetscDebugger,"lldb",&islldb);CHKERRQ(ierr); 256 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 ierr = PetscStrncmp(DebugTerminal,"screen",6,&cmp);CHKERRQ(ierr); 295 if (!cmp) {ierr = PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);CHKERRQ(ierr);} 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 ierr = PetscStrchr(tmp,' ',&tmp1);CHKERRQ(ierr); 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; 312 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); 355 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 ierr = PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);CHKERRQ(ierr); 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 PetscFunctionReturn(0); 395 } 396 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. 401 402 Not Collective 403 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 412 413 Options Database Keys: 414 . -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates 415 debugger attachment 416 417 Level: developer 418 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). 422 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) 427 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. 435 436 Concepts: debugger^error handler 437 Concepts: error handler^attach debugger 438 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 { 444 PetscErrorCode ierr; 445 446 PetscFunctionBegin; 447 if (!fun) fun = "User provided function"; 448 if (!mess) mess = " "; 449 450 (*PetscErrorPrintf)("%s() line %d in %s %s\n",fun,line,file,mess); 451 452 ierr = PetscAttachDebugger(); 453 if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */ 454 PetscFunctionReturn(0); 455 } 456 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. 461 462 Not Collective 463 464 Level: developer 465 466 Notes: 467 This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work. 468 469 Developer Notes: 470 Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()? 471 472 Concepts: debugger^waiting for attachment 473 474 .seealso: PetscSetDebugger(), PetscAttachDebugger() 475 @*/ 476 PetscErrorCode PetscStopForDebugger(void) 477 { 478 PetscErrorCode ierr; 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 486 487 PetscFunctionBegin; 488 #if defined(PETSC_CANNOT_START_DEBUGGER) 489 (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n"); 490 #else 491 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); 492 if (ierr) rank = 0; /* ignore error since this may be already in error handler */ 493 ierr = PetscGetHostName(hostname,256); 494 if (ierr) { 495 (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n"); 496 PetscFunctionReturn(0); 497 } 498 499 ierr = PetscGetProgramName(program,256); 500 if (ierr) { 501 (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n"); 502 PetscFunctionReturn(0); 503 } 504 if (!program[0]) { 505 (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n"); 506 PetscFunctionReturn(0); 507 } 508 509 ppid = getpid(); 510 511 ierr = PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);CHKERRQ(ierr); 512 ierr = PetscStrcmp(PetscDebugger,"ddd",&isddd);CHKERRQ(ierr); 513 ierr = PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);CHKERRQ(ierr); 514 ierr = PetscStrcmp(PetscDebugger,"ups",&isups);CHKERRQ(ierr); 515 ierr = PetscStrcmp(PetscDebugger,"xldb",&isxldb);CHKERRQ(ierr); 516 ierr = PetscStrcmp(PetscDebugger,"xdb",&isxdb);CHKERRQ(ierr); 517 ierr = PetscStrcmp(PetscDebugger,"dbx",&isdbx);CHKERRQ(ierr); 518 ierr = PetscStrcmp(PetscDebugger,"lldb",&islldb);CHKERRQ(ierr); 519 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 */ 537 538 fflush(stdout); /* ignore error because may already be in error handler */ 539 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 PetscFunctionReturn(0); 564 } 565 566 567 568