proc.go 18.6 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
	"fmt"
8
	"go/constant"
9
	"os"
10
	"path/filepath"
11
	"runtime"
12
	"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"
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 43 44
	// Maps package names to package paths, needed to lookup types inside DWARF info
	packageMap map[string]string

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

D
Derek Parker 已提交
61 62
func New(pid int) *Process {
	dbp := &Process{
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),
		ptraceChan:     make(chan func()),
		ptraceDoneChan: make(chan interface{}),
	}
	go dbp.handlePtraceFuncs()
	return dbp
D
Derek Parker 已提交
73 74
}

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

D
Derek Parker 已提交
86
// Detach from the process being debugged, optionally killing it.
D
Derek Parker 已提交
87
func (dbp *Process) Detach(kill bool) (err error) {
D
Derek Parker 已提交
88 89 90 91 92
	if dbp.Running() {
		if err = dbp.Halt(); err != nil {
			return
		}
	}
93 94 95 96 97 98 99 100
	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 已提交
101
			}
102 103 104
		}
	}
	dbp.execPtraceFunc(func() {
105 106 107 108
		err = PtraceDetach(dbp.Pid, 0)
		if err != nil {
			return
		}
109
		if kill {
110
			err = sys.Kill(dbp.Pid, sys.SIGINT)
111 112 113
		}
	})
	return
D
Derek Parker 已提交
114 115
}

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

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

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

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

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

	return nil
}

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) {
D
Derek Parker 已提交
171 172
	origfn := dbp.goSymTable.LookupFunc(funcName)
	if origfn == nil {
173 174
		return 0, fmt.Errorf("Could not find function %s\n", funcName)
	}
175

176
	if firstLine {
D
Derek Parker 已提交
177
		filename, lineno, _ := dbp.goSymTable.PCToLine(origfn.Entry)
178
		if filepath.Ext(filename) != ".go" {
D
Derek Parker 已提交
179
			return origfn.Entry, nil
180
		}
D
Derek Parker 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194
		for {
			lineno++
			pc, fn, _ := dbp.goSymTable.LineToPC(filename, lineno)
			if fn != nil {
				if fn.Name != funcName {
					if strings.Contains(fn.Name, funcName) {
						continue
					}
					break
				}
				if fn.Name == funcName {
					return pc, nil
				}
			}
195
		}
D
Derek Parker 已提交
196
		return origfn.Entry, nil
197
	} else if lineOffset > 0 {
D
Derek Parker 已提交
198
		filename, lineno, _ := dbp.goSymTable.PCToLine(origfn.Entry)
199 200
		breakAddr, _, err := dbp.goSymTable.LineToPC(filename, lineno+lineOffset)
		return breakAddr, err
D
Derek Parker 已提交
201 202
	}

D
Derek Parker 已提交
203
	return origfn.Entry, nil
204 205
}

D
Derek Parker 已提交
206 207
// Sends out a request that the debugged process halt
// execution. Sends SIGSTOP to all threads.
D
Derek Parker 已提交
208
func (dbp *Process) RequestManualStop() error {
D
Derek Parker 已提交
209
	dbp.halt = true
D
Derek Parker 已提交
210
	return dbp.requestManualStop()
D
Derek Parker 已提交
211 212
}

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

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

D
Derek Parker 已提交
225
// Clears a breakpoint.
226
func (dbp *Process) ClearBreakpoint(addr uint64) (*Breakpoint, error) {
227
	bp, ok := dbp.FindBreakpoint(addr)
228 229 230 231
	if !ok {
		return nil, NoBreakpointError{addr: addr}
	}

232 233
	if _, err := bp.Clear(dbp.CurrentThread); err != nil {
		return nil, err
234 235 236 237 238
	}

	delete(dbp.Breakpoints, addr)

	return bp, nil
239 240
}

241
// Returns the status of the current main thread context.
D
Derek Parker 已提交
242
func (dbp *Process) Status() *sys.WaitStatus {
243 244 245 246
	return dbp.CurrentThread.Status
}

// Step over function calls.
D
Derek Parker 已提交
247
func (dbp *Process) Next() error {
D
Derek Parker 已提交
248 249
	return dbp.run(dbp.next)
}
250

251
func (dbp *Process) next() (err error) {
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
	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
		}
	}()
269

D
Derek Parker 已提交
270 271 272 273
	// 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.
274 275
	if _, err = dbp.setChanRecvBreakpoints(); err != nil {
		return
D
Derek Parker 已提交
276 277
	}

278 279 280
	// Get the goroutine for the current thread. We will
	// use it later in order to ensure we are on the same
	// goroutine.
A
aarzilli 已提交
281
	g, err := dbp.CurrentThread.GetG()
D
Derek Parker 已提交
282 283 284
	if err != nil {
		return err
	}
285

