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

3
import (
4
	"errors"
5
	"fmt"
D
Derek Parker 已提交
6

D
Derek Parker 已提交
7
	"github.com/derekparker/delve/pkg/dwarf/frame"
8
	"github.com/derekparker/delve/pkg/dwarf/op"
9
)
10

A
Alessandro Arzilli 已提交
11 12 13 14 15
// This code is partly adaped from runtime.gentraceback in
// $GOROOT/src/runtime/traceback.go

const runtimeStackBarrier = "runtime.stackBarrier"

D
Derek Parker 已提交
16
// NoReturnAddr is returned when return address
N
Nan Xiao 已提交
17
// could not be found during stack trace.
18
type NoReturnAddr struct {
19
	Fn string
20 21 22
}

func (nra NoReturnAddr) Error() string {
23
	return fmt.Sprintf("could not find return address for %s", nra.Fn)
24 25
}

D
Derek Parker 已提交
26
// Stackframe represents a frame in a system stack.
27
type Stackframe struct {
28
	// Address the function above this one on the call stack will return to.
29 30 31
	Current Location
	// Address of the call instruction for the function above on the call stack.
	Call Location
32 33
	// Frame registers.
	Regs op.DwarfRegisters
34 35
	// High address of the stack.
	StackHi uint64
36
	// Return address for this stack frame (as read from the stack frame itself).
37
	Ret uint64
A
Alessandro Arzilli 已提交
38 39
	// Address to the memory location containing the return address
	addrret uint64
40 41
	// Err is set if an error occoured during stacktrace
	Err error
42 43
}

44
// ThreadStacktrace returns the stack trace for thread.
D
Derek Parker 已提交
45
// Note the locations in the array are return addresses not call addresses.
46
func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) {
47
	regs, err := thread.Registers(true)
48
	if err != nil {
D
Derek Parker 已提交
49
		return nil, err
50
	}
51
	it := newStackIterator(thread.BinInfo(), thread, thread.BinInfo().Arch.RegistersToDwarfRegisters(regs), 0, nil, -1)
A
aarzilli 已提交
52
	return it.stacktrace(depth)
A
aarzilli 已提交
53 54
}

A
aarzilli 已提交
55
func (g *G) stackIterator() (*stackIterator, error) {
A
Alessandro Arzilli 已提交
56 57 58 59
	stkbar, err := g.stkbar()
	if err != nil {
		return nil, err
	}
60
	if g.Thread != nil {
61
		regs, err := g.Thread.Registers(true)
62 63 64
		if err != nil {
			return nil, err
		}
65
		return newStackIterator(g.variable.bi, g.Thread, g.variable.bi.Arch.RegistersToDwarfRegisters(regs), g.stackhi, stkbar, g.stkbarPos), nil
A
aarzilli 已提交
66
	}
67
	return newStackIterator(g.variable.bi, g.variable.mem, g.variable.bi.Arch.GoroutineToDwarfRegisters(g), g.stackhi, stkbar, g.stkbarPos), nil
A
aarzilli 已提交
68 69 70 71 72 73 74 75
}

// Stacktrace returns the stack trace for a goroutine.
// Note the locations in the array are return addresses not call addresses.
func (g *G) Stacktrace(depth int) ([]Stackframe, error) {
	it, err := g.stackIterator()
	if err != nil {
		return nil, err
A
aarzilli 已提交
76
	}
A
aarzilli 已提交
77
	return it.stacktrace(depth)
A
aarzilli 已提交
78 79
}

D
Derek Parker 已提交
80
// NullAddrError is an error for a null address.
81 82 83 84 85 86
type NullAddrError struct{}

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

A
aarzilli 已提交
87
// stackIterator holds information
D
Derek Parker 已提交
88 89
// required to iterate and walk the program
// stack.
A
aarzilli 已提交
90
type stackIterator struct {
91 92 93 94 95 96 97
	pc    uint64
	top   bool
	atend bool
	frame Stackframe
	bi    *BinaryInfo
	mem   MemoryReadWriter
	err   error
98

99
	stackhi        uint64
A
Alessandro Arzilli 已提交
100 101
	stackBarrierPC uint64
	stkbar         []savedLR
102

103 104
	// regs is the register set for the current frame
	regs op.DwarfRegisters
A
Alessandro Arzilli 已提交
105 106 107 108 109 110 111
}

type savedLR struct {
	ptr uint64
	val uint64
}

