proc.go 15.9 KB
Newer Older
D
Derek Parker 已提交
1
package proc
2 3

import (
D
Derek Parker 已提交
4
	"debug/dwarf"
5
	"debug/gosym"
6
	"encoding/binary"
7 8
	"fmt"
	"os"
9
	"path/filepath"
10
	"runtime"
11 12
	"strconv"
	"strings"
D
Derek Parker 已提交
13
	"sync"
14

15 16
	sys "golang.org/x/sys/unix"

17
	"github.com/derekparker/delve/dwarf/frame"
D
Derek Parker 已提交
18
	"github.com/derekparker/delve/dwarf/line"
19
	"github.com/derekparker/delve/dwarf/reader"
D
Derek Parker 已提交
20
	"github.com/derekparker/delve/source"
21 22
)

D
Derek Parker 已提交
23 24 25 26
func init() {
	runtime.GOMAXPROCS(2)
}

D
Derek Parker 已提交
27
// Process represents all of the information the debugger
28
// is holding onto regarding the process we are debugging.
D
Derek Parker 已提交
29
type Process struct {
30 31 32
	Pid     int         // Process Pid
	Process *os.Process // Pointer to process struct for the actual process we are debugging

33 34
	// Breakpoint table, hold information on software / hardware breakpoints.
	// Maps instruction address to Breakpoint struct.
D
Derek Parker 已提交
35
	Breakpoints map[uint64]*Breakpoint
36

D
Derek Parker 已提交
37 38
	// List of threads mapped as such: pid -> *Thread
	Threads map[int]*Thread
39 40

	// Active thread. This is the default thread used for setting breakpoints, evaluating variables, etc..
D
Derek Parker 已提交
41
	CurrentThread *Thread
42

43 44 45 46 47 48 49
	dwarf                   *dwarf.Data
	goSymTable              *gosym.Table
	frameEntries            frame.FrameDescriptionEntries
	lineInfo                *line.DebugLineInfo
	firstStart              bool
	singleStepping          bool
	os                      *OSProcessDetails
50
	arch                    Arch
51 52 53 54 55
	ast                     *source.Searcher
	breakpointIDCounter     int
	tempBreakpointIDCounter int
	halt                    bool
	exited                  bool
56 57 58 59
	ptraceChan              chan func()
	ptraceDoneChan          chan interface{}
}

D
Derek Parker 已提交
60 61
func New(pid int) *Process {
	dbp := &Process{
62 63 64 65 66 67 68 69 70 71 72
		Pid:            pid,
		Threads:        make(map[int]*Thread),
		Breakpoints:    make(map[uint64]*Breakpoint),
		firstStart:     true,
		os:             new(OSProcessDetails),
		ast:            source.New(),
		ptraceChan:     make(chan func()),
		ptraceDoneChan: make(chan interface{}),
	}
	go dbp.handlePtraceFuncs()
	return dbp
D
Derek Parker 已提交
73 74
}

D
Derek Parker 已提交
75 76
// A ManualStopError happens when the user triggers a
// manual stop via SIGERM.
D
Derek Parker 已提交
77 78 79 80 81 82
type ManualStopError struct{}

func (mse ManualStopError) Error() string {
	return "Manual stop requested"
}

83 84 85 86 87 88 89 90
// ProcessExitedError indicates that the process has exited and contains both
// process id and exit status.
type ProcessExitedError struct {
	Pid    int
	Status int
}

func (pe ProcessExitedError) Error() string {
D
Derek Parker 已提交
91
	return fmt.Sprintf("Process %d has exited with status %d", pe.Pid, pe.Status)
92 93
}

D
Derek Parker 已提交
94
// Attach to an existing process with the given PID.
D
Derek Parker 已提交
95
func Attach(pid int) (*Process, error) {
96
	dbp, err := initializeDebugProcess(New(pid), "", true)
97 98 99 100 101 102
	if err != nil {
		return nil, err
	}
	return dbp, nil
}

