fix(debug): handle mapping edges, stray traps and dying debuggees
Assisted-by: GLM 5.3
This commit is contained in:
+62
-14
@@ -71,7 +71,12 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
case "step", "s":
|
||||
n := 1
|
||||
if len(parts) > 1 {
|
||||
n, _ = strconv.Atoi(parts[1])
|
||||
v, err := strconv.Atoi(parts[1])
|
||||
if err != nil || v < 0 {
|
||||
fmt.Printf("invalid count: %s\n", parts[1])
|
||||
continue
|
||||
}
|
||||
n = v
|
||||
}
|
||||
for range n {
|
||||
if s.Exited() {
|
||||
@@ -82,8 +87,13 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
fmt.Println(err)
|
||||
break
|
||||
}
|
||||
if sig := s.LastSignal(); sig != 0 {
|
||||
regs, _ := s.GetRegs()
|
||||
fmt.Printf("stopped on signal %v at %#x\n", sig, regs.GetPC())
|
||||
break
|
||||
}
|
||||
}
|
||||
if !s.Exited() {
|
||||
if !s.Exited() && s.LastSignal() == 0 {
|
||||
regs, _ := s.GetRegs()
|
||||
pc := regs.GetPC()
|
||||
text, _, _ := s.Disassemble(pc)
|
||||
@@ -106,16 +116,16 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
}
|
||||
if err := s.Continue(); err != nil {
|
||||
fmt.Println(err)
|
||||
bm.Clear(afterAddr)
|
||||
clearNextBp(bm, afterAddr)
|
||||
continue
|
||||
}
|
||||
if s.Exited() {
|
||||
bm.Clear(afterAddr)
|
||||
clearNextBp(bm, afterAddr)
|
||||
fmt.Println("debuggee exited")
|
||||
continue
|
||||
}
|
||||
if sig := s.LastSignal(); sig != 0 {
|
||||
bm.Clear(afterAddr)
|
||||
clearNextBp(bm, afterAddr)
|
||||
regs, _ := s.GetRegs()
|
||||
fmt.Printf("stopped on signal %v at %#x\n", sig, regs.GetPC())
|
||||
continue
|
||||
@@ -125,12 +135,17 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
// snapshot, and a stale SetRegs would clobber live state.
|
||||
regs, _ = s.GetRegs()
|
||||
bm.HandleTrap(®s)
|
||||
bm.Clear(afterAddr)
|
||||
clearNextBp(bm, afterAddr)
|
||||
} else {
|
||||
if err := s.Step(); err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
if sig := s.LastSignal(); sig != 0 {
|
||||
regs, _ := s.GetRegs()
|
||||
fmt.Printf("stopped on signal %v at %#x\n", sig, regs.GetPC())
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !s.Exited() {
|
||||
regs, _ := s.GetRegs()
|
||||
@@ -156,16 +171,16 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
}
|
||||
if err := s.Continue(); err != nil {
|
||||
fmt.Println(err)
|
||||
bm.Clear(retAddr)
|
||||
clearNextBp(bm, retAddr)
|
||||
continue
|
||||
}
|
||||
if s.Exited() {
|
||||
bm.Clear(retAddr)
|
||||
clearNextBp(bm, retAddr)
|
||||
fmt.Println("debuggee exited")
|
||||
continue
|
||||
}
|
||||
if sig := s.LastSignal(); sig != 0 {
|
||||
bm.Clear(retAddr)
|
||||
clearNextBp(bm, retAddr)
|
||||
regs, _ := s.GetRegs()
|
||||
fmt.Printf("stopped on signal %v at %#x\n", sig, regs.GetPC())
|
||||
continue
|
||||
@@ -174,7 +189,7 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
// does: HandleTrap must see the PC the trap left behind.
|
||||
regs, _ = s.GetRegs()
|
||||
bm.HandleTrap(®s)
|
||||
bm.Clear(retAddr)
|
||||
clearNextBp(bm, retAddr)
|
||||
if s.Exited() {
|
||||
fmt.Println("debuggee exited")
|
||||
} else {
|
||||
@@ -214,6 +229,7 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
break
|
||||
}
|
||||
regs, _ := s.GetRegs()
|
||||
trapPC := regs.GetPC()
|
||||
if bp := bm.HandleTrap(®s); bp != nil {
|
||||
// Execute the instruction under the restored breakpoint
|
||||
// so the next continue cannot re-trap on the same
|
||||
@@ -229,6 +245,13 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
fmt.Printf("breakpoint hit: %s (func+%#x)\n", name, bp.Addr-codeBase-uint64(funcOffset))
|
||||
break
|
||||
}
|
||||
// The trap matched no breakpoint of ours. When the PC still
|
||||
// stands on the trapping instruction, resuming would re-execute
|
||||
// it and trap forever, so surface the stop instead of spinning.
|
||||
if TrapStray(s, reason, trapPC) {
|
||||
fmt.Printf("SIGTRAP at %#x matches no breakpoint; the PC did not advance\n", trapPC-uint64(breakpointPCAdjust))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
case "break", "b":
|
||||
@@ -326,6 +349,10 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
length := 64
|
||||
if len(parts) > 1 {
|
||||
addr, _ = resolveAddr(parts[1], codeBase, uint64(funcOffset), labels)
|
||||
if addr == 0 {
|
||||
fmt.Printf("unknown address: %s\n", parts[1])
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(parts) > 2 {
|
||||
// A malformed or non-positive length would panic
|
||||
@@ -399,9 +426,13 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
case "disas", "u":
|
||||
n := 5
|
||||
if len(parts) > 1 {
|
||||
n, _ = strconv.Atoi(parts[1])
|
||||
if n <= 0 {
|
||||
n = 5
|
||||
v, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
fmt.Printf("invalid count: %s\n", parts[1])
|
||||
continue
|
||||
}
|
||||
if v > 0 {
|
||||
n = v
|
||||
}
|
||||
}
|
||||
regs, _ := s.GetRegs()
|
||||
@@ -496,10 +527,18 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
typ = WatchRead
|
||||
case "w":
|
||||
typ = WatchWrite
|
||||
default:
|
||||
fmt.Printf("unknown watchpoint type: %s (want r or w)\n", parts[2])
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(parts) > 3 {
|
||||
size, _ = strconv.Atoi(parts[3])
|
||||
v, err := strconv.Atoi(parts[3])
|
||||
if err != nil || v <= 0 {
|
||||
fmt.Printf("invalid size: %s\n", parts[3])
|
||||
continue
|
||||
}
|
||||
size = v
|
||||
}
|
||||
slot := s.FindFreeWatchpointSlot()
|
||||
if slot < 0 {
|
||||
@@ -543,6 +582,15 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
s.Kill()
|
||||
}
|
||||
|
||||
// clearNextBp removes one of the temporary breakpoints the next and finish
|
||||
// commands plant, reporting a failure instead of silently leaving the trap
|
||||
// instruction behind in the debuggee.
|
||||
func clearNextBp(bm *Breakpoints, addr uint64) {
|
||||
if err := bm.Clear(addr); err != nil {
|
||||
fmt.Printf("cannot remove temporary breakpoint at %#x: %v\n", addr, err)
|
||||
}
|
||||
}
|
||||
|
||||
func hexDump(addr uint64, data []byte) {
|
||||
for i := 0; i < len(data); i += 16 {
|
||||
end := min(i+16, len(data))
|
||||
|
||||
Reference in New Issue
Block a user