 470d3ee057
			
		
	
	470d3ee057
	
	
	
		
			
			The fuzzer is broken and it breaks OSS-Fuzz according to #7288. Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
		
			
				
	
	
		
			272 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			272 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package asm
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| //go:generate stringer -output opcode_string.go -type=Class
 | |
| 
 | |
| // Class of operations
 | |
| //
 | |
| //    msb      lsb
 | |
| //    +---+--+---+
 | |
| //    |  ??  |CLS|
 | |
| //    +---+--+---+
 | |
| type Class uint8
 | |
| 
 | |
| const classMask OpCode = 0x07
 | |
| 
 | |
| const (
 | |
| 	// LdClass loads immediate values into registers.
 | |
| 	// Also used for non-standard load operations from cBPF.
 | |
| 	LdClass Class = 0x00
 | |
| 	// LdXClass loads memory into registers.
 | |
| 	LdXClass Class = 0x01
 | |
| 	// StClass stores immediate values to memory.
 | |
| 	StClass Class = 0x02
 | |
| 	// StXClass stores registers to memory.
 | |
| 	StXClass Class = 0x03
 | |
| 	// ALUClass describes arithmetic operators.
 | |
| 	ALUClass Class = 0x04
 | |
| 	// JumpClass describes jump operators.
 | |
| 	JumpClass Class = 0x05
 | |
| 	// Jump32Class describes jump operators with 32-bit comparisons.
 | |
| 	// Requires kernel 5.1.
 | |
| 	Jump32Class Class = 0x06
 | |
| 	// ALU64Class describes arithmetic operators in 64-bit mode.
 | |
| 	ALU64Class Class = 0x07
 | |
| )
 | |
| 
 | |
| // IsLoad checks if this is either LdClass or LdXClass.
 | |
| func (cls Class) IsLoad() bool {
 | |
| 	return cls == LdClass || cls == LdXClass
 | |
| }
 | |
| 
 | |
| // IsStore checks if this is either StClass or StXClass.
 | |
| func (cls Class) IsStore() bool {
 | |
| 	return cls == StClass || cls == StXClass
 | |
| }
 | |
| 
 | |
| func (cls Class) isLoadOrStore() bool {
 | |
| 	return cls.IsLoad() || cls.IsStore()
 | |
| }
 | |
| 
 | |
| // IsALU checks if this is either ALUClass or ALU64Class.
 | |
| func (cls Class) IsALU() bool {
 | |
| 	return cls == ALUClass || cls == ALU64Class
 | |
| }
 | |
| 
 | |
| // IsJump checks if this is either JumpClass or Jump32Class.
 | |
| func (cls Class) IsJump() bool {
 | |
| 	return cls == JumpClass || cls == Jump32Class
 | |
| }
 | |
| 
 | |
| func (cls Class) isJumpOrALU() bool {
 | |
| 	return cls.IsJump() || cls.IsALU()
 | |
| }
 | |
| 
 | |
| // OpCode is a packed eBPF opcode.
 | |
| //
 | |
| // Its encoding is defined by a Class value:
 | |
| //
 | |
| //    msb      lsb
 | |
| //    +----+-+---+
 | |
| //    | ???? |CLS|
 | |
| //    +----+-+---+
 | |
| type OpCode uint8
 | |
| 
 | |
| // InvalidOpCode is returned by setters on OpCode
 | |
| const InvalidOpCode OpCode = 0xff
 | |
| 
 | |
| // rawInstructions returns the number of BPF instructions required
 | |
| // to encode this opcode.
 | |
| func (op OpCode) rawInstructions() int {
 | |
| 	if op.IsDWordLoad() {
 | |
| 		return 2
 | |
| 	}
 | |
| 	return 1
 | |
| }
 | |
| 
 | |
| func (op OpCode) IsDWordLoad() bool {
 | |
| 	return op == LoadImmOp(DWord)
 | |
| }
 | |
