11#if DETWS_ENABLE_EXC_DECODER
19bool hexval(
char c, uint8_t *v)
21 if (c >=
'0' && c <=
'9')
22 *v = (uint8_t)(c -
'0');
23 else if (c >=
'a' && c <=
'f')
24 *v = (uint8_t)(c -
'a' + 10);
25 else if (c >=
'A' && c <=
'F')
26 *v = (uint8_t)(c -
'A' + 10);
32const char *skip_ws(
const char *p)
34 while (*p ==
' ' || *p ==
'\t')
40const char *parse_hex(
const char *p, uint32_t *out)
42 if (p[0] !=
'0' || (p[1] !=
'x' && p[1] !=
'X'))
48 while (hexval(*p, &d) && n < 8)
60void put_json_str(
DetSb *b,
const char *s)
63 for (
const char *p = s ? s :
""; *p; p++)
65 if (*p ==
'"' || *p ==
'\\')
67 char esc[3] = {
'\\', *p,
'\0'};
70 else if (b->
len + 1 < b->
cap)
79void put_hex32(
DetSb *b, uint32_t v)
81 char t[13] =
"\"0x00000000\"";
82 static const char *H =
"0123456789abcdef";
83 for (
int i = 0; i < 8; i++)
84 t[3 + i] = H[(v >> ((7 - i) * 4)) & 0xF];
88void put_int(
DetSb *b,
int v)
93 unsigned u = neg ? (unsigned)(-(
long)v) : (unsigned)v;
96 t[n++] = (char)(
'0' + u % 10);
104 for (
int i = 0; i < n; i++)
105 o[k++] = t[n - 1 - i];
112int parse_small_int(
const char *p)
115 while (*p >=
'0' && *p <=
'9')
118 n = n * 10 + (*p -
'0');
125void parse_cause(
const char *text, ExcInfo *out)
127 const char *c = strstr(text,
"panic'ed (");
132 while (i <
sizeof(out->cause) - 1 && c[i] && c[i] !=
')')
134 out->cause[i] = c[i];
137 out->cause[i] =
'\0';
141void parse_core(
const char *text, ExcInfo *out)
143 const char *co = strstr(text,
"Core ");
146 const char *p = skip_ws(co + 5);
147 if (*p >=
'0' && *p <=
'9')
148 out->core = parse_small_int(p);
152void parse_excvaddr(
const char *text, ExcInfo *out)
154 const char *e = strstr(text,
"EXCVADDR");
157 const char *colon = strchr(e,
':');
161 if (parse_hex(skip_ws(colon + 1), &v))
164 out->has_excvaddr =
true;
169void parse_pc(
const char *text, ExcInfo *out)
171 const char *pcl = (strncmp(text,
"PC", 2) == 0) ? text : strstr(text,
"\nPC");
174 const char *colon = strchr(pcl,
':');
178 if (parse_hex(skip_ws(colon + 1), &v))
183void parse_backtrace(
const char *text, ExcInfo *out)
185 const char *bt = strstr(text,
"Backtrace:");
188 const char *p = bt + 10;
189 while (out->frame_count < DETWS_EXC_MAX_FRAMES)
194 const char *q = parse_hex(p, &pc);
197 const char *r = parse_hex(q + 1, &sp);
200 out->frames[out->frame_count].pc = pc;
201 out->frames[out->frame_count].sp = sp;
208bool detws_exc_parse(
const char *text, ExcInfo *out)
213 out->cause[0] =
'\0';
216 out->has_excvaddr =
false;
217 out->frame_count = 0;
219 parse_cause(text, out);
220 parse_core(text, out);
221 parse_excvaddr(text, out);
223 parse_backtrace(text, out);
225 if (out->pc == 0 && out->frame_count > 0)
226 out->pc = out->frames[0].pc;
228 return out->cause[0] !=
'\0' || out->pc != 0 || out->frame_count > 0;
231size_t detws_exc_json(
const ExcInfo *info,
char *out,
size_t cap)
233 if (!info || !out || cap == 0)
235 DetSb b = {out, cap, 0,
true};
241 put_int(&b, info->core);
247 put_json_str(&b, info->cause);
249 put_hex32(&b, info->pc);
250 if (info->has_excvaddr)
253 put_hex32(&b, info->excvaddr);
256 for (
size_t i = 0; i < info->frame_count; i++)
260 put_hex32(&b, info->frames[i].pc);
ESP32 panic / exception decoder for a live diagnostics panel (DETWS_ENABLE_EXC_DECODER).
Bounded no-heap string builder that fails closed on overflow (one shared copy).
void det_sb_put(DetSb *b, const char *s)
Append NUL-terminated s; leaves the buffer untouched and clears ok if it would not fit.
Bump-append target; ok latches false once an append would overflow cap.