From 94b98468bbf8915752945859ba359d5b2a27c975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Balv=C3=ADn?= Date: Fri, 21 Aug 2026 01:07:21 +0200 Subject: [PATCH] feat(debug): support register-register conditional breakpoints Assisted-by: MiMo V2.5 Pro --- debug/breakpoint.go | 43 ++++++++++++++++++++++++++++++++----------- debug/repl.go | 14 ++++++++------ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/debug/breakpoint.go b/debug/breakpoint.go index ab6b3fd..cdf0ab6 100644 --- a/debug/breakpoint.go +++ b/debug/breakpoint.go @@ -17,12 +17,17 @@ type Breakpoint struct { hits int } -// Condition is a simple register-comparison condition evaluated when a -// breakpoint is hit. Format: . +// Condition is a register-comparison condition evaluated when a breakpoint +// is hit. Supports three forms: +// - register vs constant: +// - register vs register: +// - register vs memory: * type Condition struct { - Reg string // register name (rax, rbx, rip, rsp, ...) - Op string // comparison operator: ==, !=, <, >, <=, >= - Value uint64 + Reg string // register name (rax, rbx, rip, rsp, ...) + Op string // comparison operator: ==, !=, <, >, <=, >= + Value uint64 // constant value (when Reg2 == "" and MemAddr == 0) + Reg2 string // second register name (for register-register comparison) + MemAddr uint64 // memory address (for register-memory comparison, prefixed with *) } // Eval checks the condition against the current registers. @@ -31,19 +36,35 @@ func (c *Condition) Eval(regs *Regs) bool { if !ok { return true // unknown register — don't block } + var expected uint64 + switch { + case c.Reg2 != "": + // Register-register comparison. + v, ok := regs.RegValue(c.Reg2) + if !ok { + return true + } + expected = v + case c.MemAddr != 0: + // Register-memory comparison — requires a Session, not available here. + // Fall back to treating as constant (the caller should resolve). + expected = c.Value + default: + expected = c.Value + } switch c.Op { case "==", "=": - return actual == c.Value + return actual == expected case "!=": - return actual != c.Value + return actual != expected case "<": - return actual < c.Value + return actual < expected case ">": - return actual > c.Value + return actual > expected case "<=": - return actual <= c.Value + return actual <= expected case ">=": - return actual >= c.Value + return actual >= expected default: return true } diff --git a/debug/repl.go b/debug/repl.go index 375ddf1..28ed1b3 100644 --- a/debug/repl.go +++ b/debug/repl.go @@ -210,14 +210,16 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar } var cond *Condition if len(parts) >= 6 && parts[2] == "if" { - val, err := strconv.ParseUint(parts[5], 0, 64) - if err != nil { - fmt.Printf("invalid condition value: %s\n", parts[5]) - continue + reg := strings.ToLower(parts[3]) + op := parts[4] + operand := parts[5] + if val, err := strconv.ParseUint(operand, 0, 64); err == nil { + cond = &Condition{Reg: reg, Op: op, Value: val} + } else { + cond = &Condition{Reg: reg, Op: op, Reg2: strings.ToLower(operand)} } - cond = &Condition{Reg: strings.ToLower(parts[3]), Op: parts[4], Value: val} } else if len(parts) >= 4 && parts[2] == "if" { - fmt.Println("usage: break if ") + fmt.Println("usage: break if ") continue } bp, err := bm.SetWithCond(addr, label, cond)