This is sister-question of How to find load relocation for a PIE binary? which was solved by using _r_debug.r_map->l_addr
. Now I need to do this on Android NDK 19.
I need to print backtrace without symbols. I can do this with following code:
#include <iostream>
#include <iomanip>
#include <unwind.h>
#include <dlfcn.h>
#include <sstream>
#include <android/log.h>
namespace {
struct BacktraceState
{
void** current;
void** end;
};
static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg)
{
BacktraceState* state = static_cast<BacktraceState*>(arg);
uintptr_t pc = _Unwind_GetIP(context);
if (pc) {
if (state->current == state->end) {
return _URC_END_OF_STACK;
} else {
*state->current++ = reinterpret_cast<void*>(pc);
}
}
return _URC_NO_REASON;
}
}
size_t captureBacktrace(void** buffer, size_t max)
{
BacktraceState state = {buffer, buffer + max};
_Unwind_Backtrace(unwindCallback, &state);
return state.current - buffer;
}
namespace clog {
std::string bt(int from, int max_stack) {
const size_t MAX_STACK = 30;
if (from >= max_stack)
from = 0;
if (max_stack > MAX_STACK)
max_stack = MAX_STACK;
void* array[MAX_STACK];
std::ostringstream msg;
size_t size = captureBacktrace(array, MAX_STACK);
if (size >= 2) {
msg << "[bt]" << std::hex;
for (int i = from; i < size; ++i) {
msg << "0x" << reinterpret_cast<uintptr_t>(array[i]) << " ";
}
msg << "[/bt]" << std::dec;
}
return msg.str();
}
}
It prints addresses that include offset from ASLR. On Linux I fixed this by changing
msg << "0x" << reinterpret_cast<uintptr_t>(array[i]) << " ";
to
#include <execinfo.h>
#include <link.h>
...
static const uintptr_t relocation = _r_debug.r_map->l_addr;
msg << "0x" << reinterpret_cast<uintptr_t>(array[i]) - reinterpret_cast<uintptr_t>(relocation) << " ";
_r_debug.r_map->l_addr
is not available on Android as far as I can see. Is there some equivalent?