xref: /petsc/src/sys/error/adebug.c (revision bef158480efac06de457f7a665168877ab3c2fd7)
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