Whitespace
[amule.git] / src / libs / common / MuleDebug.cpp
blob5d8d75890f44c1eb95ef0d05ada652e6014b19e5
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2005-2011 Mikkel Schubert ( xaignar@users.sourceforge.net )
5 // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program 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 General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <cstdlib> // Needed for std::abort()
28 #ifdef HAVE_CONFIG_H
29 # include "config.h" // Needed for HAVE_CXXABI and HAVE_EXECINFO
30 #endif
32 #include "MuleDebug.h" // Interface declaration
33 #include "StringFunctions.h" // Needed for unicode2char
34 #include "Format.h" // Needed for CFormat
36 #ifdef HAVE_EXECINFO
37 # include <execinfo.h>
38 # include <wx/utils.h> // Needed for wxArrayString
39 # ifndef HAVE_BFD
40 # include <wx/thread.h> // Needed for wxThread
41 # endif
42 #endif
44 #ifdef HAVE_CXXABI
45 # ifdef HAVE_TYPEINFO
46 # include <typeinfo> // Needed for some MacOSX versions with broken system headers
47 # endif
48 # include <cxxabi.h>
49 #endif
52 #if wxUSE_STACKWALKER && defined(__WINDOWS__)
53 #include <wx/stackwalk.h> // Do_not_auto_remove
54 #elif defined(HAVE_BFD)
55 #include <ansidecl.h> // Do_not_auto_remove
56 #include <bfd.h> // Do_not_auto_remove
57 #endif
59 #include <vector>
62 /**
63 * This functions displays a verbose description of
64 * any unhandled exceptions that occour and then
65 * terminate the program by raising SIGABRT.
67 void OnUnhandledException()
69 // Revert to the original exception handler, to avoid
70 // infinate recursion, in case something goes wrong in
71 // this function.
72 std::set_terminate(std::abort);
74 #ifdef HAVE_CXXABI
75 std::type_info *t = __cxxabiv1::__cxa_current_exception_type();
76 FILE* output = stderr;
77 #else
78 FILE* output = stdout;
79 bool t = true;
80 #endif
81 if (t) {
82 int status = -1;
83 char *dem = 0;
84 #ifdef HAVE_CXXABI
85 // Note that "name" is the mangled name.
86 char const *name = t->name();
88 dem = __cxxabiv1::__cxa_demangle(name, 0, 0, &status);
89 #else
90 const char* name = "Unknown";
91 #endif
92 fprintf(output, "\nTerminated after throwing an instance of '%s'\n", (status ? name : dem));
93 free(dem);
95 try {
96 throw;
97 } catch (const std::exception& e) {
98 fprintf(output, "\twhat(): %s\n", e.what());
99 } catch (const CMuleException& e) {
100 fprintf(output, "\twhat(): %s\n", (const char*)unicode2char(e.what()));
101 } catch (const wxString& e) {
102 fprintf(output, "\twhat(): %s\n", (const char*)unicode2char(e));
103 } catch (...) {
104 // Unable to retrieve cause of exception
107 fprintf(output, "\tbacktrace:\n%s\n", (const char*)unicode2char(get_backtrace(1)));
109 std::abort();
113 void InstallMuleExceptionHandler()
115 std::set_terminate(OnUnhandledException);
119 // Make it 1 for getting the file path also
120 #define TOO_VERBOSE_BACKTRACE 0
122 #if wxUSE_STACKWALKER && defined(__WINDOWS__)
124 // Derived class to define the actions to be done on frame print.
125 // I was tempted to name it MuleSkyWalker
126 class MuleStackWalker : public wxStackWalker
128 public:
129 MuleStackWalker() {};
130 ~MuleStackWalker() {};
132 void OnStackFrame(const wxStackFrame& frame)
134 wxString btLine = CFormat(wxT("[%u] ")) % frame.GetLevel();
135 wxString filename = frame.GetName();
137 if (!filename.IsEmpty()) {
138 btLine += filename + wxT(" (") +
139 #if TOO_VERBOSE_BACKTRACE
140 frame.GetModule()
141 #else
142 frame.GetModule().AfterLast(wxT('/'))
143 #endif
144 + wxT(")");
145 } else {
146 btLine += CFormat(wxT("%p")) % frame.GetAddress();
149 if (frame.HasSourceLocation()) {
150 btLine += wxT(" at ") +
151 #if TOO_VERBOSE_BACKTRACE
152 frame.GetFileName()
153 #else
154 frame.GetFileName().AfterLast(wxT('/'))
155 #endif
156 + CFormat(wxT(":%u")) % frame.GetLine();
157 } else {
158 btLine += wxT(" (Unknown file/line)");
161 //! Contains the entire backtrace
162 m_trace += btLine + wxT("\n");
165 wxString m_trace;
169 wxString get_backtrace(unsigned n)
171 MuleStackWalker walker; // Texas ranger?
172 walker.Walk(n); // Skip this one and Walk() also!
174 return walker.m_trace;
177 #elif defined(__LINUX__)
179 #ifdef HAVE_BFD
181 static bfd* s_abfd;
182 static asymbol** s_symbol_list;
183 static bool s_have_backtrace_symbols = false;
184 static const char* s_file_name;
185 static const char* s_function_name;
186 static unsigned int s_line_number;
187 static int s_found;
191 * read all symbols in the executable into an array
192 * and return the pointer to the array in symbol_list.
193 * Also return the number of actual symbols read
194 * If there's any error, return -1
196 static int get_backtrace_symbols(bfd *abfd, asymbol ***symbol_list_ptr)
198 int vectorsize = bfd_get_symtab_upper_bound(abfd);
200 if (vectorsize < 0) {
201 fprintf (stderr, "Error while getting vector size for backtrace symbols : %s",
202 bfd_errmsg(bfd_get_error()));
203 return -1;
206 if (vectorsize == 0) {
207 fprintf (stderr, "Error while getting backtrace symbols : No symbols (%s)",
208 bfd_errmsg(bfd_get_error()));
209 return -1;
212 *symbol_list_ptr = (asymbol**)malloc(vectorsize);
214 if (*symbol_list_ptr == NULL) {
215 fprintf (stderr, "Error while getting backtrace symbols : Cannot allocate memory");
216 return -1;
219 vectorsize = bfd_canonicalize_symtab(abfd, *symbol_list_ptr);
221 if (vectorsize < 0) {
222 fprintf(stderr, "Error while getting symbol table : %s",
223 bfd_errmsg(bfd_get_error()));
224 return -1;
227 return vectorsize;
232 * print file, line and function information for address
233 * The info is actually set into global variables. This
234 * function is called from the iterator bfd_map_over_sections
237 void init_backtrace_info()
239 bfd_init();
240 s_abfd = bfd_openr("/proc/self/exe", NULL);
242 if (s_abfd == NULL) {
243 fprintf(stderr, "Error while opening file for backtrace symbols : %s",
244 bfd_errmsg(bfd_get_error()));
245 return;
248 if (!(bfd_check_format_matches(s_abfd, bfd_object, NULL))) {
249 fprintf (stderr, "Error while init. backtrace symbols : %s",
250 bfd_errmsg (bfd_get_error ()));
251 bfd_close(s_abfd);
252 return;
255 s_have_backtrace_symbols = (get_backtrace_symbols(s_abfd, &s_symbol_list) > 0);
259 void get_file_line_info(bfd *abfd, asection *section, void* _address)
261 wxASSERT(s_symbol_list);
263 if (s_found) {
264 return;
267 if ((section->flags & SEC_ALLOC) == 0) {
268 return;
271 bfd_vma vma = bfd_get_section_vma(abfd, section);
273 unsigned long address = (unsigned long)_address;
274 if (address < vma) {
275 return;
278 bfd_size_type size = bfd_section_size(abfd, section);
279 if (address > (vma + size)) {
280 return;
283 s_found = bfd_find_nearest_line(abfd, section, s_symbol_list,
284 address - vma, &s_file_name, &s_function_name, &s_line_number);
287 #endif // HAVE_BFD
289 wxString demangle(const wxString& function)
291 #ifdef HAVE_CXXABI
292 wxString result;
294 if (function.Mid(0,2) == wxT("_Z")) {
295 int status;
296 char *demangled = abi::__cxa_demangle(function.mb_str(), NULL, NULL, &status);
298 if (!status) {
299 result = wxConvCurrent->cMB2WX(demangled);
302 if (demangled) {
303 free(demangled);
307 return result;
308 #else
309 return wxEmptyString;
310 #endif
314 // Print a stack backtrace if available
315 wxString get_backtrace(unsigned n)
317 #ifdef HAVE_EXECINFO
318 // (stkn) create backtrace
319 void *bt_array[100]; // 100 should be enough ?!?
320 char **bt_strings;
321 int num_entries;
323 if ((num_entries = backtrace(bt_array, 100)) < 0) {
324 fprintf(stderr, "* Could not generate backtrace\n");
325 return wxEmptyString;
328 if ((bt_strings = backtrace_symbols(bt_array, num_entries)) == NULL) {
329 fprintf(stderr, "* Could not get symbol names for backtrace\n");
330 return wxEmptyString;
333 std::vector<wxString> libname(num_entries);
334 std::vector<wxString> funcname(num_entries);
335 std::vector<wxString> address(num_entries);
336 wxString AllAddresses;
338 for (int i = 0; i < num_entries; ++i) {
339 wxString wxBtString = wxConvCurrent->cMB2WX(bt_strings[i]);
340 int posLPar = wxBtString.Find(wxT('('));
341 int posRPar = wxBtString.Find(wxT(')'));
342 int posLBra = wxBtString.Find(wxT('['));
343 int posRBra = wxBtString.Find(wxT(']'));
344 bool hasFunction = true;
345 if (posLPar == -1 || posRPar == -1) {
346 if (posLBra == -1 || posRBra == -1) {
347 /* It is important to have exactly num_entries
348 * addresses in AllAddresses */
349 AllAddresses += wxT("0x0000000 ");
350 continue;
352 posLPar = posLBra;
353 hasFunction = false;
355 /* Library name */
356 int len = posLPar;
357 libname[i] = wxBtString.Mid(0, len);
358 /* Function name */
359 if (hasFunction) {
360 int posPlus = wxBtString.Find(wxT('+'), true);
361 if (posPlus == -1)
362 posPlus = posRPar;
363 len = posPlus - posLPar - 1;
364 funcname[i] = wxBtString.Mid(posLPar + 1, len);
365 wxString demangled = demangle(funcname[i]);
366 if (!demangled.IsEmpty()) {
367 funcname[i] = demangled;
370 /* Address */
371 if ( posLBra == -1 || posRBra == -1) {
372 address[i] = wxT("0x0000000");
373 } else {
374 len = posRBra - posLBra - 1;
375 address[i] = wxBtString.Mid(posLBra + 1, len);
376 AllAddresses += address[i] + wxT(" ");
379 free(bt_strings);
381 /* Get line numbers from addresses */
382 wxArrayString out;
383 bool hasLineNumberInfo = false;
385 #ifdef HAVE_BFD
386 if (!s_have_backtrace_symbols) {
387 init_backtrace_info();
388 wxASSERT(s_have_backtrace_symbols);
391 for (int i = 0; i < num_entries; ++i) {
392 s_file_name = NULL;
393 s_function_name = NULL;
394 s_line_number = 0;
395 s_found = false ;
397 unsigned long addr;
398 address[i].ToULong(&addr,0); // As it's "0x" prepended, wx will read it as base 16. Hopefully.
400 bfd_map_over_sections(s_abfd, get_file_line_info, (void*)addr);
402 if (s_found) {
403 wxString function = wxConvCurrent->cMB2WX(s_function_name);
404 wxString demangled = demangle(function);
405 if (!demangled.IsEmpty()) {
406 function = demangled;
407 funcname[i] = demangled;
409 out.Insert(wxConvCurrent->cMB2WX(s_function_name),i*2);
410 out.Insert(CFormat(wxT("%s:%u")) % wxString(wxConvCurrent->cMB2WX(s_file_name)) % s_line_number, i*2+1);
411 } else {
412 out.Insert(wxT("??"),i*2);
413 out.Insert(wxT("??"),i*2+1);
417 hasLineNumberInfo = true;
419 #else /* !HAVE_BFD */
420 if (wxThread::IsMain()) {
421 wxString command;
422 command << wxT("addr2line -C -f -s -e /proc/") <<
423 getpid() << wxT("/exe ") << AllAddresses;
424 // The output of the command is this wxArrayString, in which
425 // the even elements are the function names, and the odd elements
426 // are the line numbers.
428 hasLineNumberInfo = wxExecute(command, out) != -1;
431 #endif /* HAVE_BFD / !HAVE_BFD */
433 wxString trace;
434 // Remove 'n+1' first entries (+1 because of this function)
435 for (int i = n+1; i < num_entries; ++i) {
436 /* If we have no function name, use the result from addr2line */
437 if (funcname[i].IsEmpty()) {
438 if (hasLineNumberInfo) {
439 funcname[i] = out[2*i];
440 } else {
441 funcname[i] = wxT("??");
444 wxString btLine;
445 btLine << wxT("[") << i << wxT("] ") << funcname[i] << wxT(" in ");
446 /* If addr2line did not find a line number, use bt_string */
447 if (!hasLineNumberInfo || out[2*i+1].Mid(0,2) == wxT("??")) {
448 btLine += libname[i] + wxT("[") + address[i] + wxT("]");
449 } else if (hasLineNumberInfo) {
450 #if TOO_VERBOSE_BACKTRACE
451 btLine += out[2*i+1];
452 #else
453 btLine += out[2*i+1].AfterLast(wxT('/'));
454 #endif
455 } else {
456 btLine += libname[i];
459 trace += btLine + wxT("\n");
462 return trace;
463 #else /* !HAVE_EXECINFO */
464 fprintf(stderr, "--== cannot generate backtrace ==--\n\n");
465 return wxEmptyString;
466 #endif /* HAVE_EXECINFO */
469 #elif defined( __APPLE__ )
471 // According to sources, parts of this code originate at http://www.tlug.org.za/wiki/index.php/Obtaining_a_stack_trace_in_C_upon_SIGSEGV
472 // which doesn't exist anymore.
474 // Other code (stack frame list and demangle related) has been modified from code with license:
476 // Copyright 2007 Edd Dawson.
477 // Distributed under the Boost Software License, Version 1.0.
478 // (See accompanying file LICENSE_1_0.txt or copy at
479 // http://www.boost.org/LICENSE_1_0.txt)
481 #include <string>
482 #include <dlfcn.h>
483 #include <cxxabi.h>
484 #include <sstream>
486 class stack_frame
488 public:
489 stack_frame(const void * f_instruction, const std::string& f_function) : frame_instruction(f_instruction), frame_function(f_function) {};
491 const void *instruction() const { return frame_instruction; }
492 const std::string& function() const { return frame_function; }
494 private:
495 const void * frame_instruction;
496 const std::string frame_function;
499 std::string demangle(const char *name)
501 int status = 0;
502 char *d = 0;
503 std::string ret = name;
504 try {
505 if ((d = abi::__cxa_demangle(name, 0, 0, &status))) {
506 ret = d;
508 } catch(...) { }
510 std::free(d);
511 return ret;
515 void fill_frames(std::list<stack_frame> &frames)
517 try {
518 void **fp = (void **) __builtin_frame_address (1);
519 void *saved_pc = NULL;
521 // First frame is skipped
522 while (fp != NULL) {
523 fp = (void**)(*fp);
524 if (*fp == NULL) {
525 break;
528 #if defined(__i386__)
529 saved_pc = fp[1];
530 #elif defined(__ppc__)
531 saved_pc = *(fp + 2);
532 #else
533 // ?
534 saved_pc = *(fp + 2);
535 #endif
536 if (saved_pc) {
537 Dl_info info;
539 if (dladdr(saved_pc, &info)) {
540 frames.push_back(stack_frame(saved_pc, demangle(info.dli_sname) + " in " + info.dli_fname));
544 } catch (...) {
545 // Nothing to be done here, just leave.
549 wxString get_backtrace(unsigned n)
551 std::list<stack_frame> frames;
552 fill_frames(frames);
553 std::ostringstream backtrace;
554 std::list<stack_frame>::iterator it = frames.begin();
556 int count = 0;
557 while (it != frames.end()) {
558 if (count >= n) {
559 backtrace << (*it).instruction() << " : " << (*it).function() << std::endl;
560 ++it;
563 ++count;
566 return wxString(backtrace.str().c_str(), wxConvUTF8);
569 #else /* ! __APPLE__ */
571 wxString get_backtrace(unsigned WXUNUSED(n))
573 return wxT("--== no BACKTRACE for your platform ==--\n\n");
576 #endif /* !__LINUX__ */
578 void print_backtrace(unsigned n)
580 wxString trace = get_backtrace(n);
582 // This is because the string is ansi anyway, and the conv classes are very slow
583 fprintf(stderr, "%s\n", (const char*)unicode2char(trace));
586 // File_checked_for_headers