Implement wxStackWalker for wxOSX.

Use atos(1) to map address to their symbolic names.

Closes #10067.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71513 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2012-05-20 20:29:22 +00:00
parent 816e7781b0
commit abf99aad2d
3 changed files with 94 additions and 47 deletions

View File

@@ -581,6 +581,7 @@ OSX:
- Provide native implementations of wxDatePickerCtrl and wxTimePickerCtrl.
- Fix handling of positional parameters in wxPrintf() &c (David Connet).
- Implement wxStackWalker.
Univ:

View File

@@ -14,13 +14,6 @@
#ifndef _WX_OSX_CHKCONF_H_
#define _WX_OSX_CHKCONF_H_
#if wxUSE_STACKWALKER
/* not supported under Mac */
# undef wxUSE_STACKWALKER
# define wxUSE_STACKWALKER 0
#endif /* wxUSE_STACKWALKER */
/*
* check graphics context option, must be on for every os x platform
* we only use core graphics now on all builds, try to catch attempts

View File

@@ -130,10 +130,12 @@ void wxStackFrame::OnGetName()
m_module.assign(syminfo, posOpen);
}
#ifndef __WXOSX__
else // not in "module(funcname+offset)" format
{
m_module = syminfo;
}
#endif // !__WXOSX__
}
@@ -204,6 +206,28 @@ void wxStackWalker::FreeStack()
m_depth = 0;
}
namespace
{
// Helper function to read a line from the file and return it without the
// trailing newline. Line number is only used for error reporting.
bool ReadLine(FILE* fp, unsigned long num, wxString* line)
{
if ( !fgets(g_buf, WXSIZEOF(g_buf), fp) )
{
wxLogDebug(wxS("cannot read address information for stack frame #%lu"),
num);
return false;
}
*line = wxString::FromAscii(g_buf);
line->RemoveLast();
return true;
}
} // anonymous namespace
int wxStackWalker::InitFrames(wxStackFrame *arr, size_t n, void **addresses, char **syminfo)
{
// we need to launch addr2line tool to get this information and we need to
@@ -220,9 +244,13 @@ int wxStackWalker::InitFrames(wxStackFrame *arr, size_t n, void **addresses, cha
}
}
// build the (long) command line for executing addr2line in an optimized way
// (e.g. use always chars, even in Unicode build: popen() always takes chars)
// build the command line for executing addr2line or atos under OS X using
// char* directly to avoid the conversions from Unicode
#ifdef __WXOSX__
int len = snprintf(g_buf, BUFSIZE, "atos -p %d", (int)getpid());
#else
int len = snprintf(g_buf, BUFSIZE, "addr2line -C -f -e \"%s\"", (const char*) exepath.mb_str());
#endif
len = (len <= 0) ? strlen(g_buf) : len; // in case snprintf() is broken
for (size_t i=0; i<n; i++)
{
@@ -236,54 +264,79 @@ int wxStackWalker::InitFrames(wxStackFrame *arr, size_t n, void **addresses, cha
if ( !fp )
return 0;
// parse addr2line output (should be exactly 2 lines for each address)
// reusing the g_buf used for building the command line above
// parse the output reusing the same buffer to avoid any big memory
// allocations which could fail if our program is in a bad state
wxString name, filename;
unsigned long line = 0,
curr = 0;
for ( size_t i = 0; i < n; i++ )
{
// 1st line has function name
if ( fgets(g_buf, WXSIZEOF(g_buf), fp) )
{
name = wxString::FromAscii(g_buf);
name.RemoveLast(); // trailing newline
#ifdef __WXOSX__
wxString buffer;
if ( !ReadLine(fp, i, &buffer) )
return false;
if ( name == wxT("??") )
name.clear();
line = 0;
filename.clear();
// We can get back either the string in the following format:
//
// func(args) (in module) (file:line)
//
// or just the same address back if it couldn't be resolved.
const size_t posIn = buffer.find("(in ");
if ( posIn != wxString::npos )
{
name.assign(buffer, 0, posIn);
size_t posAt = buffer.find(") (", posIn + 3);
if ( posAt != wxString::npos )
{
posAt += 3; // Skip ") ("
// Discard the two last characters which are ")\n"
wxString location(buffer, posAt, buffer.length() - posAt - 2);
wxString linenum;
filename = location.BeforeFirst(':', &linenum);
if ( !linenum.empty() )
linenum.ToULong(&line);
}
}
#else // !__WXOSX__
// 1st line has function name
if ( !ReadLine(fp, i, &name) )
return false;
name = wxString::FromAscii(g_buf);
name.RemoveLast(); // trailing newline
if ( name == wxT("??") )
name.clear();
// 2nd one -- the file/line info
if ( !ReadLine(fp, i, &filename) )
return false;
const size_t posColon = filename.find(wxT(':'));
if ( posColon != wxString::npos )
{
// parse line number (it's ok if it fails, this will just leave
// line at its current, invalid, 0 value)
wxString(filename, posColon + 1, wxString::npos).ToULong(&line);
// remove line number from 'filename'
filename.erase(posColon);
if ( filename == wxT("??") )
filename.clear();
}
else
{
wxLogDebug(wxT("cannot read addr2line output for stack frame #%lu"),
(unsigned long)i);
return false;
}
// 2nd one -- the file/line info
if ( fgets(g_buf, WXSIZEOF(g_buf), fp) )
{
filename = wxString::FromAscii(g_buf);
filename.RemoveLast();
const size_t posColon = filename.find(wxT(':'));
if ( posColon != wxString::npos )
{
// parse line number (it's ok if it fails, this will just leave
// line at its current, invalid, 0 value)
wxString(filename, posColon + 1, wxString::npos).ToULong(&line);
// remove line number from 'filename'
filename.erase(posColon);
if ( filename == wxT("??") )
filename.clear();
}
else
{
wxLogDebug(wxT("Unexpected addr2line format: \"%s\" - ")
wxT("the semicolon is missing"),
filename.c_str());
}
wxLogDebug(wxT("Unexpected addr2line format: \"%s\" - ")
wxT("the semicolon is missing"),
filename.c_str());
}
#endif // __WXOSX__/!__WXOSX__
// now we've got enough info to initialize curr-th stack frame
// (at worst, only addresses[i] and syminfo[i] have been initialized,