> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veecle.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Find out why firmware crashes

> Find where firmware stops by reading the UART output, and make crashes visible with handlers that print over the UART.

The firmware panics on the virtual board. You read the `uart` output to see how far it got.

## What you'll do

**1. Run on the virtual board**

Your agent uploads the ELF and runs it on the board model, with the UARTs to capture. Only those UARTs are written into the output.

**2. Read the captured output and run status**

`run` returns a `run_id` immediately. Your agent waits for the job and reads the status: `running`, `succeeded`, or `failed`. `uart` is the captured UART output. A crashing firmware still returns `succeeded`, so check the `uart` output. See [Core concepts](/concepts).

**3. Ask about chip-specific gotchas**

Ask Chiplab about the gotchas for that board. `ask` takes a natural-language question and returns chip-specific gotchas and validated fixes from real runs.

**4. Fix and run again**

Change the firmware, build the ELF again, and run it on the same board.

## What you see when firmware crashes

The run still returns `succeeded`, with no fault details. `wait_for_job` does not include an error string, fault registers, a PC, or a panic message.

The `uart` output keeps everything printed before the crash, so the last line shows how far the firmware got.

A firmware that prints `before fault` and then hits a HardFault returns status `succeeded` and a `uart` output of `before fault`.

To see more, make the firmware report the crash over the UART: a panic handler that prints the panic message (instead of panic-halt), and a HardFault handler that prints the fault address and PC. Your agent can add these for you.

A run lasts up to 5 seconds of virtual time.

## Catch crashes with a test

A [test](/tools/test) that waits for an expected line fails when the firmware crashes before printing it. `runUntilUartLine` times out, so that test is a fail even though the job can still return `succeeded`.

## Ask your agent

```text theme={null}
This firmware stops early on the STM32F4 Discovery. Add a panic handler and a HardFault handler that print to usart2, run it, and tell me the last line it printed and where it faulted.
```

## What you get back

You get the `uart` output up to the point where the firmware stopped. With a panic handler and a HardFault handler that print over the UART, that output also shows the panic message or the fault address. `ask` returns the gotchas for that board.

## Next

> **[run](/tools/run)**
>
> Execute an ELF on a virtual board and read the UART.

> **[ask](/tools/ask)**
>
> Look up boards, tools, and chip-specific gotchas.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.