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