]> git.saurik.com Git - wxWidgets.git/blob - src/unix/stackwalk.cpp
implemented wxStackWalker for Unix (using glibc-specific methods); moved wxUSE_STACKW...
[wxWidgets.git] / src / unix / stackwalk.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/stackwalk.cpp
3 // Purpose: wxStackWalker implementation for Unix/glibc
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 2005-01-18
7 // RCS-ID: $Id$
8 // Copyright: (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_STACKWALKER
27
28 #ifndef WX_PRECOMP
29 #include "wx/string.h"
30 #endif
31
32 #include "wx/stackwalk.h"
33
34 #include <execinfo.h>
35
36 #ifdef HAVE_CXA_DEMANGLE
37 #include <cxxabi.h>
38 #endif // HAVE_CXA_DEMANGLE
39
40 // ============================================================================
41 // implementation
42 // ============================================================================
43
44 wxString wxStackWalker::ms_exepath;
45
46 // ----------------------------------------------------------------------------
47 // wxStackFrame
48 // ----------------------------------------------------------------------------
49
50 void wxStackFrame::OnGetName()
51 {
52 if ( m_hasName )
53 return;
54
55 m_hasName = true;
56
57 // try addr2line first because it always gives us demangled names (even if
58 // __cxa_demangle is not available) and because it seems less error-prone
59 // when it works, backtrace_symbols() sometimes returns incorrect results
60 OnGetLocation();
61
62 // format is: "module(funcname+offset) [address]" but the part in
63 // parentheses can be not present
64 wxString syminfo = wxString::FromAscii(m_syminfo);
65 const size_t posOpen = syminfo.find(_T('('));
66 if ( posOpen != wxString::npos )
67 {
68 const size_t posPlus = syminfo.find(_T('+'), posOpen + 1);
69 if ( posPlus != wxString::npos )
70 {
71 const size_t posClose = syminfo.find(_T(')'), posPlus + 1);
72 if ( posClose != wxString::npos )
73 {
74 if ( m_name.empty() )
75 {
76 m_name.assign(syminfo, posOpen + 1, posPlus - posOpen - 1);
77
78 #ifdef HAVE_CXA_DEMANGLE
79 int rc = -1;
80 char *cppfunc = __cxxabiv1::__cxa_demangle
81 (
82 m_name.mb_str(),
83 NULL, // output buffer (none, alloc it)
84 NULL, // [out] len of output buffer
85 &rc
86 );
87 if ( rc == 0 )
88 m_name = wxString::FromAscii(cppfunc);
89
90 free(cppfunc);
91 #endif // HAVE_CXA_DEMANGLE
92 }
93
94 unsigned long ofs;
95 if ( wxString(syminfo, posPlus + 1, posClose - posPlus - 1).
96 ToULong(&ofs, 0) )
97 m_offset = ofs;
98 }
99 }
100 }
101
102 m_module.assign(syminfo, posOpen);
103 }
104
105 void wxStackFrame::OnGetLocation()
106 {
107 if ( m_hasLocation )
108 return;
109
110 m_hasLocation = true;
111
112 // we need to launch addr2line tool to get this information and we need to
113 // have the program name for this
114 wxString exepath = wxStackWalker::GetExePath();
115 if ( exepath.empty() )
116 {
117 if ( !wxTheApp || !wxTheApp->argv )
118 return;
119 exepath = wxTheApp->argv[0];
120 }
121
122 wxArrayString output;
123 wxLogNull noLog;
124 if ( wxExecute(wxString::Format(_T("addr2line -C -f -e \"%s\" %p"),
125 exepath.c_str(),
126 m_address), output) == 0 )
127 {
128 if ( output.GetCount() != 2 )
129 {
130 wxLogDebug(_T("Unexpected addr2line output."));
131 }
132 else // 1st line has function name, 2nd one -- the file/line info
133 {
134 if ( GetName().empty() )
135 {
136 m_name = output[0];
137 if ( m_name == _T("??") )
138 m_name.clear();
139 }
140
141 const size_t posColon = output[1].find(_T(':'));
142 if ( posColon != wxString::npos )
143 {
144 m_filename.assign(output[1], 0, posColon);
145 if ( m_filename == _T("??") )
146 {
147 m_filename.clear();
148 }
149 else
150 {
151 unsigned long line;
152 if ( wxString(output[1], posColon + 1, wxString::npos).
153 ToULong(&line) )
154 m_line = line;
155 }
156 }
157 else
158 {
159 wxLogDebug(_T("Unexpected addr2line format: \"%s\""),
160 output[1].c_str());
161 }
162 }
163 }
164 }
165
166 // ----------------------------------------------------------------------------
167 // wxStackWalker
168 // ----------------------------------------------------------------------------
169
170 void wxStackWalker::Walk(size_t skip)
171 {
172 // that many frames should be enough for everyone
173 void *addresses[200];
174
175 int depth = backtrace(addresses, WXSIZEOF(addresses));
176 if ( !depth )
177 return;
178
179 char **symbols = backtrace_symbols(addresses, depth);
180
181 for ( int n = 0; n < depth; n++ )
182 {
183 wxStackFrame frame(n, addresses[n], symbols[n]);
184 OnStackFrame(frame);
185 }
186 }
187
188 #endif // wxUSE_STACKWALKER