]> git.saurik.com Git - wxWidgets.git/blame - src/unix/stackwalk.cpp
properly NUL-terminate the output in wxMBConvUTF16swap::WC2MB()
[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 }
eaff0f0d 132
1872e042
VZ
133 m_module.assign(syminfo, posOpen);
134 }
135 else // not in "module(funcname+offset)" format
136 {
137 m_module = syminfo;
138 }
eaff0f0d
VZ
139}
140
141void wxStackFrame::OnGetLocation()
142{
143 if ( m_hasLocation )
144 return;
145
146 m_hasLocation = true;
147
148 // we need to launch addr2line tool to get this information and we need to
149 // have the program name for this
150 wxString exepath = wxStackWalker::GetExePath();
151 if ( exepath.empty() )
152 {
153 if ( !wxTheApp || !wxTheApp->argv )
154 return;
155 exepath = wxTheApp->argv[0];
156 }
157
ede3a6d6
VZ
158 wxStdioPipe fp(wxString::Format(_T("addr2line -C -f -e \"%s\" %p"),
159 exepath.c_str(), m_address).mb_str(),
160 "r");
161
162 if ( !fp )
163 return;
164
165 // parse addr2line output
166 char buf[1024];
167 if ( !fgets(buf, WXSIZEOF(buf), fp) )
eaff0f0d 168 {
ede3a6d6
VZ
169 wxLogDebug(_T("Empty addr2line output?"));
170 return;
171 }
172
173 // 1st line has function name
174 if ( GetName().empty() )
175 {
176 m_name = wxString::FromAscii(buf);
177 m_name.RemoveLast(); // trailing newline
178
179 if ( m_name == _T("??") )
180 m_name.clear();
181 }
eaff0f0d 182
ede3a6d6
VZ
183 // 2nd one -- the file/line info
184 if ( fgets(buf, WXSIZEOF(buf), fp) )
185 {
186 wxString output(wxString::FromAscii(buf));
187 output.RemoveLast();
188
189 const size_t posColon = output.find(_T(':'));
190 if ( posColon != wxString::npos )
191 {
192 m_filename.assign(output, 0, posColon);
193 if ( m_filename == _T("??") )
eaff0f0d 194 {
ede3a6d6 195 m_filename.clear();
eaff0f0d
VZ
196 }
197 else
198 {
ede3a6d6
VZ
199 unsigned long line;
200 if ( wxString(output, posColon + 1, wxString::npos).
201 ToULong(&line) )
202 m_line = line;
eaff0f0d
VZ
203 }
204 }
ede3a6d6
VZ
205 else
206 {
207 wxLogDebug(_T("Unexpected addr2line format: \"%s\""),
208 output.c_str());
209 }
eaff0f0d
VZ
210 }
211}
212
213// ----------------------------------------------------------------------------
214// wxStackWalker
215// ----------------------------------------------------------------------------
216
217void wxStackWalker::Walk(size_t skip)
218{
219 // that many frames should be enough for everyone
220 void *addresses[200];
221
222 int depth = backtrace(addresses, WXSIZEOF(addresses));
223 if ( !depth )
224 return;
225
226 char **symbols = backtrace_symbols(addresses, depth);
227
d2dfef5f
VZ
228 // we have 3 more "intermediate" frames which the calling code doesn't know
229 // about., account for them
230 skip += 3;
2c9b3131
JS
231
232 for ( int n = skip; n < depth; n++ )
eaff0f0d 233 {
d2dfef5f 234 wxStackFrame frame(n - skip, addresses[n], symbols[n]);
eaff0f0d
VZ
235 OnStackFrame(frame);
236 }
237}
238
239#endif // wxUSE_STACKWALKER