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.
|
- Provide native implementations of wxDatePickerCtrl and wxTimePickerCtrl.
|
||||||
- Fix handling of positional parameters in wxPrintf() &c (David Connet).
|
- Fix handling of positional parameters in wxPrintf() &c (David Connet).
|
||||||
|
- Implement wxStackWalker.
|
||||||
|
|
||||||
Univ:
|
Univ:
|
||||||
|
|
||||||
|
@@ -14,13 +14,6 @@
|
|||||||
#ifndef _WX_OSX_CHKCONF_H_
|
#ifndef _WX_OSX_CHKCONF_H_
|
||||||
#define _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
|
* 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
|
* 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);
|
m_module.assign(syminfo, posOpen);
|
||||||
}
|
}
|
||||||
|
#ifndef __WXOSX__
|
||||||
else // not in "module(funcname+offset)" format
|
else // not in "module(funcname+offset)" format
|
||||||
{
|
{
|
||||||
m_module = syminfo;
|
m_module = syminfo;
|
||||||
}
|
}
|
||||||
|
#endif // !__WXOSX__
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -204,6 +206,28 @@ void wxStackWalker::FreeStack()
|
|||||||
m_depth = 0;
|
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)
|
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
|
// 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
|
// build the command line for executing addr2line or atos under OS X using
|
||||||
// (e.g. use always chars, even in Unicode build: popen() always takes chars)
|
// 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());
|
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
|
len = (len <= 0) ? strlen(g_buf) : len; // in case snprintf() is broken
|
||||||
for (size_t i=0; i<n; i++)
|
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 )
|
if ( !fp )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// parse addr2line output (should be exactly 2 lines for each address)
|
// parse the output reusing the same buffer to avoid any big memory
|
||||||
// reusing the g_buf used for building the command line above
|
// allocations which could fail if our program is in a bad state
|
||||||
wxString name, filename;
|
wxString name, filename;
|
||||||
unsigned long line = 0,
|
unsigned long line = 0,
|
||||||
curr = 0;
|
curr = 0;
|
||||||
for ( size_t i = 0; i < n; i++ )
|
for ( size_t i = 0; i < n; i++ )
|
||||||
{
|
{
|
||||||
// 1st line has function name
|
#ifdef __WXOSX__
|
||||||
if ( fgets(g_buf, WXSIZEOF(g_buf), fp) )
|
wxString buffer;
|
||||||
{
|
if ( !ReadLine(fp, i, &buffer) )
|
||||||
name = wxString::FromAscii(g_buf);
|
return false;
|
||||||
name.RemoveLast(); // trailing newline
|
|
||||||
|
|
||||||
if ( name == wxT("??") )
|
line = 0;
|
||||||
name.clear();
|
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
|
else
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("cannot read addr2line output for stack frame #%lu"),
|
wxLogDebug(wxT("Unexpected addr2line format: \"%s\" - ")
|
||||||
(unsigned long)i);
|
wxT("the semicolon is missing"),
|
||||||
return false;
|
filename.c_str());
|
||||||
}
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif // __WXOSX__/!__WXOSX__
|
||||||
|
|
||||||
// now we've got enough info to initialize curr-th stack frame
|
// now we've got enough info to initialize curr-th stack frame
|
||||||
// (at worst, only addresses[i] and syminfo[i] have been initialized,
|
// (at worst, only addresses[i] and syminfo[i] have been initialized,
|
||||||
|
Reference in New Issue
Block a user