3 * Copyright (C) 2007, Harbour, All rights reserved.
10 bool F::sigsegv_ = false;
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);
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)
41 init_demangler(NULL, NULL, NULL);
45 return cplus_demangle(mngl, DMGL_AUTO);
50 const char *F::demangled_(const char *mngl)
52 static std::string mangled;
57 // do we need to free ptr ?
58 const char *dm = abi::__cxa_demangle(mangled.c_str(), ptr, &len, &status);
61 return mangled.c_str();
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)
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 '('
83 size_t fname_end = mangled.rfind('+');
84 if (fname_end == std::string::npos) // no '+'
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());
92 if (demangled.find("()") == std::string::npos)
93 demangled.append("()");
94 demangled.append(mngl + fname_end);
99 #define demangle_(x) std::string(x)
102 #include <sys/utsname.h>
103 #include <gnu/libc-version.h>
105 // ËÒÁÔËÉÅ Ó×ÅÄÅÎÉÑ Ï ÓÉÓÔÅÍÅ
106 static inline void print_sysinfo(F_App *app)
109 int err = uname(&buf);
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 static inline void print_backtrace(siginfo_t* siginfo, signal_regs_t *regs)
140 // may be implement smth. like show_regs ...?
142 size_t bas = backtrace(ba, 128);
143 char **bts = backtrace_symbols(ba, bas);
145 std::clog << "*** Siginfo: pid "<< getpid() << ", tid " << pthread_self()
146 << ", fault eip 0x" << std::hex << regs->eip << ", fault addr " <<
147 siginfo->si_addr << std::endl << std::dec;
148 std::clog << "*** Current thread backtrace (" << (bas - 3) << " funcs) :" <<
149 std::endl << std::endl;
150 for (size_t i = 3; i < bas; i++) // ÐÅÒ×ÙÅ ÔÒÉ ÎÅ ÎÕÖÎÙ
151 std::clog << "[" << (i - 3) << "] " << demangle_(bts[i]) << std::endl;
152 std::clog << std::endl;
157 // ÔÁËÖÅ ÄÌÑ ÚÁ×ÉÓÛÉÈ ×ÁÒÉÁÎÔÏ× ÍÏÖÎÏ ÚÁÄÁÔØ ÓÉÇÎÁÌ (F_TRACE_SIGNAL) É ÐÏ ÎÅÍÕ
158 // ÐÅÞÁÔÁÔØ backtrace(), ÔÏËÍÁ ÓÌÅÄÕÅÔØ ÕÞÅÓÔØ ÛÏ ÜÎÔÏÔ ÓÉÇÎÁÌ ÐÏÌÕÞÁÀÔØ ÕÓÅ
159 // ÔÒÅÄÙ, ÔÏ ÂÉÛØ ÐÏÌÕÞÉÍ ËÉÐÕ backtrac'Ï× ÄÌÑ multithread app ...
162 void F_App::signal_handler(int signo, siginfo_t* siginfo, void* ptr)
164 struct sigaction dfl_handler;
165 sigemptyset(&dfl_handler.sa_mask);
166 dfl_handler.sa_flags = SA_SIGINFO | SA_RESTART;
167 dfl_handler.sa_handler = 0;
168 dfl_handler.sa_restorer = NULL;
172 dfl_handler.sa_sigaction = F_App::signal_handler;
173 sigaction(SIGTSTP, &dfl_handler, NULL);
174 sigaction(SIGSTOP, &dfl_handler, NULL);
175 if (this_->stopped) {
178 this_->ui_->sigcont();
179 this_->stopped = false;
184 // temporary disable signals
185 dfl_handler.sa_handler = SIG_IGN;
186 sigaction(SIGINT, &dfl_handler, NULL);
187 sigaction(SIGQUIT, &dfl_handler, NULL);
188 // ask user if he/she want to leave app
189 if (this_->exit_confirm(1))
191 else { // reenable sigs
192 dfl_handler.sa_sigaction = F_App::signal_handler;
193 sigaction(SIGINT, &dfl_handler, NULL);
194 sigaction(SIGQUIT, &dfl_handler, NULL);
199 if (!this_->sigstop()) // app doesn't accept sigstops
201 this_->stopped = true;
203 this_->ui_->sigstop();
204 dfl_handler.sa_handler = SIG_DFL;
205 sigaction(SIGTSTP, &dfl_handler, NULL);
209 if (this_->ui_ && (getpid() == F_UI::pid)) // deliver only to ui thread
210 this_->ui_->sigwinch();
214 std::clog << "\n*** Got backtrace signal \'" << strsignal(signo) <<
216 print_backtrace(siginfo, (signal_regs_t *)ptr);
223 this_->ui_->sigsegv();
224 std::clog << "\n*** Got " << strsignal(signo) << " signal, exiting ...\n";
225 print_backtrace(siginfo, (signal_regs_t *)ptr);
226 print_sysinfo(this_);
227 std::clog << "*** You may send this backtrace to \'" << this_->author_ <<
235 this_->ui_->shutdown();
236 log("signal_handler", ALERT_LEVEL, "ðÒÅËÒÁÝÅÎÉÅ ÒÁÂÏÔÙ (%s signal)",
241 static void out_of_memory()
243 std::cerr << "Out of memory, bye ..." << std::endl;
244 // if we can free some memory for backtrace it will be wonderfull ...
245 // kill(getpid(), F_TRACE_SIGNAL);
249 void F_App::signals_setup(void)
251 struct sigaction new_action;
252 sigemptyset(&new_action.sa_mask);
253 new_action.sa_handler = 0;
254 new_action.sa_restorer = NULL;
255 new_action.sa_sigaction = F_App::signal_handler;
256 new_action.sa_flags = SA_SIGINFO | SA_ONESHOT;
257 // system signals - default action is to terminate app
258 sigaction (SIGHUP, &new_action, NULL);
259 sigaction (SIGSEGV, &new_action, NULL);
260 sigaction (SIGILL, &new_action, NULL);
261 sigaction (SIGFPE, &new_action, NULL);
262 sigaction (SIGBUS, &new_action, NULL);
264 new_action.sa_flags = SA_SIGINFO | SA_RESTART;
265 sigaction (SIGCHLD, &new_action, NULL);
266 sigaction (SIGSTOP, &new_action, NULL); // sigstop is no reacheable for app
267 sigaction (SIGCONT, &new_action, NULL);
268 sigaction (SIGTSTP, &new_action, NULL);
269 sigaction (SIGQUIT, &new_action, NULL);
270 sigaction (SIGINT, &new_action, NULL);
271 sigaction (SIGWINCH, &new_action, NULL);
272 sigaction (F_TRACE_SIGNAL, &new_action, NULL);
275 void F_App::default_idle(void)
277 ost::Thread::sleep(10);
282 void F_App::f_app_constructor(int argc, char **argv, const char *name, const char *version,
283 const char *author, const char *license, ost::CommandOption *user_cmd_opts,
284 const char *comment, const char *l_prefix)
287 std::cerr << "Only one F_App instance is allowed, bye ..." << std::endl;
293 old_new_handler = std::set_new_handler(out_of_memory);
295 std::set_terminate (__gnu_cxx::__verbose_terminate_handler);
298 name_ = name ? name : "Unknown App,";
299 version_ = version ? version : "version unknown,";
300 author_ = author ? author : "Mr. Unknown <unknown@nowhere.world>";
301 license_ = license ? license : "unknown";
302 // parse internal command options
304 ost::CommandOption *tt = user_cmd_opts;
307 // this is strange - options is parsed from end ?!
308 tt->next = f_app_cmd_options;
311 comment = "program usage :";
314 cmd_opts_ = ost::makeCommandOptionParse(argc, argv, (char *)comment,
315 user_cmd_opts ? user_cmd_opts : f_app_cmd_options);
316 if (help_option.numSet) {
317 std::clog << cmd_opts_->printUsage();
320 if (version_option.numSet) {
321 std::clog << name_ << " " << version_ << " written by " << author_ <<
322 " under " << license_ << " license" << std::endl;
325 if (cmd_opts_->argsHaveError()) {
326 std::cerr << cmd_opts_->printErrors();
327 std::cerr << "Did you try " << argv[0] << " --help ?\n";
330 // create main log channel
333 log_prefix(l_prefix);
334 log("F_App", DEBUG_LEVEL, "F_App() v%0d.%0d.%0d created.", F_MAJOR_VERSION,
335 F_MINOR_VERSION, F_PATCH_VERSION);
338 void F::shutdown(int retval)
344 // do this as atexit handler ?
353 void F_App::init(void)
355 // ÅÓÌÉ ÐÒÏÇÒÁÍÍÁ ×ÙÈÏÄÉÔ ÔÕÔÁ ÐÏ Ctrl-C, ÔÏ ÔÁË ËÁË ui ËÌÁÓÓ ÍÏÖÅÔ ÂÙÔØ
356 // ÅÝÅ ÎÅ ÓÏÚÄÁÎ - ÓÌÅÄÕÅÔ ÜÔÏ ÕÞÅÓÔØ
357 parse_command_options();
359 if (!F_UI::ui_count()) {
360 log("ui_count", FATAL_LEVEL, "Oops, your app doesn't define any UI !");
363 ui_ = F_UI::make_ui();