D
Derek Parker 已提交
103
func (dbp *Process) Detach(kill bool) (err error) {
104 105 106
	// Clean up any breakpoints we've set.
	for _, bp := range dbp.Breakpoints {
		if bp != nil {
D
Derek Parker 已提交
107 108 109 110
			_, err := dbp.ClearBreakpoint(bp.Addr)
			if err != nil {
				return err
			}
111 112 113 114 115 116 117 118 119 120
		}
	}
	dbp.execPtraceFunc(func() {
		var sig int
		if kill {
			sig = int(sys.SIGINT)
		}
		err = PtraceDetach(dbp.Pid, sig)
	})
	return
D
Derek Parker 已提交
121 122
}

123 124
// Returns whether or not Delve thinks the debugged
// process has exited.
D
Derek Parker 已提交
125
func (dbp *Process) Exited() bool {
126 127 128
	return dbp.exited
}

D
Derek Parker 已提交
129 130
// Returns whether or not Delve thinks the debugged
// process is currently executing.
D
Derek Parker 已提交
131
func (dbp *Process) Running() bool {
132 133 134 135 136 137
	for _, th := range dbp.Threads {
		if th.running {
			return true
		}
	}
	return false
D
Derek Parker 已提交
138 139
}

D
Derek Parker 已提交
140 141 142 143 144
// Finds the executable and then uses it
// to parse the following information:
// * Dwarf .debug_frame section
// * Dwarf .debug_line section
// * Go symbol table.
D
Derek Parker 已提交
145
func (dbp *Process) LoadInformation(path string) error {
D
Derek Parker 已提交
146 147
	var wg sync.WaitGroup

148
	exe, err := dbp.findExecutable(path)
D
Derek Parker 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161
	if err != nil {
		return err
	}

	wg.Add(3)
	go dbp.parseDebugFrame(exe, &wg)
	go dbp.obtainGoSymbols(exe, &wg)
	go dbp.parseDebugLineInfo(exe, &wg)
	wg.Wait()

	return nil
}

162
// Find a location by string (file+line, function, breakpoint id, addr)
D
Derek Parker 已提交
163
func (dbp *Process) FindLocation(str string) (uint64, error) {
164 165 166 167 168 169 170 171 172 173 174 175 176 177
	// File + Line
	if strings.ContainsRune(str, ':') {
		fl := strings.Split(str, ":")

		fileName, err := filepath.Abs(fl[0])
		if err != nil {
			return 0, err
		}

		line, err := strconv.Atoi(fl[1])
		if err != nil {
			return 0, err
		}

178
		pc, _, err := dbp.goSymTable.LineToPC(fileName, line)
179 180 181 182
		if err != nil {
			return 0, err
		}
		return pc, nil
D
Derek Parker 已提交
183
	}
184

D
Derek Parker 已提交
185
	// Try to lookup by function name
186
	fn := dbp.goSymTable.LookupFunc(str)
D
Derek Parker 已提交
187 188 189 190 191 192 193 194 195
	if fn != nil {
		return fn.Entry, nil
	}

	// Attempt to parse as number for breakpoint id or raw address
	id, err := strconv.ParseUint(str, 0, 64)
	if err != nil {
		return 0, fmt.Errorf("unable to find location for %s", str)
	}
196

D
Derek Parker 已提交
197
	for _, bp := range dbp.Breakpoints {
D
Derek Parker 已提交
198 199 200 201 202 203 204
		if uint64(bp.ID) == id {
			return bp.Addr, nil
		}
	}

	// Last resort, use as raw address
	return id, nil
205 206
}