112
func newStackIterator(bi *BinaryInfo, mem MemoryReadWriter, regs op.DwarfRegisters, stackhi uint64, stkbar []savedLR, stkbarPos int) *stackIterator {
113
	stackBarrierFunc := bi.LookupFunc[runtimeStackBarrier] // stack barriers were removed in Go 1.9
114 115 116
	var stackBarrierPC uint64
	if stackBarrierFunc != nil && stkbar != nil {
		stackBarrierPC = stackBarrierFunc.Entry
117
		fn := bi.PCToFunc(regs.PC())
A
Alessandro Arzilli 已提交
118 119 120
		if fn != nil && fn.Name == runtimeStackBarrier {
			// We caught the goroutine as it's executing the stack barrier, we must
			// determine whether or not g.stackPos has already been incremented or not.
121
			if len(stkbar) > 0 && stkbar[stkbarPos].ptr < regs.SP() {
A
Alessandro Arzilli 已提交
122
				// runtime.stackBarrier has not incremented stkbarPos.
123
			} else if stkbarPos > 0 && stkbar[stkbarPos-1].ptr < regs.SP() {
A
Alessandro Arzilli 已提交
124 125 126
				// runtime.stackBarrier has incremented stkbarPos.
				stkbarPos--
			} else {
127
				return &stackIterator{err: fmt.Errorf("failed to unwind through stackBarrier at SP %x", regs.SP())}
A
Alessandro Arzilli 已提交
128 129 130 131
			}
		}
		stkbar = stkbar[stkbarPos:]
	}
132
	return &stackIterator{pc: regs.PC(), regs: regs, top: true, bi: bi, mem: mem, err: nil, atend: false, stackhi: stackhi, stackBarrierPC: stackBarrierPC, stkbar: stkbar}
133 134
}

D
Derek Parker 已提交
135
// Next points the iterator to the next stack frame.
A
aarzilli 已提交
136
func (it *stackIterator) Next() bool {
137 138 139
	if it.err != nil || it.atend {
		return false
	}
140
	callFrameRegs, ret, retaddr := it.advanceRegs()
141
	it.frame = it.newStackframe(ret, retaddr)
142 143 144 145 146

	if it.frame.Ret <= 0 {
		it.atend = true
		return true
	}
A
Alessandro Arzilli 已提交
147 148 149 150 151 152 153

	if it.stkbar != nil && it.frame.Ret == it.stackBarrierPC && it.frame.addrret == it.stkbar[0].ptr {
		// Skip stack barrier frames
		it.frame.Ret = it.stkbar[0].val
		it.stkbar = it.stkbar[1:]
	}

154
	// Look for "top of stack" functions.
155
	if it.frame.Current.Fn != nil && (it.frame.Current.Fn.Name == "runtime.goexit" || it.frame.Current.Fn.Name == "runtime.rt0_go" || it.frame.Current.Fn.Name == "runtime.mcall") {
156 157 158 159 160 161
		it.atend = true
		return true
	}

	it.top = false
	it.pc = it.frame.Ret
162
	it.regs = callFrameRegs
163 164 165
	return true
}

D
Derek Parker 已提交
166
// Frame returns the frame the iterator is pointing at.
A
aarzilli 已提交
167
func (it *stackIterator) Frame() Stackframe {
168 169 170
	return it.frame
}

D
Derek Parker 已提交
171
// Err returns the error encountered during stack iteration.
A
aarzilli 已提交
172
func (it *stackIterator) Err() error {
173 174 175
	return it.err
}

176
func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe {
177
	if retaddr == 0 {
178 179
		it.err = NullAddrError{}
		return Stackframe{}
180
	}
181 182 183 184
	f, l, fn := it.bi.PCToLine(it.pc)
	if fn == nil {
		f = "?"
		l = -1
185
	}
186 187 188 189 190 191 192
	r := Stackframe{Current: Location{PC: it.pc, File: f, Line: l, Fn: fn}, Regs: it.regs, Ret: ret, addrret: retaddr, StackHi: it.stackhi}
	if !it.top {
		r.Call.File, r.Call.Line, r.Call.Fn = it.bi.PCToLine(it.pc - 1)
		if r.Call.Fn == nil {
			r.Call.File = "?"
			r.Call.Line = -1
		}
193
		r.Call.PC = r.Current.PC
194 195 196
	} else {
		r.Call = r.Current
	}
197
	return r
198 199
}

A
aarzilli 已提交
200
func (it *stackIterator) stacktrace(depth int) ([]Stackframe, error) {
201 202 203
	if depth < 0 {
		return nil, errors.New("negative maximum stack depth")
	}
204
	frames := make([]Stackframe, 0, depth+1)
205 206 207
	for it.Next() {
		frames = append(frames, it.Frame())
		if len(frames) >= depth+1 {
A
aarzilli 已提交
208 209
			break
		}
210 211
	}
	if err := it.Err(); err != nil {
212 213 214 215
		if len(frames) == 0 {
			return nil, err
		}
		frames = append(frames, Stackframe{Err: err})
216
	}
217
	return frames, nil
218
}
219 220 221 222

