From 3a73acb20a018cce376794e9e39e77a3f39698dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Balv=C3=ADn?= Date: Sat, 19 Sep 2026 23:49:27 +0200 Subject: [PATCH] docs: drop process labels and refresh the architecture and manual pages Assisted-by: GLM 5.3 --- CONTRIBUTING.md | 5 +- cmd/gasm/man_test.go | 84 ++++++++++++++++++++++++++++++ docs/ARCHITECTURE.md | 21 ++++---- docs/CLI.md | 3 +- docs/DEVELOPMENT.md | 2 + docs/man/gasm-asm.1 | 2 +- docs/man/gasm-audit-instructions.1 | 2 +- docs/man/gasm-debug.1 | 10 ++-- docs/man/gasm-diff.1 | 2 +- docs/man/gasm-dis.1 | 2 +- docs/man/gasm-fmt.1 | 2 +- docs/man/gasm-lint.1 | 2 +- docs/man/gasm-lsp.1 | 2 +- docs/man/gasm-parse.1 | 2 +- docs/man/gasm-profile.1 | 2 +- docs/man/gasm-scaffold.1 | 2 +- docs/man/gasm-tokens.1 | 2 +- docs/man/gasm-verify.1 | 2 +- docs/man/gasm.1 | 5 +- 19 files changed, 123 insertions(+), 31 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d50e062..6e946f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 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 -`fmt.Errorf("context: %w", err)`, and nothing panics outside `main`. The `golang` -skill holds the rules the project follows; the recipe file holds the commands. +`fmt.Errorf("context: %w", err)`, and nothing panics outside `main`. The recipe file holds +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: `gasm dis` and the debugger's listings decode through it. Everything else is the diff --git a/cmd/gasm/man_test.go b/cmd/gasm/man_test.go index 0d397ec..e325ab6 100644 --- a/cmd/gasm/man_test.go +++ b/cmd/gasm/man_test.go @@ -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 -h` output. func helpFlags(help string) map[string]bool { m := map[string]bool{} @@ -123,6 +159,54 @@ func roffFlags(page string) map[string]bool { 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\-(1)` or `.B gasm `. +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. func helpUsage(help string) string { for line := range strings.SplitSeq(help, "\n") { diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index b1798b6..7125b1b 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -44,10 +44,10 @@ flowchart TD 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 -semantic highlighting. The phases follow a dependency chain: Phase 1 (static -analysis) builds only on the AST, Phase 2 (the standalone assembler) emits -object code, and Phases 3 (dynamic analysis) and 4 (the debugger) both consume -the execution substrate that the assembler provides. +semantic highlighting. The packages follow a dependency chain: static analysis +builds only on the AST, the standalone assembler emits object code, and both +the dynamic analysis and the debugger consume the execution substrate the +assembler provides. ## Packages @@ -62,6 +62,7 @@ the execution substrate that the assembler provides. | `format` | canonical formatter over the token stream | | `lsp` | the language server | | `asm` | standalone assembler: encoders, image layout, object emitters | +| `disasm` | disassembly backend over golang.org/x/arch | | `verify` | JIT execution, ABI checks, differential fuzzing | | `debug` | interactive ptrace debugger | | `cmd/gasm` | the CLI | @@ -230,20 +231,20 @@ them from the standard LSP legend, so no editor-specific grammar is needed. ### `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, 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 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 pseudo-instruction and SB/global symbol references (AUIPC pairs with R_RISCV_PCREL_HI20/LO12 relocations). The encoder compresses eligible instructions to 16-bit RVC forms and is validated byte-for-byte against `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 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/ @@ -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 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 (scaled unsigned immediate and unscaled9-bit immediate), conditional and unconditional branches, the MOV pseudo-instruction and its constant @@ -389,7 +390,7 @@ compiled packages it references. ### `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, 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 watchdog is armed before the ptrace attach, so a sandboxed debuggee cannot 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 diff --git a/docs/CLI.md b/docs/CLI.md index a425d96..23426e1 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -260,7 +260,7 @@ Usage: gasm debug --func | `-buf` | empty | buffer spec: `name:size:pattern[,name:size:pattern]` (zero, ones, seq or hex) | | `-args` | empty | file containing the ABI0 argument block | | `-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 | The debugger spawns the debuggee from the `gasm` binary on `$PATH`, so install @@ -447,6 +447,7 @@ version control. | `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 | | `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 diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 93adf49..baf1f8f 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -38,6 +38,8 @@ Every recipe in the `justfile`, and what it does. | `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 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 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 | diff --git a/docs/man/gasm-asm.1 b/docs/man/gasm-asm.1 index f94d4ea..d4f31da 100644 --- a/docs/man/gasm-asm.1 +++ b/docs/man/gasm-asm.1 @@ -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 gasm-asm \- assemble Plan 9 assembly without the Go toolchain .SH SYNOPSIS diff --git a/docs/man/gasm-audit-instructions.1 b/docs/man/gasm-audit-instructions.1 index 4fba7a6..4de2577 100644 --- a/docs/man/gasm-audit-instructions.1 +++ b/docs/man/gasm-audit-instructions.1 @@ -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 gasm-audit-instructions \- diff the encoder against the Go toolchain, or measure a corpus .SH SYNOPSIS diff --git a/docs/man/gasm-debug.1 b/docs/man/gasm-debug.1 index b143763..aadaa7c 100644 --- a/docs/man/gasm-debug.1 +++ b/docs/man/gasm-debug.1 @@ -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 gasm-debug \- interactive source-level debugger for JIT-assembled functions .SH SYNOPSIS @@ -98,10 +98,12 @@ Run REPL commands from a file (one per line) and exit; - reads stdin. .TP .B \-timeout \fIduration\fR Kill the debuggee after this duration (e.g. 30s); for headless --script -runs. +runs; a timeout exits 3. .SH EXIT STATUS -Exits 0 when the scripted session completes and 1 when the debuggee -crashes or a check fails; the debugger is Linux-only. +Exits 0 when the scripted session completes, 1 when the debuggee crashes +or a check fails, and 3 when +.B \-\-timeout +kills the debuggee; the debugger is Linux-only. .SH EXAMPLES .nf gasm debug \-\-func name k.s diff --git a/docs/man/gasm-diff.1 b/docs/man/gasm-diff.1 index d5cfbf1..0d6f385 100644 --- a/docs/man/gasm-diff.1 +++ b/docs/man/gasm-diff.1 @@ -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 gasm-diff \- compare the machine code of two assembly files .SH SYNOPSIS diff --git a/docs/man/gasm-dis.1 b/docs/man/gasm-dis.1 index e1ad652..a59f7cf 100644 --- a/docs/man/gasm-dis.1 +++ b/docs/man/gasm-dis.1 @@ -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 gasm-dis \- disassemble machine code to instruction text .SH SYNOPSIS diff --git a/docs/man/gasm-fmt.1 b/docs/man/gasm-fmt.1 index f8d5093..827fb44 100644 --- a/docs/man/gasm-fmt.1 +++ b/docs/man/gasm-fmt.1 @@ -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 gasm-fmt \- canonicalise the formatting of Plan 9 assembly sources .SH SYNOPSIS diff --git a/docs/man/gasm-lint.1 b/docs/man/gasm-lint.1 index 421a6a1..8500b7d 100644 --- a/docs/man/gasm-lint.1 +++ b/docs/man/gasm-lint.1 @@ -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 gasm-lint \- run the static checks over assembly files .SH SYNOPSIS diff --git a/docs/man/gasm-lsp.1 b/docs/man/gasm-lsp.1 index 7a0a24a..71791f0 100644 --- a/docs/man/gasm-lsp.1 +++ b/docs/man/gasm-lsp.1 @@ -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 gasm-lsp \- run the Plan 9 assembly language server .SH SYNOPSIS diff --git a/docs/man/gasm-parse.1 b/docs/man/gasm-parse.1 index 98bdde5..0e86f41 100644 --- a/docs/man/gasm-parse.1 +++ b/docs/man/gasm-parse.1 @@ -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 gasm-parse \- parse an assembly file and report syntax errors .SH SYNOPSIS diff --git a/docs/man/gasm-profile.1 b/docs/man/gasm-profile.1 index bc06828..a386e9b 100644 --- a/docs/man/gasm-profile.1 +++ b/docs/man/gasm-profile.1 @@ -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 gasm-profile \- show the basic-block structure of functions .SH SYNOPSIS diff --git a/docs/man/gasm-scaffold.1 b/docs/man/gasm-scaffold.1 index 235cfac..219e278 100644 --- a/docs/man/gasm-scaffold.1 +++ b/docs/man/gasm-scaffold.1 @@ -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 gasm-scaffold \- generate a differential test skeleton for a kernel file .SH SYNOPSIS diff --git a/docs/man/gasm-tokens.1 b/docs/man/gasm-tokens.1 index adffb18..8f24613 100644 --- a/docs/man/gasm-tokens.1 +++ b/docs/man/gasm-tokens.1 @@ -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 gasm-tokens \- print the lexical token stream of an assembly file .SH SYNOPSIS diff --git a/docs/man/gasm-verify.1 b/docs/man/gasm-verify.1 index 0dbaeee..b1cf358 100644 --- a/docs/man/gasm-verify.1 +++ b/docs/man/gasm-verify.1 @@ -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 gasm-verify \- JIT-assemble a file and run dynamic checks against it .SH SYNOPSIS diff --git a/docs/man/gasm.1 b/docs/man/gasm.1 index 1817338..a8fbed0 100644 --- a/docs/man/gasm.1 +++ b/docs/man/gasm.1 @@ -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 gasm \- developer tooling for Go's Plan 9 assembler .SH SYNOPSIS @@ -82,7 +82,8 @@ Show the command overview. Print the version the toolchain recorded at build time. .SH EXIT STATUS 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 .BR gasm\-asm (1), .BR gasm\-fmt (1),