#define MAX_INSNS      512
 #define MAX_MATCHES    16
 
+struct bpf_reg_match {
+       unsigned int line;
+       const char *match;
+};
+
 struct bpf_align_test {
        const char *descr;
        struct bpf_insn insns[MAX_INSNS];
                REJECT
        } result;
        enum bpf_prog_type prog_type;
-       const char *matches[MAX_MATCHES];
+       /* Matches must be in order of increasing line */
+       struct bpf_reg_match matches[MAX_MATCHES];
 };
 
 static struct bpf_align_test tests[] = {
+       /* Four tests of known constants.  These aren't staggeringly
+        * interesting since we track exact values now.
+        */
        {
                .descr = "mov",
                .insns = {
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .matches = {
-                       "1: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
-                       "2: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
-                       "3: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
-                       "4: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
-                       "5: R1=ctx R3=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
+                       {1, "R1=ctx(id=0,off=0,imm=0)"},
+                       {1, "R10=fp0"},
+                       {1, "R3=inv2"},
+                       {2, "R3=inv4"},
+                       {3, "R3=inv8"},
+                       {4, "R3=inv16"},
+                       {5, "R3=inv32"},
                },
        },
        {
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .matches = {
-                       "1: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
-                       "2: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
-                       "3: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
-                       "4: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
-                       "5: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
-                       "6: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
-                       "7: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
-                       "8: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
-                       "9: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
-                       "10: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
-                       "11: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
+                       {1, "R1=ctx(id=0,off=0,imm=0)"},
+                       {1, "R10=fp0"},
+                       {1, "R3=inv1"},
+                       {2, "R3=inv2"},
+                       {3, "R3=inv4"},
+                       {4, "R3=inv8"},
+                       {5, "R3=inv16"},
+                       {6, "R3=inv1"},
+                       {7, "R4=inv32"},
+                       {8, "R4=inv16"},
+                       {9, "R4=inv8"},
+                       {10, "R4=inv4"},
+                       {11, "R4=inv2"},
                },
        },
        {
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .matches = {
-                       "1: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
-                       "2: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=4 R10=fp",
-                       "3: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R10=fp",
-                       "4: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
-                       "5: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm12,min_value=12,max_value=12,min_align=4 R10=fp",
-                       "6: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
+                       {1, "R1=ctx(id=0,off=0,imm=0)"},
+                       {1, "R10=fp0"},
+                       {1, "R3=inv4"},
+                       {2, "R3=inv8"},
+                       {3, "R3=inv10"},
+                       {4, "R4=inv8"},
+                       {5, "R4=inv12"},
+                       {6, "R4=inv14"},
                },
        },
        {
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .matches = {
-                       "1: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
-                       "2: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
-                       "3: R1=ctx R3=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
-                       "4: R1=ctx R3=imm56,min_value=56,max_value=56,min_align=4 R10=fp",
+                       {1, "R1=ctx(id=0,off=0,imm=0)"},
+                       {1, "R10=fp0"},
+                       {1, "R3=inv7"},
+                       {2, "R3=inv7"},
+                       {3, "R3=inv14"},
+                       {4, "R3=inv56"},
                },
        },
 
+       /* Tests using unknown values */
 #define PREP_PKT_POINTERS \
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \
                    offsetof(struct __sk_buff, data)), \
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .matches = {
-                       "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
-                       "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv55,min_align=2 R10=fp",
-                       "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv54,min_align=4 R10=fp",
-                       "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv53,min_align=8 R10=fp",
-                       "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv52,min_align=16 R10=fp",
-                       "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv56 R10=fp",
-                       "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv51,min_align=32 R10=fp",
-                       "20: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv52,min_align=16 R10=fp",
-                       "21: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv53,min_align=8 R10=fp",
-                       "22: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv54,min_align=4 R10=fp",
-                       "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv55,min_align=2 R10=fp",
+                       {7, "R0=pkt(id=0,off=8,r=8,imm=0)"},
+                       {7, "R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {8, "R3=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
+                       {9, "R3=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
+                       {10, "R3=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
+                       {11, "R3=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
+                       {18, "R3=pkt_end(id=0,off=0,imm=0)"},
+                       {18, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {19, "R4=inv(id=0,umax_value=8160,var_off=(0x0; 0x1fe0))"},
+                       {20, "R4=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
+                       {21, "R4=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
+                       {22, "R4=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
+                       {23, "R4=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
                },
        },
        {
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .matches = {
-                       "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
-                       "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
-                       "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv55,min_align=1 R10=fp",
-                       "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
-                       "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv54,min_align=2 R10=fp",
-                       "12: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
-                       "13: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv53,min_align=4 R10=fp",
-                       "14: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
-                       "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv52,min_align=8 R10=fp",
-                       "16: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv50,min_align=8 R10=fp"
+                       {7, "R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {8, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {9, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {10, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {11, "R4=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
+                       {12, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {13, "R4=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
+                       {14, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {15, "R4=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
+                       {16, "R4=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
                },
        },
        {
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .matches = {
-                       "4: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=0,r=0) R10=fp",
-                       "5: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=14,r=0) R10=fp",
-                       "6: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R4=pkt(id=0,off=14,r=0) R5=pkt(id=0,off=14,r=0) R10=fp",
-                       "10: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv56 R5=pkt(id=0,off=14,r=18) R10=fp",
-                       "14: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
-                       "15: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
+                       {4, "R5=pkt(id=0,off=0,r=0,imm=0)"},
+                       {5, "R5=pkt(id=0,off=14,r=0,imm=0)"},
+                       {6, "R4=pkt(id=0,off=14,r=0,imm=0)"},
+                       {10, "R2=pkt(id=0,off=0,r=18,imm=0)"},
+                       {10, "R5=pkt(id=0,off=14,r=18,imm=0)"},
+                       {10, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
+                       {14, "R4=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"},
+                       {15, "R4=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"},
                },
        },
        {
                        /* Calculated offset in R6 has unknown value, but known
                         * alignment of 4.
                         */
-                       "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R6=inv54,min_align=4 R10=fp",
-
-                       /* Offset is added to packet pointer R5, resulting in known
-                        * auxiliary alignment and offset.
+                       {8, "R2=pkt(id=0,off=0,r=8,imm=0)"},
+                       {8, "R6=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
+                       /* Offset is added to packet pointer R5, resulting in
+                        * known fixed offset, and variable offset from R6.
                         */
-                       "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R5=pkt(id=1,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
-
+                       {11, "R5=pkt(id=1,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
                        /* At the time the word size load is performed from R5,
                         * it's total offset is NET_IP_ALIGN + reg->off (0) +
                         * reg->aux_off (14) which is 16.  Then the variable
                         * offset is considered using reg->aux_off_align which
                         * is 4 and meets the load's requirements.
                         */
-                       "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=1,off=4,r=4),aux_off=14,aux_off_align=4 R5=pkt(id=1,off=0,r=4),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
-
-
+                       {15, "R4=pkt(id=1,off=18,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"},
+                       {15, "R5=pkt(id=1,off=14,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"},
                        /* Variable offset is added to R5 packet pointer,
                         * resulting in auxiliary alignment of 4.
                         */
-                       "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=0,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
-
+                       {18, "R5=pkt(id=2,off=0,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
                        /* Constant offset is added to R5, resulting in
                         * reg->off of 14.
                         */
-                       "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=14,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
-
+                       {19, "R5=pkt(id=2,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
                        /* At the time the word size load is performed from R5,
-                        * it's total offset is NET_IP_ALIGN + reg->off (14) which
-                        * is 16.  Then the variable offset is considered using
-                        * reg->aux_off_align which is 4 and meets the load's
-                        * requirements.
+                        * its total fixed offset is NET_IP_ALIGN + reg->off
+                        * (14) which is 16.  Then the variable offset is 4-byte
+                        * aligned, so the total offset is 4-byte aligned and
+                        * meets the load's requirements.
                         */
-                       "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=2,off=18,r=18),aux_off_align=4 R5=pkt(id=2,off=14,r=18),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
-
+                       {23, "R4=pkt(id=2,off=18,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"},
+                       {23, "R5=pkt(id=2,off=14,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"},
                        /* Constant offset is added to R5 packet pointer,
                         * resulting in reg->off value of 14.
                         */
-                       "26: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=0,off=14,r=8) R6=inv54,min_align=4 R10=fp",
-                       /* Variable offset is added to R5, resulting in an
-                        * auxiliary offset of 14, and an auxiliary alignment of 4.
+                       {26, "R5=pkt(id=0,off=14,r=8"},
+                       /* Variable offset is added to R5, resulting in a
+                        * variable offset of (4n).
                         */
-                       "27: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
-                       /* Constant is added to R5 again, setting reg->off to 4. */
-                       "28: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=4,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
-                       /* And once more we add a variable, which causes an accumulation
-                        * of reg->off into reg->aux_off_align, with resulting value of
-                        * 18.  The auxiliary alignment stays at 4.
+                       {27, "R5=pkt(id=3,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
+                       /* Constant is added to R5 again, setting reg->off to 18. */
+                       {28, "R5=pkt(id=3,off=18,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
+                       /* And once more we add a variable; resulting var_off
+                        * is still (4n), fixed offset is not changed.
+                        * Also, we create a new reg->id.
                         */
-                       "29: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=4,off=0,r=0),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
+                       {29, "R5=pkt(id=4,off=18,r=0,umax_value=2040,var_off=(0x0; 0x7fc))"},
                        /* At the time the word size load is performed from R5,
-                        * it's total offset is NET_IP_ALIGN + reg->off (0) +
-                        * reg->aux_off (18) which is 20.  Then the variable offset
-                        * is considered using reg->aux_off_align which is 4 and meets
-                        * the load's requirements.
+                        * its total fixed offset is NET_IP_ALIGN + reg->off (18)
+                        * which is 20.  Then the variable offset is (4n), so
+                        * the total offset is 4-byte aligned and meets the
+                        * load's requirements.
                         */
-                       "33: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=4,off=4,r=4),aux_off=18,aux_off_align=4 R5=pkt(id=4,off=0,r=4),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
+                       {33, "R4=pkt(id=4,off=22,r=22,umax_value=2040,var_off=(0x0; 0x7fc))"},
+                       {33, "R5=pkt(id=4,off=18,r=22,umax_value=2040,var_off=(0x0; 0x7fc))"},
                },
        },
 };
 {
        struct bpf_insn *prog = test->insns;
        int prog_type = test->prog_type;
+       char bpf_vlog_copy[32768];
+       const char *line_ptr;
+       int cur_line = -1;
        int prog_len, i;
        int fd_prog;
        int ret;
                ret = 1;
        } else {
                ret = 0;
+               /* We make a local copy so that we can strtok() it */
+               strncpy(bpf_vlog_copy, bpf_vlog, sizeof(bpf_vlog_copy));
+               line_ptr = strtok(bpf_vlog_copy, "\n");
                for (i = 0; i < MAX_MATCHES; i++) {
-                       const char *t, *m = test->matches[i];
+                       struct bpf_reg_match m = test->matches[i];
 
-                       if (!m)
+                       if (!m.match)
                                break;
-                       t = strstr(bpf_vlog, m);
-                       if (!t) {
-                               printf("Failed to find match: %s\n", m);
+                       while (line_ptr) {
+                               cur_line = -1;
+                               sscanf(line_ptr, "%u: ", &cur_line);
+                               if (cur_line == m.line)
+                                       break;
+                               line_ptr = strtok(NULL, "\n");
+                       }
+                       if (!line_ptr) {
+                               printf("Failed to find line %u for match: %s\n",
+                                      m.line, m.match);
+                               ret = 1;
+                               printf("%s", bpf_vlog);
+                               break;
+                       }
+                       if (!strstr(line_ptr, m.match)) {
+                               printf("Failed to find match %u: %s\n",
+                                      m.line, m.match);
                                ret = 1;
                                printf("%s", bpf_vlog);
                                break;