-
Notifications
You must be signed in to change notification settings - Fork 229
/
stackdeltatypes.go
148 lines (127 loc) · 5.34 KB
/
stackdeltatypes.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Apache License 2.0.
* See the file "LICENSE" for details.
*/
// Package stackdeltatypes provides types used to represent stack delta information as constructed
// by `nativeunwind.GetIntervalStructures` This information is a post-processed form of the
// stack delta information that is used in all relevant packages.
package stackdeltatypes
// #include "../../../support/ebpf/stackdeltatypes.h"
import "C"
const (
// ABI is the current binary compatibility version. It is incremented
// if struct IntervalData, struct StackDelta or the meaning of their contents
// changes, and can be used to determine if the data is compatible
ABI = 15
// MinimumGap determines the minimum number of alignment bytes needed
// in order to keep the created STOP stack delta between functions
MinimumGap = 15
// UnwindOpcodes from the C header file
UnwindOpcodeCommand uint8 = C.UNWIND_OPCODE_COMMAND
UnwindOpcodeBaseCFA uint8 = C.UNWIND_OPCODE_BASE_CFA
UnwindOpcodeBaseSP uint8 = C.UNWIND_OPCODE_BASE_SP
UnwindOpcodeBaseFP uint8 = C.UNWIND_OPCODE_BASE_FP
UnwindOpcodeBaseLR uint8 = C.UNWIND_OPCODE_BASE_LR
UnwindOpcodeFlagDeref uint8 = C.UNWIND_OPCODEF_DEREF
// UnwindCommands from the C header file
UnwindCommandInvalid int32 = C.UNWIND_COMMAND_INVALID
UnwindCommandStop int32 = C.UNWIND_COMMAND_STOP
UnwindCommandPLT int32 = C.UNWIND_COMMAND_PLT
UnwindCommandSignal int32 = C.UNWIND_COMMAND_SIGNAL
// UnwindDeref handling from the C header file
UnwindDerefMask int32 = C.UNWIND_DEREF_MASK
UnwindDerefMultiplier int32 = C.UNWIND_DEREF_MULTIPLIER
// UnwindHintNone indicates that no flags are set.
UnwindHintNone uint8 = 0
// UnwindHintKeep flags important intervals that should not be removed
// (e.g. has CALL/SYSCALL assembly opcode, or is part of function prologue)
UnwindHintKeep uint8 = 1
// UnwindHintGap indicates that the delta marks function end
UnwindHintGap uint8 = 4
)
// UnwindInfo contains the data needed to unwind PC, SP and FP
type UnwindInfo struct {
Opcode, FPOpcode, MergeOpcode uint8
Param, FPParam int32
}
// UnwindInfoInvalid is the stack delta info indicating invalid or unsupported PC.
var UnwindInfoInvalid = UnwindInfo{Opcode: UnwindOpcodeCommand, Param: UnwindCommandInvalid}
// UnwindInfoStop is the stack delta info indicating root function of a stack.
var UnwindInfoStop = UnwindInfo{Opcode: UnwindOpcodeCommand, Param: UnwindCommandStop}
// UnwindInfoSignal is the stack delta info indicating signal return frame.
var UnwindInfoSignal = UnwindInfo{Opcode: UnwindOpcodeCommand, Param: UnwindCommandSignal}
// UnwindInfoFramePointer contains the description to unwind a frame with valid frame pointer.
var UnwindInfoFramePointer = UnwindInfo{
Opcode: UnwindOpcodeBaseFP,
Param: 16,
FPOpcode: UnwindOpcodeBaseCFA,
FPParam: -16,
}
// StackDelta defines the start address for the delta interval, along with
// the unwind information.
type StackDelta struct {
Address uint64
Hints uint8
Info UnwindInfo
}
// StackDeltaArray defines an address space where consecutive entries establish
// intervals for the stack deltas
type StackDeltaArray []StackDelta
// IntervalData contains everything that a userspace agent needs to have
// to populate eBPF maps for the kernel-space native unwinder to do its job:
type IntervalData struct {
// Deltas contains all stack deltas for a single binary.
// Two consecutive entries describe an interval.
Deltas StackDeltaArray
}
// AddEx adds a new stack delta to the array.
func (deltas *StackDeltaArray) AddEx(delta StackDelta, sorted bool) {
num := len(*deltas)
if delta.Info.Opcode == UnwindOpcodeCommand {
// FP information is invalid/unused for command opcodes.
// But DWARF info often leaves bogus data there, so resetting it
// reduces the number of unique Info contents generated.
delta.Info.FPOpcode = UnwindOpcodeCommand
delta.Info.FPParam = UnwindCommandInvalid
}
if num > 0 && sorted {
prev := &(*deltas)[num-1]
if prev.Hints&UnwindHintGap != 0 && prev.Address+MinimumGap >= delta.Address {
// The previous opcode is end-of-function marker, and
// the gap is not large. Reduce deltas by overwriting it.
if num <= 1 || (*deltas)[num-2].Info != delta.Info {
*prev = delta
return
}
// The delta before end-of-function marker is same as
// what is being inserted now. Overwrite that.
prev = &(*deltas)[num-2]
*deltas = (*deltas)[:num-1]
}
if prev.Info == delta.Info {
prev.Hints |= delta.Hints & UnwindHintKeep
return
}
if prev.Address == delta.Address {
*prev = delta
return
}
}
*deltas = append(*deltas, delta)
}
// Add adds a new stack delta from a sorted source.
func (deltas *StackDeltaArray) Add(delta StackDelta) {
deltas.AddEx(delta, true)
}
// PackDerefParam compresses pre- and post-dereference parameters to single value
func PackDerefParam(preDeref, postDeref int32) (int32, bool) {
if postDeref < 0 || postDeref > 0x20 || postDeref%UnwindDerefMultiplier != 0 {
return 0, false
}
return preDeref + postDeref/UnwindDerefMultiplier, true
}
// UnpackDerefParam splits the pre- and post-dereference parameters from single value
func UnpackDerefParam(param int32) (preDeref, postDeref int32) {
return param &^ UnwindDerefMask, (param & UnwindDerefMask) * UnwindDerefMultiplier
}