286 287 288 289 290 291 292
	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:
293
			return
294 295 296
		}
	}

D
Derek Parker 已提交
297
	for _, th := range dbp.Threads {
298 299
		if err = th.Continue(); err != nil {
			return
300 301
		}
	}
302

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

D
Derek Parker 已提交
335
func (dbp *Process) setChanRecvBreakpoints() (int, error) {
D
Derek Parker 已提交
336
	var count int
D
Derek Parker 已提交
337 338
	allg, err := dbp.GoroutinesInfo()
	if err != nil {
D
Derek Parker 已提交
339
		return 0, err
D
Derek Parker 已提交
340
	}
341

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

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

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

	return dbp.run(fn)
}

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

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

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

450
	var (
A
aarzilli 已提交
451 452 453
		threadg = map[int]*Thread{}
		allg    []*G
		rdr     = dbp.DwarfReader()
454 455
	)

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

466
	addr, err := rdr.AddrFor("runtime.allglen")
467 468 469
	if err != nil {
		return nil, err
	}
470 471 472 473 474 475 476
	allglenBytes, err := dbp.CurrentThread.readMemory(uintptr(addr), 8)
	if err != nil {
		return nil, err
	}
	allglen := binary.LittleEndian.Uint64(allglenBytes)

	rdr.Seek(0)
477
	allgentryaddr, err := rdr.AddrFor("runtime.allgs")
478
	if err != nil {
479 480 481 482 483
		// try old name (pre Go 1.6)
		allgentryaddr, err = rdr.AddrFor("runtime.allg")
		if err != nil {
			return nil, err
		}
484
	}
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
			// Prefer actual thread location information.
500
			g.CurrentLoc = *loc
A
aarzilli 已提交
501
		}
502 503 504
		if g.Status != Gdead {
			allg = append(allg, g)
		}
505
	}
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
	// Check to see if address is past the breakpoint, (i.e. breakpoint was hit).
569 570
	if bp, ok := dbp.Breakpoints[pc-uint64(dbp.arch.BreakpointSize())]; ok {
		return bp, true
D
Derek Parker 已提交
571
	}
572
	// Directly use addr to lookup breakpoint.
D
Derek Parker 已提交
573
	if bp, ok := dbp.Breakpoints[pc]; ok {
D
Derek Parker 已提交
574 575 576 577 578
		return bp, true
	}
	return nil, false
}

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

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

	dbp.Process = proc
599
	err = dbp.LoadInformation(path)
D
Derek Parker 已提交
600 601 602 603
	if err != nil {
		return nil, err
	}

604 605 606 607 608
	switch runtime.GOARCH {
	case "amd64":
		dbp.arch = AMD64Arch()
	}

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

613 614 615 616 617
	ver, isextld, err := dbp.getGoInformation()
	if err != nil {
		return nil, err
	}

618
	dbp.arch.SetGStructOffset(ver, isextld)
619 620 621 622 623
	// 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()
624

625
	return dbp, nil
D
Derek Parker 已提交
626
}
627

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

D
Derek Parker 已提交
640
func (dbp *Process) handleBreakpointOnThread(id int) (*Thread, error) {
D
Derek Parker 已提交
641 642
	thread, ok := dbp.Threads[id]
	if !ok {
643
		return nil, fmt.Errorf("could not find thread for %d", id)
D
Derek Parker 已提交
644
	}
D
Derek Parker 已提交
645
	pc, err := thread.PC()
D
Derek Parker 已提交
646
	if err != nil {
647
		return nil, err
D
Derek Parker 已提交
648
	}
649 650
	// Check to see if we have hit a breakpoint.
	if bp, ok := dbp.FindBreakpoint(pc); ok {
651
		thread.CurrentBreakpoint = bp
D
Derek Parker 已提交
652 653 654
		if err = thread.SetPC(bp.Addr); err != nil {
			return nil, err
		}
655 656 657 658
		if g, err := thread.GetG(); err == nil {
			thread.CurrentBreakpoint.HitCount[g.Id]++
		}
		thread.CurrentBreakpoint.TotalHitCount++
D
Derek Parker 已提交
659 660 661
		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
	// We must ensure here that we are running on the same thread during
692
	// while invoking the ptrace(2) syscall. This is due to the fact that ptrace(2) expects
693 694 695 696 697 698 699 700 701
	// 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
	if err != nil {
710 711
		err = fmt.Errorf("Could not determine version number: %v\n", err)
		return
712 713
	}

714
	ver, ok := parseVersionString(constant.StringVal(vv.Value))
715
	if !ok {
716
		err = fmt.Errorf("Could not parse version number: %v\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

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

777
	out.PC, out.CFA = locs[frame].Current.PC, locs[frame].CFA
778 779 780

	return &out, nil
}
781 782 783 784 785 786

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