stack.go 2.2 KB
Newer Older
D
Derek Parker 已提交
1
package proc
2

3
import "encoding/binary"
4 5

// Takes an offset from RSP and returns the address of the
D
Derek Parker 已提交
6
// instruction the current function is going to return to.
D
Derek Parker 已提交
7
func (thread *Thread) ReturnAddress() (uint64, error) {
D
Derek Parker 已提交
8
	locations, err := thread.Stacktrace(2)
9 10 11
	if err != nil {
		return 0, err
	}
D
Derek Parker 已提交
12
	return locations[1].PC, nil
A
aarzilli 已提交
13 14
}

D
Derek Parker 已提交
15 16 17
// Returns the stack trace for thread.
// Note the locations in the array are return addresses not call addresses.
func (thread *Thread) Stacktrace(depth int) ([]Location, error) {
A
aarzilli 已提交
18
	regs, err := thread.Registers()
19
	if err != nil {
D
Derek Parker 已提交
20
		return nil, err
21
	}
D
Derek Parker 已提交
22
	return thread.dbp.stacktrace(regs.PC(), regs.SP(), depth)
A
aarzilli 已提交
23 24
}

D
Derek Parker 已提交
25 26 27
// Returns the stack trace for a goroutine.
// Note the locations in the array are return addresses not call addresses.
func (dbp *Process) GoroutineStacktrace(g *G, depth int) ([]Location, error) {
A
aarzilli 已提交
28 29 30
	if g.thread != nil {
		return g.thread.Stacktrace(depth)
	}
A
aarzilli 已提交
31
	locs, err := dbp.stacktrace(g.PC, g.SP, depth)
D
Derek Parker 已提交
32
	return locs, err
A
aarzilli 已提交
33 34
}

D
Derek Parker 已提交
35
func (dbp *Process) GoroutineLocation(g *G) *Location {
A
aarzilli 已提交
36 37
	f, l, fn := dbp.PCToLine(g.PC)
	return &Location{PC: g.PC, File: f, Line: l, Fn: fn}
38 39
}

40 41 42 43 44 45
type NullAddrError struct{}

func (n NullAddrError) Error() string {
	return "NULL address"
}

D
Derek Parker 已提交
46
func (dbp *Process) stacktrace(pc, sp uint64, depth int) ([]Location, error) {
47 48
	var (
		ret       = pc
49
		data      = make([]byte, dbp.arch.PtrSize())
50
		btoffset  int64
A
aarzilli 已提交
51
		locations []Location
52 53
		retaddr   uintptr
	)
D
Derek Parker 已提交
54 55
	f, l, fn := dbp.PCToLine(pc)
	locations = append(locations, Location{PC: pc, File: f, Line: l, Fn: fn})
56 57 58 59 60 61
	for i := int64(0); i < int64(depth); i++ {
		fde, err := dbp.frameEntries.FDEForPC(ret)
		if err != nil {
			return nil, err
		}
		btoffset += fde.ReturnAddressOffset(ret)
62
		retaddr = uintptr(int64(sp) + btoffset + (i * int64(dbp.arch.PtrSize())))
63 64 65
		if retaddr == 0 {
			return nil, NullAddrError{}
		}
66 67 68 69 70
		_, err = readMemory(dbp.CurrentThread, retaddr, data)
		if err != nil {
			return nil, err
		}
		ret = binary.LittleEndian.Uint64(data)
A
aarzilli 已提交
71 72 73
		if ret <= 0 {
			break
		}
D
Derek Parker 已提交
74
		f, l, fn = dbp.goSymTable.PCToLine(ret)
A
aarzilli 已提交
75 76 77 78
		locations = append(locations, Location{PC: ret, File: f, Line: l, Fn: fn})
		if fn != nil && fn.Name == "runtime.goexit" {
			break
		}
79 80 81
	}
	return locations, nil
}