feat(debug): instruction-level coverage and FP register display
Assisted-by: GLM 5.3 Flash
This commit is contained in:
+39
-15
@@ -52,7 +52,7 @@ REPL commands:
|
||||
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")
|
||||
script := fs.String("script", "", "run REPL commands from a file (one per line) and exit; '-' reads stdin")
|
||||
cover := fs.Bool("cover", false, "run to completion with breakpoints on every label and report which blocks executed")
|
||||
cover := fs.Bool("cover", false, "run to completion with a breakpoint on every instruction and report which executed and how often")
|
||||
timeout := fs.Duration("timeout", 0, "kill the debuggee after this duration (e.g. 30s); for headless --script runs")
|
||||
fs.Parse(args)
|
||||
|
||||
@@ -195,32 +195,49 @@ REPL commands:
|
||||
srcLines = append(srcLines, debug.SourceLine{Offset: le.Offset, Line: le.Line})
|
||||
}
|
||||
|
||||
// Coverage mode: pre-register a breakpoint on every label (the basic
|
||||
// blocks of a hand-written kernel) and let the kernel run to completion.
|
||||
// Each hit removes its breakpoint, so the final report lists exactly the
|
||||
// labels execution reached — the fast answer to "did my test ever enter
|
||||
// the tail loop / the negative branch?".
|
||||
// Coverage mode: pre-register a breakpoint on every instruction (walked
|
||||
// by length through the function body while the debuggee is stopped) and
|
||||
// let the kernel run to completion. Each trap counts a hit for that
|
||||
// instruction, so the final report shows exactly which instructions
|
||||
// executed and how often, with the label-level view derived from it.
|
||||
// Expect the run to slow to ptrace speed: one trap per executed
|
||||
// instruction.
|
||||
if *cover {
|
||||
covered := map[string]bool{}
|
||||
for _, l := range labels {
|
||||
addr := sess.CodeBase() + uint64(fl.Offset) + uint64(l.Offset)
|
||||
name := l.Name
|
||||
if _, err := bm.SetWithCond(addr, name, nil); err != nil {
|
||||
base := sess.CodeBase() + uint64(fl.Offset)
|
||||
type coverInstr struct {
|
||||
off uint64
|
||||
text string
|
||||
}
|
||||
var instrs []coverInstr
|
||||
for off := uint64(0); off < uint64(fl.Size); {
|
||||
text, ln, err := sess.Disassemble(base + off)
|
||||
if err != nil || ln == 0 {
|
||||
break
|
||||
}
|
||||
instrs = append(instrs, coverInstr{off: off, text: text})
|
||||
off += uint64(ln)
|
||||
}
|
||||
for _, in := range instrs {
|
||||
if _, err := bm.SetWithCond(base+in.off, fmt.Sprintf("func+%#x", in.off), nil); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "gasm debug: cover: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
fmt.Printf("gasm debug: coverage run over %d labels\n", len(labels))
|
||||
hits := map[uint64]int{}
|
||||
traps := 0
|
||||
fmt.Printf("gasm debug: coverage run over %d instructions\n", len(instrs))
|
||||
for {
|
||||
for _, bp := range bm.All() {
|
||||
bm.Reinsert(bp.Addr)
|
||||
}
|
||||
// Remove the breakpoint the run is parked on, then continue.
|
||||
// Remove the breakpoint the run is parked on, count the hit,
|
||||
// then continue.
|
||||
regs, rerr := sess.GetRegs()
|
||||
if rerr == nil {
|
||||
if bp := bm.At(regs.GetPC()); bp != nil {
|
||||
bm.Clear(bp.Addr)
|
||||
covered[bp.Label] = true
|
||||
traps++
|
||||
hits[regs.GetPC()-base]++
|
||||
}
|
||||
}
|
||||
if err := sess.Continue(); err != nil {
|
||||
@@ -233,7 +250,7 @@ REPL commands:
|
||||
var hit []string
|
||||
var missed []string
|
||||
for _, l := range labels {
|
||||
if covered[l.Name] {
|
||||
if hits[uint64(l.Offset)] > 0 {
|
||||
hit = append(hit, l.Name)
|
||||
} else {
|
||||
missed = append(missed, l.Name)
|
||||
@@ -241,6 +258,7 @@ REPL commands:
|
||||
}
|
||||
sort.Strings(hit)
|
||||
sort.Strings(missed)
|
||||
fmt.Printf("coverage: %d/%d instructions executed (%d traps)\n", len(hits), len(instrs), traps)
|
||||
fmt.Printf("coverage: %d/%d labels reached\n", len(hit), len(labels))
|
||||
for _, l := range hit {
|
||||
fmt.Printf(" covered %s\n", l)
|
||||
@@ -248,6 +266,12 @@ REPL commands:
|
||||
for _, l := range missed {
|
||||
fmt.Printf(" MISSED %s\n", l)
|
||||
}
|
||||
fmt.Println("executed instructions:")
|
||||
for _, in := range instrs {
|
||||
if n := hits[in.off]; n > 0 {
|
||||
fmt.Printf(" func+%#04x %4dx %s\n", in.off, n, in.text)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user