github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/emulator/registers.go (about) 1 package emulator 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/dylandreimerink/gobpfld/ebpf" 8 ) 9 10 // Registers the registers of the eBPF VM 11 // https://github.com/torvalds/linux/blob/master/Documentation/bpf/instruction-set.rst#Registers-and-calling-convention 12 // 13 // R0 - R5 are scratch Registers and eBPF programs needs to spill/fill them if necessary across calls. 14 type Registers struct { 15 // Program counter, keeps track of which instruction to execute next, can't be read, only be modified 16 // via branching instructions. 17 PC int 18 // Program index, keeps track of which program we are executing. 19 PI int 20 // Stack frame number of the current stack frame, increments when we tailcall or do a bpf-to-bpf function call 21 // and decrements after we return from a bpf-to-bpf function call. 22 SF int 23 24 // return value from function calls, and exit value for eBPF programs 25 R0 RegisterValue 26 27 // arguments for function calls 28 R1 RegisterValue 29 R2 RegisterValue 30 R3 RegisterValue 31 R4 RegisterValue 32 R5 RegisterValue 33 34 // callee saved registers that function calls will preserve 35 R6 RegisterValue 36 R7 RegisterValue 37 R8 RegisterValue 38 R9 RegisterValue 39 40 // read-only frame pointer to access stack 41 R10 FramePointer 42 } 43 44 func (r *Registers) Clone() Registers { 45 return Registers{ 46 PC: r.PC, 47 SF: r.SF, 48 R0: r.R0.Clone(), 49 R1: r.R1.Clone(), 50 R2: r.R2.Clone(), 51 R3: r.R3.Clone(), 52 R4: r.R4.Clone(), 53 R5: r.R5.Clone(), 54 R6: r.R6.Clone(), 55 R7: r.R7.Clone(), 56 R8: r.R8.Clone(), 57 R9: r.R9.Clone(), 58 R10: *r.R10.Clone().(*FramePointer), 59 } 60 } 61 62 func (r *Registers) Copy(reg ebpf.Register) (RegisterValue, error) { 63 switch reg { 64 case ebpf.BPF_REG_0: 65 return r.R0.Copy(), nil 66 case ebpf.BPF_REG_1: 67 return r.R1.Copy(), nil 68 case ebpf.BPF_REG_2: 69 return r.R2.Copy(), nil 70 case ebpf.BPF_REG_3: 71 return r.R3.Copy(), nil 72 case ebpf.BPF_REG_4: 73 return r.R4.Copy(), nil 74 case ebpf.BPF_REG_5: 75 return r.R5.Copy(), nil 76 case ebpf.BPF_REG_6: 77 return r.R6.Copy(), nil 78 case ebpf.BPF_REG_7: 79 return r.R7.Copy(), nil 80 case ebpf.BPF_REG_8: 81 return r.R8.Copy(), nil 82 case ebpf.BPF_REG_9: 83 return r.R9.Copy(), nil 84 case ebpf.BPF_REG_10: 85 return r.R10.Copy(), nil 86 } 87 88 return nil, fmt.Errorf("unknown register '%d'", reg) 89 } 90 91 func (r *Registers) Get(reg ebpf.Register) (RegisterValue, error) { 92 switch reg { 93 case ebpf.BPF_REG_0: 94 return r.R0, nil 95 case ebpf.BPF_REG_1: 96 return r.R1, nil 97 case ebpf.BPF_REG_2: 98 return r.R2, nil 99 case ebpf.BPF_REG_3: 100 return r.R3, nil 101 case ebpf.BPF_REG_4: 102 return r.R4, nil 103 case ebpf.BPF_REG_5: 104 return r.R5, nil 105 case ebpf.BPF_REG_6: 106 return r.R6, nil 107 case ebpf.BPF_REG_7: 108 return r.R7, nil 109 case ebpf.BPF_REG_8: 110 return r.R8, nil 111 case ebpf.BPF_REG_9: 112 return r.R9, nil 113 } 114 115 return nil, fmt.Errorf("unknown register '%d'", reg) 116 } 117 118 // Assign is used to assign a value to a register directly 119 func (r *Registers) Assign(reg ebpf.Register, value RegisterValue) error { 120 switch reg { 121 case ebpf.BPF_REG_0: 122 r.R0 = value 123 case ebpf.BPF_REG_1: 124 r.R1 = value 125 case ebpf.BPF_REG_2: 126 r.R2 = value 127 case ebpf.BPF_REG_3: 128 r.R3 = value 129 case ebpf.BPF_REG_4: 130 r.R4 = value 131 case ebpf.BPF_REG_5: 132 r.R5 = value 133 case ebpf.BPF_REG_6: 134 r.R6 = value 135 case ebpf.BPF_REG_7: 136 r.R7 = value 137 case ebpf.BPF_REG_8: 138 r.R8 = value 139 case ebpf.BPF_REG_9: 140 r.R9 = value 141 // REG_10 is missing on purpose, it can't be modified by assinging it a value. 142 // It is only changed on tail calls an bpf-to-bpf function calls. Such changes are preformed by the instructions 143 // directly instread of using this helper 144 default: 145 return fmt.Errorf("Can't assign register '%d'", reg) 146 } 147 148 return nil 149 } 150 151 // RegisterValue represents the contents of a single register. Depending on the implementation a register type might 152 // carry additional information which is not directly accessible to the eBPF program. The additional type information 153 // is created and changed depending on where he eBPF program gets the value and what it does with it. 154 type RegisterValue interface { 155 // Value returns the integer value of the register 156 Value() int64 157 // Copy returns a copy of the register. 158 // A copy can have different properties, like being modifyable while the original was not, the stack pointer for 159 // example. 160 Copy() RegisterValue 161 // Clone makes an exact copy of the register, with no differences. 162 Clone() RegisterValue 163 Assign(int64) error 164 String() string 165 } 166 167 // PointerValue is a type of RegisterValue which can be dereferenced. 168 type PointerValue interface { 169 // Dereferences the pointer and returns the value of given size at the memory location + additional offset 170 Deref(offset int, size ebpf.Size) (RegisterValue, error) 171 // ReadRange reads of bytes from the pointer+offset to pointer+offset+count 172 ReadRange(offset, count int) ([]byte, error) 173 } 174 175 // IMMValue is an immediate value, has no special meaning 176 type IMMValue int64 177 178 func (iv *IMMValue) Value() int64 { 179 return int64(*iv) 180 } 181 182 func (iv *IMMValue) Copy() RegisterValue { 183 return newIMM(int64(*iv)) 184 } 185 186 func (iv *IMMValue) Clone() RegisterValue { 187 return newIMM(int64(*iv)) 188 } 189 190 func (iv *IMMValue) Assign(v int64) error { 191 *iv = IMMValue(v) 192 return nil 193 } 194 195 func (iv *IMMValue) String() string { 196 return fmt.Sprintf("0x%016x (s%d / u%d)", uint64(*iv), *iv, uint64(*iv)) 197 } 198 199 func newIMM(v int64) *IMMValue { 200 val := IMMValue(v) 201 return &val 202 } 203 204 var _ RegisterValue = (*MemoryPtr)(nil) 205 206 // MemoryPtr is a pointer to a particular piece of memory. The eBPF program can't manipulate this pointer once gotten, 207 // it can only manipulate to offset from the start of the memory. When the pointer is dereferenced a lookup into the 208 // memory happens at the offset param + the offset property. 209 type MemoryPtr struct { 210 Memory Memory 211 Offset int64 212 } 213 214 func (mp *MemoryPtr) Value() int64 { 215 return mp.Offset 216 } 217 218 func (mp *MemoryPtr) Deref(offset int, size ebpf.Size) (RegisterValue, error) { 219 return mp.Memory.Read(int(mp.Offset)+offset, size) 220 } 221 222 func (mp *MemoryPtr) ReadRange(offset, count int) ([]byte, error) { 223 return mp.Memory.ReadRange(int(mp.Offset)+offset, count) 224 } 225 226 func (mp *MemoryPtr) Copy() RegisterValue { 227 return &MemoryPtr{ 228 Memory: mp.Memory, 229 Offset: mp.Offset, 230 } 231 } 232 233 func (mp *MemoryPtr) Clone() RegisterValue { 234 ptr := &MemoryPtr{ 235 Memory: mp.Memory.Clone(), 236 Offset: mp.Offset, 237 } 238 239 return ptr 240 } 241 242 func (mp *MemoryPtr) Assign(v int64) error { 243 mp.Offset = v 244 245 return nil 246 } 247 248 func (mp *MemoryPtr) String() string { 249 return fmt.Sprintf("%s + %d", mp.Memory.Name(), mp.Offset) 250 } 251 252 var _ RegisterValue = (*FramePointer)(nil) 253 254 // FramePointer is a memory pointer just like the MemoryPointer, the major difference is that a FramePointer will always 255 // point to a Piece of memory which is part of the stack frame. We have a distinct type for two reasons, first is that 256 // the frame pointer at R10 is read-only, only copies are writable. Second is that frame pointers always point at the 257 // end of a block of memory instread of the start. 258 type FramePointer struct { 259 // Slice of the actual underlying memory 260 Memory Memory 261 // The index of the current stack frame 262 Index int 263 // Offset into the stack frame 264 Offset int64 265 // If true, the offset may not be modified 266 Readonly bool 267 } 268 269 func (mp *FramePointer) Value() int64 { 270 return mp.Offset 271 } 272 273 func (mp *FramePointer) Deref(offset int, size ebpf.Size) (RegisterValue, error) { 274 off := mp.Memory.Size() + int(mp.Offset) + offset 275 return mp.Memory.Read(off, size) 276 } 277 278 func (mp *FramePointer) ReadRange(offset, count int) ([]byte, error) { 279 off := mp.Memory.Size() + int(mp.Offset) + offset 280 return mp.Memory.ReadRange(off, count) 281 } 282 283 func (mp *FramePointer) Copy() RegisterValue { 284 return &FramePointer{ 285 Memory: mp.Memory, 286 Offset: mp.Offset, 287 Index: mp.Index, 288 289 // When a copy of a read only pointer may be written to 290 Readonly: false, 291 } 292 } 293 294 func (mp *FramePointer) Clone() RegisterValue { 295 ptr := &FramePointer{ 296 Memory: mp.Memory.Clone(), 297 Index: mp.Index, 298 Offset: mp.Offset, 299 Readonly: mp.Readonly, 300 } 301 302 return ptr 303 } 304 305 func (mp *FramePointer) Assign(v int64) error { 306 if mp.Readonly { 307 return errors.New("can't modify a readonly pointer") 308 } 309 310 mp.Offset = v 311 312 return nil 313 } 314 315 func (mp *FramePointer) String() string { 316 sign := "+" 317 offset := mp.Offset 318 if offset < 0 { 319 sign = "-" 320 offset = -offset 321 } 322 323 return fmt.Sprintf("fp%d %s %d", mp.Index, sign, offset) 324 }