]> git.saurik.com Git - wxWidgets.git/blame - src/unix/stackwalk.cpp
'[1219035] cleanup: miscellaneous' and minor source cleaning.
[wxWidgets.git] / src / unix / stackwalk.cpp
CommitLineData
eaff0f0d
VZ
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"
7a3ba35d
KH
30 #include "wx/app.h"
31 #include "wx/log.h"
32 #include "wx/utils.h"
eaff0f0d
VZ
33#endif
34
35#include "wx/stackwalk.h"
36
37#include <execinfo.h>
38
39#ifdef HAVE_CXA_DEMANGLE
40 #include <cxxabi.h>
41#endif // HAVE_CXA_DEMANGLE
42
ede3a6d6
VZ
43// ----------------------------------------------------------------------------
44// tiny helper wrapper around popen/pclose()
45// ----------------------------------------------------------------------------
46
47class wxStdioPipe
48{
49public:
50 // ctor parameters are passed to popen()
51 wxStdioPipe(const char *command, const char *type)
52 {
53 m_fp = popen(command, type);
54 }
55
56 // conversion to stdio FILE
57 operator FILE *() const { return m_fp; }
58
59 // dtor closes the pipe
60 ~wxStdioPipe()
61 {
62 if ( m_fp )
63 pclose(m_fp);
64 }
65
66private:
67 FILE *m_fp;
68
69 DECLARE_NO_COPY_CLASS(wxStdioPipe)
70};
71
eaff0f0d
VZ
72// ============================================================================
73// implementation
74// ============================================================================
75
76wxString wxStackWalker::ms_exepath;
77
78// ----------------------------------------------------------------------------
79// wxStackFrame
80// ----------------------------------------------------------------------------
81
82void wxStackFrame::OnGetName()
83{
84 if ( m_hasName )
85 return;
86
87 m_hasName = true;
88
89 // try addr2line first because it always gives us demangled names (even if
90 // __cxa_demangle is not available) and because it seems less error-prone
91 // when it works, backtrace_symbols() sometimes returns incorrect results
92 OnGetLocation();
93
94 // format is: "module(funcname+offset) [address]" but the part in
95 // parentheses can be not present
96 wxString syminfo = wxString::FromAscii(m_syminfo);
97 const size_t posOpen = syminfo.find(_T('('));
98 if ( posOpen != wxString::npos )
99 {
100 const size_t posPlus = syminfo.find(_T('+'), posOpen + 1);
101 if ( posPlus != wxString::npos )
102 {
103 const size_t posClose = syminfo.find(_T(')'), posPlus + 1);
104 if ( posClose != wxString::npos )
105 {
106 if ( m_name.empty() )
107 {
108 m_name.assign(syminfo, posOpen + 1, posPlus - posOpen - 1);
109
110#ifdef HAVE_CXA_DEMANGLE
111 int rc = -1;
112 char *cppfunc = __cxxabiv1::__cxa_demangle
113 (
114 m_name.mb_str(),
115 NULL, // output buffer (none, alloc it)
116 NULL, // [out] len of output buffer
117 &rc
118 );
119 if ( rc == 0 )
120 m_name = wxString::FromAscii(cppfunc);
121
122 free(cppfunc);
123#endif // HAVE_CXA_DEMANGLE
124 }
125
126 unsigned long ofs;
127 if ( wxString(syminfo, posPlus + 1, posClose - posPlus - 1).
128 ToULong(&ofs, 0) )
129 m_offset = ofs;
130 }
131 }
132 }
133
134 m_module.assign(syminfo, posOpen);
135}
136
137void wxStackFrame::OnGetLocation()
138{
139 if ( m_hasLocation )
140 return;
141
142 m_hasLocation = true;
143
144 // we need to launch addr2line tool to get this information and we need to
145 // have the program name for this
146 wxString exepath = wxStackWalker::GetExePath();
147 if ( exepath.empty() )
148 {
149 if ( !wxTheApp || !wxTheApp->argv )
150 return;
151 exepath = wxTheApp->argv[0];
152 }
153
ede3a6d6
VZ
154 wxStdioPipe fp(wxString::Format(_T("addr2line -C -f -e \"%s\" %p"),
155 exepath.c_str(), m_address).mb_str(),
156 "r");
157
158 if ( !fp )
159 return;
160
161 // parse addr2line output
162 char buf[1024];
163 if ( !fgets(buf, WXSIZEOF(buf), fp) )
eaff0f0d 164 {
ede3a6d6
VZ
165 wxLogDebug(_T("Empty addr2line output?"));
166 return;
167 }
168
169 // 1st line has function name
170 if ( GetName().empty() )
171 {
172 m_name = wxString::FromAscii(buf);
173 m_name.RemoveLast(); // trailing newline
174
175 if ( m_name == _T("??") )
176 m_name.clear();
177 }
eaff0f0d 178
ede3a6d6
VZ
179 // 2nd one -- the file/line info
180 if ( fgets(buf, WXSIZEOF(buf), fp) )
181 {
182 wxString output(wxString::FromAscii(buf));
183 output.RemoveLast();
184
185 const size_t posColon = output.find(_T(':'));
186 if ( posColon != wxString::npos )
187 {
188 m_filename.assign(output, 0, posColon);
189 if ( m_filename == _T("??") )
eaff0f0d 190 {
ede3a6d6 191 m_filename.clear();
eaff0f0d
VZ
192 }
193 else
194 {
ede3a6d6
VZ
195 unsigned long line;
196 if ( wxString(output, posColon + 1, wxString::npos).
197 ToULong(&line) )
198 m_line = line;
eaff0f0d
VZ
199 }
200 }
ede3a6d6
VZ
201 else
202 {
203 wxLogDebug(_T("Unexpected addr2line format: \"%s\""),
204 output.c_str());
205 }
eaff0f0d
VZ
206 }
207}
208
209// ----------------------------------------------------------------------------
210// wxStackWalker
211// ----------------------------------------------------------------------------
212
213void wxStackWalker::Walk(size_t skip)
214{
215 // that many frames should be enough for everyone
216 void *addresses[200];
217
218 int depth = backtrace(addresses, WXSIZEOF(addresses));
219 if ( !depth )
220 return;
221
222 char **symbols = backtrace_symbols(addresses, depth);
223
2c9b3131
JS
224 if (skip > (size_t) depth)
225 skip = (size_t) depth;
226
227 for ( int n = skip; n < depth; n++ )
eaff0f0d 228 {
2c9b3131 229 wxStackFrame frame(n, addresses[n-skip], symbols[n-skip]);
eaff0f0d
VZ
230 OnStackFrame(frame);
231 }
232}
233
234#endif // wxUSE_STACKWALKER