D
Derek Parker 已提交
207 208
// Sends out a request that the debugged process halt
// execution. Sends SIGSTOP to all threads.
D
Derek Parker 已提交
209
func (dbp *Process) RequestManualStop() error {
D
Derek Parker 已提交
210
	dbp.halt = true
D
Derek Parker 已提交
211 212 213
	err := dbp.requestManualStop()
	if err != nil {
		return err
D
Derek Parker 已提交
214
	}
D
Derek Parker 已提交
215 216 217 218
	err = dbp.Halt()
	if err != nil {
		return err
	}
D
Derek Parker 已提交
219
	return nil
D
Derek Parker 已提交
220 221
}

D
Derek Parker 已提交
222 223 224 225 226 227 228 229 230
// Sets a breakpoint at addr, and stores it in the process wide
// break point table. Setting a break point must be thread specific due to
// ptrace actions needing the thread to be in a signal-delivery-stop.
//
// Depending on hardware support, Delve will choose to either
// set a hardware or software breakpoint. Essentially, if the
// hardware supports it, and there are free debug registers, Delve
// will set a hardware breakpoint. Otherwise we fall back to software
// breakpoints, which are a bit more work for us.
231
func (dbp *Process) SetBreakpoint(addr uint64) (*Breakpoint, error) {
232 233 234
	return dbp.setBreakpoint(dbp.CurrentThread.Id, addr, false)
}

D
Derek Parker 已提交
235
// Sets a temp breakpoint, for the 'next' command.
236
func (dbp *Process) SetTempBreakpoint(addr uint64) (*Breakpoint, error) {
237
	return dbp.setBreakpoint(dbp.CurrentThread.Id, addr, true)
238 239 240
}

// Sets a breakpoint by location string (function, file+line, address)
241
func (dbp *Process) SetBreakpointByLocation(loc string) (*Breakpoint, error) {
242 243 244 245
	addr, err := dbp.FindLocation(loc)
	if err != nil {
		return nil, err
	}
246
	return dbp.SetBreakpoint(addr)
247 248 249
}

// Clears a breakpoint in the current thread.
250
func (dbp *Process) ClearBreakpoint(addr uint64) (*Breakpoint, error) {
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
	bp, ok := dbp.Breakpoints[addr]
	if !ok {
		return nil, NoBreakpointError{addr: addr}
	}

	for _, thread := range dbp.Threads {
		if _, err := bp.Clear(thread); err != nil {
			return nil, err
		}
		if !bp.hardware {
			break
		}
	}

	if bp.hardware {
		dbp.arch.SetHardwareBreakpointUsage(bp.reg, false)
	}
	delete(dbp.Breakpoints, addr)

	return bp, nil
271 272 273
}

// Clears a breakpoint by location (function, file+line, address, breakpoint id)
274
func (dbp *Process) ClearBreakpointByLocation(loc string) (*Breakpoint, error) {
275 276 277 278
	addr, err := dbp.FindLocation(loc)
	if err != nil {
		return nil, err
	}
279
	return dbp.ClearBreakpoint(addr)
280 281 282
}

// Returns the status of the current main thread context.
D
Derek Parker 已提交
283
func (dbp *Process) Status() *sys.WaitStatus {
284 285 286 287
	return dbp.CurrentThread.Status
}

// Step over function calls.
D
Derek Parker 已提交
288
func (dbp *Process) Next() error {
D
Derek Parker 已提交
289 290
	return dbp.run(dbp.next)
}
291

