AuroraRuntime/Source/Debug/Stack.Unix.cpp

135 lines
3.1 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Stack.Unix.cpp
Date: 2022-1-26
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "Stack.hpp"
#include "Stack.Unix.hpp"
#include <libunwind.h>
#include <dlfcn.h>
namespace Aurora::Debug
{
static void TryComplete(StackTraceEntry &entry)
{
}
static StackTrace DumpContext(unw_context_t *uc)
{
StackTrace ret;
unw_cursor_t cursor;
unw_word_t ip;
::unw_init_local(&cursor, uc);
while (::unw_step(&cursor) > 0)
{
StackTraceEntry entry;
::unw_get_reg(&cursor, UNW_REG_IP, &ip);
// module
{
unw_word_t off;
char procName[512];
if (unw_get_proc_name(&cursor, procName, AuArraySize(procName), &off) == 0)
{
AuString str;
str = AuString(procName, strlen(procName));
str += fmt::format("+0x{:x}", off);
entry.label = str;
}
}
{
Dl_info dlinfo;
AuSInt originalIP {};
AuUInt moduleAddress {};
const char *dllPathName {};
if (::dladdr((const void *)ip, &dlinfo))
{
dllPathName = dlinfo.dli_fname;
moduleAddress = (AuUInt)dlinfo.dli_fbase;
originalIP = (AuUInt)ip - moduleAddress;
}
entry.address = ip;
entry.relAddress = originalIP;
if (dllPathName)
{
entry.module = dllPathName;
}
}
AuTryInsert(ret, entry);
}
return ret;
}
StackTrace DumpContextPlatform(ucontext_t &uc)
{
// VALID:
// Linux: https://github.com/libunwind/libunwind/blob/3be832395426b72248969247a4a66e3c3623578d/include/libunwind-x86.h#L170
// ???
// MACOS: https://github.com/JuliaLang/libosxunwind/blob/master/include/libunwind.h#L57
return DumpContext((unw_context_t *)&uc);
}
StackTrace DumpContext(ucontext_t &uc)
{
return DumpContextPlatform(uc);
}
StackTrace DumpContext(void *pContext)
{
return DumpContext((unw_context_t *)pContext);
}
StackTrace PlatformWalkCallStack()
{
#if 0
StackTrace ret;
void *ips[1024];
int count = ::backtrace(ips, AuArraySize(ips));
auto messages = ::backtrace_symbols(ips, count);
if (!messages)
{
return {};
}
for (int i = 0; i < count; i++)
{
StackTraceEntry entry;
entry.address = AuUInt64(ips[i]);
entry.label = AuUInt64(messages[i]);
TryComplete(entry);
AuTryInsert(ret, entry);
}
free(messages);
return ret;
#endif
::unw_context_t uc;
::unw_getcontext(&uc);
return DumpContext(&uc);
}
}