struct bpf_reg_state *stack_arg_regs; /* Outgoing on-stack arguments */
};
-#define MAX_CALL_FRAMES 8
+#define MAX_CALL_FRAMES 16
/* instruction history flags, used in bpf_jmp_history_entry.flags field.
* Frame number and SPI are stored in dedicated fields of bpf_jmp_history_entry.
struct bpf_jmp_history_entry {
/* insn idx can't be bigger than 1 million */
u32 idx : 20;
- u32 frame : 3; /* stack access frame number */
+ u32 frame : 4; /* stack access frame number */
u32 spi : 6; /* stack slot index (0..63) */
- u32 : 3;
+ u32 : 2;
u32 prev_idx : 20;
/* special INSN_F_xxx flags */
u32 flags : 4;
u32 : 8;
- /* additional registers that need precision tracking when this
- * jump is backtracked, vector of six 10-bit records
+ /*
+ * additional registers that need precision tracking when this
+ * jump is backtracked, vector of five 11-bit records
*/
u64 linked_regs;
};
-static_assert(MAX_CALL_FRAMES <= (1 << 3));
+static_assert(MAX_CALL_FRAMES <= (1 << 4));
static_assert(MAX_BPF_STACK / 8 <= (1 << 6));
/* Maximum number of bpf_reg_state objects that can exist at once */
env->insn_aux_data[idx].indirect_target = true;
}
-#define LR_FRAMENO_BITS 3
+#define LR_FRAMENO_BITS 4
#define LR_SPI_BITS 6
#define LR_ENTRY_BITS (LR_SPI_BITS + LR_FRAMENO_BITS + 1)
#define LR_SIZE_BITS 4
#define LR_SIZE_MASK ((1ull << LR_SIZE_BITS) - 1)
#define LR_SPI_OFF LR_FRAMENO_BITS
#define LR_IS_REG_OFF (LR_SPI_BITS + LR_FRAMENO_BITS)
-#define LINKED_REGS_MAX 6
+#define LINKED_REGS_MAX 5
+
+static_assert(MAX_CALL_FRAMES <= (1 << LR_FRAMENO_BITS));
+static_assert(LINKED_REGS_MAX < (1 << LR_SIZE_BITS));
+static_assert(LINKED_REGS_MAX * LR_ENTRY_BITS + LR_SIZE_BITS <= 64);
struct linked_reg {
u8 frameno;
return NULL;
}
-/* Use u64 as a vector of 6 10-bit values, use first 4-bits to track
+/*
+ * Use u64 as a vector of 5 11-bit values, use first 4-bits to track
* number of elements currently in stack.
- * Pack one history entry for linked registers as 10 bits in the following format:
- * - 3-bits frameno
+ * Pack one history entry for linked registers as 11 bits in the following format:
+ * - 4-bits frameno
* - 6-bits spi_or_reg
* - 1-bit is_reg
*/
return f7(skb);
}
+static __attribute__ ((noinline))
+int f9(struct __sk_buff *skb)
+{
+ return f8(skb);
+}
+
+static __attribute__ ((noinline))
+int f10(struct __sk_buff *skb)
+{
+ return f9(skb);
+}
+
+static __attribute__ ((noinline))
+int f11(struct __sk_buff *skb)
+{
+ return f10(skb);
+}
+
+static __attribute__ ((noinline))
+int f12(struct __sk_buff *skb)
+{
+ return f11(skb);
+}
+
+static __attribute__ ((noinline))
+int f13(struct __sk_buff *skb)
+{
+ return f12(skb);
+}
+
+static __attribute__ ((noinline))
+int f14(struct __sk_buff *skb)
+{
+ return f13(skb);
+}
+
+static __attribute__ ((noinline))
+int f15(struct __sk_buff *skb)
+{
+ return f14(skb);
+}
+
+static __attribute__ ((noinline))
+int f16(struct __sk_buff *skb)
+{
+ return f15(skb);
+}
+
SEC("tc")
-__failure __msg("the call stack of 9 frames")
+__failure __msg("the call stack of 17 frames")
int global_func3(struct __sk_buff *skb)
{
- return f8(skb);
+ return f16(skb);
}
* FP offset at each call site. arg_track keys on (frame, off[]), so
* r1=fp-8, r1=fp-16, ... r1=fp-400 produce 50 unique cache keys per level.
*
- * This test chains 8 subprograms (the MAX_CALL_FRAMES limit). Each
+ * This test chains 8 subprograms (within the MAX_CALL_FRAMES limit). Each
* intermediate function calls the next one 50 times, each time with a
* different FP-relative offset in r1.
*
SEC("socket")
__success __log_level(2)
__flag(BPF_F_TEST_STATE_FREQ)
-/* check that r0 and r6 have different IDs after 'if',
- * collect_linked_regs() can't tie more than 6 registers for a single insn.
+/*
+ * check that r0 and r5 have different IDs after 'if',
+ * collect_linked_regs() can't tie more than 5 registers for a single insn.
*/
-__msg("8: (25) if r0 > 0x7 goto pc+0 ; R0=scalar(id=1")
-__msg("14: (bf) r6 = r6 ; R6=scalar(id=2")
-/* check that r{0-5} are marked precise after 'if' */
-__msg("frame0: regs=r0 stack= before 8: (25) if r0 > 0x7 goto pc+0")
-__msg("frame0: parent state regs=r0,r1,r2,r3,r4,r5 stack=:")
+__msg("7: (25) if r0 > 0x7 goto pc+0 ; R0=scalar(id=1")
+__msg("12: (bf) r5 = r5 ; R5=scalar(id=2")
+/* check that r{0-4} are marked precise after 'if' */
+__msg("frame0: regs=r0 stack= before 7: (25) if r0 > 0x7 goto pc+0")
+__msg("frame0: parent state regs=r0,r1,r2,r3,r4 stack=:")
__naked void linked_regs_too_many_regs(void)
{
asm volatile (
/* r0 = random number up to 0xff */
"call %[bpf_ktime_get_ns];"
"r0 &= 0xff;"
- /* tie r{0-6} IDs */
+ /* tie r{0-5} IDs */
"r1 = r0;"
"r2 = r0;"
"r3 = r0;"
"r4 = r0;"
"r5 = r0;"
- "r6 = r0;"
- /* propagate range for r{0-6} */
+ /* propagate range for r{0-5} */
"if r0 > 7 goto +0;"
- /* keep r{1-5} live */
+ /* keep r{1-4} live */
"r1 = r1;"
"r2 = r2;"
"r3 = r3;"
"r4 = r4;"
+ /* make r5 appear in the log */
"r5 = r5;"
- /* make r6 appear in the log */
- "r6 = r6;"
/* force r0 to be precise,
* this would cause r{0-4} to be precise because of shared IDs
*/
BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call H */
BPF_EXIT_INSN(),
/* H */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call I */
+ BPF_EXIT_INSN(),
+ /* I */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call J */
+ BPF_EXIT_INSN(),
+ /* J */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call K */
+ BPF_EXIT_INSN(),
+ /* K */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call L */
+ BPF_EXIT_INSN(),
+ /* L */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call M */
+ BPF_EXIT_INSN(),
+ /* M */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call N */
+ BPF_EXIT_INSN(),
+ /* N */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call O */
+ BPF_EXIT_INSN(),
+ /* O */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call P */
+ BPF_EXIT_INSN(),
+ /* P */
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call H */
BPF_EXIT_INSN(),
/* H */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call I */
+ BPF_EXIT_INSN(),
+ /* I */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call J */
+ BPF_EXIT_INSN(),
+ /* J */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call K */
+ BPF_EXIT_INSN(),
+ /* K */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call L */
+ BPF_EXIT_INSN(),
+ /* L */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call M */
+ BPF_EXIT_INSN(),
+ /* M */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call N */
+ BPF_EXIT_INSN(),
+ /* N */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call O */
+ BPF_EXIT_INSN(),
+ /* O */
+ BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call P */
+ BPF_EXIT_INSN(),
+ /* P */
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},