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

3
import (
4
	"debug/dwarf"
5
	"errors"
6
	"fmt"
D
Derek Parker 已提交
7

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

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

const runtimeStackBarrier = "runtime.stackBarrier"

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

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

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

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

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

// 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 已提交
77
	}
A
aarzilli 已提交
78
	return it.stacktrace(depth)
A
aarzilli 已提交
79 80
}

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

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

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

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

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

type savedLR struct {
	ptr uint64
	val uint64
}

113
func newStackIterator(bi *BinaryInfo, mem MemoryReadWriter, regs op.DwarfRegisters, stackhi uint64, stkbar []savedLR, stkbarPos int) *stackIterator {
114
	stackBarrierFunc := bi.LookupFunc[runtimeStackBarrier] // stack barriers were removed in Go 1.9
115 116 117
	var stackBarrierPC uint64
	if stackBarrierFunc != nil && stkbar != nil {
		stackBarrierPC = stackBarrierFunc.Entry
118
		fn := bi.PCToFunc(regs.PC())
A
Alessandro Arzilli 已提交
119 120 121
		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.
122
			if len(stkbar) > 0 && stkbar[stkbarPos].ptr < regs.SP() {
A
Alessandro Arzilli 已提交
123
				// runtime.stackBarrier has not incremented stkbarPos.
124
			} else if stkbarPos > 0 && stkbar[stkbarPos-1].ptr < regs.SP() {
A
Alessandro Arzilli 已提交
125 126 127
				// runtime.stackBarrier has incremented stkbarPos.
				stkbarPos--
			} else {
128
				return &stackIterator{err: fmt.Errorf("failed to unwind through stackBarrier at SP %x", regs.SP())}
A
Alessandro Arzilli 已提交
129 130 131 132
			}
		}
		stkbar = stkbar[stkbarPos:]
	}
133
	return &stackIterator{pc: regs.PC(), regs: regs, top: true, bi: bi, mem: mem, err: nil, atend: false, stackhi: stackhi, stackBarrierPC: stackBarrierPC, stkbar: stkbar}
134 135
}

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

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

	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:]
	}

155
	// Look for "top of stack" functions.
156
	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") {
157 158 159 160 161 162
		it.atend = true
		return true
	}

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

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

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

177 178 179 180 181 182 183 184 185 186 187 188 189
// frameBase calculates the frame base pseudo-register for DWARF for fn and
// the current frame.
func (it *stackIterator) frameBase(fn *Function) int64 {
	rdr := it.bi.dwarf.Reader()
	rdr.Seek(fn.offset)
	e, err := rdr.Next()
	if err != nil {
		return 0
	}
	fb, _, _ := it.bi.Location(e, dwarf.AttrFrameBase, it.pc, it.regs)
	return fb
}

190
func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe {
191
	if retaddr == 0 {
192 193
		it.err = NullAddrError{}
		return Stackframe{}
194
	}
195 196 197 198
	f, l, fn := it.bi.PCToLine(it.pc)
	if fn == nil {
		f = "?"
		l = -1
199 200
	} else {
		it.regs.FrameBase = it.frameBase(fn)
201
	}
202 203 204 205 206 207 208
	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
		}
209
		r.Call.PC = r.Current.PC
210 211 212
	} else {
		r.Call = r.Current
	}
213
	return r
214 215
}

A
aarzilli 已提交
216
func (it *stackIterator) stacktrace(depth int) ([]Stackframe, error) {
217 218 219
	if depth < 0 {
		return nil, errors.New("negative maximum stack depth")
	}
220
	frames := make([]Stackframe, 0, depth+1)
221 222 223
	for it.Next() {
		frames = append(frames, it.Frame())
		if len(frames) >= depth+1 {
A
aarzilli 已提交
224 225
			break
		}
226 227
	}
	if err := it.Err(); err != nil {
228 229 230 231
		if len(frames) == 0 {
			return nil, err
		}
		frames = append(frames, Stackframe{Err: err})
232
	}
233
	return frames, nil
234
}
235 236 237 238

// advanceRegs calculates it.callFrameRegs using it.regs and the frame
// descriptor entry for the current stack frame.
// it.regs.CallFrameCFA is updated.
239
func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uint64, retaddr uint64) {
240 241 242 243 244 245 246 247 248 249 250
	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)
251
		return op.DwarfRegisters{}, 0, 0
252 253 254
	}
	it.regs.CFA = int64(cfareg.Uint64Val)

255
	callFrameRegs = op.DwarfRegisters{ByteOrder: it.regs.ByteOrder, PCRegNum: it.regs.PCRegNum, SPRegNum: it.regs.SPRegNum}
256 257 258 259 260 261 262 263

	// 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
264
	callFrameRegs.AddReg(uint64(amd64DwarfSPRegNum), cfareg)
265 266 267

	for i, regRule := range framectx.Regs {
		reg, err := it.executeFrameRegRule(i, regRule, it.regs.CFA)
268
		callFrameRegs.AddReg(i, reg)
269 270 271 272 273 274 275 276 277 278 279 280 281
		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)
		}
	}

282
	return callFrameRegs, ret, retaddr
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
}

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:
300
		v, _, err := op.ExecuteStackProgram(it.regs, rule.Expression)
301 302 303 304 305
		if err != nil {
			return nil, err
		}
		return it.readRegisterAt(regnum, uint64(v))
	case frame.RuleValExpression:
306
		v, _, err := op.ExecuteStackProgram(it.regs, rule.Expression)
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
		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
}