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