proc.go 18.4 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
	// Breakpoint table, holds information on breakpoints.
29
	// 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
		}
	}
	dbp.execPtraceFunc(func() {
104 105 106 107
		err = PtraceDetach(dbp.Pid, 0)
		if err != nil {
			return
		}
108
		if kill {
109
			err = sys.Kill(dbp.Pid, sys.SIGINT)
110 111 112
		}
	})
	return
D
Derek Parker 已提交
113 114
}

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

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

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

140
	exe, err := dbp.findExecutable(path)
D
Derek Parker 已提交
141 142 143 144
	if err != nil {
		return err
	}

145 146
	wg.Add(4)
	go dbp.loadProcessInformation(&wg)
D
Derek Parker 已提交
147 148 149 150 151 152 153 154
	go dbp.parseDebugFrame(exe, &wg)
	go dbp.obtainGoSymbols(exe, &wg)
	go dbp.parseDebugLineInfo(exe, &wg)
	wg.Wait()

	return nil
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
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)
	}
174

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

181
		lines, err := dbp.ast.NextLines(filename, lineno)
182 183 184 185
		if err != nil {
			return 0, err
		}

186 187 188
		if len(lines) > 0 {
			linePC, _, err := dbp.goSymTable.LineToPC(filename, lines[0])
			return linePC, err
189
		}
D
Derek Parker 已提交
190
		return fn.Entry, nil
191 192 193 194
	} 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 已提交
195 196
	}

197
	return fn.Entry, nil
198 199
}

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

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

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

D
Derek Parker 已提交
219
// Clears a breakpoint.
220
func (dbp *Process) ClearBreakpoint(addr uint64) (*Breakpoint, error) {
221
	bp, ok := dbp.FindBreakpoint(addr)
222 223 224 225
	if !ok {
		return nil, NoBreakpointError{addr: addr}
	}

226 227
	if _, err := bp.Clear(dbp.CurrentThread); err != nil {
		return nil, err
228 229 230 231 232
	}

	delete(dbp.Breakpoints, addr)

	return bp, nil
233 234
}

235
// Returns the status of the current main thread context.
D
Derek Parker 已提交
236
func (dbp *Process) Status() *sys.WaitStatus {
237 238 239 240
	return dbp.CurrentThread.Status
}

// Step over function calls.
D
Derek Parker 已提交
241
func (dbp *Process) Next() error {
D
Derek Parker 已提交
242 243
	return dbp.run(dbp.next)
}
244

245
func (dbp *Process) next() (err error) {
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
	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
		}
	}()
263

D
Derek Parker 已提交
264 265 266 267
	// 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.
268 269
	if _, err = dbp.setChanRecvBreakpoints(); err != nil {
		return
D
Derek Parker 已提交
270 271
	}

272 273 274
	// Get the goroutine for the current thread. We will
	// use it later in order to ensure we are on the same
	// goroutine.
A
aarzilli 已提交
275
	g, err := dbp.CurrentThread.GetG()
D
Derek Parker 已提交
276 277 278
	if err != nil {
		return err
	}
279

280 281 282 283 284 285 286
	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:
287
			return
288 289 290
		}
	}

D
Derek Parker 已提交
291
	for _, th := range dbp.Threads {
292 293
		if err = th.Continue(); err != nil {
			return
294 295
		}
	}
296

297
	for {
298
		_, err := dbp.trapWait(-1)
299
		if err != nil {
D
Derek Parker 已提交
300 301
			return err
		}
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
		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 {
323
				return err
D
Derek Parker 已提交
324
			}
325 326 327 328
		}
	}
}

D
Derek Parker 已提交
329
func (dbp *Process) setChanRecvBreakpoints() (int, error) {
D
Derek Parker 已提交
330
	var count int
D
Derek Parker 已提交
331 332
	allg, err := dbp.GoroutinesInfo()
	if err != nil {
D
Derek Parker 已提交
333
		return 0, err
D
Derek Parker 已提交
334
	}
335

D
Derek Parker 已提交
336 337 338 339
	for _, g := range allg {
		if g.ChanRecvBlocked() {
			ret, err := g.chanRecvReturnAddr(dbp)
			if err != nil {
340 341 342
				if _, ok := err.(NullAddrError); ok {
					continue
				}
D
Derek Parker 已提交
343
				return 0, err
D
Derek Parker 已提交
344
			}
345
			if _, err = dbp.SetTempBreakpoint(ret); err != nil {
346 347 348 349 350
				if _, ok := err.(BreakpointExistsError); ok {
					// Ignore duplicate breakpoints in case if multiple
					// goroutines wait on the same channel
					continue
				}
D
Derek Parker 已提交
351
				return 0, err
D
Derek Parker 已提交
352
			}
D
Derek Parker 已提交
353
			count++
D
Derek Parker 已提交
354 355
		}
	}
D
Derek Parker 已提交
356
	return count, nil
D
Derek Parker 已提交
357 358
}

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

