| [0b990d] | 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
 | 
|---|
 | 82 | handler(int sig)
 | 
|---|
 | 83 | {
 | 
|---|
 | 84 |   if (signals[sig]) signals[sig]->got_signal(sig);
 | 
|---|
 | 85 | }
 | 
|---|
 | 86 | 
 | 
|---|
 | 87 | static void
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 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 | 
 | 
|---|
 | 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 | 
 | 
|---|
 | 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 | 
 | 
|---|
 | 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 | 
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 310 | Debugger::set_prefix(int i)
 | 
|---|
 | 311 | {
 | 
|---|
 | 312 |   char p[128];
 | 
|---|
 | 313 |   sprintf(p, "%3d: ", i);
 | 
|---|
 | 314 |   set_prefix(p);
 | 
|---|
 | 315 | }
 | 
|---|
 | 316 | 
 | 
|---|
 | 317 | void
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 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
 | 
|---|
 | 437 | Debugger::set_debug_on_signal(int v)
 | 
|---|
 | 438 | {
 | 
|---|
 | 439 |   debug_ = v;
 | 
|---|
 | 440 | }
 | 
|---|
 | 441 | 
 | 
|---|
 | 442 | void
 | 
|---|
 | 443 | Debugger::set_traceback_on_signal(int v)
 | 
|---|
 | 444 | {
 | 
|---|
 | 445 |   traceback_ = v;
 | 
|---|
 | 446 | }
 | 
|---|
 | 447 | 
 | 
|---|
 | 448 | void
 | 
|---|
 | 449 | Debugger::set_wait_for_debugger(int v)
 | 
|---|
 | 450 | {
 | 
|---|
 | 451 |   wait_for_debugger_ = v;
 | 
|---|
 | 452 | }
 | 
|---|
 | 453 | 
 | 
|---|
 | 454 | void
 | 
|---|
 | 455 | Debugger::set_exit_on_signal(int v)
 | 
|---|
 | 456 | {
 | 
|---|
 | 457 |   exit_on_signal_ = v;
 | 
|---|
 | 458 | }
 | 
|---|
 | 459 | 
 | 
|---|
 | 460 | void
 | 
|---|
 | 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 *
 | 
|---|
 | 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
 | 
|---|
 | 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:
 | 
|---|