|
ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
|
🚨 Per-statement logging for crash debugging in C programs
🚨 Per-statement logging for crash debugging in C programs
Panic instrumentation provides per-statement logging for debugging crashes in C programs. The core idea is simple: the last line printed before a crash is the crashing line (or the line immediately before it in most cases).
Implementation: src/tooling/panic/tool.cpp
Key Features:
ascii-panic-report toolThe Problem: C programs crash without error messages. When a segfault or other crash occurs, you get no information about which line of code caused it. Traditional debugging approaches have limitations:
The Solution: What if we automatically insert a log before every line of code? When the program crashes, the last line printed tells you exactly where it crashed.
Why This Works:
Why Hasn't This Been Done Before?
Tools like this exist in various forms (SanitizerCoverage, -finstrument-functions, dynamic binary instrumentation), but they typically:
This approach is deliberately simple: print the actual source code text, so the crash location is immediately readable. No symbolization, no post-processing.
With multiple threads, the "last printed line globally" might be from a different thread than the one that crashed. The solution:
ascii-instr-<pid>-<tid>.log)ascii-panic-report to find the last line from each threadUse panic instrumentation when:
The panic instrumentation tool transforms your C source code to print each statement before executing it:
Single-Threaded Programs: The last log line is the crash location.
Multi-Threaded Programs: Each thread writes to its own log file (ascii-instr-<pid>-<tid>.log). Use ascii-panic-report to summarize the last statement executed by each thread.
For multi-threaded programs, ascii-panic-report parses all log files and shows the last executed statement per thread:
Each log line contains:
pid: Process IDtid: Thread IDseq: Sequence number for this threadts: Timestamp (ISO 8601 format)elapsed: Time since runtime initializationfile: Source file pathline: Line numberfunc: Function namemacro: Macro flag (0=normal, 1=from macro expansion, 2=macro invocation)snippet: The source code being executedReduce log volume by filtering what gets logged. Filters are checked before formatting to minimize overhead.
| Variable | Purpose |
|---|---|
ASCII_INSTR_SOURCE_PRINT_INCLUDE | Only log files matching substring |
ASCII_INSTR_SOURCE_PRINT_EXCLUDE | Skip files matching substring |
ASCII_INSTR_SOURCE_PRINT_THREAD | Comma-separated thread IDs to log |
ASCII_INSTR_SOURCE_PRINT_FUNCTION_INCLUDE | Only log functions matching substring |
ASCII_INSTR_SOURCE_PRINT_FUNCTION_EXCLUDE | Skip functions matching substring |
ASCII_INSTR_SOURCE_PRINT_OUTPUT_DIR | Directory for log files |
ASCII_INSTR_SOURCE_PRINT_RATE | Log every Nth statement (throttle) |
ASCII_INSTR_SOURCE_PRINT_ENABLE | Set to "0" to disable at runtime |
| Variable | Purpose |
|---|---|
ASCII_INSTR_SOURCE_PRINT_INCLUDE_REGEX | POSIX regex include filter on file path |
ASCII_INSTR_SOURCE_PRINT_EXCLUDE_REGEX | POSIX regex exclude filter on file path |
ASCII_INSTR_SOURCE_PRINT_FUNCTION_INCLUDE_REGEX | POSIX regex include filter on function name |
ASCII_INSTR_SOURCE_PRINT_FUNCTION_EXCLUDE_REGEX | POSIX regex exclude filter on function name |
The ASCII_INSTR_SOURCE_PRINT_ONLY variable supports sophisticated allow-list filtering using comma-separated selectors:
| Syntax | Description |
|---|---|
file=<glob> | Match files by glob pattern |
func=<glob> | Match functions by glob pattern |
module=<name> | Match files under /name/ directory |
module=<name>:<glob> | Match files under /name/ with basename matching glob |
<name>:<glob> | Shorthand for module=<name>:<glob> |
<substring> | Match files containing substring |
Examples:
For debugging specific issues, you can direct all output to a single file:
Mark functions that must remain async-signal-safe:
The panic instrumentation tool skips any function carrying that annotation, ensuring inserted logging calls never appear inside signal handlers.
build/instrumented/write() call, so concurrent threads cannot interleave recordsASCII_PANIC_THREAD.src/tooling/panic/tool.cpp (Clang libTooling rewriter)lib/tooling/panic/instrument_log.c and .hlib/tooling/panic/instrument_cov.ccmake/tooling/Panic.cmakecmake/tooling/run_panic_instrumentation.shsrc/tooling/panic/report.cbuild/instrumented/| Option | Default | Description |
|---|---|---|
ASCIICHAT_BUILD_WITH_PANIC | OFF | Enable panic instrumentation |
ASCIICHAT_PANIC_TOOL | "" | Path to pre-built tool (faster rebuilds) |
For lightweight edge coverage without full statement logging:
Coverage mode logs compact pc=0x... entries that can be symbolized with llvm-symbolizer or addr2line to map back to source locations.
The ascii-instr-panic tool supports:
| Option | Description |
|---|---|
--output-dir <path> | Where to write instrumented sources |
--input-root <path> | Root for computing relative paths |
--log-macro-expansions | Instrument statements from macro expansions |
--log-macro-invocations | Emit synthetic log for macro call sites |
--filter-file <substring> | Only instrument files matching substring |
--filter-function <substring> | Only instrument functions matching substring |
--signal-handler-annotation <name> | Annotation to skip (default: ASCII_INSTR_PANIC_SIGNAL_HANDLER) |
No logs emitted:
unset ASCII_INSTR_SOURCE_PRINT_INCLUDE)ASCII_INSTR_SOURCE_PRINT_ENABLE isn't set to "0"**"Refusing to overwrite" errors**:
build/instrumented/ directoryPartial log files:
Thread IDs don't match:
| Tool | Approach | Pros | Cons |
|---|---|---|---|
| Panic instrumentation | Source rewriting | Readable output, no symbolization | High overhead |
| SanitizerCoverage | Edge callbacks | Lower overhead | Needs symbolization |
| -finstrument-functions | Function entry/exit | Very low overhead | Function granularity only |
| rr (record/replay) | Deterministic replay | Perfect reproduction | Linux only, heavyweight |
| ASan/UBSan | Memory/UB detection | Catches specific bugs | Not for all crash types |
| gdb/lldb | Debugger | Full control | May perturb timing |
Panic instrumentation is best when you need: