source: ThirdParty/mpqc_open/src/lib/util/misc/bug.cc@ 860145

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChronosMutex Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids_IntegrationTest JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 860145 was 860145, checked in by Frederik Heber <heber@…>, 8 years ago

Merge commit '0b990dfaa8c6007a996d030163a25f7f5fc8a7e7' as 'ThirdParty/mpqc_open'

  • Property mode set to 100644
File size: 11.7 KB
Line 
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
61using namespace std;
62using namespace sc;
63
64//////////////////////////////////////////////////////////////////////
65// static variables
66
67static Debugger *signals[NSIG];
68
69//////////////////////////////////////////////////////////////////////
70// static routines
71
72extern "C" {
73#ifdef SIGHASELLIP
74// required for CC -64 on IRIX 6.0.1 and for gcc on IRIX 5.3
75typedef RETSIGTYPE (*handler_type)(...);
76#else
77typedef RETSIGTYPE (*handler_type)(int);
78#endif
79}
80
81static void
82handler(int sig)
83{
84 if (signals[sig]) signals[sig]->got_signal(sig);
85}
86
87static void
88append(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
98static void
99append(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
107static void
108append(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
118Debugger *Debugger::default_debugger_ = 0;
119
120static ClassDesc Debugger_cd(
121 typeid(Debugger),"Debugger",1,"public SavableState",
122 0, create<Debugger>, create<Debugger>);
123
124Debugger::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
136Debugger::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
173Debugger::~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
184Debugger::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
207void
208Debugger::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
226void
227Debugger::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
245void
246Debugger::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
256void
257Debugger::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
283void
284Debugger::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
296void
297Debugger::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
309void
310Debugger::set_prefix(int i)
311{
312 char p[128];
313 sprintf(p, "%3d: ", i);
314 set_prefix(p);
315}
316
317void
318Debugger::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
338void
339Debugger::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
351void
352Debugger::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
405void
406Debugger::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
436void
437Debugger::set_debug_on_signal(int v)
438{
439 debug_ = v;
440}
441
442void
443Debugger::set_traceback_on_signal(int v)
444{
445 traceback_ = v;
446}
447
448void
449Debugger::set_wait_for_debugger(int v)
450{
451 wait_for_debugger_ = v;
452}
453
454void
455Debugger::set_exit_on_signal(int v)
456{
457 exit_on_signal_ = v;
458}
459
460void
461Debugger::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
472Debugger *
473Debugger::default_debugger()
474{
475 return default_debugger_;
476}
477
478#define SIMPLE_STACK (defined(linux) && defined(i386)) \
479 || (defined(__OSF1__) && defined(i860))
480
481void
482Debugger::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:
Note: See TracBrowser for help on using the repository browser.