#ifdef UNSAFE_BUFFERS_BUILD
# pragma allow_unsafe_buffers
#endif
#include "backtrace_utils.h"
#include <dlfcn.h>
#include <unwind.h>
namespace
{
constexpr uint32_t kMaxBacktraceSize = 16;
struct UnwindCallbackFnState
{
UnwindCallbackFnState() : current(nullptr), end(nullptr) {}
UnwindCallbackFnState(void **current, void **end) : current(current), end(end) {}
void **current;
void **end;
};
_Unwind_Reason_Code unwindCallbackFn(struct _Unwind_Context *context, void *args)
{
auto *state = reinterpret_cast<UnwindCallbackFnState *>(args);
uintptr_t ip = _Unwind_GetIP(context);
if (ip == 0)
{
return _URC_NO_REASON;
}
if (state->current == state->end)
{
return _URC_END_OF_STACK;
}
*state->current++ = reinterpret_cast<void *>(ip);
return _URC_NO_REASON;
}
}
namespace angle
{
void BacktraceInfo::populateBacktraceInfo(void **stackAddressBuffer, size_t stackAddressCount)
{
ASSERT(mStackAddresses.empty() && mStackSymbols.empty());
for (size_t i = 0; i < stackAddressCount; i++)
{
void *stackAddr = stackAddressBuffer[i];
mStackAddresses.push_back(stackAddr);
Dl_info dlInfo;
if (dladdr(stackAddr, &dlInfo) != 0 && dlInfo.dli_sname)
{
mStackSymbols.emplace_back(dlInfo.dli_sname);
}
else
{
mStackSymbols.emplace_back("unknown_symbol");
}
}
ASSERT(mStackAddresses.size() == mStackSymbols.size());
}
BacktraceInfo getBacktraceInfo()
{
void *stackAddrBuffer[kMaxBacktraceSize];
UnwindCallbackFnState unwindFnState(stackAddrBuffer, stackAddrBuffer + kMaxBacktraceSize);
_Unwind_Backtrace(unwindCallbackFn, &unwindFnState);
auto stackAddressCount = static_cast<size_t>(unwindFnState.current - stackAddrBuffer);
BacktraceInfo backtraceInfo;
backtraceInfo.populateBacktraceInfo(stackAddrBuffer, stackAddressCount);
return backtraceInfo;
}
}