docs: drop process labels and refresh the architecture and manual pages

Assisted-by: GLM 5.3
This commit is contained in:
2026-09-19 23:49:27 +02:00
parent 7604a9443f
commit 3a73acb20a
19 changed files with 123 additions and 31 deletions
+3 -2
View File
@@ -56,8 +56,9 @@ workflow builds the assets and publishes the release and its notes.
`gofmt` and `go vet` run through `just fmt` and `just vet`, with zero diff and zero `gofmt` and `go vet` run through `just fmt` and `just vet`, with zero diff and zero
warnings tolerated. `just gates` is the definition of done in one command, and the recipe warnings tolerated. `just gates` is the definition of done in one command, and the recipe
file names what it contains. Errors are checked explicitly, wrapped as file names what it contains. Errors are checked explicitly, wrapped as
`fmt.Errorf("context: %w", err)`, and nothing panics outside `main`. The `golang` `fmt.Errorf("context: %w", err)`, and nothing panics outside `main`. The recipe file holds
skill holds the rules the project follows; the recipe file holds the commands. the commands, and the language and standard-library surface is the one the `go` directive
in `go.mod` pins.
- `golang.org/x/arch` is the one module dependency, and it is linked into the binary: - `golang.org/x/arch` is the one module dependency, and it is linked into the binary:
`gasm dis` and the debugger's listings decode through it. Everything else is the `gasm dis` and the debugger's listings decode through it. Everything else is the
+84
View File
@@ -62,6 +62,42 @@ func TestManPagesTrackTheCLI(t *testing.T) {
} }
} }
// TestManCommandsTrackHelp compares the gasm(1) COMMANDS list with the
// top-level help output, so a subcommand added to the binary cannot miss
// its man entry and a stale entry cannot outlive its command.
func TestManCommandsTrackHelp(t *testing.T) {
if testing.Short() {
t.Skip("builds the gasm binary")
}
bin := filepath.Join(t.TempDir(), "gasm")
if out, err := exec.Command("go", "build", "-o", bin, ".").CombinedOutput(); err != nil {
t.Fatalf("build gasm: %v\n%s", err, out)
}
raw, err := os.ReadFile(filepath.Join("..", "..", "docs", "man", "gasm.1"))
if err != nil {
t.Fatalf("read man page: %v", err)
}
helpOut, err := exec.Command(bin, "--help").Output()
if err != nil {
t.Fatalf("gasm --help: %v", err)
}
binCmds := helpCommands(string(helpOut))
pageCmds := roffCommands(string(raw))
for c := range binCmds {
if !pageCmds[c] {
t.Errorf("command %q is in the binary's help but missing from gasm(1) COMMANDS", c)
}
}
for c := range pageCmds {
if !binCmds[c] {
t.Errorf("command %q is in gasm(1) COMMANDS but the binary does not list it", c)
}
}
}
// helpFlags extracts the flag names from a `gasm <cmd> -h` output. // helpFlags extracts the flag names from a `gasm <cmd> -h` output.
func helpFlags(help string) map[string]bool { func helpFlags(help string) map[string]bool {
m := map[string]bool{} m := map[string]bool{}
@@ -123,6 +159,54 @@ func roffFlags(page string) map[string]bool {
return m return m
} }
// helpCommands extracts the command names from the top-level help output's
// Commands section.
func helpCommands(help string) map[string]bool {
m := map[string]bool{}
inCmds := false
for line := range strings.SplitSeq(help, "\n") {
if strings.TrimSpace(line) == "Commands:" {
inCmds = true
continue
}
if !inCmds {
continue
}
t := strings.TrimSpace(line)
if t == "" {
break
}
name, _, _ := strings.Cut(t, " ")
m[name] = true
}
return m
}
// roffCommands extracts the command names from gasm(1)'s COMMANDS section,
// where each entry is written as `.B gasm\-<name>(1)` or `.B gasm <name>`.
func roffCommands(page string) map[string]bool {
m := map[string]bool{}
inCmds := false
for line := range strings.SplitSeq(page, "\n") {
if strings.HasPrefix(line, ".SH ") {
inCmds = strings.HasPrefix(line, ".SH COMMANDS")
continue
}
if !inCmds || !strings.HasPrefix(line, ".B gasm") {
continue
}
entry := strings.ReplaceAll(strings.TrimPrefix(line, ".B "), `\-`, "-")
entry = strings.TrimSuffix(entry, "(1)")
switch {
case strings.HasPrefix(entry, "gasm-"):
m[strings.TrimPrefix(entry, "gasm-")] = true
case strings.HasPrefix(entry, "gasm "):
m[strings.TrimPrefix(entry, "gasm ")] = true
}
}
return m
}
// helpUsage returns the command's usage line without the "Usage: " prefix. // helpUsage returns the command's usage line without the "Usage: " prefix.
func helpUsage(help string) string { func helpUsage(help string) string {
for line := range strings.SplitSeq(help, "\n") { for line := range strings.SplitSeq(help, "\n") {
+11 -10
View File
@@ -44,10 +44,10 @@ flowchart TD
The lexer is the shared foundation: the parser builds the AST from it, the The lexer is the shared foundation: the parser builds the AST from it, the
formatter re-spaces its tokens directly, and the language server uses it for formatter re-spaces its tokens directly, and the language server uses it for
semantic highlighting. The phases follow a dependency chain: Phase 1 (static semantic highlighting. The packages follow a dependency chain: static analysis
analysis) builds only on the AST, Phase 2 (the standalone assembler) emits builds only on the AST, the standalone assembler emits object code, and both
object code, and Phases 3 (dynamic analysis) and 4 (the debugger) both consume the dynamic analysis and the debugger consume the execution substrate the
the execution substrate that the assembler provides. assembler provides.
## Packages ## Packages
@@ -62,6 +62,7 @@ the execution substrate that the assembler provides.
| `format` | canonical formatter over the token stream | | `format` | canonical formatter over the token stream |
| `lsp` | the language server | | `lsp` | the language server |
| `asm` | standalone assembler: encoders, image layout, object emitters | | `asm` | standalone assembler: encoders, image layout, object emitters |
| `disasm` | disassembly backend over golang.org/x/arch |
| `verify` | JIT execution, ABI checks, differential fuzzing | | `verify` | JIT execution, ABI checks, differential fuzzing |
| `debug` | interactive ptrace debugger | | `debug` | interactive ptrace debugger |
| `cmd/gasm` | the CLI | | `cmd/gasm` | the CLI |
@@ -230,20 +231,20 @@ them from the standard LSP legend, so no editor-specific grammar is needed.
### `asm` ### `asm`
The standalone assembler (Phase 2). Its core is an amd64 instruction encoder: The standalone assembler. Its core is an amd64 instruction encoder:
a REX/ModR-M/SIB/displacement/immediate engine plus the scalar instruction set, a REX/ModR-M/SIB/displacement/immediate engine plus the scalar instruction set,
with the Plan 9 operand order (source first) mapped onto the x86 encoding. with the Plan 9 operand order (source first) mapped onto the x86 encoding.
Every encoding is validated by decoding it again with `golang.org/x/arch`, the Every encoding is validated by decoding it again with `golang.org/x/arch`, the
one module dependency, which also backs the `gasm dis` listings. one module dependency, which also backs the `gasm dis` listings.
A **RISC-V encoder** (Phase 5, RV64IMAFDC + RVC compression) encodes the full A **RISC-V encoder** (RV64IMAFDC + RVC compression) encodes the full
integer, atomic, float/double, FMA and CSR instruction sets with the MOV integer, atomic, float/double, FMA and CSR instruction sets with the MOV
pseudo-instruction and SB/global symbol references (AUIPC pairs with pseudo-instruction and SB/global symbol references (AUIPC pairs with
R_RISCV_PCREL_HI20/LO12 relocations). The encoder compresses eligible R_RISCV_PCREL_HI20/LO12 relocations). The encoder compresses eligible
instructions to 16-bit RVC forms and is validated byte-for-byte against instructions to 16-bit RVC forms and is validated byte-for-byte against
`GOARCH=riscv64 go tool asm`. `GOARCH=riscv64 go tool asm`.
A **LoongArch encoder** (Phase 5, LoongArch64) encodes the integer and A **LoongArch encoder** (LoongArch64) encodes the integer and
floating-point instruction sets with the dual-form arithmetic mnemonics (3R floating-point instruction sets with the dual-form arithmetic mnemonics (3R
vs 2RI12), the 16/21-bit branch families, the MOV pseudo-instruction and its vs 2RI12), the 16/21-bit branch families, the MOV pseudo-instruction and its
constant materialisation (the dcon classification driving lu12i.w/ori/lu32i.d/ constant materialisation (the dcon classification driving lu12i.w/ori/lu32i.d/
@@ -254,7 +255,7 @@ relocations). Like the RISC-V encoder it is validated byte-for-byte against
`GOARCH=loong64 go tool asm`, and its GOOBJ output is proven end-to-end by `GOARCH=loong64 go tool asm`, and its GOOBJ output is proven end-to-end by
substituting it into a cross-compiled `go build` and linking with `cmd/link`. substituting it into a cross-compiled `go build` and linking with `cmd/link`.
An **AArch64 encoder** (Phase 5, arm64) encodes the integer instruction set An **AArch64 encoder** (arm64) encodes the integer instruction set
with the data-processing (shifted register and immediate forms), load/store with the data-processing (shifted register and immediate forms), load/store
(scaled unsigned immediate and unscaled9-bit immediate), conditional and (scaled unsigned immediate and unscaled9-bit immediate), conditional and
unconditional branches, the MOV pseudo-instruction and its constant unconditional branches, the MOV pseudo-instruction and its constant
@@ -389,7 +390,7 @@ compiled packages it references.
### `verify` ### `verify`
The dynamic-analysis substrate (Phase 3). It JIT-loads assembled images into The dynamic-analysis substrate. It JIT-loads assembled images into
executable memory and invokes them directly, enabling differential testing, executable memory and invokes them directly, enabling differential testing,
runtime ABI checks and coverage profiling. runtime ABI checks and coverage profiling.
@@ -462,7 +463,7 @@ For non-interactive use, `--script` runs REPL commands from a file (or
stdin) and exits, `--timeout` kills the debuggee when a run hangs (the stdin) and exits, `--timeout` kills the debuggee when a run hangs (the
watchdog is armed before the ptrace attach, so a sandboxed debuggee cannot watchdog is armed before the ptrace attach, so a sandboxed debuggee cannot
block it), and `--cover` runs to completion with a breakpoint on every block it), and `--cover` runs to completion with a breakpoint on every
label and reports which blocks executed. instruction and reports which instructions executed and how often.
### Extending the toolkit ### Extending the toolkit
+2 -1
View File
@@ -260,7 +260,7 @@ Usage: gasm debug <file.s> --func <name>
| `-buf` | empty | buffer spec: `name:size:pattern[,name:size:pattern]` (zero, ones, seq or hex) | | `-buf` | empty | buffer spec: `name:size:pattern[,name:size:pattern]` (zero, ones, seq or hex) |
| `-args` | empty | file containing the ABI0 argument block | | `-args` | empty | file containing the ABI0 argument block |
| `-script` | empty | run REPL commands from a file, one per line, and exit; `-` reads stdin | | `-script` | empty | run REPL commands from a file, one per line, and exit; `-` reads stdin |
| `-timeout` | 0 | kill the debuggee after this duration, for headless `-script` runs | | `-timeout` | 0 | kill the debuggee after this duration, for headless `-script` runs; a timeout exits 3 |
| `-cover` | off | run to completion with a breakpoint on every instruction and report which executed | | `-cover` | off | run to completion with a breakpoint on every instruction and report which executed |
The debugger spawns the debuggee from the `gasm` binary on `$PATH`, so install The debugger spawns the debuggee from the `gasm` binary on `$PATH`, so install
@@ -447,6 +447,7 @@ version control.
| `0` | success | | `0` | success |
| `1` | a failure the program detected: a parse or assembly error, an error-severity lint diagnostic, a mismatch in `verify`, a file that cannot be read | | `1` | a failure the program detected: a parse or assembly error, an error-severity lint diagnostic, a mismatch in `verify`, a file that cannot be read |
| `2` | the arguments were wrong: a missing or extra argument, an unknown command or format, an invalid `--map` pair | | `2` | the arguments were wrong: a missing or extra argument, an unknown command or format, an invalid `--map` pair |
| `3` | `debug --timeout` killed the debuggee |
## Examples ## Examples
+2
View File
@@ -38,6 +38,8 @@ Every recipe in the `justfile`, and what it does.
| `just clean` | removes the build artefacts, `bin/` and `coverage.out` | | `just clean` | removes the build artefacts, `bin/` and `coverage.out` |
| `just install` | builds, then copies the binary into `bindir` (`~/.local/bin`); `gasm debug` needs an installed binary, because it spawns the debuggee from `$PATH` | | `just install` | builds, then copies the binary into `bindir` (`~/.local/bin`); `gasm debug` needs an installed binary, because it spawns the debuggee from `$PATH` |
| `just uninstall` | removes the installed binary from `bindir` | | `just uninstall` | removes the installed binary from `bindir` |
| `just install-man` | installs the man pages under `docs/man` into `~/.local/share/man/man1` (`MANDIR` overrides), gzip-compressed; not a gate |
| `just uninstall-man` | removes the installed man pages |
| `just run` | runs the CLI with `go run -buildvcs=true`; the recipe takes no arguments, so flags go through the package instead | | `just run` | runs the CLI with `go run -buildvcs=true`; the recipe takes no arguments, so flags go through the package instead |
| `just dev` | the same as `run`; the project has no watcher to add | | `just dev` | the same as `run`; the project has no watcher to add |
| `just gen` | regenerates the `arch` instruction tables from the Go toolchain source; not a gate | | `just gen` | regenerates the `arch` instruction tables from the Go toolchain source; not a gate |
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-ASM 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-ASM 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-asm \- assemble Plan 9 assembly without the Go toolchain gasm-asm \- assemble Plan 9 assembly without the Go toolchain
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-AUDIT-INSTRUCTIONS 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-AUDIT-INSTRUCTIONS 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-audit-instructions \- diff the encoder against the Go toolchain, or measure a corpus gasm-audit-instructions \- diff the encoder against the Go toolchain, or measure a corpus
.SH SYNOPSIS .SH SYNOPSIS
+6 -4
View File
@@ -1,4 +1,4 @@
.TH GASM-DEBUG 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-DEBUG 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-debug \- interactive source-level debugger for JIT-assembled functions gasm-debug \- interactive source-level debugger for JIT-assembled functions
.SH SYNOPSIS .SH SYNOPSIS
@@ -98,10 +98,12 @@ Run REPL commands from a file (one per line) and exit; - reads stdin.
.TP .TP
.B \-timeout \fIduration\fR .B \-timeout \fIduration\fR
Kill the debuggee after this duration (e.g. 30s); for headless --script Kill the debuggee after this duration (e.g. 30s); for headless --script
runs. runs; a timeout exits 3.
.SH EXIT STATUS .SH EXIT STATUS
Exits 0 when the scripted session completes and 1 when the debuggee Exits 0 when the scripted session completes, 1 when the debuggee crashes
crashes or a check fails; the debugger is Linux-only. or a check fails, and 3 when
.B \-\-timeout
kills the debuggee; the debugger is Linux-only.
.SH EXAMPLES .SH EXAMPLES
.nf .nf
gasm debug \-\-func name k.s gasm debug \-\-func name k.s
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-DIFF 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-DIFF 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-diff \- compare the machine code of two assembly files gasm-diff \- compare the machine code of two assembly files
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-DIS 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-DIS 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-dis \- disassemble machine code to instruction text gasm-dis \- disassemble machine code to instruction text
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-FMT 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-FMT 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-fmt \- canonicalise the formatting of Plan 9 assembly sources gasm-fmt \- canonicalise the formatting of Plan 9 assembly sources
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-LINT 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-LINT 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-lint \- run the static checks over assembly files gasm-lint \- run the static checks over assembly files
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-LSP 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-LSP 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-lsp \- run the Plan 9 assembly language server gasm-lsp \- run the Plan 9 assembly language server
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-PARSE 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-PARSE 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-parse \- parse an assembly file and report syntax errors gasm-parse \- parse an assembly file and report syntax errors
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-PROFILE 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-PROFILE 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-profile \- show the basic-block structure of functions gasm-profile \- show the basic-block structure of functions
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-SCAFFOLD 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-SCAFFOLD 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-scaffold \- generate a differential test skeleton for a kernel file gasm-scaffold \- generate a differential test skeleton for a kernel file
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-TOKENS 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-TOKENS 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-tokens \- print the lexical token stream of an assembly file gasm-tokens \- print the lexical token stream of an assembly file
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,4 +1,4 @@
.TH GASM-VERIFY 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM-VERIFY 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm-verify \- JIT-assemble a file and run dynamic checks against it gasm-verify \- JIT-assemble a file and run dynamic checks against it
.SH SYNOPSIS .SH SYNOPSIS
+3 -2
View File
@@ -1,4 +1,4 @@
.TH GASM 1 "2026-09-19" "gasm 0.33.0" "User Commands" .TH GASM 1 "2026-09-19" "gasm" "User Commands"
.SH NAME .SH NAME
gasm \- developer tooling for Go's Plan 9 assembler gasm \- developer tooling for Go's Plan 9 assembler
.SH SYNOPSIS .SH SYNOPSIS
@@ -82,7 +82,8 @@ Show the command overview.
Print the version the toolchain recorded at build time. Print the version the toolchain recorded at build time.
.SH EXIT STATUS .SH EXIT STATUS
Exits 0 on success, 1 when a command fails, and 2 on a usage error. An Exits 0 on success, 1 when a command fails, and 2 on a usage error. An
unknown command exits 2. unknown command exits 2; \fBgasm debug\fR exits 3 when \-\-timeout kills
the debuggee.
.SH SEE ALSO .SH SEE ALSO
.BR gasm\-asm (1), .BR gasm\-asm (1),
.BR gasm\-fmt (1), .BR gasm\-fmt (1),