/*
    * CrashReport.hpp
    * Structured crash report for userspace process faults
    * Copyright (c) 2026 Daniel Hammer
*/

#pragma once
#include <cstdint>
#include <cstddef>

namespace CrashReport {

static constexpr int MaxReports = 8;

struct Report {
    int pid;
    char processName[64];
    uint8_t exceptionVector;
    char exceptionName[32];

    uint64_t faultingAddress;
    uint64_t instructionPointer;
    uint64_t stackPointer;
    uint64_t codeSegment;
    uint64_t flags;
    uint64_t stackSegment;

    // Page fault error code bits (vector 0xE / page fault only)
    uint8_t pfPresent : 1;
    uint8_t pfWrite : 1;
    uint8_t pfUser : 1;
    uint8_t pfReservedWrite : 1;
    uint8_t pfInstructionFetch : 1;
    uint8_t pfProtectionKey : 1;
    uint8_t pfShadowStack : 1;
    uint8_t pfSGX : 1;

    uint64_t timestampTick;
    bool valid;
};

// Kernel-side ring buffer (written by exception handlers, read by SYS_CRASH_REPORT).
// All access is serialized by an internal interrupt-disabling spinlock: the
// writer (AddReport) runs in exception/interrupt context and the reader
// (TakeOldest) runs in syscall context, possibly on different CPUs.
extern Report g_reports[MaxReports];
extern int g_reportHead;
extern int g_reportCount;

// Add a report to the kernel ring buffer (called from exception handlers).
void AddReport(const Report& report);

// Pop the oldest report into `out`. Returns the number of reports that were
// present before this call (0 if the buffer was empty, in which case `out` is
// left untouched). Safe against concurrent AddReport / TakeOldest.
int TakeOldest(Report& out);

} // namespace CrashReport
