125 lines
3.2 KiB
C++
125 lines
3.2 KiB
C++
#pragma once
|
|
|
|
#include "Environment.hpp"
|
|
#include "Map.hpp"
|
|
|
|
#define MAX_CALL_DEPTH_CAPTURE 16
|
|
#define MAX_CALL_CAPTURES_MEM_SIZE_MB 16
|
|
#define MAX_DEBUG_INFO_LEN 63
|
|
#define FRAMES_TO_SKIP_START 2
|
|
#define FRAMES_TO_SKIP_END 3
|
|
|
|
namespace tp {
|
|
|
|
class CallStackCapture {
|
|
public:
|
|
typedef tp::alni FramePointer;
|
|
|
|
class CallStack {
|
|
friend CallStackCapture;
|
|
FramePointer frames[MAX_CALL_DEPTH_CAPTURE];
|
|
|
|
public:
|
|
[[nodiscard]] ualni getDepth() const;
|
|
|
|
class Iterator {
|
|
const FramePointer* mFrame;
|
|
public:
|
|
explicit Iterator(const FramePointer* frame) : mFrame(frame) {};
|
|
FramePointer getFrame() { return *mFrame; }
|
|
bool operator==(const Iterator& in) const { return in.mFrame == mFrame; }
|
|
void operator++() { mFrame++; }
|
|
const Iterator& operator*() const { return *this; }
|
|
};
|
|
|
|
[[nodiscard]] Iterator begin() const { return Iterator(frames + FRAMES_TO_SKIP_START); }
|
|
[[nodiscard]] Iterator end() const { return Iterator(frames + FRAMES_TO_SKIP_START + getDepth()); }
|
|
};
|
|
|
|
class DebugSymbols {
|
|
friend CallStackCapture;
|
|
char function[MAX_DEBUG_INFO_LEN + 1] = { 0 };
|
|
char file[MAX_DEBUG_INFO_LEN + 1] = { 0 };
|
|
ualni line = 0;
|
|
public:
|
|
[[nodiscard]] const char* getFunc() const { return function; }
|
|
[[nodiscard]] const char* getFile() const { return file; }
|
|
[[nodiscard]] ualni getLine() const { return line; }
|
|
};
|
|
|
|
public:
|
|
CallStackCapture();
|
|
~CallStackCapture();
|
|
|
|
[[nodiscard]] const CallStack* getSnapshot();
|
|
const DebugSymbols* getSymbols(FramePointer fp);
|
|
|
|
static void printSnapshot(const CallStack* snapshot);
|
|
void logLeaks();
|
|
|
|
public:
|
|
|
|
template<class Saver>
|
|
void write(Saver& file) {
|
|
file.write(mBuffLoad);
|
|
for (auto cs : *this) {
|
|
file.write(cs.getCallStack()->getDepth());
|
|
for (auto frame : *cs.getCallStack()) {
|
|
file.write((ualni) frame.getFrame());
|
|
}
|
|
}
|
|
file.write(mSymbols);
|
|
}
|
|
|
|
// independent of the configuration
|
|
template<class Loader>
|
|
void read(Loader& file) {
|
|
clear();
|
|
ualni loadLen;
|
|
file.read(loadLen);
|
|
for (auto cs = loadLen; cs; cs--) {
|
|
ualni callStackLen;
|
|
file.read(callStackLen);
|
|
for (auto fp = callStackLen; fp; fp--) {
|
|
// --
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
class Iterator {
|
|
const CallStack* mSnapshot;
|
|
public:
|
|
explicit Iterator(const CallStack* start) : mSnapshot(start) {};
|
|
const CallStack* getCallStack() { return mSnapshot; }
|
|
bool operator==(const Iterator& in) const { return in.mSnapshot == mSnapshot; }
|
|
void operator++() { mSnapshot++; }
|
|
const Iterator& operator*() const { return *this; }
|
|
};
|
|
|
|
[[nodiscard]] Iterator begin() const { return Iterator(mBuff); }
|
|
[[nodiscard]] Iterator end() const { return Iterator(mBuff + mBuffLoad); }
|
|
|
|
private:
|
|
|
|
struct CallStackKey {
|
|
CallStack* cs;
|
|
bool operator==(const CallStackKey& in) const;
|
|
};
|
|
|
|
static void platformWriteStackTrace(CallStack* stack);
|
|
static void platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out);
|
|
[[nodiscard]] static ualni hashCallStack(CallStackKey key);
|
|
|
|
void clear();
|
|
|
|
private:
|
|
ualni mBuffLen;
|
|
ualni mBuffLoad;
|
|
CallStack* mBuff;
|
|
Map<CallStackKey, CallStack*, DefaultAllocator, hashCallStack> mSnapshots;
|
|
Map<FramePointer, DebugSymbols> mSymbols;
|
|
};
|
|
|
|
extern CallStackCapture* gCSCapture;
|
|
}
|