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:
@@ -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:
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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,34 +264,59 @@ 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) )
|
||||
#ifdef __WXOSX__
|
||||
wxString buffer;
|
||||
if ( !ReadLine(fp, i, &buffer) )
|
||||
return false;
|
||||
|
||||
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();
|
||||
}
|
||||
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();
|
||||
if ( !ReadLine(fp, i, &filename) )
|
||||
return false;
|
||||
|
||||
const size_t posColon = filename.find(wxT(':'));
|
||||
if ( posColon != wxString::npos )
|
||||
@@ -283,7 +336,7 @@ int wxStackWalker::InitFrames(wxStackFrame *arr, size_t n, void **addresses, cha
|
||||
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,
|
||||
|
Reference in New Issue
Block a user