D
Derek Parker 已提交
393
// Single step, will execute a single instruction.
D
Derek Parker 已提交
394
func (dbp *Process) Step() (err error) {
D
Derek Parker 已提交
395 396 397 398 399
	fn := func() error {
		for _, th := range dbp.Threads {
			if th.blocked() {
				continue
			}
400
			if err := th.Step(); err != nil {
D
Derek Parker 已提交
401 402 403 404 405 406 407 408 409
				return err
			}
		}
		return nil
	}

	return dbp.run(fn)
}

410
// Change from current thread to the thread specified by `tid`.
D
Derek Parker 已提交
411
func (dbp *Process) SwitchThread(tid int) error {
412
	if th, ok := dbp.Threads[tid]; ok {
413
		dbp.CurrentThread = th
414
		dbp.SelectedGoroutine, _ = dbp.CurrentThread.GetG()
415 416 417 418 419
		return nil
	}
	return fmt.Errorf("thread %d does not exist", tid)
}

420 421
// Change from current thread to the thread running the specified goroutine
func (dbp *Process) SwitchGoroutine(gid int) error {
A
aarzilli 已提交
422
	g, err := dbp.FindGoroutine(gid)
423 424 425
	if err != nil {
		return err
	}
A
aarzilli 已提交
426 427 428
	if g == nil {
		// user specified -1 and SelectedGoroutine is nil
		return nil
429
	}
A
aarzilli 已提交
430 431 432 433 434
	if g.thread != nil {
		return dbp.SwitchThread(g.thread.Id)
	}
	dbp.SelectedGoroutine = g
	return nil
435 436
}

D
Derek Parker 已提交
437 438
// Returns an array of G structures representing the information
// Delve cares about from the internal runtime G structure.
D
Derek Parker 已提交
439
func (dbp *Process) GoroutinesInfo() ([]*G, error) {
440 441 442 443
	if dbp.allGCache != nil {
		return dbp.allGCache, nil
	}

444
	var (
A
aarzilli 已提交
445 446 447
		threadg = map[int]*Thread{}
		allg    []*G
		rdr     = dbp.DwarfReader()
448 449
	)

A
aarzilli 已提交
450 451 452 453
	for i := range dbp.Threads {
		if dbp.Threads[i].blocked() {
			continue
		}
A
aarzilli 已提交
454
		g, _ := dbp.Threads[i].GetG()
A
aarzilli 已提交
455 456 457 458 459
		if g != nil {
			threadg[g.Id] = dbp.Threads[i]
		}
	}

460
	addr, err := rdr.AddrFor("runtime.allglen")
461 462 463
	if err != nil {
		return nil, err
	}
464 465 466 467 468 469 470 471
	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")
472 473 474
	if err != nil {
		return nil, err
	}
475
	faddr, err := dbp.CurrentThread.readMemory(uintptr(allgentryaddr), dbp.arch.PtrSize())
476 477 478
	allgptr := binary.LittleEndian.Uint64(faddr)

	for i := uint64(0); i < allglen; i++ {
479
		g, err := parseG(dbp.CurrentThread, allgptr+(i*uint64(dbp.arch.PtrSize())), true)
480 481 482
		if err != nil {
			return nil, err
		}
A
aarzilli 已提交
483
		if thread, allocated := threadg[g.Id]; allocated {
484 485 486 487
			loc, err := thread.Location()
			if err != nil {
				return nil, err
			}
A
aarzilli 已提交
488
			g.thread = thread
489 490 491 492
			// Prefer actual thread location information.
			g.File = loc.File
			g.Line = loc.Line
			g.Func = loc.Fn
A
aarzilli 已提交
493
		}
494 495 496
		if g.Status != Gdead {
			allg = append(allg, g)
		}
497
	}
498
	dbp.allGCache = allg
499 500 501
	return allg, nil
}

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

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

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

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

528
// Returns a reader for the dwarf data
D
Derek Parker 已提交
529
func (dbp *Process) DwarfReader() *reader.Reader {
530 531 532
	return reader.New(dbp.dwarf)
}

D
Derek Parker 已提交
533
// Returns list of source files that comprise the debugged binary.
D
Derek Parker 已提交
534
func (dbp *Process) Sources() map[string]*gosym.Obj {
535 536 537
	return dbp.goSymTable.Files
}

D
Derek Parker 已提交
538
// Returns list of functions present in the debugged program.
D
Derek Parker 已提交
539
func (dbp *Process) Funcs() []gosym.Func {
540 541 542
	return dbp.goSymTable.Funcs
}

D
Derek Parker 已提交
543
// Converts an instruction address to a file/line/function.
D
Derek Parker 已提交
544
func (dbp *Process) PCToLine(pc uint64) (string, int, *gosym.Func) {
545
	return dbp.goSymTable.PCToLine(pc)
546 547
}

