proc.go 16.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 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. This is the default thread used for setting breakpoints, evaluating variables, etc..
D
Derek Parker 已提交
36
	CurrentThread *Thread
37

38 39 40 41 42 43
	dwarf                   *dwarf.Data
	goSymTable              *gosym.Table
	frameEntries            frame.FrameDescriptionEntries
	lineInfo                *line.DebugLineInfo
	firstStart              bool
	os                      *OSProcessDetails
44
	arch                    Arch
45 46 47 48 49
	ast                     *source.Searcher
	breakpointIDCounter     int
	tempBreakpointIDCounter int
	halt                    bool
	exited                  bool
50 51 52 53
	ptraceChan              chan func()
	ptraceDoneChan          chan interface{}
}

D
Derek Parker 已提交
54 55
func New(pid int) *Process {
	dbp := &Process{
56 57 58 59 60 61 62 63 64 65 66
		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 已提交
67 68
}

69 70 71 72 73 74 75 76
// 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 已提交
77
	return fmt.Sprintf("Process %d has exited with status %d", pe.Pid, pe.Status)
78 79
}

D
Derek Parker 已提交
80
// Detach from the process being debugged, optionally killing it.
D
Derek Parker 已提交
81
func (dbp *Process) Detach(kill bool) (err error) {
D
Derek Parker 已提交
82 83 84 85 86
	if dbp.Running() {
		if err = dbp.Halt(); err != nil {
			return
		}
	}
87 88 89 90 91 92 93 94
	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 已提交
95
			}
96 97 98 99 100 101 102 103 104 105
		}
	}
	dbp.execPtraceFunc(func() {
		var sig int
		if kill {
			sig = int(sys.SIGINT)
		}
		err = PtraceDetach(dbp.Pid, sig)
	})
	return
D
Derek Parker 已提交
106 107
}

108 109
// Returns whether or not Delve thinks the debugged
// process has exited.
D
Derek Parker 已提交
110
func (dbp *Process) Exited() bool {
111 112 113
	return dbp.exited
}

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

D
Derek Parker 已提交
125 126 127 128 129
// 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 已提交
130
func (dbp *Process) LoadInformation(path string) error {
D
Derek Parker 已提交
131 132
	var wg sync.WaitGroup

133
	exe, err := dbp.findExecutable(path)
D
Derek Parker 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146
	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
}

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
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)
	}
166

167 168 169 170
	if firstLine {
		filename, lineno, _ := dbp.goSymTable.PCToLine(fn.Entry)
		if filepath.Ext(filename) != ".go" {
			return fn.Entry, nil
171 172
		}

173
		lines, err := dbp.ast.NextLines(filename, lineno)
174 175 176 177
		if err != nil {
			return 0, err
		}

178 179 180
		if len(lines) > 0 {
			linePC, _, err := dbp.goSymTable.LineToPC(filename, lines[0])
			return linePC, err
181
		} else {
182
			return fn.Entry, nil
183
		}
184 185 186 187
	} 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 已提交
188 189
	}

190
	return fn.Entry, nil
191 192
}

D
Derek Parker 已提交
193 194
// Sends out a request that the debugged process halt
// execution. Sends SIGSTOP to all threads.
D
Derek Parker 已提交
195
func (dbp *Process) RequestManualStop() error {
D
Derek Parker 已提交
196
	dbp.halt = true
D
Derek Parker 已提交
197
	return dbp.requestManualStop()
D
Derek Parker 已提交
198 199
}

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

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

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

245
// Returns the status of the current main thread context.
D
Derek Parker 已提交
246
func (dbp *Process) Status() *sys.WaitStatus {
247 248 249 250
	return dbp.CurrentThread.Status
}

// Step over function calls.
D
Derek Parker 已提交
251
func (dbp *Process) Next() error {
D
Derek Parker 已提交
252 253
	return dbp.run(dbp.next)
}
254

