1 //
2 // bug.cc
3 //
4 // Copyright (C) 1996 Limit Point Systems, Inc.
5 //
6 // Author: Curtis Janssen <cljanss@limitpt.com>
7 // Maintainer: LPS
8 //
9 // This file is part of the SC Toolkit.
10 //
11 // The SC Toolkit is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; either version 2, or (at your option)
14 // any later version.
15 //
16 // The SC Toolkit is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
23 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // The U.S. Government is granted a limited license as per AL 91-7.
26 //
27 
28 #ifdef __GNUG__
29 #pragma implementation
30 #endif
31 
32 #ifdef HAVE_CONFIG_H
33 #include <scconfig.h>
34 #endif
35 
36 #include <fcntl.h>
37 #ifndef F_SETFD
38 #  define F_SETFD 2
39 #endif
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <iostream>
46 #include <signal.h>
47 
48 #ifdef HAVE_BACKTRACE
49 #  include <execinfo.h>
50 #endif
51 
52 #include <util/keyval/keyval.h>
53 #include <util/misc/bug.h>
54 #include <util/state/stateio.h>
55 
56 // usually in signal.h, but not always.
57 #ifndef NSIG
58 #  define NSIG 100
59 #endif
60 
61 using namespace std;
62 using namespace sc;
63 
64 //////////////////////////////////////////////////////////////////////
65 // static variables
66 
67 static Debugger *signals[NSIG];
68 
69 //////////////////////////////////////////////////////////////////////
70 // static routines
71 
72 extern "C" {
73 #ifdef SIGHASELLIP
74 // required for CC -64 on IRIX 6.0.1 and for gcc on IRIX 5.3
75 typedef RETSIGTYPE (*handler_type)(...);
76 #else
77 typedef RETSIGTYPE (*handler_type)(int);
78 #endif
79 }
80 
81 static void
handler(int sig)82 handler(int sig)
83 {
84   if (signals[sig]) signals[sig]->got_signal(sig);
85 }
86 
87 static void
append(char * cmd,const char * a,int len)88 append(char *cmd, const char *a, int len)
89 {
90   int l = strlen(cmd) + strlen(a)+1;
91   if (l > len) {
92       ExEnv::outn() << "Debugger: command string too long" << endl;
93       abort();
94     }
95   strcat(cmd,a);
96 }
97 
98 static void
append(char * cmd,char a,int len)99 append(char *cmd, char a, int len)
100 {
101   char aa[2];
102   aa[0] = a;
103   aa[1] = '\0';
104   append(cmd, aa, len);
105 }
106 
107 static void
append(char * cmd,int i,int len)108 append(char *cmd, int i, int len)
109 {
110   char a[128];
111   sprintf(a,"%d",i);
112   append(cmd, a, len);
113 }
114 
115 //////////////////////////////////////////////////////////////////////
116 // Debugger class definition
117 
118 Debugger *Debugger::default_debugger_ = 0;
119 
120 static ClassDesc Debugger_cd(
121     typeid(Debugger),"Debugger",1,"public SavableState",
122     0, create<Debugger>, create<Debugger>);
123 
Debugger(const char * exec)124 Debugger::Debugger(const char *exec)
125 {
126   init();
127 
128   prefix_ = new char[1];
129   prefix_[0] = '\0';
130 
131   set_exec(exec);
132 
133   default_cmd();
134 }
135 
Debugger(const Ref<KeyVal> & keyval)136 Debugger::Debugger(const Ref<KeyVal> &keyval)
137 {
138   init();
139 
140   debug_ = keyval->booleanvalue("debug");
141   if (keyval->error() != KeyVal::OK) debug_ = 1;
142 
143   traceback_ = keyval->booleanvalue("traceback");
144   if (keyval->error() != KeyVal::OK) traceback_ = 1;
145 
146   exit_on_signal_ = keyval->booleanvalue("exit");
147   if (keyval->error() != KeyVal::OK) exit_on_signal_ = 1;
148 
149   sleep_ = keyval->intvalue("sleep");
150   if (keyval->error() != KeyVal::OK) sleep_ = 0;
151 
152   wait_for_debugger_ = keyval->booleanvalue("wait_for_debugger");
153   if (keyval->error() != KeyVal::OK) wait_for_debugger_ = 1;
154 
155   cmd_ = keyval->pcharvalue("cmd");
156 
157   prefix_ = keyval->pcharvalue("prefix");
158 
159   handle_sigint_ = keyval->booleanvalue("handle_sigint");
160   if (keyval->error() != KeyVal::OK) handle_sigint_=1;
161 
162   if (keyval->booleanvalue("handle_defaults")) handle_defaults();
163   if (keyval->error() != KeyVal::OK) handle_defaults();
164 
165   if (cmd_ == 0) default_cmd();
166 
167   if (prefix_ == 0) {
168       prefix_ = new char[1];
169       prefix_[0] = '\0';
170     }
171 }
172 
~Debugger()173 Debugger::~Debugger()
174 {
175   delete[] prefix_;
176   delete[] exec_;
177   delete[] cmd_;
178   for (int i=0; i<NSIG; i++) {
179       if (mysigs_[i]) signals[i] = 0;
180     }
181   delete[] mysigs_;
182 }
183 
Debugger(StateIn & s)184 Debugger::Debugger(StateIn&s):
185   SavableState(s)
186 {
187   init();
188 
189   s.getstring(prefix_);
190   s.getstring(exec_);
191   s.getstring(cmd_);
192   s.get(sleep_);
193   s.get(debug_);
194   s.get(traceback_);
195   s.get(exit_on_signal_);
196   s.get(wait_for_debugger_);
197   s.get(handle_sigint_);
198 
199   int i, nsig, tmp;
200   s.get(nsig);
201   for (i=0; i<nsig; i++) {
202       s.get(tmp);
203       handle(tmp);
204     }
205 }
206 
207 void
save_data_state(StateOut & s)208 Debugger::save_data_state(StateOut&s)
209 {
210   s.putstring(prefix_);
211   s.putstring(exec_);
212   s.putstring(cmd_);
213   s.put(sleep_);
214   s.put(debug_);
215   s.put(traceback_);
216   s.put(exit_on_signal_);
217   s.put(wait_for_debugger_);
218   s.put(handle_sigint_);
219 
220   int i, nsig = 0;
221   for (i=0; i<NSIG; i++) if (mysigs_[i]) nsig++;
222   s.put(nsig);
223   for (i=0; i<NSIG; i++) if (mysigs_[i]) s.put(i);
224 }
225 
226 void
init()227 Debugger::init()
228 {
229   exec_ = 0;
230   prefix_ = 0;
231   cmd_ = 0;
232   sleep_ = 0;
233 
234   exit_on_signal_ = 1;
235   traceback_ = 1;
236   debug_ = 1;
237   wait_for_debugger_ = 1;
238 
239   mysigs_ = new int[NSIG];
240   for (int i=0; i<NSIG; i++) {
241       mysigs_[i] = 0;
242     }
243 }
244 
245 void
handle(int sig)246 Debugger::handle(int sig)
247 {
248   if (sig >= NSIG) return;
249 #ifdef HAVE_SIGNAL
250   signal(sig, (handler_type)handler);
251 #endif
252   signals[sig] = this;
253   mysigs_[sig] = 1;
254 }
255 
256 void
handle_defaults()257 Debugger::handle_defaults()
258 {
259 #ifdef SIGSEGV
260   handle(SIGSEGV);
261 #endif
262 #ifdef SIGFPE
263   handle(SIGFPE);
264 #endif
265 #ifdef SIGQUIT
266   handle(SIGQUIT);
267 #endif
268 #ifdef SIGIOT
269   handle(SIGIOT);
270 #endif
271 #ifdef SIGINT
272   if (handle_sigint_)
273       handle(SIGINT);
274 #endif
275 #ifdef SIGHUP
276   handle(SIGHUP);
277 #endif
278 #ifdef SIGBUS
279   handle(SIGBUS);
280 #endif
281 }
282 
283 void
set_exec(const char * exec)284 Debugger::set_exec(const char *exec)
285 {
286   delete[] exec_;
287   if (exec) {
288       exec_ = new char[strlen(exec)+1];
289       strcpy(exec_, exec);
290     }
291   else {
292       exec_ = 0;
293     }
294 }
295 
296 void
set_prefix(const char * p)297 Debugger::set_prefix(const char *p)
298 {
299   delete[] prefix_;
300   if (p) {
301       prefix_ = new char[strlen(p)+1];
302       strcpy(prefix_, p);
303     }
304   else {
305       prefix_ = 0;
306     }
307 }
308 
309 void
set_prefix(int i)310 Debugger::set_prefix(int i)
311 {
312   char p[128];
313   sprintf(p, "%3d: ", i);
314   set_prefix(p);
315 }
316 
317 void
default_cmd()318 Debugger::default_cmd()
319 {
320 #ifdef __GNUG__
321   int gcc = 1;
322 #else
323   int gcc = 0;
324 #endif
325   int has_x11_display = (getenv("DISPLAY") != 0);
326 
327   if (!gcc && sizeof(void*) == 8 && has_x11_display) {
328       set_cmd("xterm -title \"$(PREFIX)$(EXEC)\" -e dbx -p $(PID) $(EXEC) &");
329     }
330   else if (has_x11_display) {
331       set_cmd("xterm -title \"$(PREFIX)$(EXEC)\" -e gdb $(EXEC) $(PID) &");
332     }
333   else {
334       set_cmd(0);
335     }
336 }
337 
338 void
set_cmd(const char * cmd)339 Debugger::set_cmd(const char *cmd)
340 {
341   delete[] cmd_;
342   if (cmd) {
343       cmd_ = new char[strlen(cmd)+1];
344       strcpy(cmd_, cmd);
345     }
346   else {
347       cmd_ = 0;
348     }
349 }
350 
351 void
debug(const char * reason)352 Debugger::debug(const char *reason)
353 {
354   ExEnv::outn() << prefix_ << "Debugger::debug: ";
355   if (reason) ExEnv::outn() << reason;
356   else ExEnv::outn() << "no reason given";
357   ExEnv::outn() << endl;
358 
359 #ifndef HAVE_SYSTEM
360   abort();
361 #else
362   if (cmd_) {
363       int pid = getpid();
364       // contruct the command name
365       const int cmdlen = 512;
366       char cmd[cmdlen];
367       cmd[0] = '\0';
368       for (char *c=cmd_; *c;) {
369           if (!strncmp("$(PID)",c,6)) {
370               append(cmd,pid,cmdlen);
371               c += 6;
372             }
373           else if (!strncmp("$(EXEC)",c,7)) {
374               if (exec_) append(cmd,exec_,cmdlen);
375               c += 7;
376             }
377           else if (!strncmp("$(PREFIX)",c,9)) {
378               if (prefix_) append(cmd,prefix_,cmdlen);
379               c += 9;
380             }
381           else {
382               append(cmd,*c,cmdlen);
383               c++;
384             }
385         }
386       // start the debugger
387       ExEnv::outn() << prefix_ << "Debugger: starting \"" << cmd << "\"" << endl;
388       debugger_ready_ = 0;
389       system(cmd);
390       // wait until the debugger is ready
391       if (sleep_) {
392           ExEnv::outn() << prefix_ << "Sleeping " << sleep_
393                << " seconds to wait for debugger ..." << endl;
394           sleep(sleep_);
395       }
396       if (wait_for_debugger_) {
397           ExEnv::outn() << prefix_
398                         << ": Spinning until debugger_ready_ is set ..." << endl;
399           while(!debugger_ready_);
400         }
401     }
402 #endif
403 }
404 
405 void
got_signal(int sig)406 Debugger::got_signal(int sig)
407 {
408   const char *signame;
409   if (sig == SIGSEGV) signame = "SIGSEGV";
410   else if (sig == SIGFPE) signame = "SIGFPE";
411   else if (sig == SIGHUP) signame = "SIGHUP";
412   else if (sig == SIGINT) signame = "SIGINT";
413 #ifdef SIGBUS
414   else if (sig == SIGBUS) signame = "SIGBUS";
415 #endif
416   else signame = "UNKNOWN SIGNAL";
417 
418   if (traceback_) {
419       traceback(signame);
420     }
421   if (debug_) {
422       debug(signame);
423     }
424 
425   if (exit_on_signal_) {
426       ExEnv::outn() << prefix_ << "Debugger: exiting" << endl;
427       exit(1);
428     }
429   else {
430       ExEnv::outn() << prefix_ << "Debugger: continuing" << endl;
431     }
432 
433   //handle(sig);
434 }
435 
436 void
set_debug_on_signal(int v)437 Debugger::set_debug_on_signal(int v)
438 {
439   debug_ = v;
440 }
441 
442 void
set_traceback_on_signal(int v)443 Debugger::set_traceback_on_signal(int v)
444 {
445   traceback_ = v;
446 }
447 
448 void
set_wait_for_debugger(int v)449 Debugger::set_wait_for_debugger(int v)
450 {
451   wait_for_debugger_ = v;
452 }
453 
454 void
set_exit_on_signal(int v)455 Debugger::set_exit_on_signal(int v)
456 {
457   exit_on_signal_ = v;
458 }
459 
460 void
set_default_debugger(const Ref<Debugger> & d)461 Debugger::set_default_debugger(const Ref<Debugger> &d)
462 {
463   if (default_debugger_) {
464       default_debugger_->dereference();
465       // let a smart pointer figure out what to do with the old debugger
466       Ref<Debugger> old(default_debugger_);
467     }
468   if (d.pointer()) d.pointer()->reference();
469   default_debugger_ = d.pointer();
470 }
471 
472 Debugger *
default_debugger()473 Debugger::default_debugger()
474 {
475   return default_debugger_;
476 }
477 
478 #define SIMPLE_STACK (defined(linux) && defined(i386)) \
479                      || (defined(__OSF1__) && defined(i860))
480 
481 void
traceback(const char * reason)482 Debugger::traceback(const char *reason)
483 {
484 #ifdef HAVE_BACKTRACE
485   ExEnv::outn() << prefix_ << "Debugger::traceback(using backtrace):";
486   if (reason) ExEnv::outn() << reason;
487   else ExEnv::outn() << "no reason given";
488   ExEnv::outn() << endl;
489 
490   const int n = 100;
491   void *p[n];
492   int nret = backtrace(p,n);
493   if (nret == 0) {
494       ExEnv::outn() << prefix_ << "backtrace returned no state information" << std::endl;
495     }
496   for (int i=0; i<nret; i++) {
497       ExEnv::outn() << prefix_
498                     << "frame " << i
499                     << ": return address = " << p[i]
500                     << std::endl;
501     }
502 #else // HAVE_BACKTRACE
503 #if SIMPLE_STACK
504   int bottom = 0x1234;
505   void **topstack = (void**)0xffffffffL;
506   void **botstack = (void**)0x70000000L;
507   // signal handlers can put weird things in the return address slot,
508   // so it is usually best to keep toptext large.
509   void **toptext = (void**)0xffffffffL;
510   void **bottext = (void**)0x00010000L;
511 #endif // SIMPLE_STACK
512 
513   ExEnv::outn() << prefix_ << "Debugger::traceback:";
514   if (reason) ExEnv::outn() << reason;
515   else ExEnv::outn() << "no reason given";
516   ExEnv::outn() << endl;
517 #if (defined(linux) && defined(i386))
518   topstack = (void**)0xc0000000;
519   botstack = (void**)0xb0000000;
520 #endif
521 #if (defined(__OSF1__) && defined(i860))
522   topstack = (void**)0x80000000;
523   botstack = (void**)0x70000000;
524 #endif
525 
526 #if SIMPLE_STACK
527   // This will go through the stack assuming a simple linked list
528   // of pointers to the previous frame followed by the return address.
529   // It trys to be careful and avoid creating new execptions, but there
530   // are no guarantees.
531   void **stack = (void**) &bottom;
532 
533   void **frame_pointer = (void**) stack[3];
534   while(frame_pointer >= botstack
535         && frame_pointer < topstack
536         && frame_pointer[1] >= bottext
537         && frame_pointer[1] < toptext) {
538       ExEnv::outn() << prefix_ << "frame: " << (void*)frame_pointer;
539       ExEnv::outn().flush();
540       ExEnv::outn() << "  retaddr: " << frame_pointer[1] << endl;
541       frame_pointer = (void**)*frame_pointer;
542     }
543 #else
544   ExEnv::outn() << prefix_ << "traceback not available for this arch" << endl;
545 #endif // SIMPLE_STACK
546 #endif // HAVE_BACKTRACE
547 }
548 
549 /////////////////////////////////////////////////////////////////////////////
550 
551 // Local Variables:
552 // mode: c++
553 // c-file-style: "CLJ"
554 // End:
555