Imported Upstream version 17.12.0
[platform/upstream/libzypp.git] / zypp / base / Backtrace.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/base/Backtrace.cc
10  */
11 #include <execinfo.h>
12 #include <cxxabi.h>
13
14 #include <iostream>
15 #include "zypp/base/LogTools.h"
16 #include "zypp/base/String.h"
17 #include "zypp/base/Backtrace.h"
18
19 using std::endl;
20
21 ///////////////////////////////////////////////////////////////////
22 namespace zypp
23 {
24   std::ostream & dumpBacktrace( std::ostream & stream_r )
25   {
26     // get void*'s for all entries on the stack
27     static const size_t arraySize = 50;
28     void *array[arraySize];
29     size_t size = ::backtrace( array, arraySize );
30
31     // Print out all frames to stderr. Separate sigsegvHandler stack
32     // [dumpBacktrace][sigsegvHandler][libc throwing] from actual
33     // code stack.
34     char ** messages = ::backtrace_symbols( array, size );
35     if ( messages )
36     {
37       static const size_t handlerStack = 3; // [dumpBacktrace][sigsegvHandler][libc throwing]
38       static const size_t first = 0;
39       for ( size_t i = first; i < size; ++i )
40       {
41         char * mangled_name = 0;
42         char * offset_begin = 0;
43         char * offset_end = 0;
44
45         // find parentheses and +address offset surrounding mangled name
46         for ( char * p = messages[i]; *p; ++p )
47         {
48           if ( *p == '(' )
49           {
50             mangled_name = p;
51           }
52           else if ( *p == '+' )
53           {
54             offset_begin = p;
55           }
56           else if ( *p == ')' )
57           {
58             offset_end = p;
59             break;
60           }
61         }
62
63         int btLevel = i-handlerStack; // negative level in sigsegvHandler
64         if ( i > first )
65         {
66           stream_r << endl;
67           if ( btLevel == 0 )
68             stream_r << "vvvvvvvvvv----------------------------------------" << endl;
69         }
70         stream_r << "[" << (btLevel<0 ?"hd":"bt") << "]: (" << btLevel << ") ";
71
72         // if the line could be processed, attempt to demangle the symbol
73         if ( mangled_name && offset_begin && offset_end && mangled_name < offset_begin )
74         {
75           *mangled_name++ = '\0';
76           *offset_begin++ = '\0';
77           *offset_end++ = '\0';
78
79           int status;
80           char * real_name = ::abi::__cxa_demangle( mangled_name, 0, 0, &status );
81
82           // if demangling is successful, output the demangled function name
83           if ( status == 0 )
84           {
85             stream_r << messages[i] << " : " << real_name << "+" << offset_begin << offset_end;
86           }
87           // otherwise, output the mangled function name
88           else
89           {
90             stream_r << messages[i] << " : " << mangled_name << "+" << offset_begin << offset_end;
91           }
92           ::free( real_name );
93         }
94         else
95         {
96           // otherwise, print the whole line
97           stream_r << messages[i];
98         }
99       }
100       ::free( messages );
101     }
102     return stream_r;
103   }
104
105 } // namespace zypp
106 ///////////////////////////////////////////////////////////////////