refactor(cmd): re-enter child modes via environment instead of hidden flags

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-08-30 11:00:40 +02:00
parent 56f8babbce
commit 6d7f10f13e
3 changed files with 46 additions and 26 deletions
+24 -9
View File
@@ -24,15 +24,30 @@ function in a traced subprocess (ptrace), then provides a REPL for
single-stepping, breakpoints, register and memory inspection.
REPL commands:
break <label|addr> set a breakpoint at a label or absolute address
step [n] single-step n instructions (default 1)
continue run until next breakpoint or exit
regs print general-purpose registers
break <label|addr> [if <reg> <op> <val>]
set a breakpoint, optionally conditional on a
register comparison (reg-reg or reg-immediate)
delete <label|addr> remove a breakpoint
info break list all breakpoints
step [n], s single-step n instructions (default 1)
next, n step over a CALL
finish, fin run until the function returns
continue, c run until a breakpoint, watchpoint or exit
disas [n], u disassemble n instructions at PC
regs print general-purpose and vector registers
where show source line and nearest label at PC
stack show stack near RSP (return address + ABI0 args)
bt, backtrace backtrace (current frame + return address)
x [addr] [len] hex-dump memory (default: current PC, 64 bytes)
labels list function labels and offsets
quit kill the debuggee and exit
w <addr> <val...> write bytes to memory
set <reg> <value> set a register
watch <addr> [r|w] [size]
set a hardware watchpoint (write by default)
unwatch [<slot>] clear one watchpoint, or all without an argument
labels, l list function labels and offsets
help, h, ? show command help
quit, q kill the debuggee and exit
`)
target := fs.Bool("target", false, "") // hidden: debuggee subprocess mode
funcName := fs.String("func", "", "function to debug")
argsFile := fs.String("args", "", "file containing the ABI0 argument block")
bufSpec := fs.String("buf", "", "buffer specification: name:size:pattern[,name:size:pattern...] where pattern is zero, ones, seq, or hex")
@@ -42,10 +57,10 @@ REPL commands:
fs.Parse(args)
// --- Debuggee mode (internal, spawned by the debugger) ---
if *target {
if os.Getenv("GASM_DEBUG_TARGET") != "" {
tmpDir := os.Getenv("GASM_DEBUG_TMP")
if tmpDir == "" || fs.NArg() < 1 || *funcName == "" || *argsFile == "" {
fmt.Fprintln(os.Stderr, "gasm debug --target: internal mode")
fmt.Fprintln(os.Stderr, "gasm debug: internal debuggee mode")
return 2
}
if err := debug.RunTarget(fs.Arg(0), *funcName, *argsFile, tmpDir); err != nil {
+20 -15
View File
@@ -1054,8 +1054,6 @@ decoders) that crash on random input but should succeed on valid data.
groundTruth := set.Bool("ground-truth", false, "compare machine code byte-for-byte against go tool asm")
fuzz := set.Bool("fuzz", false, "differential fuzz: JIT both gasm and go-tool-asm versions, compare outputs")
fuzzN := set.Int("n", 1000, "number of fuzz iterations per function")
fuzzOne := set.String("fuzz-one", "", "") // hidden: fuzz a single function (subprocess mode)
sweepOne := set.String("sweep-one", "", "") // hidden: smoke/abi a single function (subprocess mode)
call := set.String("call", "", "call a single function with -buf instead of the sweeps")
bufSpec := set.String("buf", "", "buffer spec for -call: name:size:pattern[,name:size:pattern] (zero, ones, seq, or hex)")
scalarSpec := set.String("args", "", "scalar args for -call: name=value[,name=value] (decimal or 0x hex)")
@@ -1100,8 +1098,11 @@ decoders) that crash on random input but should succeed on valid data.
return cmdVerifyCall(k, path, *call, *bufSpec, *scalarSpec, *repeat)
}
// Subprocess mode: fuzz a single function and exit.
if *fuzzOne != "" {
// Subprocess mode: fuzz a single function and exit. The parent selects
// the function through the environment, so no internal flag leaks into
// the -h output.
fuzzOne := os.Getenv("GASM_VERIFY_FUZZ_ONE")
if fuzzOne != "" {
gt, err := verify.GroundTruth(path)
if err != nil {
fmt.Fprintf(os.Stderr, "gasm verify: %v\n", err)
@@ -1113,17 +1114,17 @@ decoders) that crash on random input but should succeed on valid data.
return 1
}
sigs := verify.ExtractSignatures(src)
sig, ok := sigs[*fuzzOne]
sig, ok := sigs[fuzzOne]
if !ok {
fmt.Printf("%s: no signature\n", *fuzzOne)
fmt.Printf("%s: no signature\n", fuzzOne)
return 0
}
goCode, ok := gt[*fuzzOne]
goCode, ok := gt[fuzzOne]
if !ok {
fmt.Printf("%s: not in go tool asm\n", *fuzzOne)
fmt.Printf("%s: not in go tool asm\n", fuzzOne)
return 0
}
res := k.FuzzFunc(*fuzzOne, sig, goCode, *fuzzN, 42)
res := k.FuzzFunc(fuzzOne, sig, goCode, *fuzzN, 42)
fmt.Printf("%s\n", res)
if !res.OK() {
return 1
@@ -1134,13 +1135,15 @@ decoders) that crash on random input but should succeed on valid data.
// Subprocess mode: run the smoke/abi checks for a single function and
// exit with the accumulated status. The parent interprets a clean exit
// as success, a non-zero exit as failure and death-by-signal as a crash.
if *sweepOne != "" {
fl, err := k.Func(*sweepOne)
// Like the fuzz mode, the parent selects the function through the
// environment instead of an internal flag.
if sweepOne := os.Getenv("GASM_VERIFY_SWEEP_ONE"); sweepOne != "" {
fl, err := k.Func(sweepOne)
if err != nil || !fl.NoSplit {
fmt.Fprintf(os.Stderr, "gasm verify: %s: %v\n", *sweepOne, err)
fmt.Fprintf(os.Stderr, "gasm verify: %s: %v\n", sweepOne, err)
return 1
}
msgs, failed := runSweepChecks(k, path, *sweepOne, fl, *smoke, *abi, *abiN)
msgs, failed := runSweepChecks(k, path, sweepOne, fl, *smoke, *abi, *abiN)
for _, m := range msgs {
fmt.Println(m)
}
@@ -1324,7 +1327,8 @@ func fuzzInSubprocess(path, funcName string, n int) string {
if err != nil {
return fmt.Sprintf("%s: cannot find self: %v", funcName, err)
}
cmd := exec.Command(self, "verify", "--fuzz-one="+funcName, "-n", strconv.Itoa(n), path)
cmd := exec.Command(self, "verify", "-n", strconv.Itoa(n), path)
cmd.Env = append(os.Environ(), "GASM_VERIFY_FUZZ_ONE="+funcName)
out, err := cmd.CombinedOutput()
if err != nil {
// Check if the child was killed by a signal.
@@ -1363,7 +1367,7 @@ func sweepInSubprocess(path, funcName string, smoke, abi bool, abiN int) (string
if err != nil {
return fmt.Sprintf(" smoke/abi: FAIL — cannot find self: %v", err), true
}
args := []string{"verify", "--sweep-one=" + funcName}
args := []string{"verify"}
if smoke {
args = append(args, "-smoke")
}
@@ -1372,6 +1376,7 @@ func sweepInSubprocess(path, funcName string, smoke, abi bool, abiN int) (string
}
args = append(args, path)
cmd := exec.Command(self, args...)
cmd.Env = append(os.Environ(), "GASM_VERIFY_SWEEP_ONE="+funcName)
out, err := cmd.CombinedOutput()
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {