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  }