Demangling C++ Names

March 26th, 2008 by Joe Ranieri

RuntimeException.stack is one of the most useful things to be added to REALbasic. However, we can make it a bit better by demangling any C++ function names that might be in the stack trace.

Function CPPDemangle(name as string) As string
  //! Demangles a C++ function name. Returns an empty string on failure.
  //! Only works on Mac OS X.
 
  #if targetMacOS
      declare function __cxa_demangle lib "/usr/lib/libstdc++.6.dylib" ( name as CString, _
      outBuffer as ptr, outLength as ptr, byref outState as integer ) as CString
    declare sub free lib "System" ( value as CString )
    const kStateSuccess = 0
 
    dim state as integer
    dim demangledString as CString = __cxa_demangle( name, nil, nil, state )
 
    if state = kStateSuccess then
      // create our RB string, then free the string demangle gave us
      dim result as string = demangledString
      free( demangledString )
 
      return result
    end if
  #endif
End Function

Then you can apply this function to the exception’s stack like so:

Function GetErrorStack(err as RuntimeException) As string()
  //! Gets the stack trace for our exception. This differs from
 //! RuntimeException.stack in that it demangles C++ names.
 
  // this can crash in some cases, giving us a completely useless crash log
  // <rb-feedback://keeqghwg>, hopefully this will be fixed someday...
  dim stack() as string = err.stack
  dim cleanedStack() as string
 
  // the order of RB's "for each" isn't defined <rb-feedback://hdcdbgfi>, so we have
  // to use a normal loop
  for i as integer = 0 to stack.ubound
    dim name as string = stack( i )
    dim demangledName as string = cppDemangle( name )
 
    if demangledName <> "" then
      cleanedStack.append( demangledName )
    else
      cleanedStack.append( name )
    end if
  next
 
  return cleanedStack
End Function

So, instead of seeing “__ZN14RuntimeListbox7GetTextE15getTextSelectorll” in an exception trace, you will see “RuntimeListbox::GetText(getTextSelector, long, long)“. Much, much easier on the eyes. :)


C++ instance method addresses

November 16th, 2007 by Joe Ranieri

Sorry if this looks like a repeat; it is a rewrite of a post on our old blog. It may differ from the original content.

C++ doesn’t let you get the address of an instance method. Even if you were to get the address, you couldn’t call it because the convention requires that ‘this’ be in the ecx register. However, with a little creativity we can work around this requirement.

(Please do not stare directly at the following code block until we manage to come up with a new color scheme for GeSHi!)

#include &lt;stdarg.h&gt;
 
void* GetInstanceMethodAddr(char x, ...) {
	va_list argp;
	void *addr;
 
	va_start(argp, x);
	addr = va_arg(argp, void *);
	va_end(argp);
 
	return addr;
}
 
// For example,
void *func = GetInstanceMethodAddr(42, &std::string::size);

The first parameter is arbitrary, and is only used because it’s required by varargs. You can change it as necessary.