D
Derek Parker 已提交
292
func (dbp *Process) next() error {
D
Derek Parker 已提交
293
	// Make sure we clean up the temp breakpoints created by thread.Next
294 295
	defer dbp.clearTempBreakpoints()

D
Derek Parker 已提交
296 297 298 299 300
	chanRecvCount, err := dbp.setChanRecvBreakpoints()
	if err != nil {
		return err
	}

301
	g, err := dbp.CurrentThread.getG()
D
Derek Parker 已提交
302 303 304
	if err != nil {
		return err
	}
305

306
	if g.DeferPC != 0 {
307
		_, err = dbp.SetTempBreakpoint(g.DeferPC)
308 309 310 311 312
		if err != nil {
			return err
		}
	}

313
	var goroutineExiting bool
D
Derek Parker 已提交
314
	var waitCount int
D
Derek Parker 已提交
315
	for _, th := range dbp.Threads {
316 317
		if th.blocked() {
			// Ignore threads that aren't running go code.
D
Derek Parker 已提交
318 319
			continue
		}
D
Derek Parker 已提交
320
		waitCount++
321
		if err = th.SetNextBreakpoints(); err != nil {
322
			if err, ok := err.(GoroutineExitingError); ok {
D
Derek Parker 已提交
323
				waitCount = waitCount - 1 + chanRecvCount
324
				if err.goid == g.Id {
325 326 327 328
					goroutineExiting = true
				}
				continue
			}
D
Derek Parker 已提交
329 330 331
			return err
		}
	}
332 333 334 335 336
	for _, th := range dbp.Threads {
		if err = th.Continue(); err != nil {
			return err
		}
	}
337

D
Derek Parker 已提交
338
	for waitCount > 0 {
339
		thread, err := dbp.trapWait(-1)
D
Derek Parker 已提交
340 341
		if err != nil {
			return err
D
Derek Parker 已提交
342
		}
343
		tg, err := thread.getG()
D
Derek Parker 已提交
344 345 346
		if err != nil {
			return err
		}
D
Derek Parker 已提交
347
		// Make sure we're on the same goroutine, unless it has exited.
348
		if tg.Id == g.Id || goroutineExiting {
349 350
			if dbp.CurrentThread != thread {
				dbp.SwitchThread(thread.Id)
D
Derek Parker 已提交
351
			}
352
		}
D
Derek Parker 已提交
353
		waitCount--
354
	}
D
Derek Parker 已提交
355
	return dbp.Halt()
356 357
}

D
Derek Parker 已提交
358
func (dbp *Process) setChanRecvBreakpoints() (int, error) {
D
Derek Parker 已提交
359
	var count int
D
Derek Parker 已提交
360 361
	allg, err := dbp.GoroutinesInfo()
	if err != nil {
D
Derek Parker 已提交
362
		return 0, err
D
Derek Parker 已提交
363 364 365 366 367
	}
	for _, g := range allg {
		if g.ChanRecvBlocked() {
			ret, err := g.chanRecvReturnAddr(dbp)
			if err != nil {
368 369 370
				if _, ok := err.(NullAddrError); ok {
					continue
				}
D
Derek Parker 已提交
371
				return 0, err
D
Derek Parker 已提交
372
			}
373
			if _, err = dbp.SetTempBreakpoint(ret); err != nil {
D
Derek Parker 已提交
374
				return 0, err
D
Derek Parker 已提交
375
			}
D
Derek Parker 已提交
376
			count++
D
Derek Parker 已提交
377 378
		}
	}
D
Derek Parker 已提交
379
	return count, nil
D
Derek Parker 已提交
380 381
}

382
// Resume process.
D
Derek Parker 已提交
383
func (dbp *Process) Continue() error {
384 385 386
	for _, thread := range dbp.Threads {
		err := thread.Continue()
		if err != nil {
387
			return fmt.Errorf("could not continue thread %d %s", thread.Id, err)
388 389
		}
	}
390 391
	return dbp.run(dbp.resume)
}
392

D
Derek Parker 已提交
393
func (dbp *Process) resume() error {
394
	thread, err := dbp.trapWait(-1)
395 396 397 398 399 400
	if err != nil {
		return err
	}
	if dbp.CurrentThread != thread {
		dbp.SwitchThread(thread.Id)
	}
D
Derek Parker 已提交
401
	pc, err := thread.PC()
402 403 404
	if err != nil {
		return err
	}
D
Derek Parker 已提交
405 406
	if dbp.CurrentBreakpoint != nil || dbp.halt {
		return dbp.Halt()
407 408
	}
	// Check to see if we hit a runtime.breakpoint
409
	fn := dbp.goSymTable.PCToFunc(pc)
410 411 412 413 414
	if fn != nil && fn.Name == "runtime.breakpoint" {
		// step twice to get back to user code
		for i := 0; i < 2; i++ {
			if err = thread.Step(); err != nil {
				return err
D
Derek Parker 已提交
415 416
			}
		}
417
		return dbp.Halt()
418
	}
419 420

	return fmt.Errorf("unrecognized breakpoint %#v", pc)
421 422
}