548
// Finds the breakpoint for the given ID.
D
Derek Parker 已提交
549
func (dbp *Process) FindBreakpointByID(id int) (*Breakpoint, bool) {
550 551 552 553 554 555 556 557
	for _, bp := range dbp.Breakpoints {
		if bp.ID == id {
			return bp, true
		}
	}
	return nil, false
}

D
Derek Parker 已提交
558
// Finds the breakpoint for the given pc.
D
Derek Parker 已提交
559
func (dbp *Process) FindBreakpoint(pc uint64) (*Breakpoint, bool) {
560
	// Check to see if address is past the breakpoint, (i.e. breakpoint was hit).
561 562
	if bp, ok := dbp.Breakpoints[pc-uint64(dbp.arch.BreakpointSize())]; ok {
		return bp, true
D
Derek Parker 已提交
563
	}
564
	// Directly use addr to lookup breakpoint.
D
Derek Parker 已提交
565
	if bp, ok := dbp.Breakpoints[pc]; ok {
D
Derek Parker 已提交
566 567 568 569 570
		return bp, true
	}
	return nil, false
}

D
Derek Parker 已提交
571 572
// Returns a new Process struct.
func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, error) {
D
Derek Parker 已提交
573
	if attach {
574 575
		var err error
		dbp.execPtraceFunc(func() { err = sys.PtraceAttach(dbp.Pid) })
D
Derek Parker 已提交
576 577 578
		if err != nil {
			return nil, err
		}
579
		_, _, err = dbp.wait(dbp.Pid, 0)
D
Derek Parker 已提交
580 581 582 583 584
		if err != nil {
			return nil, err
		}
	}

585
	proc, err := os.FindProcess(dbp.Pid)
D
Derek Parker 已提交
586 587 588 589 590
	if err != nil {
		return nil, err
	}

	dbp.Process = proc
591
	err = dbp.LoadInformation(path)
D
Derek Parker 已提交
592 593 594 595
	if err != nil {
		return nil, err
	}

596 597 598 599 600
	switch runtime.GOARCH {
	case "amd64":
		dbp.arch = AMD64Arch()
	}

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

605 606 607 608 609
	ver, isextld, err := dbp.getGoInformation()
	if err != nil {
		return nil, err
	}

610
	dbp.arch.SetGStructOffset(ver, isextld)
611 612 613 614 615
	// 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()
616

617
	return dbp, nil
D
Derek Parker 已提交
618
}
619

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

D
Derek Parker 已提交
632
func (dbp *Process) handleBreakpointOnThread(id int) (*Thread, error) {
D
Derek Parker 已提交
633 634
	thread, ok := dbp.Threads[id]
	if !ok {
635
		return nil, fmt.Errorf("could not find thread for %d", id)
D
Derek Parker 已提交
636
	}
D
Derek Parker 已提交
637
	pc, err := thread.PC()
D
Derek Parker 已提交
638
	if err != nil {
639
		return nil, err
D
Derek Parker 已提交
640
	}
641 642
	// Check to see if we have hit a breakpoint.
	if bp, ok := dbp.FindBreakpoint(pc); ok {
643
		thread.CurrentBreakpoint = bp
D
Derek Parker 已提交
644 645 646
		if err = thread.SetPC(bp.Addr); err != nil {
			return nil, err
		}
647 648 649 650
		if g, err := thread.GetG(); err == nil {
			thread.CurrentBreakpoint.HitCount[g.Id]++
		}
		thread.CurrentBreakpoint.TotalHitCount++
D
Derek Parker 已提交
651 652 653
		return thread, nil
	}
	if dbp.halt {
654
		return thread, nil
D
Derek Parker 已提交
655
	}
D
Derek Parker 已提交
656 657 658 659 660 661 662 663 664
	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 已提交
665
	return nil, NoBreakpointError{addr: pc}
D
Derek Parker 已提交
666
}
D
Derek Parker 已提交
667

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

D
Derek Parker 已提交
682
func (dbp *Process) handlePtraceFuncs() {
683
	// We must ensure here that we are running on the same thread during
684
	// while invoking the ptrace(2) syscall. This is due to the fact that ptrace(2) expects
685 686 687 688 689 690 691 692 693
	// 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 已提交
694
func (dbp *Process) execPtraceFunc(fn func()) {
695 696 697
	dbp.ptraceChan <- fn
	<-dbp.ptraceDoneChan
}
698 699

func (dbp *Process) getGoInformation() (ver GoVersion, isextld bool, err error) {
700
	vv, err := dbp.EvalPackageVariable("runtime.buildVersion")
701 702 703 704 705 706 707 708
	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)
709
		return
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
	}

	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
}
725 726 727 728 729 730 731 732 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

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)
	}

769
	out.PC, out.CFA = locs[frame].Current.PC, locs[frame].CFA
770 771 772

	return &out, nil
}
773 774 775 776 777 778

func (dbp *Process) postExit() {
	dbp.exited = true
	close(dbp.ptraceChan)
	close(dbp.ptraceDoneChan)
}