12#if PC_ENABLE_EXC_DECODER
18bool hexval(
char c, uint8_t *v)
20 if (c >=
'0' && c <=
'9')
22 *v = (uint8_t)(c -
'0');
24 else if (c >=
'a' && c <=
'f')
26 *v = (uint8_t)(c -
'a' + 10);
28 else if (c >=
'A' && c <=
'F')
30 *v = (uint8_t)(c -
'A' + 10);
39const char *skip_ws(
const char *p)
41 while (*p ==
' ' || *p ==
'\t')
49const char *parse_hex(
const char *p, uint32_t *out)
51 if (p[0] !=
'0' || (p[1] !=
'x' && p[1] !=
'X'))
59 while (hexval(*p, &d) && n < 8)
73void put_json_str(
pc_sb *b,
const char *s)
76 const char *src = s ? s :
"";
77 for (
const char *p = src; *p; p++)
79 if (*p ==
'"' || *p ==
'\\')
81 char esc[3] = {
'\\', *p,
'\0'};
84 else if (b->
len + 1 < b->
cap)
97void put_hex32(
pc_sb *b, uint32_t v)
99 char t[13] =
"\"0x00000000\"";
100 static const char *H =
"0123456789abcdef";
101 for (
int i = 0; i < 8; i++)
103 t[3 + i] = H[(v >> ((7 - i) * 4)) & 0xF];
108void put_int(
pc_sb *b,
int v)
113 unsigned u = neg ? (unsigned)(-(
long)v) : (unsigned)v;
116 t[n++] = (char)(
'0' + u % 10);
127 for (
int i = 0; i < n; i++)
129 o[k++] = t[n - 1 - i];
137int parse_small_int(
const char *p)
140 while (*p >=
'0' && *p <=
'9')
144 n = n * 10 + (*p -
'0');
152void parse_cause(
const char *text, ExcInfo *out)
154 const char *c = strstr(text,
"panic'ed (");
161 while (i <
sizeof(out->cause) - 1 && c[i] && c[i] !=
')')
163 out->cause[i] = c[i];
166 out->cause[i] =
'\0';
170void parse_core(
const char *text, ExcInfo *out)
172 const char *co = strstr(text,
"Core ");
177 const char *p = skip_ws(co + 5);
178 if (*p >=
'0' && *p <=
'9')
180 out->core = parse_small_int(p);
185void parse_excvaddr(
const char *text, ExcInfo *out)
187 const char *e = strstr(text,
"EXCVADDR");
192 const char *colon = strchr(e,
':');
198 if (parse_hex(skip_ws(colon + 1), &v))
201 out->has_excvaddr =
true;
206void parse_pc(
const char *text, ExcInfo *out)
208 const char *pcl = (strncmp(text,
"PC", 2) == 0) ? text : strstr(text,
"\nPC");
213 const char *colon = strchr(pcl,
':');
219 if (parse_hex(skip_ws(colon + 1), &v))
226void parse_backtrace(
const char *text, ExcInfo *out)
228 const char *bt = strstr(text,
"Backtrace:");
233 const char *p = bt + 10;
234 while (out->frame_count < PC_EXC_MAX_FRAMES)
239 const char *q = parse_hex(p, &pc);
244 const char *r = parse_hex(q + 1, &sp);
249 out->frames[out->frame_count].pc = pc;
250 out->frames[out->frame_count].sp = sp;
257bool pc_exc_parse(
const char *text, ExcInfo *out)
264 out->cause[0] =
'\0';
267 out->has_excvaddr =
false;
268 out->frame_count = 0;
270 parse_cause(text, out);
271 parse_core(text, out);
272 parse_excvaddr(text, out);
274 parse_backtrace(text, out);
276 if (out->pc == 0 && out->frame_count > 0)
278 out->pc = out->frames[0].pc;
281 return out->cause[0] !=
'\0' || out->pc != 0 || out->frame_count > 0;
284size_t pc_exc_json(
const ExcInfo *info,
char *out,
size_t cap)
286 if (!info || !out || cap == 0)
290 pc_sb b = {out, cap, 0,
true};
296 put_int(&b, info->core);
304 put_json_str(&b, info->cause);
306 put_hex32(&b, info->pc);
307 if (info->has_excvaddr)
310 put_hex32(&b, info->excvaddr);
313 for (
size_t i = 0; i < info->frame_count; i++)
319 put_hex32(&b, info->frames[i].pc);
ESP32 panic / exception decoder for a live diagnostics panel (PC_ENABLE_EXC_DECODER).
Bounded no-heap string builder that fails closed on overflow (one shared copy).
void pc_sb_put(pc_sb *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.