bpf: simplify disasm state machine.

The code ends up slightly longer, but the decoding is more consistent from
one instruction class to another, so hopefully it's easier to make sense of it.

Change-Id: Ia22c2ebb0865536da0c3dac6876bdb0b20075f04
Reviewed-on: https://go-review.googlesource.com/21215
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
David Anderson
2016-03-27 16:04:17 -07:00
committed by Mikio Hara
parent 3c208088b6
commit 9c7b3c72db
2 changed files with 121 additions and 101 deletions

View File

@@ -125,7 +125,19 @@ const (
// The following gives names to various bit patterns used in opcode construction.
const opClsMask uint16 = 0x7
const (
opMaskCls uint16 = 0x7
// opClsLoad masks
opMaskLoadDest = 0x01
opMaskLoadWidth = 0x18
opMaskLoadMode = 0xe0
// opClsALU
opMaskOperandSrc = 0x08
opMaskOperator = 0xf0
// opClsJump
opMaskJumpConst = 0x0f
opMaskJumpCond = 0xf0
)
const (
// +---------------+-----------------+---+---+---+
@@ -179,9 +191,6 @@ const (
)
// Operator defined by ALUOp*
const opALUOpMask = 0xf0
const opALUSrcMask = 0x08
const (
opALUSrcConstant uint16 = iota << 3

View File

@@ -31,122 +31,133 @@ func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
// Disassemble parses ri into an Instruction and returns it. If ri is
// not recognized by this package, ri itself is returned.
func (ri RawInstruction) Disassemble() Instruction {
switch ri.Op {
case opClsLoadA | opLoadWidth4 | opAddrModeImmediate:
return LoadConstant{Dst: RegA, Val: ri.K}
case opClsLoadX | opLoadWidth4 | opAddrModeImmediate:
return LoadConstant{Dst: RegX, Val: ri.K}
case opClsLoadA | opLoadWidth4 | opAddrModeScratch:
if ri.K > 15 {
return ri
}
return LoadScratch{Dst: RegA, N: int(ri.K)}
case opClsLoadX | opLoadWidth4 | opAddrModeScratch:
if ri.K > 15 {
return ri
}
return LoadScratch{Dst: RegX, N: int(ri.K)}
case opClsLoadA | opLoadWidth4 | opAddrModeAbsolute:
ext := Extension(uint32(ri.K) + 0x1000)
switch ext {
case ExtProto, ExtType, ExtPayloadOffset, ExtInterfaceIndex, ExtNetlinkAttr, ExtNetlinkAttrNested, ExtMark, ExtQueue, ExtLinkLayerType, ExtRXHash, ExtCPUID, ExtVLANTag, ExtVLANTagPresent, ExtVLANProto, ExtRand:
return LoadExtension{Num: ext}
switch ri.Op & opMaskCls {
case opClsLoadA, opClsLoadX:
reg := Register(ri.Op & opMaskLoadDest)
sz := 0
switch ri.Op & opMaskLoadWidth {
case opLoadWidth4:
sz = 4
case opLoadWidth2:
sz = 2
case opLoadWidth1:
sz = 1
default:
return LoadAbsolute{Off: ri.K, Size: 4}
return ri
}
switch ri.Op & opMaskLoadMode {
case opAddrModeImmediate:
if sz != 4 {
return ri
}
return LoadConstant{Dst: reg, Val: ri.K}
case opAddrModeScratch:
if sz != 4 || ri.K > 15 {
return ri
}
return LoadScratch{Dst: reg, N: int(ri.K)}
case opAddrModeAbsolute:
return LoadAbsolute{Size: sz, Off: ri.K}
case opAddrModeIndirect:
return LoadIndirect{Size: sz, Off: ri.K}
case opAddrModePacketLen:
if sz != 4 {
return ri
}
return LoadExtension{Num: ExtLen}
case opAddrModeIPv4HeaderLen:
return LoadIPv4HeaderLen{Off: ri.K}
default:
return ri
}
case opClsLoadA | opLoadWidth2 | opAddrModeAbsolute:
return LoadAbsolute{Off: ri.K, Size: 2}
case opClsLoadA | opLoadWidth1 | opAddrModeAbsolute:
return LoadAbsolute{Off: ri.K, Size: 1}
case opClsLoadA | opLoadWidth4 | opAddrModeIndirect:
return LoadIndirect{Off: ri.K, Size: 4}
case opClsLoadA | opLoadWidth2 | opAddrModeIndirect:
return LoadIndirect{Off: ri.K, Size: 2}
case opClsLoadA | opLoadWidth1 | opAddrModeIndirect:
return LoadIndirect{Off: ri.K, Size: 1}
case opClsLoadX | opLoadWidth1 | opAddrModeIPv4HeaderLen:
return LoadIPv4HeaderLen{Off: ri.K}
case opClsLoadA | opLoadWidth4 | opAddrModePacketLen:
return LoadExtension{Num: ExtLen}
case opClsStoreA:
if ri.K > 15 {
if ri.Op != opClsStoreA || ri.K > 15 {
return ri
}
return StoreScratch{Src: RegA, N: int(ri.K)}
case opClsStoreX:
if ri.K > 15 {
if ri.Op != opClsStoreX || ri.K > 15 {
return ri
}
return StoreScratch{Src: RegX, N: int(ri.K)}
case opClsALU | uint16(aluOpNeg):
return NegateA{}
case opClsJump | opJumpAlways:
return Jump{Skip: ri.K}
case opClsJump | opJumpEqual:
return JumpIf{
Cond: JumpEqual,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
case opClsJump | opJumpGT:
return JumpIf{
Cond: JumpGreaterThan,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
case opClsJump | opJumpGE:
return JumpIf{
Cond: JumpGreaterOrEqual,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
case opClsJump | opJumpSet:
return JumpIf{
Cond: JumpBitsSet,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
case opClsALU:
switch op := ALUOp(ri.Op & opMaskOperator); op {
case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
if ri.Op&opMaskOperandSrc != 0 {
return ALUOpX{Op: op}
}
return ALUOpConstant{Op: op, Val: ri.K}
case aluOpNeg:
return NegateA{}
default:
return ri
}
case opClsReturn | opRetSrcA:
return RetA{}
case opClsReturn | opRetSrcConstant:
return RetConstant{Val: ri.K}
case opClsJump:
if ri.Op&opMaskJumpConst != opClsJump {
return ri
}
switch ri.Op & opMaskJumpCond {
case opJumpAlways:
return Jump{Skip: ri.K}
case opJumpEqual:
return JumpIf{
Cond: JumpEqual,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
case opJumpGT:
return JumpIf{
Cond: JumpGreaterThan,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
case opJumpGE:
return JumpIf{
Cond: JumpGreaterOrEqual,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
case opJumpSet:
return JumpIf{
Cond: JumpBitsSet,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
default:
return ri
}
case opClsMisc | opMiscTXA:
return TXA{}
case opClsMisc | opMiscTAX:
return TAX{}
}
case opClsReturn:
switch ri.Op {
case opClsReturn | opRetSrcA:
return RetA{}
case opClsReturn | opRetSrcConstant:
return RetConstant{Val: ri.K}
default:
return ri
}
// ALU operations require bitmasking to decode, so are done
// outside the main switch.
case opClsMisc:
switch ri.Op {
case opClsMisc | opMiscTAX:
return TAX{}
case opClsMisc | opMiscTXA:
return TXA{}
default:
return ri
}
if ri.Op&opClsMask != opClsALU {
return ri
}
op := ALUOp(ri.Op & opALUOpMask)
switch op {
case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
default:
return ri
panic("unreachable") // switch is exhaustive on the bit pattern
}
if ri.Op&opALUSrcMask != 0 {
return ALUOpX{Op: op}
}
return ALUOpConstant{Op: op, Val: ri.K}
}
// LoadConstant loads Val into register Dst.