proc.go 18.7 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
	"strings"
D
Derek Parker 已提交
12
	"sync"
13

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

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

D
Derek Parker 已提交
22
// Process represents all of the information the debugger
23
// is holding onto regarding the process we are debugging.
D
Derek Parker 已提交
24
type Process struct {
25 26 27
	Pid     int         // Process Pid
	Process *os.Process // Pointer to process struct for the actual process we are debugging

28 29
	// Breakpoint table, hold information on software / hardware breakpoints.
	// Maps instruction address to Breakpoint struct.
D
Derek Parker 已提交
30
	Breakpoints map[uint64]*Breakpoint
31

D
Derek Parker 已提交
32 33
	// List of threads mapped as such: pid -> *Thread
	Threads map[int]*Thread
34

35
	// Active thread
D
Derek Parker 已提交
36
	CurrentThread *Thread
37

38 39 40 41
	// Goroutine that will be used by default to set breakpoint, eval variables, etc...
	// Normally SelectedGoroutine is CurrentThread.GetG, it will not be only if SwitchGoroutine is called with a goroutine that isn't attached to a thread
	SelectedGoroutine *G

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

D
Derek Parker 已提交
59 60
func New(pid int) *Process {
	dbp := &Process{
61 62 63 64 65 66 67 68 69 70 71
		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 已提交
72 73
}

74 75 76 77 78 79 80 81
// 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 已提交
82
	return fmt.Sprintf("Process %d has exited with status %d", pe.Pid, pe.Status)
83 84
}

D
Derek Parker 已提交
85
// Detach from the process being debugged, optionally killing it.
D
Derek Parker 已提交
86
func (dbp *Process) Detach(kill bool) (err error) {
D
Derek Parker 已提交
87 88 89 90 91
	if dbp.Running() {
		if err = dbp.Halt(); err != nil {
			return
		}
	}
92 93 94 95 96 97 98 99
	if !kill {
		// Clean up any breakpoints we've set.
		for _, bp := range dbp.Breakpoints {
			if bp != nil {
				_, err := dbp.ClearBreakpoint(bp.Addr)
				if err != nil {
					return err
				}
D
Derek Parker 已提交
100
			}
101 102 103 104 105 106 107 108 109 110
		}
	}
	dbp.execPtraceFunc(func() {
		var sig int
		if kill {
			sig = int(sys.SIGINT)
		}
		err = PtraceDetach(dbp.Pid, sig)
	})
	return
D
Derek Parker 已提交
111 112
}

113 114
// Returns whether or not Delve thinks the debugged
// process has exited.
D
Derek Parker 已提交
115
func (dbp *Process) Exited() bool {
116 117 118
	return dbp.exited
}

D
Derek Parker 已提交
119 120
// Returns whether or not Delve thinks the debugged
// process is currently executing.
D
Derek Parker 已提交
121
func (dbp *Process) Running() bool {
122 123 124 125 126 127
	for _, th := range dbp.Threads {
		if th.running {
			return true
		}
	}
	return false
D
Derek Parker 已提交
128 129
}

D
Derek Parker 已提交
130 131 132 133 134
// 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 已提交
135
func (dbp *Process) LoadInformation(path string) error {
D
Derek Parker 已提交
136 137
	var wg sync.WaitGroup

138
	exe, err := dbp.findExecutable(path)
D
Derek Parker 已提交
139 140 141 142 143 144 145 146 147 148 149 150 151
	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
}

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
func (dbp *Process) FindFileLocation(fileName string, lineno int) (uint64, error) {
	pc, _, err := dbp.goSymTable.LineToPC(fileName, lineno)
	if err != nil {
		return 0, err
	}
	return pc, nil
}

// Finds address of a function's line
// If firstLine == true is passed FindFunctionLocation will attempt to find the first line of the function
// If lineOffset is passed FindFunctionLocation will return the address of that line
// Pass lineOffset == 0 and firstLine == false if you want the address for the function's entry point
// Note that setting breakpoints at that address will cause surprising behavior:
// https://github.com/derekparker/delve/issues/170
func (dbp *Process) FindFunctionLocation(funcName string, firstLine bool, lineOffset int) (uint64, error) {
	fn := dbp.goSymTable.LookupFunc(funcName)
	if fn == nil {
		return 0, fmt.Errorf("Could not find function %s\n", funcName)
	}
171

172 173 174 175
	if firstLine {
		filename, lineno, _ := dbp.goSymTable.PCToLine(fn.Entry)
		if filepath.Ext(filename) != ".go" {
			return fn.Entry, nil
176 177
		}

178
		lines, err := dbp.ast.NextLines(filename, lineno)
179 180 181 182
		if err != nil {
			return 0, err
		}

183 184 185
		if len(lines) > 0 {
			linePC, _, err := dbp.goSymTable.LineToPC(filename, lines[0])
			return linePC, err
186
		} else {
187
			return fn.Entry, nil
188
		}
189 190 191 192
	} else if lineOffset > 0 {
		filename, lineno, _ := dbp.goSymTable.PCToLine(fn.Entry)
		breakAddr, _, err := dbp.goSymTable.LineToPC(filename, lineno+lineOffset)
		return breakAddr, err
D
Derek Parker 已提交
193 194
	}

195
	return fn.Entry, nil
196 197
}

D
Derek Parker 已提交
198 199
// Sends out a request that the debugged process halt
// execution. Sends SIGSTOP to all threads.
D
Derek Parker 已提交
200
func (dbp *Process) RequestManualStop() error {
D
Derek Parker 已提交
201
	dbp.halt = true
D
Derek Parker 已提交
202
	return dbp.requestManualStop()
D
Derek Parker 已提交
203 204
}

D
Derek Parker 已提交
205 206 207 208 209 210 211 212 213
// 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.
214
func (dbp *Process) SetBreakpoint(addr uint64) (*Breakpoint, error) {
215 216 217
	return dbp.setBreakpoint(dbp.CurrentThread.Id, addr, false)
}

D
Derek Parker 已提交
218
// Sets a temp breakpoint, for the 'next' command.
219
func (dbp *Process) SetTempBreakpoint(addr uint64) (*Breakpoint, error) {
220
	return dbp.setBreakpoint(dbp.CurrentThread.Id, addr, true)
221 222
}

D
Derek Parker 已提交
223 224 225 226
// Clears a breakpoint.
//
// If it is a hardware assisted breakpoint, iterate through all threads
// and clear the debug register. Otherwise, restore original instruction.
227
func (dbp *Process) ClearBreakpoint(addr uint64) (*Breakpoint, error) {
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
	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
248 249
}

250
// Returns the status of the current main thread context.
D
Derek Parker 已提交
251
func (dbp *Process) Status() *sys.WaitStatus {
252 253 254 255
	return dbp.CurrentThread.Status
}

// Step over function calls.
D
Derek Parker 已提交
256
func (dbp *Process) Next() error {
D
Derek Parker 已提交
257 258
	return dbp.run(dbp.next)
}
259

260
func (dbp *Process) next() (err error) {
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
	defer func() {
		// Always halt process at end of this function.
		herr := dbp.Halt()
		// Make sure we clean up the temp breakpoints.
		cerr := dbp.clearTempBreakpoints()
		// If we already had an error, return it.
		if err != nil {
			return
		}
		if herr != nil {
			err = herr
			return
		}
		if cerr != nil {
			err = cerr
		}
	}()
278

D
Derek Parker 已提交
279 280 281 282
	// Set breakpoints for any goroutine that is currently
	// blocked trying to read from a channel. This is so that
	// if control flow switches to that goroutine, we end up
	// somewhere useful instead of in runtime code.
283 284
	if _, err = dbp.setChanRecvBreakpoints(); err != nil {
		return
D
Derek Parker 已提交
285 286
	}

287 288 289
	// Get the goroutine for the current thread. We will
	// use it later in order to ensure we are on the same
	// goroutine.
A
aarzilli 已提交
290
	g, err := dbp.CurrentThread.GetG()
D
Derek Parker 已提交
291 292 293
	if err != nil {
		return err
	}
294

295 296 297 298 299 300 301
	var goroutineExiting bool
	if err = dbp.CurrentThread.setNextBreakpoints(); err != nil {
		switch t := err.(type) {
		case ThreadBlockedError, NoReturnAddr: // Noop
		case GoroutineExitingError:
			goroutineExiting = t.goid == g.Id
		default:
302
			return
303 304 305
		}
	}

D
Derek Parker 已提交
306
	for _, th := range dbp.Threads {
307 308
		if err = th.Continue(); err != nil {
			return
309 310
		}
	}
311

312
	for {
313
		_, err := dbp.trapWait(-1)
314
		if err != nil {
D
Derek Parker 已提交
315 316
			return err
		}
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
		for _, th := range dbp.Threads {
			if !th.Stopped() {
				continue
			}
			tg, err := th.GetG()
			if err != nil {
				return err
			}
			// Make sure we're on the same goroutine, unless it has exited.
			if tg.Id == g.Id || goroutineExiting {
				// Check to see if the goroutine has switched to another
				// thread, if so make it the current thread.
				if err := dbp.SwitchThread(th.Id); err != nil {
					return err
				}
				return nil
			}
			// This thread was not running our goroutine.
			// We continue it since our goroutine could
			// potentially be on this threads queue.
			if err = th.Continue(); err != nil {
338
				return err
D
Derek Parker 已提交
339
			}
340 341 342 343
		}
	}
}

D
Derek Parker 已提交
344
func (dbp *Process) setChanRecvBreakpoints() (int, error) {
D
Derek Parker 已提交
345
	var count int
D
Derek Parker 已提交
346 347
	allg, err := dbp.GoroutinesInfo()
	if err != nil {
D
Derek Parker 已提交
348
		return 0, err
D
Derek Parker 已提交
349 350 351 352 353
	}
	for _, g := range allg {
		if g.ChanRecvBlocked() {
			ret, err := g.chanRecvReturnAddr(dbp)
			if err != nil {
354 355 356
				if _, ok := err.(NullAddrError); ok {
					continue
				}
D
Derek Parker 已提交
357
				return 0, err
D
Derek Parker 已提交
358
			}
359
			if _, err = dbp.SetTempBreakpoint(ret); err != nil {
D
Derek Parker 已提交
360
				return 0, err
D
Derek Parker 已提交
361
			}
D
Derek Parker 已提交
362
			count++
D
Derek Parker 已提交
363 364
		}
	}
D
Derek Parker 已提交
365
	return count, nil
D
Derek Parker 已提交
366 367
}

368
// Resume process.
D
Derek Parker 已提交
369
func (dbp *Process) Continue() error {
370 371 372
	for _, thread := range dbp.Threads {
		err := thread.Continue()
		if err != nil {
373
			return fmt.Errorf("could not continue thread %d %s", thread.Id, err)
374 375
		}
	}
376 377 378 379 380 381 382 383
	return dbp.run(func() error {
		thread, err := dbp.trapWait(-1)
		if err != nil {
			return err
		}
		if err := dbp.Halt(); err != nil {
			return err
		}
384
		dbp.SwitchThread(thread.Id)
385
		loc, err := thread.Location()
386 387 388 389
		if err != nil {
			return err
		}
		// Check to see if we hit a runtime.breakpoint
390
		if loc.Fn != nil && loc.Fn.Name == "runtime.breakpoint" {
D
Derek Parker 已提交
391
			// Step twice to get back to user code
392 393 394 395
			for i := 0; i < 2; i++ {
				if err = thread.Step(); err != nil {
					return err
				}
D
Derek Parker 已提交
396 397
			}
		}
398 399
		return nil
	})
400 401
}

D
Derek Parker 已提交
402
// Single step, will execute a single instruction.
D
Derek Parker 已提交
403
func (dbp *Process) Step() (err error) {
D
Derek Parker 已提交
404 405 406 407 408
	fn := func() error {
		for _, th := range dbp.Threads {
			if th.blocked() {
				continue
			}
409
			if err := th.Step(); err != nil {
D
Derek Parker 已提交
410 411 412 413 414 415 416 417 418
				return err
			}
		}
		return nil
	}

	return dbp.run(fn)
}

419
// Change from current thread to the thread specified by `tid`.
D
Derek Parker 已提交
420
func (dbp *Process) SwitchThread(tid int) error {
421
	if th, ok := dbp.Threads[tid]; ok {
422
		dbp.CurrentThread = th
423
		dbp.SelectedGoroutine, _ = dbp.CurrentThread.GetG()
424 425 426 427 428
		return nil
	}
	return fmt.Errorf("thread %d does not exist", tid)
}

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
// Change from current thread to the thread running the specified goroutine
func (dbp *Process) SwitchGoroutine(gid int) error {
	gs, err := dbp.GoroutinesInfo()
	if err != nil {
		return err
	}
	for _, g := range gs {
		if g.Id == gid {
			if g.thread != nil {
				return dbp.SwitchThread(g.thread.Id)
			}
			dbp.SelectedGoroutine = g
			return nil
		}
	}
	return fmt.Errorf("could not find goroutine %d", gid)
}

D
Derek Parker 已提交
447 448
// Returns an array of G structures representing the information
// Delve cares about from the internal runtime G structure.
D
Derek Parker 已提交
449
func (dbp *Process) GoroutinesInfo() ([]*G, error) {
450 451 452 453
	if dbp.allGCache != nil {
		return dbp.allGCache, nil
	}

454
	var (
A
aarzilli 已提交
455 456 457
		threadg = map[int]*Thread{}
		allg    []*G
		rdr     = dbp.DwarfReader()
458 459
	)

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

470
	addr, err := rdr.AddrFor("runtime.allglen")
471 472 473
	if err != nil {
		return nil, err
	}
474 475 476 477 478 479 480 481
	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")
482 483 484
	if err != nil {
		return nil, err
	}
485
	faddr, err := dbp.CurrentThread.readMemory(uintptr(allgentryaddr), dbp.arch.PtrSize())
486 487 488
	allgptr := binary.LittleEndian.Uint64(faddr)

	for i := uint64(0); i < allglen; i++ {
489
		g, err := parseG(dbp.CurrentThread, allgptr+(i*uint64(dbp.arch.PtrSize())), true)
490 491 492
		if err != nil {
			return nil, err
		}
A
aarzilli 已提交
493
		if thread, allocated := threadg[g.Id]; allocated {
494 495 496 497
			loc, err := thread.Location()
			if err != nil {
				return nil, err
			}
A
aarzilli 已提交
498
			g.thread = thread
499 500 501 502
			// Prefer actual thread location information.
			g.File = loc.File
			g.Line = loc.Line
			g.Func = loc.Fn
A
aarzilli 已提交
503
		}
504 505
		allg = append(allg, g)
	}
506
	dbp.allGCache = allg
507 508 509
	return allg, nil
}

D
Derek Parker 已提交
510
// Stop all threads.
D
Derek Parker 已提交
511
func (dbp *Process) Halt() (err error) {
D
Derek Parker 已提交
512 513 514 515 516 517 518 519
	for _, th := range dbp.Threads {
		if err := th.Halt(); err != nil {
			return err
		}
	}
	return nil
}

520 521
// Obtains register values from what Delve considers to be the current
// thread of the traced process.
D
Derek Parker 已提交
522
func (dbp *Process) Registers() (Registers, error) {
523 524 525
	return dbp.CurrentThread.Registers()
}

526
// Returns the PC of the current thread.
D
Derek Parker 已提交
527
func (dbp *Process) PC() (uint64, error) {
D
Derek Parker 已提交
528
	return dbp.CurrentThread.PC()
529 530
}

531
// Returns the PC of the current thread.
D
Derek Parker 已提交
532
func (dbp *Process) CurrentBreakpoint() *Breakpoint {
533 534 535
	return dbp.CurrentThread.CurrentBreakpoint
}

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

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

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

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

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

D
Derek Parker 已提交
566
// Finds the breakpoint for the given pc.
D
Derek Parker 已提交
567
func (dbp *Process) FindBreakpoint(pc uint64) (*Breakpoint, bool) {
568 569 570 571
	// 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 已提交
572
	}
573 574 575 576
	// 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 已提交
577
	if bp, ok := dbp.Breakpoints[pc]; ok {
D
Derek Parker 已提交
578 579 580 581 582
		return bp, true
	}
	return nil, false
}

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

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

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

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

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

