ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
exc_decoder.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file exc_decoder.h
6 * @brief Panic / exception decoder for a live diagnostics panel (PROTOCORE_ENABLE_EXC_DECODER).
7 *
8 * When the part panics it prints a dump: a cause ("LoadProhibited"), a per-core register
9 * dump (PC, EXCVADDR, ...), and a backtrace of `PC:SP` frame pairs. To resolve those PCs to file:line an
10 * addr2line-style panel needs the firmware ELF, which lives off-device - so the on-device job is to
11 * *extract and present* the raw decode: the cause, the faulting PC + data address, and the ordered
12 * backtrace PC list, served as JSON for a live "/exception" panel (the browser or a build server then
13 * resolves symbols). This is that extractor.
14 *
15 * It parses the panic text an app captures (from the console, a saved crash line, or a text rendering of
16 * the core-dump partition) into a structured ExcInfo, and serializes it. Pure, zero heap, no stdlib
17 * (hand-rolled hex/decimal parsing), host-testable against a captured panic string.
18 */
19
20#ifndef PROTOCORE_EXC_DECODER_H
21#define PROTOCORE_EXC_DECODER_H
22
23#include "protocore_config.h" // the entry point: protocore_types.h for the widths
24
25#if PROTOCORE_ENABLE_EXC_DECODER
26
28
29#include "server/storage/mnt/mnt.h" // protocore_mnt_backend - the store a dump is offloaded to
30#ifndef PROTOCORE_EXC_MAX_FRAMES
31#define PROTOCORE_EXC_MAX_FRAMES 32 ///< backtrace frames retained (a panic rarely exceeds this).
32#endif
33
34/** @brief One backtrace frame: a program counter and its stack pointer. */
35typedef struct
36{
37 uint32_t pc;
38 uint32_t sp;
39} ExcFrame;
40
41/** @brief A decoded panic. Fields not found in the input are left at their zeroed / -1 defaults. */
42typedef struct
43{
44 int core; ///< panicking core number, or -1 if not present.
45 char cause[32]; ///< exception cause text (e.g. "LoadProhibited"), "" if absent.
46 uint32_t pc; ///< faulting PC (register-dump PC, else first backtrace frame).
47 uint32_t excvaddr; ///< faulting data address (EXCVADDR), 0 if absent.
48 proto_bool has_excvaddr; ///< true if an EXCVADDR field was present.
49 ExcFrame frames[PROTOCORE_EXC_MAX_FRAMES]; ///< backtrace, outermost-first as printed.
50 size_t frame_count;
51} ExcInfo;
52
53/** @brief The panic a call reads, and where the decoded form lands. */
54typedef struct
55{
56 const char *text; ///< the printed panic dump a parse walks
57 ExcInfo *info; ///< where a parse or a summary lands the decoded panic
58} ExcParseArgs;
59
60/** @brief Where a stored crash image sits, and how much of it there is. */
61typedef struct
62{
63 uint32_t addr; ///< absolute flash address of the image
64 size_t size; ///< image size in bytes
65} ExcCoreDump;
66
67/** @brief The stored crash image: the span a call names, and where its bytes land. */
68typedef struct
69{
70 ExcCoreDump *img; ///< where a presence check reports the image it found
71 size_t offset; ///< where in the image a read starts
72 void *buf; ///< where those bytes land
73 size_t len; ///< how many
74 const protocore_mnt_backend *file_sys; ///< the filesystem a save writes through
75 const char *path; ///< the file it writes
76} ExcDumpArgs;
77
78/** @brief Where a report is written. */
79typedef struct
80{
81 char *out; ///< where the JSON lands
82 size_t cap; ///< how much room it has
83} ExcOutArgs;
84
85/**
86 * @brief The panic decoder and the stored crash image.
87 *
88 * A caller sets the members a call takes, invokes it through ::Exc, and reads the outcome off the
89 * same handle. The decoding is pure; the image calls reach the platform seam.
90 *
91 * @var ExcDecoderNs::parse_args the panic a call reads, and where the decoded form lands
92 * @var ExcDecoderNs::dump the stored crash image: the span a call names, and where it lands
93 * @var ExcDecoderNs::out_args where a report is written
94 * @var ExcDecoderNs::ok a call's true/false outcome
95 * @var ExcDecoderNs::n bytes a report wrote, or 0 when it did not fit
96 * @var ExcDecoderNs::parse decode a printed panic dump
97 * @var ExcDecoderNs::json serialize a decoded panic
98 * @var ExcDecoderNs::present a stored crash image exists and verifies
99 * @var ExcDecoderNs::summary the stored image's summary, decoded into an ExcInfo
100 * @var ExcDecoderNs::read read a span of the stored image
101 * @var ExcDecoderNs::save stream the whole image to a file
102 * @var ExcDecoderNs::erase discard the stored image
103 *
104 * No storage member: the parse works in the caller's ExcInfo and the image lives in the part.
105 */
106typedef struct
107{
108 ExcParseArgs parse_args;
109 ExcDumpArgs dump;
110 ExcOutArgs out_args;
111 proto_bool ok;
112 size_t n;
113#if PROTOCORE_HAS_VENDOR_COREDUMP
114#endif
115} ExcVars;
116
117/** @brief The operands and the outcome. */
118extern ExcVars ExcV;
119
120/** @brief The entries. */
121typedef struct
122{
123 void (*const parse)(uint8_t *work);
124 void (*const json)(uint8_t *work);
125 void (*const present)(uint8_t *work);
126 void (*const summary)(uint8_t *work);
127 void (*const read)(uint8_t *work);
128 void (*const save)(uint8_t *work);
129 void (*const erase)(uint8_t *work);
130} ExcDecoderNs;
131
132// What the table binds, defined once in the .c and taking one parameter each: everything
133// else an entry needs is an operand in ExcV or a region of the borrow at a fixed offset.
134void protocore_exc_parse(uint8_t *work);
135void protocore_exc_json(uint8_t *work);
136#if PROTOCORE_HAS_VENDOR_COREDUMP
137void protocore_exc_present(uint8_t *work);
138void protocore_exc_summary(uint8_t *work);
139void protocore_exc_read(uint8_t *work);
140void protocore_exc_save(uint8_t *work);
141void protocore_exc_erase(uint8_t *work);
142#endif
143
144// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
145// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
146// `Exc.parse(work)` resolves to a named function and becomes a DIRECT call. An extern table
147// leaves the call indirect and the symbol live at every level, -O2 -flto included.
148static const ExcDecoderNs Exc __attribute__((unused)) = {
149 .parse = protocore_exc_parse,
150 .json = protocore_exc_json,
151#if PROTOCORE_HAS_VENDOR_COREDUMP
152 .present = protocore_exc_present,
153 .summary = protocore_exc_summary,
154 .read = protocore_exc_read,
155 .save = protocore_exc_save,
156 .erase = protocore_exc_erase,
157#endif
158};
159
161
162#endif // PROTOCORE_ENABLE_EXC_DECODER
163
164#endif // PROTOCORE_EXC_DECODER_H
The mount: which store is behind the filesystem, and the vtable it answers through.
A storage backend. Each open call returns a small handle (>= 0) or -1.
Definition mnt.h:88
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97