| 
 | |
| // Class returns the class of operation.
 | |
| func (op OpCode) Class() Class {
 | |
| 	return Class(op & classMask)
 | |
| }
 | |
| 
 | |
| // Mode returns the mode for load and store operations.
 | |
| func (op OpCode) Mode() Mode {
 | |
| 	if !op.Class().isLoadOrStore() {
 | |
| 		return InvalidMode
 | |
| 	}
 | |
| 	return Mode(op & modeMask)
 | |
| }
 | |
| 
 | |
| // Size returns the size for load and store operations.
 | |
| func (op OpCode) Size() Size {
 | |
| 	if !op.Class().isLoadOrStore() {
 | |
| 		return InvalidSize
 | |
| 	}
 | |
| 	return Size(op & sizeMask)
 | |
| }
 | |
| 
 | |
| // Source returns the source for branch and ALU operations.
 | |
| func (op OpCode) Source() Source {
 | |
| 	if !op.Class().isJumpOrALU() || op.ALUOp() == Swap {
 | |
| 		return InvalidSource
 | |
| 	}
 | |
| 	return Source(op & sourceMask)
 | |
| }
 | |
| 
 | |
| // ALUOp returns the ALUOp.
 | |
| func (op OpCode) ALUOp() ALUOp {
 | |
| 	if !op.Class().IsALU() {
 | |
| 		return InvalidALUOp
 | |
| 	}
 | |
| 	return ALUOp(op & aluMask)
 | |
| }
 | |
| 
 | |
| // Endianness returns the Endianness for a byte swap instruction.
 | |
| func (op OpCode) Endianness() Endianness {
 | |
| 	if op.ALUOp() != Swap {
 | |
| 		return InvalidEndian
 | |
| 	}
 | |
| 	return Endianness(op & endianMask)
 | |
| }
 | |
| 
 | |
| // JumpOp returns the JumpOp.
 | |
| // Returns InvalidJumpOp if it doesn't encode a jump.
 | |
| func (op OpCode) JumpOp() JumpOp {
 | |
| 	if !op.Class().IsJump() {
 | |
| 		return InvalidJumpOp
 | |
| 	}
 | |
| 
 | |
| 	jumpOp := JumpOp(op & jumpMask)
 | |
| 
 | |
| 	// Some JumpOps are only supported by JumpClass, not Jump32Class.
 | |
| 	if op.Class() == Jump32Class && (jumpOp == Exit || jumpOp == Call || jumpOp == Ja) {
 | |
| 		return InvalidJumpOp
 | |
| 	}
 | |
| 
 | |
| 	return jumpOp
 | |
| }
 | |
| 
 | |
| // SetMode sets the mode on load and store operations.
 | |
| //
 | |
| // Returns InvalidOpCode if op is of the wrong class.
 | |
| func (op OpCode) SetMode(mode Mode) OpCode {
 | |
| 	if !op.Class().isLoadOrStore() || !valid(OpCode(mode), modeMask) {
 | |
| 		return InvalidOpCode
 | |
| 	}
 | |
| 	return (op & ^modeMask) | OpCode(mode)
 | |
| }
 | |
| 
 | |
| // SetSize sets the size on load and store operations.
 | |
| //
 | |
| // Returns InvalidOpCode if op is of the wrong class.
 | |
| func (op OpCode) SetSize(size Size) OpCode {
 | |
| 	if !op.Class().isLoadOrStore() || !valid(OpCode(size), sizeMask) {
 | |
| 		return InvalidOpCode
 | |
| 	}
 | |
| 	return (op & ^sizeMask) | OpCode(size)
 | |
| }
 | |
| 
 | |
| // SetSource sets the source on jump and ALU operations.
 | |
| //
 | |
| // Returns InvalidOpCode if op is of the wrong class.
 | |
