#pragma once #include "Environment.hpp" #include "Map.hpp" #define MAX_CALL_DEPTH_CAPTURE 128 #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 logAll(); public: template 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 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 mSnapshots; Map mSymbols; }; extern CallStackCapture* gCSCapture; }