2 // This file is part of the aMule Project.
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 )
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
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()
29 # include "config.h" // Needed for HAVE_CXXABI and HAVE_EXECINFO
32 #include "MuleDebug.h" // Interface declaration
33 #include "StringFunctions.h" // Needed for unicode2char
34 #include "Format.h" // Needed for CFormat
37 # include <execinfo.h>
38 # include <wx/utils.h> // Needed for wxArrayString
40 # include <wx/thread.h> // Needed for wxThread
46 # include <typeinfo> // Needed for some MacOSX versions with broken system headers
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
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
72 std::set_terminate(std::abort
);
75 std::type_info
*t
= __cxxabiv1::__cxa_current_exception_type();
76 FILE* output
= stderr
;
78 FILE* output
= stdout
;
85 // Note that "name" is the mangled name.
86 char const *name
= t
->name();
88 dem
= __cxxabiv1::__cxa_demangle(name
, 0, 0, &status
);
90 const char* name
= "Unknown";
92 fprintf(output
, "\nTerminated after throwing an instance of '%s'\n", (status
? name
: dem
));
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
));
104 // Unable to retrieve cause of exception
107 fprintf(output
, "\tbacktrace:\n%s\n", (const char*)unicode2char(get_backtrace(1)));
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
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
142 frame
.GetModule().AfterLast(wxT('/'))
146 btLine
+= CFormat(wxT("%p")) % frame
.GetAddress();
149 if (frame
.HasSourceLocation()) {
150 btLine
+= wxT(" at ") +
151 #if TOO_VERBOSE_BACKTRACE
154 frame
.GetFileName().AfterLast(wxT('/'))
156 + CFormat(wxT(":%u")) % frame
.GetLine();
158 btLine
+= wxT(" (Unknown file/line)");
161 //! Contains the entire backtrace
162 m_trace
+= btLine
+ wxT("\n");
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__)
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
;
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()));
206 if (vectorsize
== 0) {
207 fprintf (stderr
, "Error while getting backtrace symbols : No symbols (%s)",
208 bfd_errmsg(bfd_get_error()));
212 *symbol_list_ptr
= (asymbol
**)malloc(vectorsize
);
214 if (*symbol_list_ptr
== NULL
) {
215 fprintf (stderr
, "Error while getting backtrace symbols : Cannot allocate memory");
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()));
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()
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()));
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 ()));
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
);
267 if ((section
->flags
& SEC_ALLOC
) == 0) {
271 bfd_vma vma
= bfd_get_section_vma(abfd
, section
);
273 unsigned long address
= (unsigned long)_address
;
278 bfd_size_type size
= bfd_section_size(abfd
, section
);
279 if (address
> (vma
+ size
)) {
283 s_found
= bfd_find_nearest_line(abfd
, section
, s_symbol_list
,
284 address
- vma
, &s_file_name
, &s_function_name
, &s_line_number
);
289 wxString
demangle(const wxString
& function
)
294 if (function
.Mid(0,2) == wxT("_Z")) {
296 char *demangled
= abi::__cxa_demangle(function
.mb_str(), NULL
, NULL
, &status
);
299 result
= wxConvCurrent
->cMB2WX(demangled
);
309 return wxEmptyString
;
314 // Print a stack backtrace if available
315 wxString
get_backtrace(unsigned n
)
318 // (stkn) create backtrace
319 void *bt_array
[100]; // 100 should be enough ?!?
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 ");
357 libname
[i
] = wxBtString
.Mid(0, len
);
360 int posPlus
= wxBtString
.Find(wxT('+'), true);
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
;
371 if ( posLBra
== -1 || posRBra
== -1) {
372 address
[i
] = wxT("0x0000000");
374 len
= posRBra
- posLBra
- 1;
375 address
[i
] = wxBtString
.Mid(posLBra
+ 1, len
);
376 AllAddresses
+= address
[i
] + wxT(" ");
381 /* Get line numbers from addresses */
383 bool hasLineNumberInfo
= false;
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
) {
393 s_function_name
= NULL
;
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
);
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);
412 out
.Insert(wxT("??"),i
*2);
413 out
.Insert(wxT("??"),i
*2+1);
417 hasLineNumberInfo
= true;
419 #else /* !HAVE_BFD */
420 if (wxThread::IsMain()) {
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 */
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
];
441 funcname
[i
] = wxT("??");
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];
453 btLine
+= out
[2*i
+1].AfterLast(wxT('/'));
456 btLine
+= libname
[i
];
459 trace
+= btLine
+ wxT("\n");
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)
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
; }
495 const void * frame_instruction
;
496 const std::string frame_function
;
499 std::string
demangle(const char *name
)
503 std::string ret
= name
;
505 if ((d
= abi::__cxa_demangle(name
, 0, 0, &status
))) {
515 void fill_frames(std::list
<stack_frame
> &frames
)
518 void **fp
= (void **) __builtin_frame_address (1);
519 void *saved_pc
= NULL
;
521 // First frame is skipped
528 #if defined(__i386__)
530 #elif defined(__ppc__)
531 saved_pc
= *(fp
+ 2);
534 saved_pc
= *(fp
+ 2);
539 if (dladdr(saved_pc
, &info
)) {
540 frames
.push_back(stack_frame(saved_pc
, demangle(info
.dli_sname
) + " in " + info
.dli_fname
));
545 // Nothing to be done here, just leave.
549 wxString
get_backtrace(unsigned n
)
551 std::list
<stack_frame
> frames
;
553 std::ostringstream backtrace
;
554 std::list
<stack_frame
>::iterator it
= frames
.begin();
557 while (it
!= frames
.end()) {
559 backtrace
<< (*it
).instruction() << " : " << (*it
).function() << std::endl
;
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