git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35878 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
240 lines
6.6 KiB
C++
240 lines
6.6 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: msw/stackwalk.cpp
|
|
// Purpose: wxStackWalker implementation for Unix/glibc
|
|
// Author: Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 2005-01-18
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_STACKWALKER
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/string.h"
|
|
#include "wx/app.h"
|
|
#include "wx/log.h"
|
|
#include "wx/utils.h"
|
|
#endif
|
|
|
|
#include "wx/stackwalk.h"
|
|
|
|
#include <execinfo.h>
|
|
|
|
#ifdef HAVE_CXA_DEMANGLE
|
|
#include <cxxabi.h>
|
|
#endif // HAVE_CXA_DEMANGLE
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// tiny helper wrapper around popen/pclose()
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class wxStdioPipe
|
|
{
|
|
public:
|
|
// ctor parameters are passed to popen()
|
|
wxStdioPipe(const char *command, const char *type)
|
|
{
|
|
m_fp = popen(command, type);
|
|
}
|
|
|
|
// conversion to stdio FILE
|
|
operator FILE *() const { return m_fp; }
|
|
|
|
// dtor closes the pipe
|
|
~wxStdioPipe()
|
|
{
|
|
if ( m_fp )
|
|
pclose(m_fp);
|
|
}
|
|
|
|
private:
|
|
FILE *m_fp;
|
|
|
|
DECLARE_NO_COPY_CLASS(wxStdioPipe)
|
|
};
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
wxString wxStackWalker::ms_exepath;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxStackFrame
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxStackFrame::OnGetName()
|
|
{
|
|
if ( m_hasName )
|
|
return;
|
|
|
|
m_hasName = true;
|
|
|
|
// try addr2line first because it always gives us demangled names (even if
|
|
// __cxa_demangle is not available) and because it seems less error-prone
|
|
// when it works, backtrace_symbols() sometimes returns incorrect results
|
|
OnGetLocation();
|
|
|
|
// format is: "module(funcname+offset) [address]" but the part in
|
|
// parentheses can be not present
|
|
wxString syminfo = wxString::FromAscii(m_syminfo);
|
|
const size_t posOpen = syminfo.find(_T('('));
|
|
if ( posOpen != wxString::npos )
|
|
{
|
|
const size_t posPlus = syminfo.find(_T('+'), posOpen + 1);
|
|
if ( posPlus != wxString::npos )
|
|
{
|
|
const size_t posClose = syminfo.find(_T(')'), posPlus + 1);
|
|
if ( posClose != wxString::npos )
|
|
{
|
|
if ( m_name.empty() )
|
|
{
|
|
m_name.assign(syminfo, posOpen + 1, posPlus - posOpen - 1);
|
|
|
|
#ifdef HAVE_CXA_DEMANGLE
|
|
int rc = -1;
|
|
char *cppfunc = __cxxabiv1::__cxa_demangle
|
|
(
|
|
m_name.mb_str(),
|
|
NULL, // output buffer (none, alloc it)
|
|
NULL, // [out] len of output buffer
|
|
&rc
|
|
);
|
|
if ( rc == 0 )
|
|
m_name = wxString::FromAscii(cppfunc);
|
|
|
|
free(cppfunc);
|
|
#endif // HAVE_CXA_DEMANGLE
|
|
}
|
|
|
|
unsigned long ofs;
|
|
if ( wxString(syminfo, posPlus + 1, posClose - posPlus - 1).
|
|
ToULong(&ofs, 0) )
|
|
m_offset = ofs;
|
|
}
|
|
}
|
|
|
|
m_module.assign(syminfo, posOpen);
|
|
}
|
|
else // not in "module(funcname+offset)" format
|
|
{
|
|
m_module = syminfo;
|
|
}
|
|
}
|
|
|
|
void wxStackFrame::OnGetLocation()
|
|
{
|
|
if ( m_hasLocation )
|
|
return;
|
|
|
|
m_hasLocation = true;
|
|
|
|
// we need to launch addr2line tool to get this information and we need to
|
|
// have the program name for this
|
|
wxString exepath = wxStackWalker::GetExePath();
|
|
if ( exepath.empty() )
|
|
{
|
|
if ( !wxTheApp || !wxTheApp->argv )
|
|
return;
|
|
exepath = wxTheApp->argv[0];
|
|
}
|
|
|
|
wxStdioPipe fp(wxString::Format(_T("addr2line -C -f -e \"%s\" %p"),
|
|
exepath.c_str(), m_address).mb_str(),
|
|
"r");
|
|
|
|
if ( !fp )
|
|
return;
|
|
|
|
// parse addr2line output
|
|
char buf[1024];
|
|
if ( !fgets(buf, WXSIZEOF(buf), fp) )
|
|
{
|
|
wxLogDebug(_T("Empty addr2line output?"));
|
|
return;
|
|
}
|
|
|
|
// 1st line has function name
|
|
if ( GetName().empty() )
|
|
{
|
|
m_name = wxString::FromAscii(buf);
|
|
m_name.RemoveLast(); // trailing newline
|
|
|
|
if ( m_name == _T("??") )
|
|
m_name.clear();
|
|
}
|
|
|
|
// 2nd one -- the file/line info
|
|
if ( fgets(buf, WXSIZEOF(buf), fp) )
|
|
{
|
|
wxString output(wxString::FromAscii(buf));
|
|
output.RemoveLast();
|
|
|
|
const size_t posColon = output.find(_T(':'));
|
|
if ( posColon != wxString::npos )
|
|
{
|
|
m_filename.assign(output, 0, posColon);
|
|
if ( m_filename == _T("??") )
|
|
{
|
|
m_filename.clear();
|
|
}
|
|
else
|
|
{
|
|
unsigned long line;
|
|
if ( wxString(output, posColon + 1, wxString::npos).
|
|
ToULong(&line) )
|
|
m_line = line;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxLogDebug(_T("Unexpected addr2line format: \"%s\""),
|
|
output.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxStackWalker
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxStackWalker::Walk(size_t skip)
|
|
{
|
|
// that many frames should be enough for everyone
|
|
void *addresses[200];
|
|
|
|
int depth = backtrace(addresses, WXSIZEOF(addresses));
|
|
if ( !depth )
|
|
return;
|
|
|
|
char **symbols = backtrace_symbols(addresses, depth);
|
|
|
|
// we have 3 more "intermediate" frames which the calling code doesn't know
|
|
// about., account for them
|
|
skip += 3;
|
|
|
|
for ( int n = skip; n < depth; n++ )
|
|
{
|
|
wxStackFrame frame(n - skip, addresses[n], symbols[n]);
|
|
OnStackFrame(frame);
|
|
}
|
|
}
|
|
|
|
#endif // wxUSE_STACKWALKER
|