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

# SEGGER J-Trace

> Set up a SEGGER J-Trace probe for ETM instruction capture, firmware source coverage, and custom pyjtrace scripts on supported Cortex targets.

Use J-Trace when you need executed instruction order or coverage without adding trace calls to firmware. A plain J-Link can debug and carry RTT, but it cannot stream the ETM instruction trace used by Embedder's coverage tools.

## Check the physical path

You need all of these:

* A SEGGER J-Trace probe detected by `hardware_status`
* The SEGGER J-Link Software and Documentation Pack
* The fine-pitch CoreSight-20 cable
* A target with ETM trace pins routed to the connector
* A valid SEGGER device name
* An ELF that matches the running firmware

<Warning>
  The wide 0.1-inch debug ribbon does not carry the required trace signals.
  An empty buffer often means the wrong cable or a target that does not drive
  `TRACECLK`.
</Warning>

Run `hardware_status` and inspect the `jtrace` provider. It reports the J-Link library path, whether a J-Trace was detected, and the probe name.

## Use the built-in tools first

| Goal                                          | Tool                                      |
| --------------------------------------------- | ----------------------------------------- |
| Read the latest bounded instruction window    | `instruction_trace`                       |
| Record instructions from the moment you start | `trace_start` with ETM, then `trace_stop` |
| Measure function and source-line coverage     | `coverage_run`                            |

The built-in tools handle the probe lease, stop managed GDB and RTT connections during handoff, store the result, and notify the Trace or Coverage tab.

```text theme={"system"}
Use J-Trace to capture three seconds from build/firmware.elf and return the
newest 1000 instructions with function and source names.
```

```text theme={"system"}
Run five seconds of function and source-line coverage, then show the functions
with the most uncovered instructions.
```

Both operations reset and run the target. They are not attach-only observations.

## Choose bounded or streamed ETM

A bounded instruction capture reads the newest window after the run. One DLL read is capped at 65,536 instruction items.

A streamed capture repeatedly:

1. Runs the target for a short slice.
2. Halts it.
3. Drains the probe.
4. Appends symbolized instructions to the session.

Streaming can retain more than 65,536 instructions, but the repeated halts slow the target and change its timing. Use it for startup order or long control-flow observation, not peripheral deadlines.

Check `summary.streaming.continuous`. If it is false, read the gap and lost-instruction counts before you trust reconstructed calls.

## Run a custom pyjtrace script

Use the SDK only when the built-in tools cannot express the capture or analysis. Good reasons include:

* Reading instruction counts directly in Python
* Combining ETM with RTT, SWO/ITM, high-speed memory sampling, or power trace
* Using J-Link target control, breakpoints, watchpoints, or memory access in the same script

Write the script under `.embedder/hardware/` and run it with `hardware_script_run`.

```python .embedder/hardware/capture_etm.py theme={"system"}
import json
from jtrace import capture_instruction_trace

session_id, result = capture_instruction_trace(
    "build/firmware.elf",
    "STM32F407VE",
    duration_ms=3000,
    cpu_freq_hz=16_000_000,
)

print(json.dumps({
    "success": True,
    "summary": "Captured J-Trace instruction window",
    "data": {
        "session_id": session_id,
        "instructions": result.summary.instruction_count,
        "frames": result.summary.frame_count,
    },
}))
```

Embedder installs the dependency-free SDK under `~/.embedder/share/pyjtrace` and adds it to the hardware script's import path. Do not patch `sys.path` when the import fails; report the failed automatic installation.

<Warning>
  Do not run a probe-driving pyjtrace command through a plain shell. Shell runs
  do not take the hardware lease and can collide with GDB, RTT, coverage, or
  another trace capture.
</Warning>

## Control the target from the SDK

Use the `JLink` context manager so the probe always closes:

```python .embedder/hardware/read_target.py theme={"system"}
import json
from jtrace import JLink

with JLink(device="STM32F407VE", interface="SWD", speed_khz=4000) as link:
    link.halt()
    registers = link.register_dump()

print(json.dumps({
    "success": True,
    "summary": "Read J-Trace target registers",
    "data": {"registers": registers},
}))
```

Only one `JLink` can be open in a process. A leaked handle blocks later flash, GDB, and RTT operations until the process exits.

The open link exposes:

* RTT and SWO/ITM
* High-speed sampling without firmware instrumentation
* Probe power trace
* CoreSight DP, AP, ETM, ETB, and CP15 access
* Instruction statistics and trace reads

Prefer the built-in coverage and trace helpers unless you need one of these lower-level combinations.

## Interpret the instruction stream

ETM records order, not duration. Frame width represents instructions executed, not elapsed time. A supplied CPU frequency creates an estimated time axis.

The probe returns its raw instruction buffer newest first. The SDK's extended reads and capture helpers reverse it to chronological order. Do not reverse the capture again.

If the target executes more than the retained window:

* `instructions_executed` still describes the whole run.
* `instruction_count` describes the retained window.
* `window_truncated` is true.
* A frame marked `open_at_start` or `open_at_end` crosses a window boundary.

## Manage large captures

The SDK can collect longer streams in slices, but storage becomes the limit. `instructions.json` is roughly 170 bytes per row in the measured implementation. A million rows is about 166 MB and the Trace tab reads the file as one payload.

The SDK warns above about 250,000 rows. For larger analysis, inspect the in-memory result in Python or use a rolling stream window. A rolling window drops the oldest instructions and marks the session truncated.

## Fix J-Trace problems

<AccordionGroup>
  <Accordion title="A plain J-Link was detected">
    Use it for GDB or RTT. Replace it with J-Trace for ETM coverage and instruction capture.
  </Accordion>

  <Accordion title="Trace starts but contains no instructions">
    Check the CoreSight-20 cable, target trace routing, `TRACECLK`, device name, and target power.
  </Accordion>

  <Accordion title="Symbols are wrong">
    Use the ELF that produced the firmware on the target. Start streamed ETM with the ELF already attached.
  </Accordion>

  <Accordion title="The firmware behaves differently while streaming">
    The stream halts between slices. Repeat timing-sensitive tests with a bounded capture or another observation method.
  </Accordion>

  <Accordion title="Later probe operations are busy">
    Stop the background script or trace session. In custom code, use the `JLink` context manager and do not leave a second link open.
  </Accordion>
</AccordionGroup>

<CardGroup cols={2}>
  <Card title="Coverage and trace" icon="timeline" href="/debug-mode/coverage-and-trace">
    Compare RTT events, bounded ETM, streamed ETM, and coverage.
  </Card>

  <Card title="Hardware scripts" icon="file-code" href="/debug-mode/hardware-scripts">
    Run custom SDK code with leases and background tasks.
  </Card>
</CardGroup>
