Skip to content

File syn_coredump.c

File List > src > syntropic > system > syn_coredump.c

Go to the documentation of this file

#if __has_include("syn_config.h")
#include "syn_config.h"
#endif

#if defined(SYN_USE_COREDUMP) && SYN_USE_COREDUMP

#include "../port/syn_port_flash.h"
#include "../port/syn_port_system.h"
#include "../util/syn_assert.h"
#include "../util/syn_crc.h"
#include "syn_coredump.h"

#include <string.h>

/* ── Helpers ────────────────────────────────────────────────────────────── */

static uint32_t coredump_compute_crc(const SYN_CoreDump *dump)
{
    /* CRC covers everything from magic through stack[] and uptime_ms,
     * i.e. everything before the crc field. */
    size_t len = offsetof(SYN_CoreDump, crc);
    return syn_crc32(dump, len);
}

/* ── API ────────────────────────────────────────────────────────────────── */

void syn_coredump_save(const SYN_FaultContext *ctx)
{
    if (ctx == NULL)
        return;

    SYN_CoreDump dump;
    memset(&dump, 0, sizeof(dump));

    dump.magic = SYN_COREDUMP_MAGIC;
    dump.regs = *ctx;

    /* Capture partial stack from SP upward.
     * On 32-bit MCU targets, ctx->sp is a valid stack pointer.
     * On 64-bit hosts (test builds), the uint32_t SP truncates the
     * pointer, so we skip the copy unless explicitly enabled. */
#if !defined(SYN_COREDUMP_CAPTURE_STACK)
#if UINTPTR_MAX == 0xFFFFFFFFu
#define SYN_COREDUMP_CAPTURE_STACK 1
#else
#define SYN_COREDUMP_CAPTURE_STACK 0
#endif
#endif
#if SYN_COREDUMP_CAPTURE_STACK
    {
        const uint8_t *sp = (const uint8_t *)(uintptr_t)ctx->sp;
        if (sp != NULL) {
            size_t to_copy = SYN_COREDUMP_STACK_SIZE;
            dump.stack_bytes = (uint32_t)to_copy;
            memcpy(dump.stack, sp, to_copy);
        } else {
            dump.stack_bytes = 0;
        }
    }
#else
    dump.stack_bytes = 0;
#endif

    dump.uptime_ms = syn_port_get_tick_ms();
    dump.crc = coredump_compute_crc(&dump);

    /* Write to flash — best-effort, ignore errors in fault context */
    syn_port_flash_erase(SYN_COREDUMP_FLASH_ADDR);
    syn_port_flash_write(SYN_COREDUMP_FLASH_ADDR, &dump, sizeof(dump));
}

bool syn_coredump_read(SYN_CoreDump *out)
{
    SYN_ASSERT(out != NULL);
    if (out == NULL) {
        return false;
    }

    SYN_CoreDump dump;
    SYN_Status st = syn_port_flash_read(SYN_COREDUMP_FLASH_ADDR, &dump, sizeof(dump));
    if (st != SYN_OK)
        return false;

    /* Validate */
    if (dump.magic != SYN_COREDUMP_MAGIC)
        return false;

    uint32_t expected_crc = coredump_compute_crc(&dump);
    if (dump.crc != expected_crc)
        return false;

    *out = dump;
    return true;
}

void syn_coredump_clear(void)
{
    syn_port_flash_erase(SYN_COREDUMP_FLASH_ADDR);
}

#endif /* SYN_USE_COREDUMP */

/* Avoid empty translation unit when feature is disabled (-pedantic) */
typedef int syn_coredump_unused_t;