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**) ⊥
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