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