Metadata-Version: 2.4
Name: stkfmt
Version: 0.1.1
Summary: Generate terminal diagrams for hand-authored memory layouts
Author: Jordan Allred
License: MIT
Project-URL: Repository, https://github.com/jordanallred/stkfmt
Project-URL: Issues, https://github.com/jordanallred/stkfmt/issues
Keywords: memory,diagram,ascii,reverse-engineering,ghidra,stack-frame
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Documentation
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# stkfmt

Generate clean terminal diagrams of hand-authored memory layouts for reverse-engineering notes, educational material, and write-ups.

## Installation

```bash
pip install stkfmt
```

## Features

- **Hand-authored memory diagrams** - describe stack, heap, and register layouts in JSON, render deterministic ASCII or Unicode text
- **Ghidra stack import** - turn a copied `Stack[...]` listing into a diagram directly, no manual transcription
- **ABI profiles** - fill in ABI-implied slots (e.g. the Windows x64 return address) that Ghidra doesn't list
- **Pointer annotations** - link a block to the region it points into with `points_to`
- **Overlap and alignment checks** - rejects overlapping blocks and validates power-of-two `align` requirements
- **Terminal, Markdown, and issue-comment friendly** - ASCII output by default for predictable copying anywhere

## Quick Start

```bash
stkfmt memory.json --unicode
stkfmt ghidra function.txt --unicode
stkfmt ghidra function.txt --abi windows-x64 --unicode
```

```json
{
  "title": "main()",
  "regions": [
    {
      "name": "Stack",
      "direction": "down",
      "blocks": [
        {
          "id": "name-ptr",
          "address": "0x7fffffffe1a8",
          "size": 8,
          "value": "0x404050",
          "label": "name",
          "type": "char *",
          "points_to": "heap-name"
        }
      ]
    },
    {
      "name": "Heap",
      "blocks": [
        {
          "id": "heap-name",
          "address": "0x404050",
          "size": 4,
          "value": "41 64 61 00",
          "label": "name",
          "type": "char[4]",
          "note": "\"Ada\""
        }
      ]
    }
  ]
}
```

## Usage

```text
stkfmt <input> [options]
stkfmt ghidra <listing.txt> [options]

  input                 JSON file path, or - to read JSON from stdin
  -s, --style STYLE     ascii or unicode (default: ascii)
  -u, --unicode         shortcut for --style unicode
  -o, --output FILE     write output to FILE instead of stdout
      --no-addresses    hide address gutters and pointer-target addresses
      --abi ABI         apply an ABI profile to a Ghidra listing (windows-x64, sysv-x64)
  -v, --version         show version
```

Each block requires `size` (bytes) and `label`. `value` is optional: omitted values render as `<unknown>`, which is useful for static Ghidra layouts. A region uses one coordinate system: either absolute `address` values, or signed `offset` values with a region `base` such as `rsp`.

An addressed block displays its inclusive byte range. An offset block displays a base-relative range, e.g. `RSP-0x148..RSP-0x39`. `stkfmt` sorts coordinate-bearing blocks into physical memory order (high-to-low for `direction: "down"`), renders unknown gaps as `unmapped`, rejects overlapping blocks, and validates an optional power-of-two `align` requirement. A gap is not assumed to be ABI padding; label an explicit block `padding` only when you know that is what it is.

## Ghidra listings

Copy or export a Ghidra function listing to a text file, then import its `Stack[...]` rows directly:

```bash
stkfmt ghidra examples/ghidra_function_listing.txt --unicode
```

The importer reads Ghidra stack offsets, storage sizes, type names, and variable names. It intentionally ignores register rows, xrefs, decompiler output, and instruction listings. Static layout imports render values as `<unknown>`.

For a Windows x64 function, add its return-address stack slot explicitly:

```bash
stkfmt ghidra examples/ghidra_function_listing.txt --abi windows-x64 --unicode
```

This labels the return address at `Stack[+0x0..+0x7]`.

For a Linux or macOS x86-64 function, use the `sysv-x64` profile instead:

```bash
stkfmt ghidra examples/ghidra_function_listing.txt --abi sysv-x64 --unicode
```

Both profiles label the same `call`-pushed return address at `Stack[+0x0..+0x7]`; only the note distinguishing which ABI added it differs. `windows-x64` and `sysv-x64` intentionally leave shadow space and the red zone, respectively, unannotated.

## License

MIT