D
Derek Parker 已提交
255
func (dbp *Process) next() error {
D
Derek Parker 已提交
256
	// Make sure we clean up the temp breakpoints created by thread.Next
257 258
	defer dbp.clearTempBreakpoints()

D
Derek Parker 已提交
259 260 261 262
	// 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.
D
Derek Parker 已提交
263 264 265 266 267
	chanRecvCount, err := dbp.setChanRecvBreakpoints()
	if err != nil {
		return err
	}

A
aarzilli 已提交
268
	g, err := dbp.CurrentThread.GetG()
D
Derek Parker 已提交
269 270 271
	if err != nil {
		return err
	}
272

273
	if g.DeferPC != 0 {
274
		_, err = dbp.SetTempBreakpoint(g.DeferPC)
275 276 277 278 279
		if err != nil {
			return err
		}
	}

280
	var goroutineExiting bool
D
Derek Parker 已提交
281
	var waitCount int
D
Derek Parker 已提交
282
	for _, th := range dbp.Threads {
283 284
		if th.blocked() {
			// Ignore threads that aren't running go code.
D
Derek Parker 已提交
285 286
			continue
		}
D
Derek Parker 已提交
287
		waitCount++
288
		if err = th.SetNextBreakpoints(); err != nil {
289
			if err, ok := err.(GoroutineExitingError); ok {
D
Derek Parker 已提交
290
				waitCount = waitCount - 1 + chanRecvCount
291
				if err.goid == g.Id {
292 293 294 295
					goroutineExiting = true
				}
				continue
			}
D
Derek Parker 已提交
296 297 298
			return err
		}
	}
299 300 301 302 303
	for _, th := range dbp.Threads {
		if err = th.Continue(); err != nil {
			return err
		}
	}
304

D
Derek Parker 已提交
305
	for waitCount > 0 {
306
		thread, err := dbp.trapWait(-1)
D
Derek Parker 已提交
307 308
		if err != nil {
			return err
D
Derek Parker 已提交
309
		}
A
aarzilli 已提交
310
		tg, err := thread.GetG()
D
Derek Parker 已提交
311 312 313
		if err != nil {
			return err
		}
D
Derek Parker 已提交
314
		// Make sure we're on the same goroutine, unless it has exited.
315
		if tg.Id == g.Id || goroutineExiting {
316 317
			if dbp.CurrentThread != thread {
				dbp.SwitchThread(thread.Id)
D
Derek Parker 已提交
318
			}
319
		}
D
Derek Parker 已提交
320
		waitCount--
321
	}
D
Derek Parker 已提交
322
	return dbp.Halt()
323 324
}

D
Derek Parker 已提交
325
func (dbp *Process) setChanRecvBreakpoints() (int, error) {
D
Derek Parker 已提交
326
	var count int
D
Derek Parker 已提交
327 328
	allg, err := dbp.GoroutinesInfo()
	if err != nil {
D
Derek Parker 已提交
329
		return 0, err
D
Derek Parker 已提交
330 331 332 333 334
	}
	for _, g := range allg {
		if g.ChanRecvBlocked() {
			ret, err := g.chanRecvReturnAddr(dbp)
			if err != nil {
335 336 337
				if _, ok := err.(NullAddrError); ok {
					continue
				}
D
Derek Parker 已提交
338
				return 0, err
D
Derek Parker 已提交
339
			}
340
			if _, err = dbp.SetTempBreakpoint(ret); err != nil {
D
Derek Parker 已提交
341
				return 0, err
D
Derek Parker 已提交
342
			}
D
Derek Parker 已提交
343
			count++
D
Derek Parker 已提交
344 345
		}
	}
D
Derek Parker 已提交
346
	return count, nil
D
Derek Parker 已提交
347 348
}

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

D
Derek Parker 已提交
385
// Single step, will execute a single instruction.
D
Derek Parker 已提交
386
func (dbp *Process) Step() (err error) {
D
Derek Parker 已提交
387 388 389 390 391
	fn := func() error {
		for _, th := range dbp.Threads {
			if th.blocked() {
				continue
			}
392
			if err := th.Step(); err != nil {
D
Derek Parker 已提交
393 394 395 396 397 398 399 400 401
				return err
			}
		}
		return nil
	}

	return dbp.run(fn)
}

402
// Change from current thread to the thread specified by `tid`.
D
Derek Parker 已提交
403
func (dbp *Process) SwitchThread(tid int) error {
404
	if th, ok := dbp.Threads[tid]; ok {
405
		dbp.CurrentThread = th
406 407 408 409 410
		return nil
	}
	return fmt.Errorf("thread %d does not exist", tid)
}

