package ebpf
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
type ByteSwap struct {
|
|
Dst Register
|
|
ByteOrder binary.ByteOrder
|
|
Size uint8
|
|
}
|
|
|
|
// Assemble implements the Instruction Assemble method.
|
|
func (a ByteSwap) Assemble() (RawInstruction, error) {
|
|
var source Opcode
|
|
if a.ByteOrder == binary.BigEndian {
|
|
source = aluSourceX
|
|
}
|
|
switch a.Size {
|
|
case 16, 32, 64:
|
|
return RawInstruction{
|
|
Op: opClassALU | source | Opcode(aluOpByteSwap),
|
|
Dst: a.Dst,
|
|
Immediate: uint64(a.Size),
|
|
}, nil
|
|
default:
|
|
return RawInstruction{}, fmt.Errorf("ebpf: invalid byte swap size %d", a.Size)
|
|
}
|
|
}
|
|
|
|
func (a ByteSwap) String() string {
|
|
if a.ByteOrder == binary.LittleEndian {
|
|
return fmt.Sprintf("le%d %s", a.Size, a.Dst)
|
|
}
|
|
return fmt.Sprintf("be%d %s", a.Size, a.Dst)
|
|
}
|
|
|
|
func (a ByteSwap) CString() string {
|
|
var endian = "le"
|
|
if a.ByteOrder == binary.BigEndian {
|
|
endian = "be"
|
|
}
|
|
return fmt.Sprintf("%s = hto%s%d(%s)", a.Dst, endian, a.Size, a.Dst)
|
|
}
|
|
|
|
func (a ByteSwap) Swap(value uint64) uint64 {
|
|
switch {
|
|
case a.Size == 16 && a.ByteOrder == binary.LittleEndian:
|
|
return uint64(htole16(uint16(value)))
|
|
case a.Size == 32 && a.ByteOrder == binary.LittleEndian:
|
|
return uint64(htole32(uint32(value)))
|
|
case a.Size == 64 && a.ByteOrder == binary.LittleEndian:
|
|
return htole64(value)
|
|
case a.Size == 16 && a.ByteOrder == binary.BigEndian:
|
|
return uint64(htobe16(uint16(value)))
|
|
case a.Size == 32 && a.ByteOrder == binary.BigEndian:
|
|
return uint64(htobe32(uint32(value)))
|
|
case a.Size == 64 && a.ByteOrder == binary.BigEndian:
|
|
return htobe64(value)
|
|
default:
|
|
return value
|
|
}
|
|
}
|
|
|
|
var _ Instruction = (*ByteSwap)(nil)
|