I implemented and adapted the solution of David Turner and it works
like a charm!
In order to let other people benefit from this, I will post below my
complete solution to get the callstack at runtime. This way I could
track memory allocations and find memory leaks. I just replaced own
typedef'd datatypes back to 'unsigned int' etc, hopefully without
mistake :)
#ifndef ANDROID_CALL_STACK_H
#define ANDROID_CALL_STACK_H
/**
@file CallStack_Android.h
@brief Getting the callstack under Android
@author Peter Holtwick
*/
#include <unwind.h>
#include <android/log.h>
#include <stdio.h>
#include <string.h>
namespace {
struct CallStackSaver
{
unsigned int* const m_PtrArr;
const unsigned short m_MaxFrames;
unsigned short m_CurrFrame;
static unsigned int m_LibraryAdjustment;
CallStackSaver( unsigned int pFrames[], unsigned short maxFrames )
:m_PtrArr( pFrames )
,m_MaxFrames( maxFrames )
,m_CurrFrame( 0 )
{
if( m_LibraryAdjustment == -1 ) {
m_LibraryAdjustment = GetLibraryAddress();
__android_log_print( ANDROID_LOG_DEBUG,
"CallStackSaver()", "Setting library adjustment to:
%p", m_LibraryAdjustment );
}
}
unsigned short
SaveCallStack()
{
_Unwind_Reason_Code res = _Unwind_Backtrace( &CallbackFunc,
this );
return m_CurrFrame; // number of collected frames
}
static _Unwind_Reason_Code
CallbackFunc( _Unwind_Context* ctx, void* a )
{
CallStackSaver* pThis = reinterpret_cast<CallStackSaver*>(a);
pThis->SaveAddress( _Unwind_GetIP(ctx) );
return _URC_OK;
}
void
SaveAddress( unsigned int rawAddr )
{
if( m_CurrFrame < m_MaxFrames ) {
m_PtrArr[ m_CurrFrame ] = rawAddr - m_LibraryAdjustment;
++m_CurrFrame;
}
}
unsigned int
GetLibraryAddress()
{
FILE* file = fopen( "/proc/self/maps", "rt");
if( file==NULL ) {
return 0;
}
unsigned int addr = 0;
const char* libraryName = "libMyLibraryName.so";
int len_libname = strlen(libraryName);
char buff[256];
while( fgets(buff, sizeof buff, file) != NULL )
{
int len = strlen(buff);
if( len > 0 && buff[len-1] == '\n' ) {
buff[--len] = '\0';
}
if (len <= len_libname || memcmp(buff + len - len_libname,
libraryName, len_libname)) {
continue;
}
unsigned int start, end, offset;
char flags[4];
if( sscanf( buff, "%zx-%zx %c%c%c%c %zx", &start, &end,
&flags[0], &flags[1], &flags[2], &flags[3],
&offset ) != 7 )
{
continue;
}
if( flags[0]=='r' && flags[1]=='-' && flags[2]=='x' ) {
addr = start - offset;
break;
}
} // while
fclose(file);
return addr;
}
};
// static
unsigned int CallStackSaver::m_LibraryAdjustment = -1;
} // namespace
unsigned short GetCallStackSnapshot( unsigned short dwMaxFrames,
unsigned int lpFrames[] )
{
CallStackSaver saver( lpFrames, dwMaxFrames );
return saver.SaveCallStack(); // number of collected frames
}
#endif // ANDROID_CALL_STACK_H