diff --git a/asm/instruction.go b/asm/instruction.go index 627d403d8..07925e8c3 100644 --- a/asm/instruction.go +++ b/asm/instruction.go @@ -396,9 +396,9 @@ func (ins Instruction) Format(f fmt.State, c rune) { } case cls.IsJump(): - fmt.Fprintf(f, "%v ", op) switch jop := op.JumpOp(); jop { case Call: + fmt.Fprintf(f, "%v ", op) switch ins.Src { case PseudoCall: // bpf-to-bpf call @@ -411,13 +411,23 @@ func (ins Instruction) Format(f fmt.State, c rune) { } case Ja: + fmt.Fprintf(f, "%v ", op) if ins.OpCode.Class() == Jump32Class { fmt.Fprintf(f, "imm: %d", ins.Constant) } else { fmt.Fprintf(f, "off: %d", ins.Offset) } + case JCOND: + switch ins.Src { + case PseudoMayGoto: + fmt.Fprintf(f, "JCond may_goto off: %d", ins.Offset) + default: + fmt.Fprintf(f, "%v", op) + } + default: + fmt.Fprintf(f, "%v ", op) fmt.Fprintf(f, "dst: %s off: %d ", ins.Dst, ins.Offset) if op.Source() == ImmSource { fmt.Fprintf(f, "imm: %d", ins.Constant) diff --git a/asm/instruction_test.go b/asm/instruction_test.go index 4ea3aebd2..d93c4cf8a 100644 --- a/asm/instruction_test.go +++ b/asm/instruction_test.go @@ -393,6 +393,8 @@ func TestISAv4(t *testing.T) { 0xcb, 0x21, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, // store_release((u16 *)(r1 + 0x0), w2) 0xc3, 0x21, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, // store_release((u32 *)(r1 + 0x0), w2) 0xdb, 0x21, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, // store_release((u64 *)(r1 + 0x0), r2) + + 0xe5, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, // may_goto +30 } insns, err := AppendInstructions(nil, bytes.NewReader(rawInsns), binary.LittleEndian, platform.Linux) @@ -427,6 +429,7 @@ func TestISAv4(t *testing.T) { "StXAtomicStRelH dst: r1 src: r2 off: 0", "StXAtomicStRelW dst: r1 src: r2 off: 0", "StXAtomicStRelDW dst: r1 src: r2 off: 0", + "JCond may_goto off: 30", } for i, ins := range insns { diff --git a/asm/jump.go b/asm/jump.go index a14bc4c89..e8a78093b 100644 --- a/asm/jump.go +++ b/asm/jump.go @@ -44,6 +44,8 @@ const ( JSLT JumpOp = 0xc0 // JSLE jumps by offset if signed r <= signed imm JSLE JumpOp = 0xd0 + // JCOND is a conditional pseudo jump to encode the may_goto instruction + JCOND JumpOp = 0xe0 ) // Return emits an exit instruction. diff --git a/asm/jump_string.go b/asm/jump_string.go index 85a4aaffa..240cb7c09 100644 --- a/asm/jump_string.go +++ b/asm/jump_string.go @@ -23,9 +23,10 @@ func _() { _ = x[JLE-176] _ = x[JSLT-192] _ = x[JSLE-208] + _ = x[JCOND-224] } -const _JumpOp_name = "JaJEqJGTJGEJSetJNEJSGTJSGECallExitJLTJLEJSLTJSLEInvalidJumpOp" +const _JumpOp_name = "JaJEqJGTJGEJSetJNEJSGTJSGECallExitJLTJLEJSLTJSLEJCONDInvalidJumpOp" var _JumpOp_map = map[JumpOp]string{ 0: _JumpOp_name[0:2], @@ -42,7 +43,8 @@ var _JumpOp_map = map[JumpOp]string{ 176: _JumpOp_name[37:40], 192: _JumpOp_name[40:44], 208: _JumpOp_name[44:48], - 255: _JumpOp_name[48:61], + 224: _JumpOp_name[48:53], + 255: _JumpOp_name[53:66], } func (i JumpOp) String() string { diff --git a/asm/opcode_test.go b/asm/opcode_test.go index e73eb8679..dbe08e0f1 100644 --- a/asm/opcode_test.go +++ b/asm/opcode_test.go @@ -44,6 +44,7 @@ func TestGetSetJumpOp(t *testing.T) { JLE, JSLT, JSLE, + JCOND, } { test(Jump32Class, op, true) test(JumpClass, op, true) diff --git a/asm/register.go b/asm/register.go index 457a3b8a8..baf03aa42 100644 --- a/asm/register.go +++ b/asm/register.go @@ -40,6 +40,7 @@ const ( PseudoCall = R1 // BPF_PSEUDO_CALL PseudoFunc = R4 // BPF_PSEUDO_FUNC PseudoKfuncCall = R2 // BPF_PSEUDO_KFUNC_CALL + PseudoMayGoto = R0 // BPF_MAY_GOTO ) func (r Register) String() string {