Correct backtrace() array size argument
[forms.git] / src / F_App.C
blob6e687c5898424ec260816488dbcda3f5506ef4ea
2  /*
3   *   Copyright (C) 2007, Harbour, All rights reserved.
4   */
6 #include <iostream>
7 #include <F_App.H>
9 using namespace F;
10 bool F::sigsegv_ = false;
12 int F_App::argc_;
13 char **F_App::argv_;
15 void (*F_App::idle_)(void);
16 F_App *F_App::this_ = 0;
17 std::string F_App::name_;
19 ost::CommandOption *f_app_cmd_options = 0;
20 ost::CommandOptionNoArg help_option("help", "h", "\t\t\tprints short usage info",
21   false, &f_app_cmd_options);
22 ost::CommandOptionNoArg version_option("version", "v",
23   "\t\tprints program name & version", false, &f_app_cmd_options);
25 #include <cxxabi.h>
27 #define F_BINUTILS_DEMANGLER
29 #ifdef F_BINUTILS_DEMANGLER
31 extern "C" int init_demangler(const char *style, const char *options,
32   const char *demangler);
33 extern "C" char *cplus_demangle(const char *mangled, int options);
35 #define DMGL_AUTO        (1 << 8)
36 const char *F::demangled_(const char *mngl)
38 #ifdef OLD_BINUTILS
39  static bool init_;
40  if (!init) {
41    init_demangler(NULL, NULL, NULL);
42    init_ = true;
43  }
44 #endif
45  return cplus_demangle(mngl, DMGL_AUTO);
48 #else
50 const char *F::demangled_(const char *mngl)
52  static std::string mangled;
53  char *ptr = NULL;
54  size_t len;
55  int status;
56  mangled = mngl;
57  // do we need to free ptr ?
58  const char *dm = abi::__cxa_demangle(mangled.c_str(), ptr, &len, &status);
59  if (dm)
60    mangled = dm;
61  return mangled.c_str();
64 #endif
66 // for this pleasure you need libiberty from binutils or cxxabi.h
67 #define F_DEMANGLED_BACKTRACE
69 #ifdef  F_DEMANGLED_BACKTRACE
71 static std::string demangle_(const char *mngl)
73  // ÂÙ×ÁÀÔ ×ÁÒÉÁÎÔÙ :
74  //
75  // [X] [0xffffe440]                                              - ÏÔÂÒÁÓÙ×ÁÅÍ
76  // [X] /lib/libpthread.so.0 [0xb7d23167]                         - ÏÔÂÒÁÓÙ×ÁÅÍ
77  // [X] ./test/demo(_ZN1F12F_Console_UID2Ev+0x35) [0x804fd25]     - ÄÅÍÁÎÇÌÉÍ
78  // ×ÙÒÅÚÁÅÍ ÏÔÓÅÄÁ|......................| ÄÏ ÓÅÄÁ ×ËÌÀÞÉÔÅÌØÎÏ
79  std::string mangled = mngl;
80  size_t fname_start = mangled.find('(');
81  if (fname_start == std::string::npos) // no '('
82    return mangled;
83  size_t fname_end = mangled.rfind('+');
84  if (fname_end == std::string::npos) // no '+'
85    return mangled;
86  std::string mfunc(mangled, fname_start + 1, fname_end - fname_start - 1);
87  std::string demangled(mangled, 0, fname_start + 1);
88  const char *dm = demangled_(mfunc.c_str());
89  if (!dm)
90    dm = mfunc.c_str();
91  demangled.append(dm);
92  if (demangled.find("()") == std::string::npos)
93    demangled.append("()");
94  demangled.append(mngl + fname_end);
95  return demangled;
98 #else
99 #define demangle_(x) std::string(x)
100 #endif
102 #include <sys/utsname.h>
103 #include <gnu/libc-version.h>
105 // ËÒÁÔËÉÅ Ó×ÅÄÅÎÉÑ Ï ÓÉÓÔÅÍÅ
106 static inline void print_sysinfo(F_App *app)
108  struct utsname buf;
109  int err = uname(&buf);
110  time_t t = time(0);
111  char occured[32];
113  setlocale(LC_ALL, "C");
114  strftime(occured, sizeof(occured), "%b %d %Y %H:%M:%S", localtime(&t));
115  setlocale(LC_ALL, "");
117  // library compiled stamp, need also app compiled one
118  std::clog << "Trace Occured\t: " << occured << std::endl;
119  std::clog << "Lib Compiled\t: " << __DATE__ << " " << __TIME__ << std::endl;
120  std::clog << "App Compiled\t: " << app->compiled_stamp_ << std::endl;
121  std::clog << "Lib version\t: v" << F_MAJOR_VERSION << "." << F_MINOR_VERSION
122    << "." << F_PATCH_VERSION << std::endl;
123  std::clog << "App version\t: " << app->version() << std::endl;
124  std::clog << "Lib GCC version\t: " << __VERSION__ << std::endl;
125  std::clog << "App GCC version\t: " << app->gcc_version_ << std::endl;
126  std::clog << "Node name\t: " << (err ? "Unknown" : buf.nodename) << std::endl;
127  std::clog << "Machine type\t: " << (err ? "Unknown" : buf.machine) << std::endl;
128  std::clog << "OS Name\t\t: " << (err ? "Unknown" : buf.sysname) << std::endl;
129  // under Linux release & version seems to be swapped ?!
130  std::clog << "OS Version\t: " << (err ? "Unknown" : buf.release) << std::endl;
131  std::clog << "OS Release\t: " << (err ? "Unknown" : buf.version) << std::endl;
132  std::clog << "GLIBC version\t: " << gnu_get_libc_version() << " " << gnu_get_libc_release() << std::endl;
133  std::clog << std::endl;
136 #include <execinfo.h>
138 // ÉÎÏÇÄÁ backtrace() ×ÙÄÁÅÔ ÁÄÒÅÓÁ ÓÏ ÓÍÅÝÅÎÉÅÍ ×ÎÕÔÒØ f()'ÉÉ, ÓÏÏÔ×ÅÔÓÔ×ÅÎÎÏ
139 // backtrace_symbols() ÎÉÞÅÇÏ ÎÅ ÎÁÈÏÄÉÔ, ×ÏÔ ÅÓÌÉ ÂÙ ÍÏÖÎÏ ÂÙÌÏ ÄÅÌÁÔØ fuzzy
140 // ÐÏÉÓË ...
141 static inline void print_backtrace(siginfo_t* siginfo, signal_regs_t *regs)
143  // may be implement smth. like show_regs ...?
144  void *ba[256];
145  size_t bas = backtrace(ba, sizeof(ba) / sizeof(ba[0]));
146  char **bts = backtrace_symbols(ba, bas);
147  if (bts) {
148    std::clog << "*** Siginfo: pid "<< getpid() << ", tid " << pthread_self()
149     << ", fault eip 0x" << std::hex << regs->eip << ", fault addr " <<
150     siginfo->si_addr <<  std::endl << std::dec;
151    std::clog << "*** Current thread backtrace (" << (bas - 3) << " funcs) :" <<
152     std::endl << std::endl;
153    for (size_t i = 3; i < bas; i++) // ÐÅÒ×ÙÅ ÔÒÉ ÎÅ ÎÕÖÎÙ
154     std::clog << "[" << (i - 3) << "] " << demangle_(bts[i]) << std::endl;
155    std::clog << std::endl;
156    free(bts);
160 // ÔÁËÖÅ ÄÌÑ ÚÁ×ÉÓÛÉÈ ×ÁÒÉÁÎÔÏ× ÍÏÖÎÏ ÚÁÄÁÔØ ÓÉÇÎÁÌ (F_TRACE_SIGNAL) É ÐÏ ÎÅÍÕ
161 // ÐÅÞÁÔÁÔØ backtrace(), ÔÏËÍÁ ÓÌÅÄÕÅÔØ ÕÞÅÓÔØ ÛÏ ÜÎÔÏÔ ÓÉÇÎÁÌ ÐÏÌÕÞÁÀÔØ ÕÓÅ
162 // ÔÒÅÄÙ, ÔÏ ÂÉÛØ ÐÏÌÕÞÉÍ ËÉÐÕ backtrac'Ï× ÄÌÑ multithread app ...
165 void F_App::signal_handler(int signo, siginfo_t* siginfo, void* ptr)
167   struct sigaction dfl_handler;
168   sigemptyset(&dfl_handler.sa_mask);
169   dfl_handler.sa_flags = SA_SIGINFO | SA_RESTART;
170   dfl_handler.sa_handler = 0;
171   dfl_handler.sa_restorer = NULL;
172   switch (signo) {
173     case SIGCONT:
174     case SIGCHLD:
175       dfl_handler.sa_sigaction = F_App::signal_handler;
176       sigaction(SIGTSTP, &dfl_handler, NULL);
177       sigaction(SIGSTOP, &dfl_handler, NULL);
178       if (this_->stopped) {
179         this_->sigcont();
180         if (this_->ui_)
181           this_->ui_->sigcont();
182         this_->stopped = false;
183       }
184       return;
185     case SIGINT:
186     case SIGQUIT:
187       // temporary disable signals
188       dfl_handler.sa_handler = SIG_IGN;
189       sigaction(SIGINT, &dfl_handler, NULL);
190       sigaction(SIGQUIT, &dfl_handler, NULL);
191       // ask user if he/she want to leave app
192       if (this_->exit_confirm(1))
193         break;
194       else { // reenable sigs
195         dfl_handler.sa_sigaction = F_App::signal_handler;
196         sigaction(SIGINT, &dfl_handler, NULL);
197         sigaction(SIGQUIT, &dfl_handler, NULL);
198       }             
199       return;
200     case SIGTSTP:
201     case SIGSTOP:
202       if (!this_->sigstop()) // app doesn't accept sigstops
203         return;
204       this_->stopped = true;
205       if (this_->ui_)
206         this_->ui_->sigstop();
207       dfl_handler.sa_handler = SIG_DFL;
208       sigaction(SIGTSTP, &dfl_handler, NULL);
209       raise(SIGTSTP);
210       return;
211     case SIGWINCH:
212       if (this_->ui_ && (getpid() == F_UI::pid)) // deliver only to ui thread
213         this_->ui_->sigwinch();
214       return;
215 #ifdef DEBUG_VERSION
216     case F_TRACE_SIGNAL:
217       std::clog << "\n*** Got backtrace signal \'" << strsignal(signo) <<
218         "\'.\n";
219       print_backtrace(siginfo, (signal_regs_t *)ptr);
220       return;
221     case SIGSEGV:
222     case SIGILL:
223     case SIGFPE:
224     case SIGBUS:
225      if (this_->ui_)
226        this_->ui_->sigsegv();
227      std::clog << "\n*** Got " << strsignal(signo) << " signal, exiting ...\n";
228      print_backtrace(siginfo, (signal_regs_t *)ptr);
229      print_sysinfo(this_);
230      std::clog << "*** You may send this backtrace to \'" << this_->author_ <<
231       "\'\n\n";
232      break;      
233 #endif
234     default:
235       break;
236    }
237  if (this_->ui_)
238    this_->ui_->shutdown();
239  log("signal_handler", ALERT_LEVEL, "ðÒÅËÒÁÝÅÎÉÅ ÒÁÂÏÔÙ (%s signal)",
240    strsignal(signo));
241  ::exit(0);
244 static void out_of_memory()
246  std::cerr << "Out of memory, bye ..." << std::endl;
247  // if we can free some memory for backtrace it will be wonderfull ...
248  // kill(getpid(), F_TRACE_SIGNAL);
249  ::exit(-1);
252 void F_App::signals_setup(void)
254  struct sigaction new_action;
255  sigemptyset(&new_action.sa_mask);
256  new_action.sa_handler = 0;
257  new_action.sa_restorer = NULL;
258  new_action.sa_sigaction = F_App::signal_handler;
259  new_action.sa_flags = SA_SIGINFO | SA_ONESHOT;
260  // system signals - default action is to terminate app
261  sigaction (SIGHUP, &new_action, NULL);
262  sigaction (SIGSEGV, &new_action, NULL);
263  sigaction (SIGILL, &new_action, NULL);
264  sigaction (SIGFPE, &new_action, NULL);
265  sigaction (SIGBUS, &new_action, NULL);
266  // user trapped sigs
267  new_action.sa_flags = SA_SIGINFO | SA_RESTART;
268  sigaction (SIGCHLD, &new_action, NULL);
269  sigaction (SIGSTOP, &new_action, NULL); // sigstop is no reacheable for app
270  sigaction (SIGCONT, &new_action, NULL);
271  sigaction (SIGTSTP, &new_action, NULL);
272  sigaction (SIGQUIT, &new_action, NULL);
273  sigaction (SIGINT, &new_action, NULL);
274  sigaction (SIGWINCH, &new_action, NULL);
275  sigaction (F_TRACE_SIGNAL, &new_action, NULL);
278 void F_App::default_idle(void)
280  ost::Thread::sleep(10);
283 #include <exception>
285 void F_App::f_app_constructor(int argc, char **argv, const char *name, const char *version,
286   const char *author, const char *license, ost::CommandOption *user_cmd_opts,
287   const char *comment, const char *l_prefix)
289  if (this_) {
290    std::cerr << "Only one F_App instance is allowed, bye ..." << std::endl;
291    ::abort();
293  this_ = this;
294  ui_ = 0;
295  stopped = false;
296  old_new_handler = std::set_new_handler(out_of_memory);
297  // GNU extension
298  std::set_terminate (__gnu_cxx::__verbose_terminate_handler);
299  signals_setup();
300  idle(default_idle);
301  name_ = name ? name : "Unknown App,";
302  version_ = version ? version : "version unknown,";
303  author_ = author ? author : "Mr. Unknown <unknown@nowhere.world>";
304  license_ = license ? license : "unknown";
305  // parse internal command options
306  if (user_cmd_opts) {
307   ost::CommandOption *tt = user_cmd_opts;
308    while (tt->next)
309     tt = tt->next;
310    // this is strange - options is parsed from end ?!
311    tt->next = f_app_cmd_options;
313  if (!comment)
314    comment = "program usage :";
315  this->argc_ = argc;
316  this->argv_ = argv; 
317  cmd_opts_ = ost::makeCommandOptionParse(argc, argv, (char *)comment,
318    user_cmd_opts ? user_cmd_opts : f_app_cmd_options);
319  if (help_option.numSet) {
320    std::clog << cmd_opts_->printUsage();
321    ::exit(0);
323  if (version_option.numSet) {
324    std::clog << name_ << " " << version_ << " written by " << author_ <<
325      " under " << license_ << " license" << std::endl;
326    ::exit(0);
328  if (cmd_opts_->argsHaveError()) {
329    std::cerr << cmd_opts_->printErrors();
330    std::cerr << "Did you try " << argv[0] << " --help ?\n";
331    ::exit(-1);
333  // create main log channel
334  log_init(argv[0]);
335  if (l_prefix)
336    log_prefix(l_prefix);
337  log("F_App", DEBUG_LEVEL, "F_App() v%0d.%0d.%0d created.", F_MAJOR_VERSION,
338    F_MINOR_VERSION, F_PATCH_VERSION);
341 void F::shutdown(int retval)
343  F_App::shutdown();
344  ::exit(retval);
347 // do this as atexit handler ?
348 F_App::~F_App()
350  shutdown();
351  if (this_)
352    delete this_;
353  this_ = 0;
356 void F_App::init(void)
358  // ÅÓÌÉ ÐÒÏÇÒÁÍÍÁ ×ÙÈÏÄÉÔ ÔÕÔÁ ÐÏ Ctrl-C, ÔÏ ÔÁË ËÁË ui ËÌÁÓÓ ÍÏÖÅÔ ÂÙÔØ
359  // ÅÝÅ ÎÅ ÓÏÚÄÁΠ- ÓÌÅÄÕÅÔ ÜÔÏ ÕÞÅÓÔØ
360  parse_command_options();
361  // create ui
362  if (!F_UI::ui_count()) {
363   log("ui_count", FATAL_LEVEL, "Oops, your app doesn't define any UI !");
364   ::exit(-1);
366  ui_ = F_UI::make_ui();