D
Derek Parker 已提交
423
// Single step, will execute a single instruction.
D
Derek Parker 已提交
424
func (dbp *Process) Step() (err error) {
D
Derek Parker 已提交
425
	fn := func() error {
426 427
		dbp.singleStepping = true
		defer func() { dbp.singleStepping = false }()
D
Derek Parker 已提交
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
		for _, th := range dbp.Threads {
			if th.blocked() {
				continue
			}
			err := th.Step()
			if err != nil {
				return err
			}
		}
		return nil
	}

	return dbp.run(fn)
}

443
// Change from current thread to the thread specified by `tid`.
D
Derek Parker 已提交
444
func (dbp *Process) SwitchThread(tid int) error {
445
	if th, ok := dbp.Threads[tid]; ok {
D
Derek Parker 已提交
446
		fmt.Printf("thread context changed from %d to %d\n", dbp.CurrentThread.Id, tid)
447
		dbp.CurrentThread = th
448 449 450 451 452
		return nil
	}
	return fmt.Errorf("thread %d does not exist", tid)
}

D
Derek Parker 已提交
453 454
// Returns an array of G structures representing the information
// Delve cares about from the internal runtime G structure.
D
Derek Parker 已提交
455
func (dbp *Process) GoroutinesInfo() ([]*G, error) {
456
	var (
A
aarzilli 已提交
457 458 459
		threadg = map[int]*Thread{}
		allg    []*G
		rdr     = dbp.DwarfReader()
460 461
	)

A
aarzilli 已提交
462 463 464 465 466 467 468 469 470 471
	for i := range dbp.Threads {
		if dbp.Threads[i].blocked() {
			continue
		}
		g, _ := dbp.Threads[i].getG()
		if g != nil {
			threadg[g.Id] = dbp.Threads[i]
		}
	}

472
	addr, err := rdr.AddrFor("runtime.allglen")
473 474 475
	if err != nil {
		return nil, err
	}
476 477 478 479 480 481 482 483
	allglenBytes, err := dbp.CurrentThread.readMemory(uintptr(addr), 8)
	if err != nil {
		return nil, err
	}
	allglen := binary.LittleEndian.Uint64(allglenBytes)

	rdr.Seek(0)
	allgentryaddr, err := rdr.AddrFor("runtime.allg")
484 485 486
	if err != nil {
		return nil, err
	}
487
	faddr, err := dbp.CurrentThread.readMemory(uintptr(allgentryaddr), dbp.arch.PtrSize())
488 489 490
	allgptr := binary.LittleEndian.Uint64(faddr)

	for i := uint64(0); i < allglen; i++ {
491
		g, err := parseG(dbp.CurrentThread, allgptr+(i*uint64(dbp.arch.PtrSize())), true)
492 493 494
		if err != nil {
			return nil, err
		}
A
aarzilli 已提交
495 496 497
		if thread, allocated := threadg[g.Id]; allocated {
			g.thread = thread
		}
498 499 500 501 502
		allg = append(allg, g)
	}
	return allg, nil
}

D
Derek Parker 已提交
503
// Stop all threads.
D
Derek Parker 已提交
504
func (dbp *Process) Halt() (err error) {
D
Derek Parker 已提交
505 506 507 508 509 510 511 512
	for _, th := range dbp.Threads {
		if err := th.Halt(); err != nil {
			return err
		}
	}
	return nil
}

