xref: /petsc/src/sys/error/adebug.c (revision c4fb7a8faa9008c2d37977d21987dcfe54952390)
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", "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 = 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("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)
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,128);CHKERRQ(ierr);
195   ierr = PetscGetProgramName(program,PETSC_MAX_PATH_LEN);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,64);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] = 0;
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] = 0;
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] = 0;
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] = 0;
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++] = 0;
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++] = 0;
307       }
308       if (islldb) {
309         j = jj;
310         args[j++] = "-p";
311         args[j++] = pid;
312         args[j++] = 0;
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++] = 0;
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,256);
477   if (ierr) {
478     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
479     PetscFunctionReturn(0);
480   }
481 
482   ierr = PetscGetProgramName(program,256);
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