xref: /petsc/src/sys/error/adebug.c (revision 2964b3c706eaac6d923cbc6619131dd4c069f845)
1 #define PETSC_DLL
2 /*
3       Code to handle PETSc starting up in debuggers,etc.
4 */
5 
6 #include "petsc.h"               /*I   "petsc.h"   I*/
7 #include <signal.h>
8 #include "petscsys.h"            /*I   "petscsys.h" I*/
9 #if defined(PETSC_HAVE_UNISTD_H)
10 #include <unistd.h>
11 #endif
12 #if defined(PETSC_HAVE_STDLIB_H)
13 #include <stdlib.h>
14 #endif
15 #include "petscfix.h"
16 
17 /*
18       These are the debugger and display used if the debugger is started up
19 */
20 static char       Debugger[PETSC_MAX_PATH_LEN];
21 static PetscTruth Xterm = PETSC_TRUE;
22 
23 #undef __FUNCT__
24 #define __FUNCT__ "PetscSetDebugger"
25 /*@C
26    PetscSetDebugger - Sets options associated with the debugger.
27 
28    Not Collective
29 
30    Input Parameters:
31 +  debugger - name of debugger, which should be in your path,
32               usually "dbx", "gdb", "idb", "xxgdb" or "ddd".  Also, HP-UX
33               supports "xdb", and IBM rs6000 supports "xldb".
34 
35 -  xterm - flag to indicate debugger window, set to either 1 (to indicate
36             debugger should be started in a new xterm) or 0 (to start debugger
37             in initial window (the option 0 makes no sense when using more
38             than one processor.)
39 
40    Level: developer
41 
42    Fortran Note:
43    This routine is not supported in Fortran.
44 
45   Concepts: debugger^setting
46 
47 .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
48 @*/
49 PetscErrorCode PETSC_DLLEXPORT PetscSetDebugger(const char debugger[],PetscTruth xterm)
50 {
51   PetscErrorCode ierr;
52 
53   PetscFunctionBegin;
54   if (debugger) {
55     ierr = PetscStrcpy(Debugger,debugger);CHKERRQ(ierr);
56   }
57   Xterm = xterm;
58 
59   PetscFunctionReturn(0);
60 }
61 
62 #undef __FUNCT__
63 #define __FUNCT__ "PetscSetDefaultDebugger"
64 /*@
65     PetscSetDefaultDebugger - Causes PETSc to use its default
66           debugger.
67 
68    Not collective
69 
70     Level: advanced
71 
72 .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
73 @*/
74 PetscErrorCode PETSC_DLLEXPORT PetscSetDefaultDebugger(void)
75 {
76   PetscErrorCode ierr;
77 
78   PetscFunctionBegin;
79 #if defined(PETSC_USE_DBX_DEBUGGER)
80   ierr = PetscSetDebugger("dbx",PETSC_TRUE);CHKERRQ(ierr);
81 #elif defined(PETSC_USE_XDB_DEBUGGER)
82   ierr = PetscSetDebugger("xdb",PETSC_TRUE);CHKERRQ(ierr);
83 #elif defined(PETSC_USE_IDB_DEBUGGER)
84   ierr = PetscSetDebugger("idb",PETSC_TRUE);CHKERRQ(ierr);
85 #else  /* Default is gdb */
86   ierr = PetscSetDebugger("gdb",PETSC_TRUE);CHKERRQ(ierr);
87 #endif
88   PetscFunctionReturn(0);
89 }
90 
91 #undef __FUNCT__
92 #define __FUNCT__ "PetscCheckDebugger_Private"
93 static PetscErrorCode PetscCheckDebugger_Private(const char defaultDbg[], const char string[], const char *debugger[])
94 {
95   PetscTruth exists;
96   char      *f;
97   PetscErrorCode ierr;
98 
99   PetscFunctionBegin;
100   ierr = PetscStrstr(string, defaultDbg, &f);CHKERRQ(ierr);
101   if (f) {
102     ierr = PetscTestFile(string, 'x', &exists);CHKERRQ(ierr);
103     if (exists) {
104       *debugger = string;
105     } else {
106       *debugger = defaultDbg;
107     }
108   }
109   PetscFunctionReturn(0);
110 }
111 
112 #undef __FUNCT__
113 #define __FUNCT__ "PetscSetDebuggerFromString"
114 /*@C
115     PetscSetDebuggerFromString - Set the complete path for the
116        debugger for PETSc to use.
117 
118    Not collective
119 
120    Level: advanced
121 
122 .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
123 @*/
124 PetscErrorCode PETSC_DLLEXPORT PetscSetDebuggerFromString(char *string)
125 {
126   const char *debugger = PETSC_NULL;
127   PetscTruth  xterm    = PETSC_TRUE;
128   char       *f;
129   PetscErrorCode ierr;
130 
131   PetscFunctionBegin;
132   ierr = PetscStrstr(string, "noxterm", &f);CHKERRQ(ierr);
133   if (f) xterm = PETSC_FALSE;
134   ierr = PetscStrstr(string, "ddd", &f);CHKERRQ(ierr);
135   if (f) xterm = PETSC_FALSE;
136   ierr = PetscCheckDebugger_Private("xdb",      string, &debugger);CHKERRQ(ierr);
137   ierr = PetscCheckDebugger_Private("dbx",      string, &debugger);CHKERRQ(ierr);
138   ierr = PetscCheckDebugger_Private("xldb",     string, &debugger);CHKERRQ(ierr);
139   ierr = PetscCheckDebugger_Private("gdb",      string, &debugger);CHKERRQ(ierr);
140   ierr = PetscCheckDebugger_Private("idb",      string, &debugger);CHKERRQ(ierr);
141   ierr = PetscCheckDebugger_Private("xxgdb",    string, &debugger);CHKERRQ(ierr);
142   ierr = PetscCheckDebugger_Private("ddd",      string, &debugger);CHKERRQ(ierr);
143   ierr = PetscCheckDebugger_Private("ups",      string, &debugger);CHKERRQ(ierr);
144   ierr = PetscCheckDebugger_Private("workshop", string, &debugger);CHKERRQ(ierr);
145   ierr = PetscCheckDebugger_Private("pgdbg",    string, &debugger);CHKERRQ(ierr);
146 
147   ierr = PetscSetDebugger(debugger, xterm);CHKERRQ(ierr);
148   PetscFunctionReturn(0);
149 }
150 
151 
152 #undef __FUNCT__
153 #define __FUNCT__ "PetscAttachDebugger"
154 /*@
155    PetscAttachDebugger - Attaches the debugger to the running process.
156 
157    Not Collective
158 
159    Level: advanced
160 
161    Concepts: debugger^starting from program
162 
163 .seealso: PetscSetDebugger()
164 @*/
165 PetscErrorCode PETSC_DLLEXPORT PetscAttachDebugger(void)
166 {
167 #if !defined(PETSC_CANNOT_START_DEBUGGER)
168   int            child=0;
169   PetscInt       sleeptime=0;
170   PetscErrorCode ierr;
171   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
172 #endif
173 
174   PetscFunctionBegin;
175 
176 #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
177   (*PetscErrorPrintf)("System cannot start debugger\n");
178   (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
179   (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
180   MPI_Finalize();
181   exit(0);
182 #else
183   ierr = PetscGetDisplay(display,128);CHKERRQ(ierr);
184   ierr = PetscGetProgramName(program,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
185   if (ierr) {
186     (*PetscErrorPrintf)("Cannot determine program name\n");
187     PetscFunctionReturn(1);
188   }
189   if (!program[0]) {
190     (*PetscErrorPrintf)("Cannot determine program name\n");
191     PetscFunctionReturn(1);
192   }
193   child = (int)fork();
194   if (child < 0) {
195     (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
196     PetscFunctionReturn(1);
197   }
198 
199   /*
200       Swap role the parent and child. This is (I think) so that control c typed
201     in the debugger goes to the correct process.
202   */
203   if (child) { child = 0; }
204   else       { child = (int)getppid(); }
205 
206   if (child) { /* I am the parent, will run the debugger */
207     const char *args[10];
208     char       pid[10];
209     PetscTruth isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd;
210 
211     ierr = PetscGetHostName(hostname,64);CHKERRQ(ierr);
212     /*
213          We need to send a continue signal to the "child" process on the
214        alpha, otherwise it just stays off forever
215     */
216 #if defined (PETSC_NEED_KILL_FOR_DEBUGGER)
217     kill(child,SIGCONT);
218 #endif
219     sprintf(pid,"%d",child);
220 
221     ierr = PetscStrcmp(Debugger,"xxgdb",&isxxgdb);CHKERRQ(ierr);
222     ierr = PetscStrcmp(Debugger,"ddd",&isddd);CHKERRQ(ierr);
223     ierr = PetscStrcmp(Debugger,"ups",&isups);CHKERRQ(ierr);
224     ierr = PetscStrcmp(Debugger,"xldb",&isxldb);CHKERRQ(ierr);
225     ierr = PetscStrcmp(Debugger,"xdb",&isxdb);CHKERRQ(ierr);
226     ierr = PetscStrcmp(Debugger,"dbx",&isdbx);CHKERRQ(ierr);
227     ierr = PetscStrcmp(Debugger,"idb",&isidb);CHKERRQ(ierr);
228     ierr = PetscStrcmp(Debugger,"workshop",&isworkshop);CHKERRQ(ierr);
229 
230     if (isxxgdb || isups || isddd) {
231       args[1] = program; args[2] = pid; args[3] = "-display";
232       args[0] = Debugger; args[4] = display; args[5] = 0;
233       (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
234       if (execvp(args[0],(char**)args)  < 0) {
235         perror("Unable to start debugger");
236         exit(0);
237       }
238     } else if (isxldb) {
239       args[1] = "-a"; args[2] = pid; args[3] = program;  args[4] = "-display";
240       args[0] = Debugger; args[5] = display; args[6] = 0;
241       (*PetscErrorPrintf)("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
242       if (execvp(args[0],(char**)args)  < 0) {
243         perror("Unable to start debugger");
244         exit(0);
245       }
246     } else if (isworkshop) {
247       args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
248       args[0] = Debugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = 0;
249       (*PetscErrorPrintf)("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
250       if (execvp(args[0],(char**)args)  < 0) {
251         perror("Unable to start debugger");
252         exit(0);
253       }
254     } else if (!Xterm) {
255       args[1] = program; args[2] = pid; args[3] = 0;
256       args[0] = Debugger;
257       if (isidb) {
258         args[1] = "-pid";
259         args[2] = pid;
260         args[3] = "-gdb";
261         args[4] = program;
262         args[5] = 0;
263       }
264 #if defined(PETSC_USE_P_FOR_DEBUGGER)
265       if (isdbx) {
266         args[1] = "-p";
267         args[2] = pid;
268         args[3] = program;
269         args[4] = 0;
270       }
271 #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
272       if (isxdb) {
273         args[1] = "-l";
274         args[2] = "ALL";
275         args[3] = "-P";
276         args[4] = pid;
277         args[5] = program;
278         args[6] = 0;
279       }
280 #elif defined(PETSC_USE_A_FOR_DEBUGGER)
281       if (isdbx) {
282         args[1] = "-a";
283         args[2] = pid;
284         args[3] = 0;
285       }
286 #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
287       if (isdbx) {
288         args[1] = "-pid";
289         args[2] = pid;
290         args[3] = program;
291         args[4] = 0;
292       }
293 #endif
294       (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on %s\n",Debugger,program,pid,hostname);
295       if (execvp(args[0],(char**)args)  < 0) {
296         perror("Unable to start debugger");
297         exit(0);
298       }
299     } else {
300       if (!display[0]) {
301         args[0] = "xterm";  args[1] = "-e";
302         args[2] = Debugger; args[3] = program;
303         args[4] = pid;      args[5] = 0;
304         if (isidb) {
305           args[3] = "-gdb";
306           args[4] = pid;
307           args[5] = "-gdb";
308           args[6] = program;
309           args[7] = 0;
310         }
311 #if defined(PETSC_USE_P_FOR_DEBUGGER)
312         if (isdbx) {
313           args[3] = "-p";
314           args[4] = pid;
315           args[5] = program;
316           args[6] = 0;
317         }
318 #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
319         if (isxdb) {
320           args[5] = program;
321           args[3] = "-P";
322           args[4] = pid;
323           args[6] = 0;
324         }
325 #elif defined(PETSC_USE_A_FOR_DEBUGGER)
326         if (isdbx) {
327           args[3] = "-a";
328           args[4] = pid;
329           args[5] = 0;
330         }
331 #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
332       if (isdbx) {
333         args[3] = "-pid";
334         args[4] = pid;
335         args[5] = program;
336         args[6] = 0;
337       }
338 #endif
339       (*PetscErrorPrintf)("PETSC: Attaching %s to %s on pid %s on %s\n",Debugger,program,pid,hostname);
340       } else {
341         args[0] = "xterm";  args[1] = "-display";
342         args[2] = display;  args[3] = "-e";
343         args[4] = Debugger; args[5] = program;
344         args[6] = pid;      args[7] = 0;
345         if (isidb) {
346           args[5] = "-pid";
347           args[6] = pid;
348           args[7] = "-gdb";
349           args[8] = program;
350           args[9] = 0;
351         }
352 #if defined(PETSC_USE_P_FOR_DEBUGGER)
353         if (isdbx) {
354           args[5] = "-p";
355           args[6] = pid;
356           args[7] = program;
357           args[8] = 0;
358         }
359 #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
360         if (isxdb) {
361           args[7] = program;
362           args[5] = "-P";
363           args[6] = pid;
364           args[8] = 0;
365         }
366 #elif defined(PETSC_USE_A_FOR_DEBUGGER)
367         if (isdbx) {
368           args[5] = "-a";
369           args[6] = pid;
370           args[7] = 0;
371         }
372 #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
373       if (isdbx) {
374         args[5] = "-pid";
375         args[6] = pid;
376         args[7] = program;
377         args[8] = 0;
378       }
379 #endif
380       (*PetscErrorPrintf)("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",Debugger,program,pid,display,hostname);
381       }
382 
383       if (execvp("xterm",(char**)args)  < 0) {
384         perror("Unable to start debugger in xterm");
385         exit(0);
386       }
387     }
388   } else {   /* I am the child, continue with user code */
389     sleeptime = 10; /* default to sleep waiting for debugger */
390     ierr = PetscOptionsGetInt(PETSC_NULL,"-debugger_pause",&sleeptime,PETSC_NULL);CHKERRQ(ierr);
391     if (sleeptime < 0) sleeptime = -sleeptime;
392 #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
393     /*
394         HP cannot attach process to sleeping debugger, hence count instead
395     */
396     {
397       PetscReal x = 1.0;
398       int i=10000000;
399       while (i--) x++ ; /* cannot attach to sleeper */
400     }
401 #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
402     /*
403         IBM sleep may return at anytime, hence must see if there is more time to sleep
404     */
405     {
406       int left = sleeptime;
407       while (left > 0) {left = PetscSleep(left) - 1;}
408     }
409 #else
410     PetscSleep(sleeptime);
411 #endif
412   }
413 #endif
414   PetscFunctionReturn(0);
415 }
416 
417 #undef __FUNCT__
418 #define __FUNCT__ "PetscAttachDebuggerErrorHandler"
419 /*@C
420    PetscAttachDebuggerErrorHandler - Error handler that attaches
421    a debugger to a running process when an error is detected.
422    This routine is useful for examining variables, etc.
423 
424    Not Collective
425 
426    Input Parameters:
427 +  line - the line number of the error (indicated by __LINE__)
428 .  fun - function where error occured (indicated by __FUNCT__)
429 .  file - the file in which the error was detected (indicated by __FILE__)
430 .  dir - the directory of the file (indicated by __SDIR__)
431 .  message - an error text string, usually just printed to the screen
432 .  number - the generic error number
433 .  p - the specific error number
434 -  ctx - error handler context
435 
436    Options Database Keys:
437 .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
438    debugger attachment
439 
440    Level: developer
441 
442    Notes:
443    By default the GNU debugger, gdb, is used.  Alternatives are dbx and
444    xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
445 
446    Most users need not directly employ this routine and the other error
447    handlers, but can instead use the simplified interface SETERR, which has
448    the calling sequence
449 $     SETERRQ(number,p,message)
450 
451    Notes for experienced users:
452    Use PetscPushErrorHandler() to set the desired error handler.  The
453    currently available PETSc error handlers are
454 $    PetscTraceBackErrorHandler()
455 $    PetscAttachDebuggerErrorHandler()
456 $    PetscAbortErrorHandler()
457    or you may write your own.
458 
459    Concepts: debugger^error handler
460    Concepts: error handler^attach debugger
461 
462 .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
463            PetscAbortErrorHandler()
464 @*/
465 PetscErrorCode PETSC_DLLEXPORT PetscAttachDebuggerErrorHandler(int line,const char* fun,const char *file,const char* dir,int num,int p,const char* mess,void *ctx)
466 {
467   PetscErrorCode ierr;
468 
469   PetscFunctionBegin;
470   if (!fun)  fun = "User provided function";
471   if (!dir)  dir = " ";
472   if (!mess) mess = " ";
473 
474   (*PetscErrorPrintf)("%s() line %d in %s%s %s\n",fun,line,dir,file,mess);
475 
476   ierr = PetscAttachDebugger();
477   if (ierr) { /* hopeless so get out */
478     MPI_Finalize();
479     exit(num);
480   }
481   PetscFunctionReturn(0);
482 }
483 
484 #undef __FUNCT__
485 #define __FUNCT__ "PetscStopForDebugger"
486 /*@C
487    PetscStopForDebugger - Prints a message to the screen indicating how to
488          attach to the process with the debugger and then waits for the
489          debugger to attach.
490 
491    Not Collective
492 
493    Level: advanced
494 
495    Concepts: debugger^waiting for attachment
496 
497 .seealso: PetscSetDebugger(), PetscAttachDebugger()
498 @*/
499 PetscErrorCode PETSC_DLLEXPORT PetscStopForDebugger(void)
500 {
501   PetscErrorCode ierr;
502   PetscInt       sleeptime=0;
503 #if !defined(PETSC_CANNOT_START_DEBUGGER)
504   int            ppid;
505   PetscMPIInt    rank;
506   char           program[PETSC_MAX_PATH_LEN],hostname[256];
507   PetscTruth     isdbx,isxldb,isxxgdb,isddd,isups,isxdb;
508 #endif
509 
510   PetscFunctionBegin;
511 #if defined(PETSC_CANNOT_START_DEBUGGER)
512   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
513 #else
514   ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
515   ierr = PetscGetHostName(hostname,256);
516   if (ierr) {
517     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
518     PetscFunctionReturn(0);
519   }
520 
521   ierr = PetscGetProgramName(program,256);
522   if (ierr) {
523     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
524     PetscFunctionReturn(0);
525   }
526   if (!program[0]) {
527     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
528     PetscFunctionReturn(0);
529   }
530 
531   ppid = getpid();
532 
533   ierr = PetscStrcmp(Debugger,"xxgdb",&isxxgdb);CHKERRQ(ierr);
534   ierr = PetscStrcmp(Debugger,"ddd",&isddd);CHKERRQ(ierr);
535   ierr = PetscStrcmp(Debugger,"ups",&isups);CHKERRQ(ierr);
536   ierr = PetscStrcmp(Debugger,"xldb",&isxldb);CHKERRQ(ierr);
537   ierr = PetscStrcmp(Debugger,"xdb",&isxdb);CHKERRQ(ierr);
538   ierr = PetscStrcmp(Debugger,"dbx",&isdbx);CHKERRQ(ierr);
539 
540   if (isxxgdb || isups || isddd ) {
541     (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,Debugger,program,ppid);
542   }
543 #if defined(PETSC_USE_A_FOR_DEBUGGER)
544   else if (isxldb) {
545     (*PetscErrorPrintf)("{%d]%s>>%s -a %d %s\n",rank,hostname,Debugger,ppid,program);
546   }
547 #endif
548 #if defined(PETSC_USE_P_FOR_DEBUGGER)
549   else if (isdbx) {
550     (*PetscErrorPrintf)("[%d]%s>>%s -p %d %s\n",rank,hostname,Debugger,ppid,program);
551   }
552 #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
553   else if (isxdb) {
554     (*PetscErrorPrintf)("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,Debugger,ppid,program);
555   }
556 #elif defined(PETSC_USE_A_FOR_DEBUGGER)
557   else if (isdbx) {
558     (*PetscErrorPrintf)("[%d]%s>>%s -a %d\n",rank,hostname,Debugger,ppid);
559   }
560 #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
561   else if (isdbx) {
562     (*PetscErrorPrintf)("[%d]%s>>%s -pid %d %s\n",rank,hostname,Debugger,ppid,program);
563   }
564 #else
565   else {
566     (*PetscErrorPrintf)("[%d]%s>>%s %s %d\n",rank,hostname,Debugger,program,ppid);
567   }
568 #endif
569 #endif /* PETSC_CANNOT_START_DEBUGGER */
570 
571   fflush(stdout);
572 
573   sleeptime = 25; /* default to sleep waiting for debugger */
574   ierr = PetscOptionsGetInt(PETSC_NULL,"-debugger_pause",&sleeptime,PETSC_NULL);CHKERRQ(ierr);
575   if (sleeptime < 0) sleeptime = -sleeptime;
576 #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
577   /*
578       HP cannot attach process to sleeping debugger, hence count instead
579   */
580   {
581     PetscReal x = 1.0;
582     int i=10000000;
583     while (i--) x++ ; /* cannot attach to sleeper */
584   }
585 #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
586   /*
587       IBM sleep may return at anytime, hence must see if there is more time to sleep
588   */
589   {
590     int left = sleeptime;
591     while (left > 0) {left = sleep(left) - 1;}
592   }
593 #else
594   PetscSleep(sleeptime);
595 #endif
596   PetscFunctionReturn(0);
597 }
598 
599 
600 
601