513 514
// Obtains register values from what Delve considers to be the current
// thread of the traced process.
D
Derek Parker 已提交
515
func (dbp *Process) Registers() (Registers, error) {
516 517 518
	return dbp.CurrentThread.Registers()
}

519
// Returns the PC of the current thread.
D
Derek Parker 已提交
520
func (dbp *Process) PC() (uint64, error) {
D
Derek Parker 已提交
521
	return dbp.CurrentThread.PC()
522 523
}

524
// Returns the PC of the current thread.
D
Derek Parker 已提交
525
func (dbp *Process) CurrentBreakpoint() *Breakpoint {
526 527 528
	return dbp.CurrentThread.CurrentBreakpoint
}

529
// Returns the value of the named symbol.
D
Derek Parker 已提交
530
func (dbp *Process) EvalVariable(name string) (*Variable, error) {
531
	return dbp.CurrentThread.EvalVariable(name)
532 533
}

534
// Returns a reader for the dwarf data
D
Derek Parker 已提交
535
func (dbp *Process) DwarfReader() *reader.Reader {
536 537 538
	return reader.New(dbp.dwarf)
}

D
Derek Parker 已提交
539
// Returns list of source files that comprise the debugged binary.
D
Derek Parker 已提交
540
func (dbp *Process) Sources() map[string]*gosym.Obj {
541 542 543
	return dbp.goSymTable.Files
}

D
Derek Parker 已提交
544
// Returns list of functions present in the debugged program.
D
Derek Parker 已提交
545
func (dbp *Process) Funcs() []gosym.Func {
546 547 548
	return dbp.goSymTable.Funcs
}

D
Derek Parker 已提交
549
// Converts an instruction address to a file/line/function.
D
Derek Parker 已提交
550
func (dbp *Process) PCToLine(pc uint64) (string, int, *gosym.Func) {
551
	return dbp.goSymTable.PCToLine(pc)
552 553
}

554
// Finds the breakpoint for the given ID.
D
Derek Parker 已提交
555
func (dbp *Process) FindBreakpointByID(id int) (*Breakpoint, bool) {
556 557 558 559 560 561 562 563
	for _, bp := range dbp.Breakpoints {
		if bp.ID == id {
			return bp, true
		}
	}
	return nil, false
}

D
Derek Parker 已提交
564
// Finds the breakpoint for the given pc.
D
Derek Parker 已提交
565
func (dbp *Process) FindBreakpoint(pc uint64) (*Breakpoint, bool) {
566 567 568 569
	// Check for software breakpoint. PC will be at
	// breakpoint instruction + size of breakpoint.
	if bp, ok := dbp.Breakpoints[pc-uint64(dbp.arch.BreakpointSize())]; ok {
		return bp, true
D
Derek Parker 已提交
570
	}
571 572 573 574
	// Check for hardware breakpoint. PC will equal
	// the breakpoint address since the CPU will stop
	// the process without executing the instruction at
	// this address.
D
Derek Parker 已提交
575
	if bp, ok := dbp.Breakpoints[pc]; ok {
D
Derek Parker 已提交
576 577 578 579 580
		return bp, true
	}
	return nil, false
}

D
Derek Parker 已提交
581 582
// Returns a new Process struct.
func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, error) {
D
Derek Parker 已提交
583
	if attach {
584 585
		var err error
		dbp.execPtraceFunc(func() { err = sys.PtraceAttach(dbp.Pid) })
D
Derek Parker 已提交
586 587 588
		if err != nil {
			return nil, err
		}
589
		_, _, err = wait(dbp.Pid, dbp.Pid, 0)
D
Derek Parker 已提交
590 591 592 593 594
		if err != nil {
			return nil, err
		}
	}

595
	proc, err := os.FindProcess(dbp.Pid)
D
Derek Parker 已提交
596 597 598 599 600
	if err != nil {
		return nil, err
	}

	dbp.Process = proc
601
	err = dbp.LoadInformation(path)
D
Derek Parker 已提交
602 603 604 605 606 607 608 609
	if err != nil {
		return nil, err
	}

	if err := dbp.updateThreadList(); err != nil {
		return nil, err
	}

610 611 612 613 614
	switch runtime.GOARCH {
	case "amd64":
		dbp.arch = AMD64Arch()
	}

615
	return dbp, nil
D
Derek Parker 已提交
616
}
617

