parser.go 3.6 KB
Newer Older
D
Derek Parker 已提交
1 2 3 4 5 6 7 8
// Package frame contains data structures and
// related functions for parsing and searching
// through Dwarf .debug_frame data.
package frame

import (
	"bytes"
	"encoding/binary"
9

10
	"github.com/go-delve/delve/pkg/dwarf/util"
D
Derek Parker 已提交
11 12
)

13
type parsefunc func(*parseContext) parsefunc
D
Derek Parker 已提交
14 15

type parseContext struct {
16 17
	staticBase uint64

18 19 20 21 22
	buf     *bytes.Buffer
	entries FrameDescriptionEntries
	common  *CommonInformationEntry
	frame   *FrameDescriptionEntry
	length  uint32
23
	ptrSize int
D
Derek Parker 已提交
24
}
D
Derek Parker 已提交
25

H
hitzhangjie 已提交
26 27 28
// Parse takes in data (a byte slice) and returns FrameDescriptionEntries,
// which is a slice of FrameDescriptionEntry. Each FrameDescriptionEntry
// has a pointer to CommonInformationEntry.
29
func Parse(data []byte, order binary.ByteOrder, staticBase uint64, ptrSize int) FrameDescriptionEntries {
D
Derek Parker 已提交
30
	var (
31
		buf  = bytes.NewBuffer(data)
32
		pctx = &parseContext{buf: buf, entries: newFrameIndex(), staticBase: staticBase, ptrSize: ptrSize}
D
Derek Parker 已提交
33 34
	)

35
	for fn := parselength; buf.Len() != 0; {
36
		fn = fn(pctx)
D
Derek Parker 已提交
37 38
	}

39 40 41 42
	for i := range pctx.entries {
		pctx.entries[i].order = order
	}

43
	return pctx.entries
D
Derek Parker 已提交
44 45 46 47 48 49
}

func cieEntry(data []byte) bool {
	return bytes.Equal(data, []byte{0xff, 0xff, 0xff, 0xff})
}

50
func parselength(ctx *parseContext) parsefunc {
51
	binary.Read(ctx.buf, binary.LittleEndian, &ctx.length)
52

53 54 55 56 57 58 59 60
	if ctx.length == 0 {
		// ZERO terminator
		return parselength
	}

	var data = ctx.buf.Next(4)

	ctx.length -= 4 // take off the length of the CIE id / CIE pointer.
D
Derek Parker 已提交
61

62
	if cieEntry(data) {
63
		ctx.common = &CommonInformationEntry{Length: ctx.length, staticBase: ctx.staticBase}
D
Derek Parker 已提交
64
		return parseCIE
D
Derek Parker 已提交
65 66
	}

67
	ctx.frame = &FrameDescriptionEntry{Length: ctx.length, CIE: ctx.common}
D
Derek Parker 已提交
68
	return parseFDE
D
Derek Parker 已提交
69 70
}

D
Derek Parker 已提交
71
func parseFDE(ctx *parseContext) parsefunc {
72
	var num uint64
73
	r := ctx.buf.Next(int(ctx.length))
D
Derek Parker 已提交
74

75 76 77 78 79
	reader := bytes.NewReader(r)
	num, _ = util.ReadUintRaw(reader, binary.LittleEndian, ctx.ptrSize)
	ctx.frame.begin = num + ctx.staticBase
	num, _ = util.ReadUintRaw(reader, binary.LittleEndian, ctx.ptrSize)
	ctx.frame.size = num
D
Derek Parker 已提交
80

81 82
	// Insert into the tree after setting address range begin
	// otherwise compares won't work.
83
	ctx.entries = append(ctx.entries, ctx.frame)
84

D
Derek Parker 已提交
85 86 87
	// The rest of this entry consists of the instructions
	// so we can just grab all of the data from the buffer
	// cursor to length.
88
	ctx.frame.Instructions = r[2*ctx.ptrSize:]
89
	ctx.length = 0
D
Derek Parker 已提交
90

91
	return parselength
D
Derek Parker 已提交
92 93
}

D
Derek Parker 已提交
94
func parseCIE(ctx *parseContext) parsefunc {
95
	data := ctx.buf.Next(int(ctx.length))
D
Derek Parker 已提交
96 97
	buf := bytes.NewBuffer(data)
	// parse version
98
	ctx.common.Version, _ = buf.ReadByte()
D
Derek Parker 已提交
99

D
Derek Parker 已提交
100
	// parse augmentation
101
	ctx.common.Augmentation, _ = util.ParseString(buf)
D
Derek Parker 已提交
102

D
Derek Parker 已提交
103
	// parse code alignment factor
104
	ctx.common.CodeAlignmentFactor, _ = util.DecodeULEB128(buf)
D
Derek Parker 已提交
105

D
Derek Parker 已提交
106
	// parse data alignment factor
107
	ctx.common.DataAlignmentFactor, _ = util.DecodeSLEB128(buf)
D
Derek Parker 已提交
108

D
Derek Parker 已提交
109
	// parse return address register
110
	ctx.common.ReturnAddressRegister, _ = util.DecodeULEB128(buf)
D
Derek Parker 已提交
111

D
Derek Parker 已提交
112
	// parse initial instructions
D
Derek Parker 已提交
113 114 115
	// The rest of this entry consists of the instructions
	// so we can just grab all of the data from the buffer
	// cursor to length.
116 117
	ctx.common.InitialInstructions = buf.Bytes() //ctx.buf.Next(int(ctx.length))
	ctx.length = 0
D
Derek Parker 已提交
118

119
	return parselength
D
Derek Parker 已提交
120
}
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

// DwarfEndian determines the endianness of the DWARF by using the version number field in the debug_info section
// Trick borrowed from "debug/dwarf".New()
func DwarfEndian(infoSec []byte) binary.ByteOrder {
	if len(infoSec) < 6 {
		return binary.BigEndian
	}
	x, y := infoSec[4], infoSec[5]
	switch {
	case x == 0 && y == 0:
		return binary.BigEndian
	case x == 0:
		return binary.BigEndian
	case y == 0:
		return binary.LittleEndian
	default:
		return binary.BigEndian
	}
}