From: Vadim Zeitlin <vadim@wxwidgets.org> Date: Sun, 20 May 2012 20:29:22 +0000 (+0000) Subject: Implement wxStackWalker for wxOSX. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/abf99aad2d70e680cdfe0ad72842c9b10e50045a?ds=inline 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 --- diff --git a/docs/changes.txt b/docs/changes.txt index dda32f3a95..84a8530d22 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -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: diff --git a/include/wx/osx/chkconf.h b/include/wx/osx/chkconf.h index 98e950215f..1b56ac8981 100644 --- a/include/wx/osx/chkconf.h +++ b/include/wx/osx/chkconf.h @@ -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 diff --git a/src/unix/stackwalk.cpp b/src/unix/stackwalk.cpp index 6c234adbea..f724816e9c 100644 --- a/src/unix/stackwalk.cpp +++ b/src/unix/stackwalk.cpp @@ -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) ) +#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 = wxString::FromAscii(g_buf); - name.RemoveLast(); // trailing newline + 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); - if ( name == wxT("??") ) - name.clear(); + wxString linenum; + filename = location.BeforeFirst(':', &linenum); + if ( !linenum.empty() ) + linenum.ToULong(&line); + } } - else - { - wxLogDebug(wxT("cannot read addr2line output for stack frame #%lu"), - (unsigned long)i); +#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 ( 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 ) - { - // 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()); - } + 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 // (at worst, only addresses[i] and syminfo[i] have been initialized,