| func (op OpCode) SetSource(source Source) OpCode {
 | |
| 	if !op.Class().isJumpOrALU() || !valid(OpCode(source), sourceMask) {
 | |
| 		return InvalidOpCode
 | |
| 	}
 | |
| 	return (op & ^sourceMask) | OpCode(source)
 | |
| }
 | |
| 
 | |
| // SetALUOp sets the ALUOp on ALU operations.
 | |
| //
 | |
| // Returns InvalidOpCode if op is of the wrong class.
 | |
| func (op OpCode) SetALUOp(alu ALUOp) OpCode {
 | |
| 	if !op.Class().IsALU() || !valid(OpCode(alu), aluMask) {
 | |
| 		return InvalidOpCode
 | |
| 	}
 | |
| 	return (op & ^aluMask) | OpCode(alu)
 | |
| }
 | |
| 
 | |
| // SetJumpOp sets the JumpOp on jump operations.
 | |
| //
 | |
| // Returns InvalidOpCode if op is of the wrong class.
 | |
| func (op OpCode) SetJumpOp(jump JumpOp) OpCode {
 | |
| 	if !op.Class().IsJump() || !valid(OpCode(jump), jumpMask) {
 | |
| 		return InvalidOpCode
 | |
| 	}
 | |
| 
 | |
| 	newOp := (op & ^jumpMask) | OpCode(jump)
 | |
| 
 | |
| 	// Check newOp is legal.
 | |
| 	if newOp.JumpOp() == InvalidJumpOp {
 | |
| 		return InvalidOpCode
 | |
| 	}
 | |
| 
 | |
| 	return newOp
 | |
| }
 | |
| 
 | |
| func (op OpCode) String() string {
 | |
| 	var f strings.Builder
 | |
| 
 | |
| 	switch class := op.Class(); {
 | |
| 	case class.isLoadOrStore():
 | |
| 		f.WriteString(strings.TrimSuffix(class.String(), "Class"))
 | |
| 
 | |
| 		mode := op.Mode()
 | |
| 		f.WriteString(strings.TrimSuffix(mode.String(), "Mode"))
 | |
| 
 | |
| 		switch op.Size() {
 | |
| 		case DWord:
 | |
| 			f.WriteString("DW")
 | |
| 		case Word:
 | |
| 			f.WriteString("W")
 | |
| 		case Half:
 | |
| 			f.WriteString("H")
 | |
| 		case Byte:
 | |
| 			f.WriteString("B")
 | |
| 		}
 | |
| 
 | |
| 	case class.IsALU():
 | |
| 		f.WriteString(op.ALUOp().String())
 | |
| 
 | |
| 		if op.ALUOp() == Swap {
 | |
| 			// Width for Endian is controlled by Constant
 | |
| 			f.WriteString(op.Endianness().String())
 | |
| 		} else {
 | |
| 			if class == ALUClass {
 | |
| 				f.WriteString("32")
 | |
| 			}
 | |
| 
 | |
| 			f.WriteString(strings.TrimSuffix(op.Source().String(), "Source"))
 | |
| 		}
 | |
| 
 | |
| 	case class.IsJump():
 | |
| 		f.WriteString(op.JumpOp().String())
 | |
| 
 | |
| 		if class == Jump32Class {
 | |
| 			f.WriteString("32")
 | |
| 		}
 | |
| 
 | |
| 		if jop := op.JumpOp(); jop != Exit && jop != Call {
 | |
| 			f.WriteString(strings.TrimSuffix(op.Source().String(), "Source"))
 | |
| 		}
 | |
| 
 | |
| 	default:
 | |
| 		fmt.Fprintf(&f, "OpCode(%#x)", uint8(op))
 | |
| 	}
 | |
| 
 | |
| 	return f.String()
 | |
| }
 | |
| 
 | |
| // valid returns true if all bits in value are covered by mask.
 | |
| func valid(value, mask OpCode) bool {
 | |
| 	return value & ^mask == 0
 | |
| }
 |