D
Derek Parker 已提交
411 412
// Returns an array of G structures representing the information
// Delve cares about from the internal runtime G structure.
D
Derek Parker 已提交
413
func (dbp *Process) GoroutinesInfo() ([]*G, error) {
414
	var (
A
aarzilli 已提交
415 416 417
		threadg = map[int]*Thread{}
		allg    []*G
		rdr     = dbp.DwarfReader()
418 419
	)

A
aarzilli 已提交
420 421 422 423
	for i := range dbp.Threads {
		if dbp.Threads[i].blocked() {
			continue
		}
A
aarzilli 已提交
424
		g, _ := dbp.Threads[i].GetG()
A
aarzilli 已提交
425 426 427 428 429
		if g != nil {
			threadg[g.Id] = dbp.Threads[i]
		}
	}

430
	addr, err := rdr.AddrFor("runtime.allglen")
431 432 433
	if err != nil {
		return nil, err
	}
434 435 436 437 438 439 440 441
	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")
442 443 444
	if err != nil {
		return nil, err
	}
445
	faddr, err := dbp.CurrentThread.readMemory(uintptr(allgentryaddr), dbp.arch.PtrSize())
446 447 448
	allgptr := binary.LittleEndian.Uint64(faddr)

	for i := uint64(0); i < allglen; i++ {
449
		g, err := parseG(dbp.CurrentThread, allgptr+(i*uint64(dbp.arch.PtrSize())), true)
450 451 452
		if err != nil {
			return nil, err
		}
A
aarzilli 已提交
453
		if thread, allocated := threadg[g.Id]; allocated {
454 455 456 457
			loc, err := thread.Location()
			if err != nil {
				return nil, err
			}
A
aarzilli 已提交
458
			g.thread = thread
459 460 461 462
			// Prefer actual thread location information.
			g.File = loc.File
			g.Line = loc.Line
			g.Func = loc.Fn
A
aarzilli 已提交
463
		}
464 465 466 467 468
		allg = append(allg, g)
	}
	return allg, nil
}

D
Derek Parker 已提交
469
// Stop all threads.
D
Derek Parker 已提交
470
func (dbp *Process) Halt() (err error) {
D
Derek Parker 已提交
471 472 473 474 475 476 477 478
	for _, th := range dbp.Threads {
		if err := th.Halt(); err != nil {
			return err
		}
	}
	return nil
}

479 480
// Obtains register values from what Delve considers to be the current
// thread of the traced process.
D
Derek Parker 已提交
481
func (dbp *Process) Registers() (Registers, error) {
482 483 484
	return dbp.CurrentThread.Registers()
}

485
// Returns the PC of the current thread.
D
Derek Parker 已提交
486
func (dbp *Process) PC() (uint64, error) {
D
Derek Parker 已提交
487
	return dbp.CurrentThread.PC()
488 489
}

490
// Returns the PC of the current thread.
D
Derek Parker 已提交
491
func (dbp *Process) CurrentBreakpoint() *Breakpoint {
492 493 494
	return dbp.CurrentThread.CurrentBreakpoint
}

495
// Returns the value of the named symbol.
D
Derek Parker 已提交
496
func (dbp *Process) EvalVariable(name string) (*Variable, error) {
497
	return dbp.CurrentThread.EvalVariable(name)
498 499
}

500
// Returns a reader for the dwarf data
D
Derek Parker 已提交
501
func (dbp *Process) DwarfReader() *reader.Reader {
502 503 504
	return reader.New(dbp.dwarf)
}

D
Derek Parker 已提交
505
// Returns list of source files that comprise the debugged binary.
D
Derek Parker 已提交
506
func (dbp *Process) Sources() map[string]*gosym.Obj {
507 508 509
	return dbp.goSymTable.Files
}

D
Derek Parker 已提交
510
// Returns list of functions present in the debugged program.
D
Derek Parker 已提交
511
func (dbp *Process) Funcs() []gosym.Func {
512 513 514
	return dbp.goSymTable.Funcs
}

D
Derek Parker 已提交
515
// Converts an instruction address to a file/line/function.
D
Derek Parker 已提交
516
func (dbp *Process) PCToLine(pc uint64) (string, int, *gosym.Func) {
517
	return dbp.goSymTable.PCToLine(pc)
518 519
}

520
// Finds the breakpoint for the given ID.
D
Derek Parker 已提交
521
func (dbp *Process) FindBreakpointByID(id int) (*Breakpoint, bool) {
522 523 524 525 526 527 528 529
	for _, bp := range dbp.Breakpoints {
		if bp.ID == id {
			return bp, true
		}
	}
	return nil, false
}

D
Derek Parker 已提交
530
// Finds the breakpoint for the given pc.
D
Derek Parker 已提交
531
func (dbp *Process) FindBreakpoint(pc uint64) (*Breakpoint, bool) {
532 533 534 535
	// 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 已提交
536
	}
537 538 539 540
	// 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 已提交
541
	if bp, ok := dbp.Breakpoints[pc]; ok {
D
Derek Parker 已提交
542 543 544 545 546
		return bp, true
	}
	return nil, false
}

