]> git.saurik.com Git - wxWidgets.git/blame - src/unix/stackwalk.cpp
better compatibility with old wxList in wxUSE_STL==1 mode (patch 1075432)
[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
43// ============================================================================
44// implementation
45// ============================================================================
46
47wxString wxStackWalker::ms_exepath;
48
49// ----------------------------------------------------------------------------
50// wxStackFrame
51// ----------------------------------------------------------------------------
52
53void wxStackFrame::OnGetName()
54{
55 if ( m_hasName )
56 return;
57
58 m_hasName = true;
59
60 // try addr2line first because it always gives us demangled names (even if
61 // __cxa_demangle is not available) and because it seems less error-prone
62 // when it works, backtrace_symbols() sometimes returns incorrect results
63 OnGetLocation();
64
65 // format is: "module(funcname+offset) [address]" but the part in
66 // parentheses can be not present
67 wxString syminfo = wxString::FromAscii(m_syminfo);
68 const size_t posOpen = syminfo.find(_T('('));
69 if ( posOpen != wxString::npos )
70 {
71 const size_t posPlus = syminfo.find(_T('+'), posOpen + 1);
72 if ( posPlus != wxString::npos )
73 {
74 const size_t posClose = syminfo.find(_T(')'), posPlus + 1);
75 if ( posClose != wxString::npos )
76 {
77 if ( m_name.empty() )
78 {
79 m_name.assign(syminfo, posOpen + 1, posPlus - posOpen - 1);
80
81#ifdef HAVE_CXA_DEMANGLE
82 int rc = -1;
83 char *cppfunc = __cxxabiv1::__cxa_demangle
84 (
85 m_name.mb_str(),
86 NULL, // output buffer (none, alloc it)
87 NULL, // [out] len of output buffer
88 &rc
89 );
90 if ( rc == 0 )
91 m_name = wxString::FromAscii(cppfunc);
92
93 free(cppfunc);
94#endif // HAVE_CXA_DEMANGLE
95 }
96
97 unsigned long ofs;
98 if ( wxString(syminfo, posPlus + 1, posClose - posPlus - 1).
99 ToULong(&ofs, 0) )
100 m_offset = ofs;
101 }
102 }
103 }
104
105 m_module.assign(syminfo, posOpen);
106}
107
108void wxStackFrame::OnGetLocation()
109{
110 if ( m_hasLocation )
111 return;
112
113 m_hasLocation = true;
114
115 // we need to launch addr2line tool to get this information and we need to
116 // have the program name for this
117 wxString exepath = wxStackWalker::GetExePath();
118 if ( exepath.empty() )
119 {
120 if ( !wxTheApp || !wxTheApp->argv )
121 return;
122 exepath = wxTheApp->argv[0];
123 }
124
125 wxArrayString output;
126 wxLogNull noLog;
127 if ( wxExecute(wxString::Format(_T("addr2line -C -f -e \"%s\" %p"),
128 exepath.c_str(),
129 m_address), output) == 0 )
130 {
131 if ( output.GetCount() != 2 )
132 {
133 wxLogDebug(_T("Unexpected addr2line output."));
134 }
135 else // 1st line has function name, 2nd one -- the file/line info
136 {
137 if ( GetName().empty() )
138 {
139 m_name = output[0];
140 if ( m_name == _T("??") )
141 m_name.clear();
142 }
143
144 const size_t posColon = output[1].find(_T(':'));
145 if ( posColon != wxString::npos )
146 {
147 m_filename.assign(output[1], 0, posColon);
148 if ( m_filename == _T("??") )
149 {
150 m_filename.clear();
151 }
152 else
153 {
154 unsigned long line;
155 if ( wxString(output[1], posColon + 1, wxString::npos).
156 ToULong(&line) )
157 m_line = line;
158 }
159 }
160 else
161 {
162 wxLogDebug(_T("Unexpected addr2line format: \"%s\""),
163 output[1].c_str());
164 }
165 }
166 }
167}
168
169// ----------------------------------------------------------------------------
170// wxStackWalker
171// ----------------------------------------------------------------------------
172
173void wxStackWalker::Walk(size_t skip)
174{
175 // that many frames should be enough for everyone
176 void *addresses[200];
177
178 int depth = backtrace(addresses, WXSIZEOF(addresses));
179 if ( !depth )
180 return;
181
182 char **symbols = backtrace_symbols(addresses, depth);
183
184 for ( int n = 0; n < depth; n++ )
185 {
186 wxStackFrame frame(n, addresses[n], symbols[n]);
187 OnStackFrame(frame);
188 }
189}
190
191#endif // wxUSE_STACKWALKER