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