D
Derek Parker 已提交
547 548
// Returns a new Process struct.
func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, error) {
D
Derek Parker 已提交
549
	if attach {
550 551
		var err error
		dbp.execPtraceFunc(func() { err = sys.PtraceAttach(dbp.Pid) })
D
Derek Parker 已提交
552 553 554
		if err != nil {
			return nil, err
		}
555
		_, _, err = wait(dbp.Pid, dbp.Pid, 0)
D
Derek Parker 已提交
556 557 558 559 560
		if err != nil {
			return nil, err
		}
	}

561
	proc, err := os.FindProcess(dbp.Pid)
D
Derek Parker 已提交
562 563 564 565 566
	if err != nil {
		return nil, err
	}

	dbp.Process = proc
567
	err = dbp.LoadInformation(path)
D
Derek Parker 已提交
568 569 570 571 572 573 574 575
	if err != nil {
		return nil, err
	}

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

576 577 578 579 580
	switch runtime.GOARCH {
	case "amd64":
		dbp.arch = AMD64Arch()
	}

581 582 583 584 585
	ver, isextld, err := dbp.getGoInformation()
	if err != nil {
		return nil, err
	}

586
	dbp.arch.SetGStructOffset(ver, isextld)
587

588
	return dbp, nil
D
Derek Parker 已提交
589
}
590

D
Derek Parker 已提交
591
func (dbp *Process) clearTempBreakpoints() error {
D
Derek Parker 已提交
592
	for _, bp := range dbp.Breakpoints {
D
Derek Parker 已提交
593 594 595
		if !bp.Temp {
			continue
		}
596
		if _, err := dbp.ClearBreakpoint(bp.Addr); err != nil {
D
Derek Parker 已提交
597 598 599 600 601
			return err
		}
	}
	return nil
}
602

D
Derek Parker 已提交
603
func (dbp *Process) handleBreakpointOnThread(id int) (*Thread, error) {
D
Derek Parker 已提交
604 605
	thread, ok := dbp.Threads[id]
	if !ok {
606
		return nil, fmt.Errorf("could not find thread for %d", id)
D
Derek Parker 已提交
607
	}
D
Derek Parker 已提交
608
	pc, err := thread.PC()
D
Derek Parker 已提交
609
	if err != nil {
610
		return nil, err
D
Derek Parker 已提交
611
	}
612 613
	// Check to see if we have hit a breakpoint.
	if bp, ok := dbp.FindBreakpoint(pc); ok {
614
		thread.CurrentBreakpoint = bp
D
Derek Parker 已提交
615 616 617 618 619 620
		if err = thread.SetPC(bp.Addr); err != nil {
			return nil, err
		}
		return thread, nil
	}
	if dbp.halt {
621
		return thread, nil
D
Derek Parker 已提交
622
	}
D
Derek Parker 已提交
623 624
	fn := dbp.goSymTable.PCToFunc(pc)
	if fn != nil && fn.Name == "runtime.breakpoint" {
625 626
		thread.singleStepping = true
		defer func() { thread.singleStepping = false }()
D
Derek Parker 已提交
627 628 629 630 631 632 633
		for i := 0; i < 2; i++ {
			if err := thread.Step(); err != nil {
				return nil, err
			}
		}
		return thread, nil
	}
D
Derek Parker 已提交
634
	return nil, NoBreakpointError{addr: pc}
D
Derek Parker 已提交
635
}
D
Derek Parker 已提交
636

D
Derek Parker 已提交
637
func (dbp *Process) run(fn func() error) error {
638
	if dbp.exited {
D
Derek Parker 已提交
639
		return fmt.Errorf("process has already exited")
640
	}
641 642 643
	for _, th := range dbp.Threads {
		th.CurrentBreakpoint = nil
	}
D
Derek Parker 已提交
644
	if err := fn(); err != nil {
D
Derek Parker 已提交
645
		return err
D
Derek Parker 已提交
646 647 648
	}
	return nil
}
649

D
Derek Parker 已提交
650
func (dbp *Process) handlePtraceFuncs() {
651 652 653 654 655 656 657 658 659 660 661
	// 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 已提交
662
func (dbp *Process) execPtraceFunc(fn func()) {
663 664 665
	dbp.ptraceChan <- fn
	<-dbp.ptraceDoneChan
}
666 667

func (dbp *Process) getGoInformation() (ver GoVersion, isextld bool, err error) {
668
	vv, err := dbp.CurrentThread.EvalPackageVariable("runtime.buildVersion")
669 670 671 672 673 674 675 676
	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)
677
		return
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
	}

	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
}