617 618 619 620 621
	ver, isextld, err := dbp.getGoInformation()
	if err != nil {
		return nil, err
	}

622
	dbp.arch.SetGStructOffset(ver, isextld)
623 624 625 626 627
	// SelectedGoroutine can not be set correctly by the call to updateThreadList
	// because without calling SetGStructOffset we can not read the G struct of CurrentThread
	// but without calling updateThreadList we can not examine memory to determine
	// the offset of g struct inside TLS
	dbp.SelectedGoroutine, _ = dbp.CurrentThread.GetG()
628

629
	return dbp, nil
D
Derek Parker 已提交
630
}
631

D
Derek Parker 已提交
632
func (dbp *Process) clearTempBreakpoints() error {
D
Derek Parker 已提交
633
	for _, bp := range dbp.Breakpoints {
D
Derek Parker 已提交
634 635 636
		if !bp.Temp {
			continue
		}
637
		if _, err := dbp.ClearBreakpoint(bp.Addr); err != nil {
D
Derek Parker 已提交
638 639 640 641 642
			return err
		}
	}
	return nil
}
643

D
Derek Parker 已提交
644
func (dbp *Process) handleBreakpointOnThread(id int) (*Thread, error) {
D
Derek Parker 已提交
645 646
	thread, ok := dbp.Threads[id]
	if !ok {
647
		return nil, fmt.Errorf("could not find thread for %d", id)
D
Derek Parker 已提交
648
	}
D
Derek Parker 已提交
649
	pc, err := thread.PC()
D
Derek Parker 已提交
650
	if err != nil {
651
		return nil, err
D
Derek Parker 已提交
652
	}
653 654
	// Check to see if we have hit a breakpoint.
	if bp, ok := dbp.FindBreakpoint(pc); ok {
655
		thread.CurrentBreakpoint = bp
D
Derek Parker 已提交
656 657 658 659 660 661
		if err = thread.SetPC(bp.Addr); err != nil {
			return nil, err
		}
		return thread, nil
	}
	if dbp.halt {
662
		return thread, nil
D
Derek Parker 已提交
663
	}
D
Derek Parker 已提交
664 665 666 667 668 669 670 671 672
	fn := dbp.goSymTable.PCToFunc(pc)
	if fn != nil && fn.Name == "runtime.breakpoint" {
		for i := 0; i < 2; i++ {
			if err := thread.Step(); err != nil {
				return nil, err
			}
		}
		return thread, nil
	}
D
Derek Parker 已提交
673
	return nil, NoBreakpointError{addr: pc}
D
Derek Parker 已提交
674
}
D
Derek Parker 已提交
675

