Modules/private/StackTrace.cpp
2023-05-26 01:35:29 +03:00

186 lines
No EOL
4.4 KiB
C++

#include "StackTrace.hpp"
#include "PrivateConfig.hpp"
#include <Windows.h>
#include <DbgHelp.h>
#include <iostream>
#include <cstdint>
#pragma comment(lib, "dbghelp.lib")
using namespace tp;
tp::CallStackSnapshots tp::gCallStackSnapshots;
// ----------------------- Dict ----------------------- //
CallStackSnapshots::SnapshotsDict::SnapshotsDict() {
mTable = (StackShapshot*)malloc(sizeof(StackShapshot) * mSize);
memsetv(mTable, sizeof(StackShapshot) * mSize, 0);
}
CallStackSnapshots::StackShapshot CallStackSnapshots::SnapshotsDict::getSlot(ualni aIdx) {
return mTable[aIdx];
}
alni CallStackSnapshots::SnapshotsDict::presents(StackShapshot aPtr) {
return findSlotRead(aPtr);
}
void CallStackSnapshots::SnapshotsDict::put(StackShapshot aPtr) {
auto idx = findSlotWrite(aPtr);
mTable[idx] = aPtr;
mEntries++;
if ((halnf)mEntries / mSize > 2.f / 3.f) {
resize();
}
}
void CallStackSnapshots::SnapshotsDict::resize() {
alni nslots_old = mSize;
auto table_old = mTable;
mSize *= 2;
mTable = (StackShapshot*)malloc(sizeof(StackShapshot) * mSize);
memsetv(mTable, sizeof(StackShapshot) * mSize, 0);
mEntries = 0;
for (alni i = 0; i < nslots_old; i++) {
if (!table_old[i]) {
continue;
}
alni idx = findSlotWrite(table_old[i]);
mTable[idx] = table_old[i];
mEntries++;
}
delete[] table_old;
}
alni CallStackSnapshots::SnapshotsDict::findSlotRead(StackShapshot key) {
ualni const hased_key = hash(key);
ualni const mask = mSize - 1;
ualni const shift = (hased_key >> 5) & ~1;
alni idx = hased_key & mask;
NEXT:
if (!mTable[idx]) {
return -1;
}
if (compare(mTable[idx], key)) {
return idx;
}
SKIP:
idx = ((5 * idx) + 1 + shift) & mask;
goto NEXT;
}
ualni CallStackSnapshots::SnapshotsDict::findSlotWrite(StackShapshot key) {
ualni const hased_key = hash(key);
ualni const mask = mSize - 1;
ualni const shift = (hased_key >> 5) & ~1;
ualni idx = hased_key & mask;
NEXT:
if (!mTable[idx]) {
return idx;
}
idx = ((5 * idx) + 1 + shift) & mask;
goto NEXT;
}
CallStackSnapshots::StackShapshot CallStackSnapshots::SnapshotsDict::newStackSnapshot(ualni aDepth) {
auto const size = sizeof(FramePointer) * (aDepth + 1);
auto out = (StackShapshot*)malloc(size);
memsetv(out, size, 0);
}
ualni CallStackSnapshots::SnapshotsDict::hash(StackShapshot snapshot) {
ualni out = 0;
for (FramePointer* iter = snapshot; iter; iter++) { out += *iter; }
return out;
}
bool CallStackSnapshots::SnapshotsDict::compare(StackShapshot left, StackShapshot right) {
FramePointer* iter_left = left;
FramePointer* iter_right = right;
do {
if (*iter_left != *iter_right) {
return false;
}
iter_left++;
iter_right++;
} while (iter_left && iter_right);
if (*iter_left != *iter_right) {
return false;
}
return true;
}
CallStackSnapshots::SnapshotsDict::~SnapshotsDict() {
for (ualni idx = 0; idx < mSize; idx++) {
if (mTable[idx]) {
free(mTable[idx]);
}
}
free(mTable);
}
// ----------------------- CallStackSnapshots ----------------------- //
CallStackSnapshots::StackShapshot CallStackSnapshots::getStack(ualni& len) {
enum { MAX_DEPTH = MEM_STACK_TRACE_MAX_DEPTH };
static FramePointer pointers[MAX_DEPTH];
len = 0;
CONTEXT context;
RtlCaptureContext(&context);
STACKFRAME64 stackFrame;
ZeroMemory(&stackFrame, sizeof(STACKFRAME64));
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Mode = AddrModeFlat;
stackFrame.AddrPC.Offset = context.Rip;
stackFrame.AddrFrame.Offset = context.Rbp;
stackFrame.AddrStack.Offset = context.Rsp;
HANDLE processHandle = GetCurrentProcess();
HANDLE threadHandle = GetCurrentThread();
while (
len < MAX_DEPTH &&
StackWalk64(IMAGE_FILE_MACHINE_AMD64, processHandle, threadHandle, &stackFrame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)
)
{
pointers[len] = stackFrame.AddrFrame.Offset;
len++;
}
return pointers;
}
CallStackSnapshots::StackShapshot CallStackSnapshots::capture() {
ualni len;
auto stack = getStack(len);
auto idx = mSnapshots.presents(stack);
if (idx == -1) {
auto new_snapshot = mSnapshots.newStackSnapshot(len + 1);
memcp(new_snapshot, stack, len * sizeof(FramePointer));
new_snapshot[len] = 0;
mSnapshots.put(new_snapshot);
return new_snapshot;
}
return mSnapshots.getSlot(idx);
}
void CallStackSnapshots::saveToFile(StackShapshot* snapshots, const char* filepath) {
}
CallStackSnapshots::StackShapshot* CallStackSnapshots::loadFromFile(const char* filepath) {
}