github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/emulator/inst_atomic.go (about)

     1  package emulator
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/dylandreimerink/gobpfld/ebpf"
     7  )
     8  
     9  var _ Instruction = (*AtomicAdd)(nil)
    10  
    11  type AtomicAdd struct {
    12  	ebpf.AtomicAdd
    13  }
    14  
    15  func (i *AtomicAdd) Clone() Instruction {
    16  	c := *i
    17  	return &c
    18  }
    19  
    20  func (i *AtomicAdd) Execute(vm *VM) error {
    21  	// TODO make actually atomic using a mutex or similar when adding multi threading support.
    22  	dr, err := vm.Registers.Copy(i.Dest)
    23  	if err != nil {
    24  		return fmt.Errorf("copy %s: %w", i.Dest, err)
    25  	}
    26  
    27  	var off int64
    28  	var memory Memory
    29  	switch dmp := dr.(type) {
    30  	case *MemoryPtr:
    31  		// Memory pointers point to the start of a memory block
    32  		off = dmp.Offset + int64(i.Offset)
    33  		memory = dmp.Memory
    34  
    35  	case *FramePointer:
    36  		// Frame pointers point to the end of a stack frame
    37  		off = int64(dmp.Memory.Size()) + dmp.Offset + int64(i.Offset)
    38  		memory = dmp.Memory
    39  
    40  	default:
    41  		return fmt.Errorf("can't store to a non-pointer register value")
    42  	}
    43  
    44  	dv, err := memory.Read(int(off), i.Size)
    45  	if err != nil {
    46  		return fmt.Errorf("memory read: %w", err)
    47  	}
    48  
    49  	sr, err := vm.Registers.Get(i.Src)
    50  	if err != nil {
    51  		return fmt.Errorf("get src: %w", err)
    52  	}
    53  
    54  	err = dv.Assign(dv.Value() + sr.Value())
    55  	if err != nil {
    56  		return fmt.Errorf("assign value: %w", err)
    57  	}
    58  
    59  	err = memory.Write(int(off), dv, i.Size)
    60  	if err != nil {
    61  		return fmt.Errorf("write dst+src: %w", err)
    62  	}
    63  
    64  	return nil
    65  }