D
Derek Parker 已提交
676
func (dbp *Process) run(fn func() error) error {
677
	dbp.allGCache = nil
678
	if dbp.exited {
D
Derek Parker 已提交
679
		return fmt.Errorf("process has already exited")
680
	}
681 682 683
	for _, th := range dbp.Threads {
		th.CurrentBreakpoint = nil
	}
D
Derek Parker 已提交
684
	if err := fn(); err != nil {
D
Derek Parker 已提交
685
		return err
D
Derek Parker 已提交
686 687 688
	}
	return nil
}
689

D
Derek Parker 已提交
690
func (dbp *Process) handlePtraceFuncs() {
691 692 693 694 695 696 697 698 699 700 701
	// 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 已提交
702
func (dbp *Process) execPtraceFunc(fn func()) {
703 704 705
	dbp.ptraceChan <- fn
	<-dbp.ptraceDoneChan
}
706 707

func (dbp *Process) getGoInformation() (ver GoVersion, isextld bool, err error) {
708
	vv, err := dbp.EvalPackageVariable("runtime.buildVersion")
709 710 711 712 713 714 715 716
	if err != nil {
		err = fmt.Errorf("Could not determine version number: %v\n", err)
		return
	}

	ver, ok := parseVersionString(vv.Value)
	if !ok {
		err = fmt.Errorf("Could not parse version number: %s\n", vv.Value)
717
		return
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
	}

	rdr := dbp.DwarfReader()
	rdr.Seek(0)
	for entry, err := rdr.NextCompileUnit(); entry != nil; entry, err = rdr.NextCompileUnit() {
		if err != nil {
			return ver, isextld, err
		}
		if prod, ok := entry.Val(dwarf.AttrProducer).(string); ok && (strings.HasPrefix(prod, "GNU AS")) {
			isextld = true
			break
		}
	}
	return
}
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

func (dbp *Process) FindGoroutine(gid int) (*G, error) {
	if gid == -1 {
		return dbp.SelectedGoroutine, nil
	}

	gs, err := dbp.GoroutinesInfo()
	if err != nil {
		return nil, err
	}
	for i := range gs {
		if gs[i].Id == gid {
			return gs[i], nil
		}
	}
	return nil, fmt.Errorf("Unknown goroutine %d", gid)
}

func (dbp *Process) ConvertEvalScope(gid, frame int) (*EvalScope, error) {
	g, err := dbp.FindGoroutine(gid)
	if err != nil {
		return nil, err
	}
	if g == nil {
		return dbp.CurrentThread.Scope()
	}

	var out EvalScope

	if g.thread == nil {
		out.Thread = dbp.CurrentThread
	} else {
		out.Thread = g.thread
	}

	locs, err := dbp.GoroutineStacktrace(g, frame)
	if err != nil {
		return nil, err
	}

	if frame >= len(locs) {
		return nil, fmt.Errorf("Frame %d does not exist in goroutine %d", frame, gid)
	}

	out.PC, out.CFA = locs[frame].PC, locs[frame].CFA

	return &out, nil
}