github.com/undoio/delve@v1.9.0/pkg/proc/breakpoints.go (about) 1 package proc 2 3 import ( 4 "debug/dwarf" 5 "errors" 6 "fmt" 7 "go/ast" 8 "go/constant" 9 "go/parser" 10 "go/token" 11 "reflect" 12 13 "github.com/undoio/delve/pkg/dwarf/godwarf" 14 "github.com/undoio/delve/pkg/dwarf/op" 15 "github.com/undoio/delve/pkg/dwarf/reader" 16 "github.com/undoio/delve/pkg/goversion" 17 "github.com/undoio/delve/pkg/proc/internal/ebpf" 18 ) 19 20 const ( 21 // UnrecoveredPanic is the name given to the unrecovered panic breakpoint. 22 UnrecoveredPanic = "unrecovered-panic" 23 24 // FatalThrow is the name given to the breakpoint triggered when the target 25 // process dies because of a fatal runtime error. 26 FatalThrow = "runtime-fatal-throw" 27 28 // HardcodedBreakpoint is the name given to hardcoded breakpoints (for 29 // example: calls to runtime.Breakpoint) 30 HardcodedBreakpoint = "hardcoded-breakpoint" 31 32 unrecoveredPanicID = -1 33 fatalThrowID = -2 34 hardcodedBreakpointID = -3 35 36 NoLogicalID = -1000 // Logical breakpoint ID for breakpoints internal breakpoints. 37 ) 38 39 // Breakpoint represents a physical breakpoint. Stores information on the break 40 // point including the byte of data that originally was stored at that 41 // address. 42 type Breakpoint struct { 43 // File & line information for printing. 44 FunctionName string 45 File string 46 Line int 47 48 Addr uint64 // Address breakpoint is set for. 49 OriginalData []byte // If software breakpoint, the data we replace with breakpoint instruction. 50 51 WatchExpr string 52 WatchType WatchType 53 HWBreakIndex uint8 // hardware breakpoint index 54 watchStackOff int64 // for watchpoints of stack variables, offset of the address from top of the stack 55 56 // Breaklets is the list of overlapping breakpoints on this physical breakpoint. 57 // There can be at most one UserBreakpoint in this list but multiple internal breakpoints are allowed. 58 Breaklets []*Breaklet 59 60 // Breakpoint information 61 Logical *LogicalBreakpoint 62 63 // ReturnInfo describes how to collect return variables when this 64 // breakpoint is hit as a return breakpoint. 65 returnInfo *returnBreakpointInfo 66 } 67 68 // Breaklet represents one of multiple breakpoints that can overlap on a 69 // single physical breakpoint. 70 type Breaklet struct { 71 // Kind describes whether this is a stepping breakpoint (for next'ing or 72 // stepping). 73 Kind BreakpointKind 74 75 LogicalID int // ID of the logical breakpoint that owns this physical breakpoint 76 77 // Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true 78 Cond ast.Expr 79 80 // DeferReturns: when kind == NextDeferBreakpoint this breakpoint 81 // will also check if the caller is runtime.gopanic or if the return 82 // address is in the DeferReturns array. 83 // Next uses NextDeferBreakpoints for the breakpoint it sets on the 84 // deferred function, DeferReturns is populated with the 85 // addresses of calls to runtime.deferreturn in the current 86 // function. This ensures that the breakpoint on the deferred 87 // function only triggers on panic or on the defer call to 88 // the function, not when the function is called directly 89 DeferReturns []uint64 90 91 // checkPanicCall checks that the breakpoint happened while the function was 92 // called by a panic. It is only checked for WatchOutOfScopeBreakpoint Kind. 93 checkPanicCall bool 94 95 // callback is called if every other condition for this breaklet is met, 96 // the return value will determine if the breaklet should be considered 97 // active. 98 // The callback can have side-effects. 99 callback func(th Thread) bool 100 101 // For WatchOutOfScopeBreakpoints and StackResizeBreakpoints the watchpoint 102 // field contains the watchpoint related to this out of scope sentinel. 103 watchpoint *Breakpoint 104 } 105 106 // BreakpointKind determines the behavior of delve when the 107 // breakpoint is reached. 108 type BreakpointKind uint16 109 110 const ( 111 // UserBreakpoint is a user set breakpoint 112 UserBreakpoint BreakpointKind = (1 << iota) 113 // NextBreakpoint is a breakpoint set by Next, Continue 114 // will stop on it and delete it 115 NextBreakpoint 116 // NextDeferBreakpoint is a breakpoint set by Next on the 117 // first deferred function. In addition to checking their condition 118 // breakpoints of this kind will also check that the function has been 119 // called by runtime.gopanic or through runtime.deferreturn. 120 NextDeferBreakpoint 121 // StepBreakpoint is a breakpoint set by Step on a CALL instruction, 122 // Continue will set a new breakpoint (of NextBreakpoint kind) on the 123 // destination of CALL, delete this breakpoint and then continue again 124 StepBreakpoint 125 126 // WatchOutOfScopeBreakpoint is a breakpoint used to detect when a watched 127 // stack variable goes out of scope. 128 WatchOutOfScopeBreakpoint 129 130 // StackResizeBreakpoint is a breakpoint used to detect stack resizes to 131 // adjust the watchpoint of stack variables. 132 StackResizeBreakpoint 133 134 steppingMask = NextBreakpoint | NextDeferBreakpoint | StepBreakpoint 135 ) 136 137 // WatchType is the watchpoint type 138 type WatchType uint8 139 140 const ( 141 WatchRead WatchType = 1 << iota 142 WatchWrite 143 ) 144 145 // Read returns true if the hardware breakpoint should trigger on memory reads. 146 func (wtype WatchType) Read() bool { 147 return wtype&WatchRead != 0 148 } 149 150 // Write returns true if the hardware breakpoint should trigger on memory writes. 151 func (wtype WatchType) Write() bool { 152 return wtype&WatchWrite != 0 153 } 154 155 // Size returns the size in bytes of the hardware breakpoint. 156 func (wtype WatchType) Size() int { 157 return int(wtype >> 4) 158 } 159 160 // withSize returns a new HWBreakType with the size set to the specified value 161 func (wtype WatchType) withSize(sz uint8) WatchType { 162 return WatchType((sz << 4) | uint8(wtype&0xf)) 163 } 164 165 var ErrHWBreakUnsupported = errors.New("hardware breakpoints not implemented") 166 167 func (bp *Breakpoint) String() string { 168 return fmt.Sprintf("Breakpoint %d at %#v %s:%d", bp.LogicalID(), bp.Addr, bp.File, bp.Line) 169 } 170 171 func (bp *Breakpoint) LogicalID() int { 172 for _, breaklet := range bp.Breaklets { 173 if breaklet.Kind == UserBreakpoint { 174 return breaklet.LogicalID 175 } 176 } 177 return NoLogicalID 178 } 179 180 // VerboseDescr returns a string describing parts of the breakpoint struct 181 // that aren't otherwise user visible, for debugging purposes. 182 func (bp *Breakpoint) VerboseDescr() []string { 183 r := []string{} 184 185 r = append(r, fmt.Sprintf("OriginalData=%#x", bp.OriginalData)) 186 187 if bp.WatchType != 0 { 188 r = append(r, fmt.Sprintf("HWBreakIndex=%#x watchStackOff=%#x", bp.HWBreakIndex, bp.watchStackOff)) 189 } 190 191 lbp := bp.Logical 192 193 for _, breaklet := range bp.Breaklets { 194 switch breaklet.Kind { 195 case UserBreakpoint: 196 r = append(r, fmt.Sprintf("User Cond=%q HitCond=%v", exprToString(breaklet.Cond), lbp.HitCond)) 197 case NextBreakpoint: 198 r = append(r, fmt.Sprintf("Next Cond=%q", exprToString(breaklet.Cond))) 199 case NextDeferBreakpoint: 200 r = append(r, fmt.Sprintf("NextDefer Cond=%q DeferReturns=%#x", exprToString(breaklet.Cond), breaklet.DeferReturns)) 201 case StepBreakpoint: 202 r = append(r, fmt.Sprintf("Step Cond=%q", exprToString(breaklet.Cond))) 203 case WatchOutOfScopeBreakpoint: 204 r = append(r, fmt.Sprintf("WatchOutOfScope Cond=%q checkPanicCall=%v", exprToString(breaklet.Cond), breaklet.checkPanicCall)) 205 case StackResizeBreakpoint: 206 r = append(r, fmt.Sprintf("StackResizeBreakpoint Cond=%q", exprToString(breaklet.Cond))) 207 default: 208 r = append(r, fmt.Sprintf("Unknown %d", breaklet.Kind)) 209 } 210 } 211 return r 212 } 213 214 // BreakpointExistsError is returned when trying to set a breakpoint at 215 // an address that already has a breakpoint set for it. 216 type BreakpointExistsError struct { 217 File string 218 Line int 219 Addr uint64 220 } 221 222 func (bpe BreakpointExistsError) Error() string { 223 return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.File, bpe.Line, bpe.Addr) 224 } 225 226 // InvalidAddressError represents the result of 227 // attempting to set a breakpoint at an invalid address. 228 type InvalidAddressError struct { 229 Address uint64 230 } 231 232 func (iae InvalidAddressError) Error() string { 233 return fmt.Sprintf("Invalid address %#v\n", iae.Address) 234 } 235 236 type returnBreakpointInfo struct { 237 retFrameCond ast.Expr 238 fn *Function 239 frameOffset int64 240 spOffset int64 241 } 242 243 // CheckCondition evaluates bp's condition on thread. 244 func (bp *Breakpoint) checkCondition(tgt *Target, thread Thread, bpstate *BreakpointState) { 245 *bpstate = BreakpointState{Breakpoint: bp, Active: false, Stepping: false, SteppingInto: false, CondError: nil} 246 for _, breaklet := range bp.Breaklets { 247 bpstate.checkCond(tgt, breaklet, thread) 248 } 249 } 250 251 func (bpstate *BreakpointState) checkCond(tgt *Target, breaklet *Breaklet, thread Thread) { 252 var condErr error 253 active := true 254 if breaklet.Cond != nil { 255 active, condErr = evalBreakpointCondition(tgt, thread, breaklet.Cond) 256 } 257 258 if condErr != nil && bpstate.CondError == nil { 259 bpstate.CondError = condErr 260 } 261 if !active { 262 return 263 } 264 265 switch breaklet.Kind { 266 case UserBreakpoint: 267 lbp := bpstate.Breakpoint.Logical 268 if lbp != nil { 269 if g, err := GetG(thread); err == nil { 270 lbp.HitCount[g.ID]++ 271 } 272 lbp.TotalHitCount++ 273 } 274 active = checkHitCond(lbp) 275 276 case StepBreakpoint, NextBreakpoint, NextDeferBreakpoint: 277 nextDeferOk := true 278 if breaklet.Kind&NextDeferBreakpoint != 0 { 279 var err error 280 frames, err := ThreadStacktrace(thread, 2) 281 if err == nil { 282 nextDeferOk, _ = isPanicCall(frames) 283 if !nextDeferOk { 284 nextDeferOk, _ = isDeferReturnCall(frames, breaklet.DeferReturns) 285 } 286 } 287 } 288 active = active && nextDeferOk 289 if active { 290 bpstate.Stepping = true 291 if breaklet.Kind == StepBreakpoint { 292 bpstate.SteppingInto = true 293 } 294 } 295 296 case WatchOutOfScopeBreakpoint: 297 if breaklet.checkPanicCall { 298 frames, err := ThreadStacktrace(thread, 2) 299 if err == nil { 300 ipc, _ := isPanicCall(frames) 301 active = active && ipc 302 } 303 } 304 305 case StackResizeBreakpoint: 306 // no further checks 307 308 default: 309 bpstate.CondError = fmt.Errorf("internal error unknown breakpoint kind %v", breaklet.Kind) 310 } 311 312 if active { 313 if breaklet.callback != nil { 314 active = breaklet.callback(thread) 315 } 316 bpstate.Active = active 317 } 318 } 319 320 // checkHitCond evaluates bp's hit condition on thread. 321 func checkHitCond(lbp *LogicalBreakpoint) bool { 322 if lbp == nil || lbp.HitCond == nil { 323 return true 324 } 325 // Evaluate the breakpoint condition. 326 switch lbp.HitCond.Op { 327 case token.EQL: 328 return int(lbp.TotalHitCount) == lbp.HitCond.Val 329 case token.NEQ: 330 return int(lbp.TotalHitCount) != lbp.HitCond.Val 331 case token.GTR: 332 return int(lbp.TotalHitCount) > lbp.HitCond.Val 333 case token.LSS: 334 return int(lbp.TotalHitCount) < lbp.HitCond.Val 335 case token.GEQ: 336 return int(lbp.TotalHitCount) >= lbp.HitCond.Val 337 case token.LEQ: 338 return int(lbp.TotalHitCount) <= lbp.HitCond.Val 339 case token.REM: 340 return int(lbp.TotalHitCount)%lbp.HitCond.Val == 0 341 } 342 return false 343 } 344 345 func isPanicCall(frames []Stackframe) (bool, int) { 346 // In Go prior to 1.17 the call stack for a panic is: 347 // 0. deferred function call 348 // 1. runtime.callN 349 // 2. runtime.gopanic 350 // in Go after 1.17 it is either: 351 // 0. deferred function call 352 // 1. deferred call wrapper 353 // 2. runtime.gopanic 354 // or: 355 // 0. deferred function call 356 // 1. runtime.gopanic 357 if len(frames) >= 3 && frames[2].Current.Fn != nil && frames[2].Current.Fn.Name == "runtime.gopanic" { 358 return true, 2 359 } 360 if len(frames) >= 2 && frames[1].Current.Fn != nil && frames[1].Current.Fn.Name == "runtime.gopanic" { 361 return true, 1 362 } 363 return false, 0 364 } 365 366 func isDeferReturnCall(frames []Stackframe, deferReturns []uint64) (bool, uint64) { 367 if len(frames) >= 2 && (len(deferReturns) > 0) { 368 // On Go 1.18 and later runtime.deferreturn doesn't use jmpdefer anymore, 369 // it's a normal function making normal calls to deferred functions. 370 if frames[1].Current.Fn != nil && frames[1].Current.Fn.Name == "runtime.deferreturn" { 371 return true, 0 372 } 373 } 374 if len(frames) >= 1 { 375 for _, pc := range deferReturns { 376 if frames[0].Ret == pc { 377 return true, pc 378 } 379 } 380 } 381 return false, 0 382 } 383 384 // IsStepping returns true if bp is an stepping breakpoint. 385 // User-set breakpoints can overlap with stepping breakpoints, in that case 386 // both IsUser and IsStepping will be true. 387 func (bp *Breakpoint) IsStepping() bool { 388 for _, breaklet := range bp.Breaklets { 389 if breaklet.Kind&steppingMask != 0 { 390 return true 391 } 392 } 393 return false 394 } 395 396 // IsUser returns true if bp is a user-set breakpoint. 397 // User-set breakpoints can overlap with stepping breakpoints, in that case 398 // both IsUser and IsStepping will be true. 399 func (bp *Breakpoint) IsUser() bool { 400 for _, breaklet := range bp.Breaklets { 401 if breaklet.Kind == UserBreakpoint { 402 return true 403 } 404 } 405 return false 406 } 407 408 // UserBreaklet returns the user breaklet for this breakpoint, or nil if 409 // none exist. 410 func (bp *Breakpoint) UserBreaklet() *Breaklet { 411 for _, breaklet := range bp.Breaklets { 412 if breaklet.Kind == UserBreakpoint { 413 return breaklet 414 } 415 } 416 return nil 417 } 418 419 func evalBreakpointCondition(tgt *Target, thread Thread, cond ast.Expr) (bool, error) { 420 if cond == nil { 421 return true, nil 422 } 423 scope, err := GoroutineScope(tgt, thread) 424 if err != nil { 425 scope, err = ThreadScope(tgt, thread) 426 if err != nil { 427 return true, err 428 } 429 } 430 v, err := scope.evalAST(cond) 431 if err != nil { 432 return true, fmt.Errorf("error evaluating expression: %v", err) 433 } 434 if v.Kind != reflect.Bool { 435 return true, errors.New("condition expression not boolean") 436 } 437 v.loadValue(loadFullValue) 438 if v.Unreadable != nil { 439 return true, fmt.Errorf("condition expression unreadable: %v", v.Unreadable) 440 } 441 return constant.BoolVal(v.Value), nil 442 } 443 444 // NoBreakpointError is returned when trying to 445 // clear a breakpoint that does not exist. 446 type NoBreakpointError struct { 447 Addr uint64 448 } 449 450 func (nbp NoBreakpointError) Error() string { 451 return fmt.Sprintf("no breakpoint at %#v", nbp.Addr) 452 } 453 454 // BreakpointMap represents an (address, breakpoint) map. 455 type BreakpointMap struct { 456 M map[uint64]*Breakpoint 457 458 // Logical is a map of logical breakpoints. 459 Logical map[int]*LogicalBreakpoint 460 461 // WatchOutOfScope is the list of watchpoints that went out of scope during 462 // the last resume operation 463 WatchOutOfScope []*Breakpoint 464 } 465 466 // NewBreakpointMap creates a new BreakpointMap. 467 func NewBreakpointMap() BreakpointMap { 468 return BreakpointMap{ 469 M: make(map[uint64]*Breakpoint), 470 } 471 } 472 473 // SetBreakpoint sets a breakpoint at addr, and stores it in the process wide 474 // break point table. 475 func (t *Target) SetBreakpoint(logicalID int, addr uint64, kind BreakpointKind, cond ast.Expr) (*Breakpoint, error) { 476 return t.setBreakpointInternal(logicalID, addr, kind, 0, cond) 477 } 478 479 // SetEBPFTracepoint will attach a uprobe to the function 480 // specified by 'fnName'. 481 func (t *Target) SetEBPFTracepoint(fnName string) error { 482 // Not every OS/arch that we support has support for eBPF, 483 // so check early and return an error if this is called on an 484 // unsupported system. 485 if !t.proc.SupportsBPF() { 486 return errors.New("eBPF is not supported") 487 } 488 fns, err := t.BinInfo().FindFunction(fnName) 489 if err != nil { 490 return err 491 } 492 493 // Get information on the Goroutine so we can tell the 494 // eBPF program where to find it in order to get the 495 // goroutine ID. 496 rdr := t.BinInfo().Images[0].DwarfReader() 497 rdr.SeekToTypeNamed("runtime.g") 498 typ, err := t.BinInfo().findType("runtime.g") 499 if err != nil { 500 return errors.New("could not find type for runtime.g") 501 } 502 var goidOffset int64 503 switch t := typ.(type) { 504 case *godwarf.StructType: 505 for _, field := range t.Field { 506 if field.Name == "goid" { 507 goidOffset = field.ByteOffset 508 break 509 } 510 } 511 } 512 513 for _, fn := range fns { 514 err := t.setEBPFTracepointOnFunc(fn, goidOffset) 515 if err != nil { 516 return err 517 } 518 } 519 return nil 520 } 521 522 func (t *Target) setEBPFTracepointOnFunc(fn *Function, goidOffset int64) error { 523 // Start putting together the argument map. This will tell the eBPF program 524 // all of the arguments we want to trace and how to find them. 525 526 // Start looping through each argument / return parameter for the function we 527 // are setting the uprobe on. Parse location information so that we can pass it 528 // along to the eBPF program. 529 dwarfTree, err := fn.cu.image.getDwarfTree(fn.offset) 530 if err != nil { 531 return err 532 } 533 variablesFlags := reader.VariablesOnlyVisible 534 if t.BinInfo().Producer() != "" && goversion.ProducerAfterOrEqual(t.BinInfo().Producer(), 1, 15) { 535 variablesFlags |= reader.VariablesTrustDeclLine 536 } 537 _, l, _ := t.BinInfo().PCToLine(fn.Entry) 538 539 var args []ebpf.UProbeArgMap 540 varEntries := reader.Variables(dwarfTree, fn.Entry, l, variablesFlags) 541 for _, entry := range varEntries { 542 _, dt, err := readVarEntry(entry.Tree, fn.cu.image) 543 if err != nil { 544 return err 545 } 546 547 offset, pieces, _, err := t.BinInfo().Location(entry, dwarf.AttrLocation, fn.Entry, op.DwarfRegisters{}, nil) 548 if err != nil { 549 return err 550 } 551 paramPieces := make([]int, 0, len(pieces)) 552 for _, piece := range pieces { 553 if piece.Kind == op.RegPiece { 554 paramPieces = append(paramPieces, int(piece.Val)) 555 } 556 } 557 isret, _ := entry.Val(dwarf.AttrVarParam).(bool) 558 offset += int64(t.BinInfo().Arch.PtrSize()) 559 args = append(args, ebpf.UProbeArgMap{ 560 Offset: offset, 561 Size: dt.Size(), 562 Kind: dt.Common().ReflectKind, 563 Pieces: paramPieces, 564 InReg: len(pieces) > 0, 565 Ret: isret, 566 }) 567 } 568 569 //TODO(aarzilli): inlined calls? 570 571 // Finally, set the uprobe on the function. 572 t.proc.SetUProbe(fn.Name, goidOffset, args) 573 return nil 574 } 575 576 // SetWatchpoint sets a data breakpoint at addr and stores it in the 577 // process wide break point table. 578 func (t *Target) SetWatchpoint(logicalID int, scope *EvalScope, expr string, wtype WatchType, cond ast.Expr) (*Breakpoint, error) { 579 if (wtype&WatchWrite == 0) && (wtype&WatchRead == 0) { 580 return nil, errors.New("at least one of read and write must be set for watchpoint") 581 } 582 583 n, err := parser.ParseExpr(expr) 584 if err != nil { 585 return nil, err 586 } 587 xv, err := scope.evalAST(n) 588 if err != nil { 589 return nil, err 590 } 591 if xv.Addr == 0 || xv.Flags&VariableFakeAddress != 0 || xv.DwarfType == nil { 592 return nil, fmt.Errorf("can not watch %q", expr) 593 } 594 if xv.Unreadable != nil { 595 return nil, fmt.Errorf("expression %q is unreadable: %v", expr, xv.Unreadable) 596 } 597 if xv.Kind == reflect.UnsafePointer || xv.Kind == reflect.Invalid { 598 return nil, fmt.Errorf("can not watch variable of type %s", xv.Kind.String()) 599 } 600 sz := xv.DwarfType.Size() 601 if sz <= 0 || sz > int64(t.BinInfo().Arch.PtrSize()) { 602 //TODO(aarzilli): it is reasonable to expect to be able to watch string 603 //and interface variables and we could support it by watching certain 604 //member fields here. 605 return nil, fmt.Errorf("can not watch variable of type %s", xv.DwarfType.String()) 606 } 607 608 stackWatch := scope.g != nil && !scope.g.SystemStack && xv.Addr >= scope.g.stack.lo && xv.Addr < scope.g.stack.hi 609 610 if stackWatch && wtype&WatchRead != 0 { 611 // In theory this would work except for the fact that the runtime will 612 // read them randomly to resize stacks so it doesn't make sense to do 613 // this. 614 return nil, errors.New("can not watch stack allocated variable for reads") 615 } 616 617 bp, err := t.setBreakpointInternal(logicalID, xv.Addr, UserBreakpoint, wtype.withSize(uint8(sz)), cond) 618 if err != nil { 619 return bp, err 620 } 621 bp.WatchExpr = expr 622 623 if stackWatch { 624 bp.watchStackOff = int64(bp.Addr) - int64(scope.g.stack.hi) 625 err := t.setStackWatchBreakpoints(scope, bp) 626 if err != nil { 627 return bp, err 628 } 629 } 630 631 return bp, nil 632 } 633 634 func (t *Target) setBreakpointInternal(logicalID int, addr uint64, kind BreakpointKind, wtype WatchType, cond ast.Expr) (*Breakpoint, error) { 635 if valid, err := t.Valid(); !valid { 636 recorded, _ := t.Recorded() 637 if !recorded { 638 return nil, err 639 } 640 } 641 bpmap := t.Breakpoints() 642 newBreaklet := &Breaklet{Kind: kind, Cond: cond} 643 if kind == UserBreakpoint { 644 newBreaklet.LogicalID = logicalID 645 } 646 647 setLogicalBreakpoint := func(bp *Breakpoint) { 648 if kind != UserBreakpoint || bp.Logical != nil { 649 return 650 } 651 if bpmap.Logical == nil { 652 bpmap.Logical = make(map[int]*LogicalBreakpoint) 653 } 654 lbp := bpmap.Logical[logicalID] 655 if lbp == nil { 656 lbp = &LogicalBreakpoint{LogicalID: logicalID} 657 lbp.HitCount = make(map[int]uint64) 658 lbp.Enabled = true 659 bpmap.Logical[logicalID] = lbp 660 } 661 bp.Logical = lbp 662 breaklet := bp.UserBreaklet() 663 if breaklet != nil && breaklet.Cond == nil { 664 breaklet.Cond = lbp.Cond 665 } 666 lbp.File = bp.File 667 lbp.Line = bp.Line 668 fn := t.BinInfo().PCToFunc(bp.Addr) 669 if fn != nil { 670 lbp.FunctionName = fn.NameWithoutTypeParams() 671 } 672 } 673 674 if bp, ok := bpmap.M[addr]; ok { 675 if !bp.canOverlap(kind) { 676 return bp, BreakpointExistsError{bp.File, bp.Line, bp.Addr} 677 } 678 bp.Breaklets = append(bp.Breaklets, newBreaklet) 679 setLogicalBreakpoint(bp) 680 return bp, nil 681 } 682 683 f, l, fn := t.BinInfo().PCToLine(uint64(addr)) 684 685 fnName := "" 686 if fn != nil { 687 fnName = fn.Name 688 } 689 690 hwidx := uint8(0) 691 if wtype != 0 { 692 m := make(map[uint8]bool) 693 for _, bp := range bpmap.M { 694 if bp.WatchType != 0 { 695 m[bp.HWBreakIndex] = true 696 } 697 } 698 for hwidx = 0; true; hwidx++ { 699 if !m[hwidx] { 700 break 701 } 702 } 703 } 704 705 newBreakpoint := &Breakpoint{ 706 FunctionName: fnName, 707 WatchType: wtype, 708 HWBreakIndex: hwidx, 709 File: f, 710 Line: l, 711 Addr: addr, 712 } 713 714 err := t.proc.WriteBreakpoint(newBreakpoint) 715 if err != nil { 716 return nil, err 717 } 718 719 newBreakpoint.Breaklets = append(newBreakpoint.Breaklets, newBreaklet) 720 setLogicalBreakpoint(newBreakpoint) 721 722 bpmap.M[addr] = newBreakpoint 723 724 return newBreakpoint, nil 725 } 726 727 // canOverlap returns true if a breakpoint of kind can be overlapped to the 728 // already existing breaklets in bp. 729 // At most one user breakpoint can be set but multiple internal breakpoints are allowed. 730 // All other internal breakpoints are allowed to overlap freely. 731 func (bp *Breakpoint) canOverlap(kind BreakpointKind) bool { 732 if kind == UserBreakpoint { 733 return !bp.IsUser() 734 } 735 return true 736 } 737 738 // ClearBreakpoint clears the breakpoint at addr. 739 func (t *Target) ClearBreakpoint(addr uint64) error { 740 if valid, err := t.Valid(); !valid { 741 recorded, _ := t.Recorded() 742 if !recorded { 743 return err 744 } 745 } 746 bp, ok := t.Breakpoints().M[addr] 747 if !ok { 748 return NoBreakpointError{Addr: addr} 749 } 750 751 for i := range bp.Breaklets { 752 if bp.Breaklets[i].Kind == UserBreakpoint { 753 bp.Breaklets[i] = nil 754 if bp.WatchExpr == "" { 755 bp.Logical = nil 756 } 757 } 758 } 759 760 _, err := t.finishClearBreakpoint(bp) 761 if err != nil { 762 return err 763 } 764 765 if bp.WatchExpr != "" && bp.watchStackOff != 0 { 766 // stack watchpoint, must remove all its WatchOutOfScopeBreakpoints/StackResizeBreakpoints 767 err := t.clearStackWatchBreakpoints(bp) 768 if err != nil { 769 return err 770 } 771 } 772 773 return nil 774 } 775 776 // ClearSteppingBreakpoints removes all stepping breakpoints from the map, 777 // calling clearBreakpoint on each one. 778 func (t *Target) ClearSteppingBreakpoints() error { 779 bpmap := t.Breakpoints() 780 threads := t.ThreadList() 781 for _, bp := range bpmap.M { 782 for i := range bp.Breaklets { 783 if bp.Breaklets[i].Kind&steppingMask != 0 { 784 bp.Breaklets[i] = nil 785 } 786 } 787 cleared, err := t.finishClearBreakpoint(bp) 788 if err != nil { 789 return err 790 } 791 if cleared { 792 for _, thread := range threads { 793 if thread.Breakpoint().Breakpoint == bp { 794 thread.Breakpoint().Clear() 795 } 796 } 797 } 798 } 799 return nil 800 } 801 802 // finishClearBreakpoint clears nil breaklets from the breaklet list of bp 803 // and if it is empty erases the breakpoint. 804 // Returns true if the breakpoint was deleted 805 func (t *Target) finishClearBreakpoint(bp *Breakpoint) (bool, error) { 806 oldBreaklets := bp.Breaklets 807 bp.Breaklets = bp.Breaklets[:0] 808 for _, breaklet := range oldBreaklets { 809 if breaklet != nil { 810 bp.Breaklets = append(bp.Breaklets, breaklet) 811 } 812 } 813 if len(bp.Breaklets) > 0 { 814 return false, nil 815 } 816 if err := t.proc.EraseBreakpoint(bp); err != nil { 817 return false, err 818 } 819 820 delete(t.Breakpoints().M, bp.Addr) 821 if bp.WatchExpr != "" && bp.Logical != nil { 822 delete(t.Breakpoints().Logical, bp.Logical.LogicalID) 823 } 824 return true, nil 825 } 826 827 // HasSteppingBreakpoints returns true if bpmap has at least one stepping 828 // breakpoint set. 829 func (bpmap *BreakpointMap) HasSteppingBreakpoints() bool { 830 for _, bp := range bpmap.M { 831 if bp.IsStepping() { 832 return true 833 } 834 } 835 return false 836 } 837 838 // HasHWBreakpoints returns true if there are hardware breakpoints. 839 func (bpmap *BreakpointMap) HasHWBreakpoints() bool { 840 for _, bp := range bpmap.M { 841 if bp.WatchType != 0 { 842 return true 843 } 844 } 845 return false 846 } 847 848 // BreakpointState describes the state of a breakpoint in a thread. 849 type BreakpointState struct { 850 *Breakpoint 851 // Active is true if the condition of any breaklet is met. 852 Active bool 853 // Stepping is true if one of the active breaklets is a stepping 854 // breakpoint. 855 Stepping bool 856 // SteppingInto is true if one of the active stepping breaklets has Kind == 857 // StepBreakpoint. 858 SteppingInto bool 859 // CondError contains any error encountered while evaluating the 860 // breakpoint's condition. 861 CondError error 862 } 863 864 // Clear zeros the struct. 865 func (bpstate *BreakpointState) Clear() { 866 bpstate.Breakpoint = nil 867 bpstate.Active = false 868 bpstate.Stepping = false 869 bpstate.SteppingInto = false 870 bpstate.CondError = nil 871 } 872 873 func (bpstate *BreakpointState) String() string { 874 s := bpstate.Breakpoint.String() 875 if bpstate.Active { 876 s += " active" 877 } 878 if bpstate.Stepping { 879 s += " stepping" 880 } 881 return s 882 } 883 884 func configureReturnBreakpoint(bi *BinaryInfo, bp *Breakpoint, topframe *Stackframe, retFrameCond ast.Expr) { 885 if topframe.Current.Fn == nil { 886 return 887 } 888 bp.returnInfo = &returnBreakpointInfo{ 889 retFrameCond: retFrameCond, 890 fn: topframe.Current.Fn, 891 frameOffset: topframe.FrameOffset(), 892 spOffset: topframe.FrameOffset() - int64(bi.Arch.PtrSize()), // must be the value that SP had at the entry point of the function 893 } 894 } 895 896 func (rbpi *returnBreakpointInfo) Collect(t *Target, thread Thread) []*Variable { 897 if rbpi == nil { 898 return nil 899 } 900 901 g, err := GetG(thread) 902 if err != nil { 903 return returnInfoError("could not get g", err, thread.ProcessMemory()) 904 } 905 scope, err := GoroutineScope(t, thread) 906 if err != nil { 907 return returnInfoError("could not get scope", err, thread.ProcessMemory()) 908 } 909 v, err := scope.evalAST(rbpi.retFrameCond) 910 if err != nil || v.Unreadable != nil || v.Kind != reflect.Bool { 911 // This condition was evaluated as part of the breakpoint condition 912 // evaluation, if the errors happen they will be reported as part of the 913 // condition errors. 914 return nil 915 } 916 if !constant.BoolVal(v.Value) { 917 // Breakpoint not hit as a return breakpoint. 918 return nil 919 } 920 921 oldFrameOffset := rbpi.frameOffset + int64(g.stack.hi) 922 oldSP := uint64(rbpi.spOffset + int64(g.stack.hi)) 923 err = fakeFunctionEntryScope(scope, rbpi.fn, oldFrameOffset, oldSP) 924 if err != nil { 925 return returnInfoError("could not read function entry", err, thread.ProcessMemory()) 926 } 927 928 vars, err := scope.Locals(0) 929 if err != nil { 930 return returnInfoError("could not evaluate return variables", err, thread.ProcessMemory()) 931 } 932 vars = filterVariables(vars, func(v *Variable) bool { 933 return (v.Flags & VariableReturnArgument) != 0 934 }) 935 936 return vars 937 } 938 939 func returnInfoError(descr string, err error, mem MemoryReadWriter) []*Variable { 940 v := newConstant(constant.MakeString(fmt.Sprintf("%s: %v", descr, err.Error())), mem) 941 v.Name = "return value read error" 942 return []*Variable{v} 943 } 944 945 // LogicalBreakpoint represents a breakpoint set by a user. 946 // A logical breakpoint can be associated with zero or many physical 947 // breakpoints. 948 // Where a physical breakpoint is associated with a specific instruction 949 // address a logical breakpoint is associated with a source code location. 950 // Therefore a logical breakpoint can be associated with zero or many 951 // physical breakpoints. 952 // It will have one or more physical breakpoints when source code has been 953 // inlined (or in the case of type parametric code). 954 // It will have zero physical breakpoints when it represents a deferred 955 // breakpoint for code that will be loaded in the future. 956 type LogicalBreakpoint struct { 957 LogicalID int 958 Name string 959 FunctionName string 960 File string 961 Line int 962 Enabled bool 963 964 Tracepoint bool // Tracepoint flag 965 TraceReturn bool 966 Goroutine bool // Retrieve goroutine information 967 Stacktrace int // Number of stack frames to retrieve 968 Variables []string // Variables to evaluate 969 LoadArgs *LoadConfig 970 LoadLocals *LoadConfig 971 972 HitCount map[int]uint64 // Number of times a breakpoint has been reached in a certain goroutine 973 TotalHitCount uint64 // Number of times a breakpoint has been reached 974 975 // HitCond: if not nil the breakpoint will be triggered only if the evaluated HitCond returns 976 // true with the TotalHitCount. 977 HitCond *struct { 978 Op token.Token 979 Val int 980 } 981 982 // Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true 983 Cond ast.Expr 984 985 UserData interface{} // Any additional information about the breakpoint 986 }