D
Derek Parker 已提交
618
func (dbp *Process) clearTempBreakpoints() error {
D
Derek Parker 已提交
619
	for _, bp := range dbp.Breakpoints {
D
Derek Parker 已提交
620 621 622
		if !bp.Temp {
			continue
		}
623
		if _, err := dbp.ClearBreakpoint(bp.Addr); err != nil {
D
Derek Parker 已提交
624 625 626 627 628
			return err
		}
	}
	return nil
}
629

D
Derek Parker 已提交
630
func (dbp *Process) handleBreakpointOnThread(id int) (*Thread, error) {
D
Derek Parker 已提交
631 632
	thread, ok := dbp.Threads[id]
	if !ok {
633
		return nil, fmt.Errorf("could not find thread for %d", id)
D
Derek Parker 已提交
634
	}
D
Derek Parker 已提交
635
	pc, err := thread.PC()
D
Derek Parker 已提交
636
	if err != nil {
637
		return nil, err
D
Derek Parker 已提交
638
	}
639 640
	// Check to see if we have hit a breakpoint.
	if bp, ok := dbp.FindBreakpoint(pc); ok {
641
		thread.CurrentBreakpoint = bp
D
Derek Parker 已提交
642 643 644 645 646 647
		if err = thread.SetPC(bp.Addr); err != nil {
			return nil, err
		}
		return thread, nil
	}
	if dbp.halt {
648
		return thread, nil
D
Derek Parker 已提交
649
	}
D
Derek Parker 已提交
650 651
	fn := dbp.goSymTable.PCToFunc(pc)
	if fn != nil && fn.Name == "runtime.breakpoint" {
652 653
		thread.singleStepping = true
		defer func() { thread.singleStepping = false }()
D
Derek Parker 已提交
654 655 656 657 658 659 660
		for i := 0; i < 2; i++ {
			if err := thread.Step(); err != nil {
				return nil, err
			}
		}
		return thread, nil
	}
D
Derek Parker 已提交
661
	return nil, NoBreakpointError{addr: pc}
D
Derek Parker 已提交
662
}
D
Derek Parker 已提交
663

D
Derek Parker 已提交
664
func (dbp *Process) run(fn func() error) error {
665
	if dbp.exited {
D
Derek Parker 已提交
666
		return fmt.Errorf("process has already exited")
667
	}
D
Derek Parker 已提交
668
	dbp.halt = false
669 670 671
	for _, th := range dbp.Threads {
		th.CurrentBreakpoint = nil
	}
D
Derek Parker 已提交
672 673 674 675 676 677 678
	if err := fn(); err != nil {
		if _, ok := err.(ManualStopError); !ok {
			return err
		}
	}
	return nil
}
679

D
Derek Parker 已提交
680
func (dbp *Process) handlePtraceFuncs() {
681 682 683 684 685 686 687 688 689 690 691
	// We must ensure here that we are running on the same thread during
	// the execution of dbg. This is due to the fact that ptrace(2) expects
	// all commands after PTRACE_ATTACH to come from the same thread.
	runtime.LockOSThread()

	for fn := range dbp.ptraceChan {
		fn()
		dbp.ptraceDoneChan <- nil
	}
}

D
Derek Parker 已提交
692
func (dbp *Process) execPtraceFunc(fn func()) {
693 694 695
	dbp.ptraceChan <- fn
	<-dbp.ptraceDoneChan
}