// advanceRegs calculates it.callFrameRegs using it.regs and the frame
// descriptor entry for the current stack frame.
// it.regs.CallFrameCFA is updated.
223
func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uint64, retaddr uint64) {
224 225 226 227 228 229 230 231 232 233 234
	fde, err := it.bi.frameEntries.FDEForPC(it.pc)
	var framectx *frame.FrameContext
	if _, nofde := err.(*frame.NoFDEForPCError); nofde {
		framectx = it.bi.Arch.FixFrameUnwindContext(nil)
	} else {
		framectx = it.bi.Arch.FixFrameUnwindContext(fde.EstablishFrame(it.pc))
	}

	cfareg, err := it.executeFrameRegRule(0, framectx.CFA, 0)
	if cfareg == nil {
		it.err = fmt.Errorf("CFA becomes undefined at PC %#x", it.pc)
235
		return op.DwarfRegisters{}, 0, 0
236 237 238
	}
	it.regs.CFA = int64(cfareg.Uint64Val)

239
	callFrameRegs = op.DwarfRegisters{ByteOrder: it.regs.ByteOrder, PCRegNum: it.regs.PCRegNum, SPRegNum: it.regs.SPRegNum}
240 241 242 243 244 245 246 247

	// According to the standard the compiler should be responsible for emitting
	// rules for the RSP register so that it can then be used to calculate CFA,
	// however neither Go nor GCC do this.
	// In the following line we copy GDB's behaviour by assuming this is
	// implicit.
	// See also the comment in dwarf2_frame_default_init in
	// $GDB_SOURCE/dwarf2-frame.c
248
	callFrameRegs.AddReg(uint64(amd64DwarfSPRegNum), cfareg)
249 250 251

	for i, regRule := range framectx.Regs {
		reg, err := it.executeFrameRegRule(i, regRule, it.regs.CFA)
252
		callFrameRegs.AddReg(i, reg)
253 254 255 256 257 258 259 260 261 262 263 264 265
		if i == framectx.RetAddrReg {
			if reg == nil {
				if err == nil {
					err = fmt.Errorf("Undefined return address at %#x", it.pc)
				}
				it.err = err
			} else {
				ret = reg.Uint64Val
			}
			retaddr = uint64(it.regs.CFA + regRule.Offset)
		}
	}

266
	return callFrameRegs, ret, retaddr
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
}

func (it *stackIterator) executeFrameRegRule(regnum uint64, rule frame.DWRule, cfa int64) (*op.DwarfRegister, error) {
	switch rule.Rule {
	default:
		fallthrough
	case frame.RuleUndefined:
		return nil, nil
	case frame.RuleSameVal:
		return it.regs.Reg(regnum), nil
	case frame.RuleOffset:
		return it.readRegisterAt(regnum, uint64(cfa+rule.Offset))
	case frame.RuleValOffset:
		return op.DwarfRegisterFromUint64(uint64(cfa + rule.Offset)), nil
	case frame.RuleRegister:
		return it.regs.Reg(rule.Reg), nil
	case frame.RuleExpression:
		v, err := op.ExecuteStackProgram(it.regs, rule.Expression)
		if err != nil {
			return nil, err
		}
		return it.readRegisterAt(regnum, uint64(v))
	case frame.RuleValExpression:
		v, err := op.ExecuteStackProgram(it.regs, rule.Expression)
		if err != nil {
			return nil, err
		}
		return op.DwarfRegisterFromUint64(uint64(v)), nil
	case frame.RuleArchitectural:
		return nil, errors.New("architectural frame rules are unsupported")
	case frame.RuleCFA:
		if it.regs.Reg(rule.Reg) == nil {
			return nil, nil
		}
		return op.DwarfRegisterFromUint64(uint64(int64(it.regs.Uint64Val(rule.Reg)) + rule.Offset)), nil
	case frame.RuleRegOffset:
		if it.regs.Reg(rule.Reg) == nil {
			return nil, nil
		}
		return it.readRegisterAt(regnum, uint64(int64(it.regs.Uint64Val(rule.Reg))+rule.Offset))
	}
}

func (it *stackIterator) readRegisterAt(regnum uint64, addr uint64) (*op.DwarfRegister, error) {
	buf := make([]byte, it.bi.Arch.RegSize(regnum))
	_, err := it.mem.ReadMemory(buf, uintptr(addr))
	if err != nil {
		return nil, err
	}
	return op.DwarfRegisterFromBytes(buf), nil
}