# How to Use forc-addr2line to Debug Compiled Sway Contracts

> Learn how to use forc-addr2line to debug compiled Sway contracts. This tool maps bytecode addresses back to source code, simplifying your development process.

- Repository: [Fuel Labs/sway](https://github.com/FuelLabs/sway)
- Tags: how-to-guide
- Published: 2026-03-04

---

**forc-addr2line translates bytecode addresses from compiled Sway contracts back to original source code locations using source-map JSON files generated during compilation.**

When debugging compiled Sway smart contracts on the Fuel network, raw opcode indices often obscure the underlying source code responsible for specific bytecode instructions. The `forc-addr2line` command bridges this gap by mapping bytecode addresses directly to Sway source files, enabling developers to pinpoint exactly which lines of code generated specific opcodes.

## What is forc-addr2line?

`forc-addr2line` is a specialized CLI utility within the Fuel Labs Sway toolchain that performs **address-to-source mapping** for compiled contracts. Unlike traditional debuggers that require DWARF symbols, this tool operates directly on the **source-map JSON** produced during `forc build`, making it lightweight and purpose-built for the Sway compiler's output format.

The tool reads the mapping between bytecode addresses and source spans, resolves file paths, and renders highlighted code snippets that show the exact source lines corresponding to a given opcode index.

## How forc-addr2line Works

The implementation in [`forc/src/cli/commands/addr2line.rs`](https://github.com/FuelLabs/sway/blob/main/forc/src/cli/commands/addr2line.rs) orchestrates a four-stage pipeline that transforms raw bytecode addresses into readable source context.

### Reading the Source-Map JSON

The command first deserializes the source-map file generated during compilation. In [`forc-pkg/src/pkg.rs`](https://github.com/FuelLabs/sway/blob/main/forc-pkg/src/pkg.rs), the compiler writes this JSON alongside the compiled binary when debug info is enabled.

```rust
let contents = fs::read(&command.sourcemap_path)?;
let sm: SourceMap = serde_json::from_slice(&contents)?;

```

The `SourceMap` struct, defined in [`sway-core/src/source_map.rs`](https://github.com/FuelLabs/sway/blob/main/sway-core/src/source_map.rs), contains the mapping data structure that links opcode indices to source file locations.

### Mapping Opcode Index to Source Span

Once loaded, the tool queries the source map using `SourceMap::addr_to_span(opcode_index)`. This method returns an optional tuple containing the file path and a `LocationRange` struct that specifies the exact start and end positions in the source file.

```rust
if let Some((mut path, range)) = sm.addr_to_span(command.opcode_index) {
    // Process the source location
}

```

The `LocationRange` contains `LineCol` positions that identify the precise character offsets within the Sway source file where the opcode was generated.

### Resolving Relative Paths and Reading Context

If the stored path is relative, the command resolves it against the user-provided search directory (`-S` flag). The helper function `read_range` in [`forc/src/cli/commands/addr2line.rs`](https://github.com/FuelLabs/sway/blob/main/forc/src/cli/commands/addr2line.rs) then opens the source file and converts `LineCol` positions into byte offsets using `line_col_to_pos`.

The tool extracts a configurable window of source lines around the target span, controlled by the `--context` parameter (defaulting to 2 lines).

### Rendering Highlighted Snippets

Finally, the extracted text and location data are wrapped in an `annotate_snippets::Snippet` struct. The diagnostic renderer, created via `forc_util::create_diagnostics_renderer()`, prints the snippet to stdout with visual highlighting that marks the exact byte range corresponding to the requested opcode.

```rust
let snippet = Snippet { 
    // title, footer, slices with source text and highlights
};
let renderer = create_diagnostics_renderer();
info!("{}", renderer.render(snippet));

```

## Step-by-Step Workflow for Debugging Contracts

Follow this workflow to debug compiled Sway contracts using opcode addresses:

1. **Compile with debug information** – Run `forc build` to generate the source-map JSON. Debug builds include this by default.

   ```bash
   forc build
   ```

2. **Identify the opcode index** – Extract the address from a panic message, stack trace, or DWARF debugger output. For example, a trace might indicate "panic at pc 215".

3. **Execute forc-addr2line** – Run the command with the source-map path, opcode index, and project root.

   ```bash
   forc addr2line \
     -g ./out/debug/debug_info.json \
     -i 215 \
     -S . \
     -c 4
   ```

4. **Analyze the output** – Review the highlighted source snippet to identify which specific expression or statement generated the opcode at that address.

## Command-Line Options and Usage Examples

The `forc addr2line` command accepts several flags to control its behavior:

- **`-g, --sourcemap-path <PATH>`** – Required. Path to the source-map JSON file generated during compilation.
- **`-i, --opcode-index <INDEX>`** – Required. The bytecode address (opcode index) to translate.
- **`-S, --search-dir <DIR>`** – Optional. Root directory for resolving relative paths stored in the source map. Defaults to current directory.
- **`-c, --context <LINES>`** – Optional. Number of context lines to display above and below the target source span. Default is 2.

### Advanced Example: Library Integration

For tooling that needs programmatic access, you can invoke the addr2line logic directly from Rust:

```rust
use forc_cli::commands::addr2line::{Command, exec};

let cmd = Command {
    search_dir: std::path::PathBuf::from("."),
    sourcemap_path: std::path::PathBuf::from("./out/debug/debug_info.json"),
    context: 3,
    opcode_index: 215,
};

exec(cmd).expect("addr2line failed");

```

## Key Implementation Files

Understanding the source code helps when extending or debugging the tool itself:

| File | Role |
|------|------|
| [`forc/src/cli/commands/addr2line.rs`](https://github.com/FuelLabs/sway/blob/main/forc/src/cli/commands/addr2line.rs) | CLI implementation that orchestrates source-map reading, address mapping, and snippet rendering. |
| [`sway-core/src/source_map.rs`](https://github.com/FuelLabs/sway/blob/main/sway-core/src/source_map.rs) | Defines the `SourceMap` struct and `addr_to_span` method that maps opcode indices to source locations. |
| [`forc-pkg/src/pkg.rs`](https://github.com/FuelLabs/sway/blob/main/forc-pkg/src/pkg.rs) | Handles generation and serialization of source-map JSON during the package build process. |

## Summary

- **forc-addr2line** bridges the gap between compiled bytecode and Sway source code by reading source-map JSON files.
- The tool maps **opcode indices** to exact source file locations using the `SourceMap::addr_to_span` method in [`sway-core/src/source_map.rs`](https://github.com/FuelLabs/sway/blob/main/sway-core/src/source_map.rs).
- Use the `-g` flag to specify the source-map path, `-i` for the opcode index, and `-c` to control context lines.
- The implementation in [`forc/src/cli/commands/addr2line.rs`](https://github.com/FuelLabs/sway/blob/main/forc/src/cli/commands/addr2line.rs) handles path resolution, source file reading, and highlighted snippet rendering via `annotate_snippets`.

## Frequently Asked Questions

### What file format does forc-addr2line require?

`forc-addr2line` requires a **source-map JSON file** generated during compilation. This file is produced automatically when running `forc build` and contains the mapping between bytecode addresses and source code spans. The tool deserializes this JSON into a `SourceMap` struct as defined in [`sway-core/src/source_map.rs`](https://github.com/FuelLabs/sway/blob/main/sway-core/src/source_map.rs).

### How do I find the opcode index to use with forc-addr2line?

You can obtain the opcode index from **panic messages**, **stack traces**, or **DWARF debugger output** when running your compiled contract. For example, a runtime error might report "panic at pc 215", where "215" is the opcode index you pass to the `-i` flag. This index represents the position in the compiled bytecode where execution triggered the event.

### Can I use forc-addr2line with release builds?

Yes, `forc-addr2line` works with both debug and release builds as long as the **source-map JSON** was generated during compilation. The source map is created by default during `forc build`, but ensure the [`debug_info.json`](https://github.com/FuelLabs/sway/blob/main/debug_info.json) or equivalent file exists in your output directory. If the file is missing, verify that your build configuration hasn't disabled debug information generation in [`forc-pkg/src/pkg.rs`](https://github.com/FuelLabs/sway/blob/main/forc-pkg/src/pkg.rs).

### What happens if the source file changed after compilation?

If the source file was modified after the contract was compiled, `forc-addr2line` may return **inaccurate line numbers** or fail to locate the exact source span. The tool relies on the byte offsets and line/column positions stored in the source-map JSON, which correspond to the state of the source files at compile time. For accurate debugging, ensure your source files match the version used during the build that generated the source map.