1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/stackwalk.cpp
3 // Purpose: wxStackWalker implementation for Unix/glibc
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
29 #include "wx/string.h"
35 #include "wx/stackwalk.h"
39 #ifdef HAVE_CXA_DEMANGLE
41 #endif // HAVE_CXA_DEMANGLE
43 // ----------------------------------------------------------------------------
44 // tiny helper wrapper around popen/pclose()
45 // ----------------------------------------------------------------------------
50 // ctor parameters are passed to popen()
51 wxStdioPipe(const char *command
, const char *type
)
53 m_fp
= popen(command
, type
);
56 // conversion to stdio FILE
57 operator FILE *() const { return m_fp
; }
59 // dtor closes the pipe
69 DECLARE_NO_COPY_CLASS(wxStdioPipe
)
72 // ============================================================================
74 // ============================================================================
76 wxString
wxStackWalker::ms_exepath
;
78 // ----------------------------------------------------------------------------
80 // ----------------------------------------------------------------------------
82 void wxStackFrame::OnGetName()
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
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
)
100 const size_t posPlus
= syminfo
.find(_T('+'), posOpen
+ 1);
101 if ( posPlus
!= wxString::npos
)
103 const size_t posClose
= syminfo
.find(_T(')'), posPlus
+ 1);
104 if ( posClose
!= wxString::npos
)
106 if ( m_name
.empty() )
108 m_name
.assign(syminfo
, posOpen
+ 1, posPlus
- posOpen
- 1);
110 #ifdef HAVE_CXA_DEMANGLE
112 char *cppfunc
= __cxxabiv1::__cxa_demangle
115 NULL
, // output buffer (none, alloc it)
116 NULL
, // [out] len of output buffer
120 m_name
= wxString::FromAscii(cppfunc
);
123 #endif // HAVE_CXA_DEMANGLE
127 if ( wxString(syminfo
, posPlus
+ 1, posClose
- posPlus
- 1).
133 m_module
.assign(syminfo
, posOpen
);
135 else // not in "module(funcname+offset)" format
141 void wxStackFrame::OnGetLocation()
146 m_hasLocation
= true;
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() )
153 if ( !wxTheApp
|| !wxTheApp
->argv
)
155 exepath
= wxTheApp
->argv
[0];
158 wxStdioPipe
fp(wxString::Format(_T("addr2line -C -f -e \"%s\" %p"),
159 exepath
.c_str(), m_address
).mb_str(),
165 // parse addr2line output
167 if ( !fgets(buf
, WXSIZEOF(buf
), fp
) )
169 wxLogDebug(_T("Empty addr2line output?"));
173 // 1st line has function name
174 if ( GetName().empty() )
176 m_name
= wxString::FromAscii(buf
);
177 m_name
.RemoveLast(); // trailing newline
179 if ( m_name
== _T("??") )
183 // 2nd one -- the file/line info
184 if ( fgets(buf
, WXSIZEOF(buf
), fp
) )
186 wxString
output(wxString::FromAscii(buf
));
189 const size_t posColon
= output
.find(_T(':'));
190 if ( posColon
!= wxString::npos
)
192 m_filename
.assign(output
, 0, posColon
);
193 if ( m_filename
== _T("??") )
200 if ( wxString(output
, posColon
+ 1, wxString::npos
).
207 wxLogDebug(_T("Unexpected addr2line format: \"%s\""),
213 // ----------------------------------------------------------------------------
215 // ----------------------------------------------------------------------------
217 void wxStackWalker::Walk(size_t skip
)
219 // that many frames should be enough for everyone
220 void *addresses
[200];
222 int depth
= backtrace(addresses
, WXSIZEOF(addresses
));
226 char **symbols
= backtrace_symbols(addresses
, depth
);
228 // we have 3 more "intermediate" frames which the calling code doesn't know
229 // about., account for them
232 for ( int n
= skip
; n
< depth
; n
++ )
234 wxStackFrame
frame(n
- skip
, addresses
[n
], symbols
[n
]);
239 #endif // wxUSE_STACKWALKER