]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/netbsd-tests/lib/libbpfjit/t_cop.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / netbsd-tests / lib / libbpfjit / t_cop.c
1 /*      $NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $ */
2
3 /*-
4  * Copyright (c) 2013-2014 Alexander Nasonov.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $");
34
35 #include <atf-c.h>
36 #include <stdint.h>
37 #include <string.h>
38
39 #define __BPF_PRIVATE
40 #include <net/bpf.h>
41 #include <net/bpfjit.h>
42
43 static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
44 static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
45 static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
46 static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
47 static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
48
49 static const bpf_copfunc_t copfuncs[] = {
50         &retA,
51         &retBL,
52         &retWL,
53         &retNF,
54         &setARG
55 };
56
57 static const bpf_ctx_t ctx = {
58         .copfuncs = copfuncs,
59         .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
60         .extwords = 0
61 };
62
63 static uint32_t
64 retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
65 {
66
67         return A;
68 }
69
70 static uint32_t
71 retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
72 {
73
74         return args->buflen;
75 }
76
77 static uint32_t
78 retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
79 {
80
81         return args->wirelen;
82 }
83
84 static uint32_t
85 retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
86 {
87
88         return bc->nfuncs;
89 }
90
91 /*
92  * COP function with a side effect.
93  */
94 static uint32_t
95 setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
96 {
97         bool *arg = (bool *)args->arg;
98         bool old = *arg;
99
100         *arg = true;
101         return old;
102 }
103
104 ATF_TC(libbpfjit_cop_no_ctx);
105 ATF_TC_HEAD(libbpfjit_cop_no_ctx, tc)
106 {
107         atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
108             "instruction isn't valid without a context");
109 }
110
111 ATF_TC_BODY(libbpfjit_cop_no_ctx, tc)
112 {
113         static struct bpf_insn insns[] = {
114                 BPF_STMT(BPF_MISC+BPF_COP, 0),
115                 BPF_STMT(BPF_RET+BPF_K, 7)
116         };
117
118         bpfjit_func_t code;
119
120         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
121
122         ATF_CHECK(!bpf_validate(insns, insn_count));
123
124         code = bpfjit_generate_code(NULL, insns, insn_count);
125         ATF_CHECK(code == NULL);
126 }
127
128 ATF_TC(libbpfjit_cop_ret_A);
129 ATF_TC_HEAD(libbpfjit_cop_ret_A, tc)
130 {
131         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
132             "that returns a content of the A register");
133 }
134
135 ATF_TC_BODY(libbpfjit_cop_ret_A, tc)
136 {
137         static struct bpf_insn insns[] = {
138                 BPF_STMT(BPF_LD+BPF_IMM, 13),
139                 BPF_STMT(BPF_MISC+BPF_COP, 0), // retA
140                 BPF_STMT(BPF_RET+BPF_A, 0)
141         };
142
143         bpfjit_func_t code;
144         uint8_t pkt[1] = { 0 };
145         bpf_args_t args = {
146                 .pkt = pkt,
147                 .buflen = sizeof(pkt),
148                 .wirelen = sizeof(pkt),
149         };
150
151         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
152
153         code = bpfjit_generate_code(&ctx, insns, insn_count);
154         ATF_REQUIRE(code != NULL);
155
156         ATF_CHECK(code(&ctx, &args) == 13);
157
158         bpfjit_free_code(code);
159 }
160
161 ATF_TC(libbpfjit_cop_ret_buflen);
162 ATF_TC_HEAD(libbpfjit_cop_ret_buflen, tc)
163 {
164         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
165             "that returns the buflen argument");
166 }
167
168 ATF_TC_BODY(libbpfjit_cop_ret_buflen, tc)
169 {
170         static struct bpf_insn insns[] = {
171                 BPF_STMT(BPF_LD+BPF_IMM, 13),
172                 BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL
173                 BPF_STMT(BPF_RET+BPF_A, 0)
174         };
175
176         bpfjit_func_t code;
177         uint8_t pkt[1] = { 0 };
178         bpf_args_t args = {
179                 .pkt = pkt,
180                 .buflen = sizeof(pkt),
181                 .wirelen = sizeof(pkt)
182         };
183
184         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
185
186         code = bpfjit_generate_code(&ctx, insns, insn_count);
187         ATF_REQUIRE(code != NULL);
188
189         ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
190
191         bpfjit_free_code(code);
192 }
193
194 ATF_TC(libbpfjit_cop_ret_wirelen);
195 ATF_TC_HEAD(libbpfjit_cop_ret_wirelen, tc)
196 {
197         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
198             "that returns the wirelen argument");
199 }
200
201 ATF_TC_BODY(libbpfjit_cop_ret_wirelen, tc)
202 {
203         static struct bpf_insn insns[] = {
204                 BPF_STMT(BPF_LD+BPF_IMM, 13),
205                 BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL
206                 BPF_STMT(BPF_RET+BPF_A, 0)
207         };
208
209         bpfjit_func_t code;
210         uint8_t pkt[1] = { 0 };
211         bpf_args_t args = {
212                 .pkt = pkt,
213                 .buflen = sizeof(pkt),
214                 .wirelen = sizeof(pkt)
215         };
216
217         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
218
219         code = bpfjit_generate_code(&ctx, insns, insn_count);
220         ATF_REQUIRE(code != NULL);
221
222         ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
223
224         bpfjit_free_code(code);
225 }
226
227 ATF_TC(libbpfjit_cop_ret_nfuncs);
228 ATF_TC_HEAD(libbpfjit_cop_ret_nfuncs, tc)
229 {
230         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
231             "that returns nfuncs member of the context argument");
232 }
233
234 ATF_TC_BODY(libbpfjit_cop_ret_nfuncs, tc)
235 {
236         static struct bpf_insn insns[] = {
237                 BPF_STMT(BPF_LD+BPF_IMM, 13),
238                 BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF
239                 BPF_STMT(BPF_RET+BPF_A, 0)
240         };
241
242         bpfjit_func_t code;
243         uint8_t pkt[1] = { 0 };
244         bpf_args_t args = {
245                 .pkt = pkt,
246                 .buflen = sizeof(pkt),
247                 .wirelen = sizeof(pkt)
248         };
249
250         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
251
252         code = bpfjit_generate_code(&ctx, insns, insn_count);
253         ATF_REQUIRE(code != NULL);
254
255         ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
256
257         bpfjit_free_code(code);
258 }
259
260 ATF_TC(libbpfjit_cop_side_effect);
261 ATF_TC_HEAD(libbpfjit_cop_side_effect, tc)
262 {
263         atf_tc_set_md_var(tc, "descr",
264             "Test that ABC optimization doesn't skip BPF_COP call");
265 }
266
267 ATF_TC_BODY(libbpfjit_cop_side_effect, tc)
268 {
269         static struct bpf_insn insns[] = {
270                 BPF_STMT(BPF_LD+BPF_IMM, 13),
271                 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
272                 BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG
273                 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
274                 BPF_STMT(BPF_RET+BPF_A, 0)
275         };
276
277         bpfjit_func_t code;
278         bool arg = false;
279         uint8_t pkt[1] = { 0 };
280         bpf_args_t args = {
281                 .pkt = pkt,
282                 .buflen = sizeof(pkt),
283                 .wirelen = sizeof(pkt),
284                 .mem = NULL,
285                 .arg = &arg
286         };
287
288         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
289
290         code = bpfjit_generate_code(&ctx, insns, insn_count);
291         ATF_REQUIRE(code != NULL);
292
293         ATF_CHECK(code(&ctx, &args) == 0);
294         ATF_CHECK(arg == true);
295
296         bpfjit_free_code(code);
297 }
298
299 ATF_TC(libbpfjit_cop_copx);
300 ATF_TC_HEAD(libbpfjit_cop_copx, tc)
301 {
302         atf_tc_set_md_var(tc, "descr",
303             "Test BPF_COP call followed by BPF_COPX call");
304 }
305
306 ATF_TC_BODY(libbpfjit_cop_copx, tc)
307 {
308         static struct bpf_insn insns[] = {
309                 BPF_STMT(BPF_LD+BPF_IMM, 1),         /* A <- 1    */
310                 BPF_STMT(BPF_MISC+BPF_COP, 0),       /* retA      */
311                 BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
312                 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
313                 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
314                 BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
315                 BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retNF     */
316                 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
317                 BPF_STMT(BPF_RET+BPF_A, 0)
318         };
319
320         bpfjit_func_t code;
321         uint8_t pkt[1] = { 2 };
322         bpf_args_t args = {
323                 .pkt = pkt,
324                 .buflen = sizeof(pkt),
325                 .wirelen = sizeof(pkt),
326         };
327
328         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
329
330         code = bpfjit_generate_code(&ctx, insns, insn_count);
331         ATF_REQUIRE(code != NULL);
332
333         ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
334
335         bpfjit_free_code(code);
336 }
337
338 ATF_TC(libbpfjit_cop_invalid_index);
339 ATF_TC_HEAD(libbpfjit_cop_invalid_index, tc)
340 {
341         atf_tc_set_md_var(tc, "descr",
342             "Test that out-of-range coprocessor function fails validation");
343 }
344
345 ATF_TC_BODY(libbpfjit_cop_invalid_index, tc)
346 {
347         static struct bpf_insn insns[] = {
348                 BPF_STMT(BPF_LD+BPF_IMM, 13),
349                 BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
350                 BPF_STMT(BPF_RET+BPF_K, 27)
351         };
352
353         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
354
355         ATF_CHECK(bpfjit_generate_code(&ctx, insns, insn_count) == NULL);
356 }
357
358 ATF_TC(libbpfjit_copx_no_ctx);
359 ATF_TC_HEAD(libbpfjit_copx_no_ctx, tc)
360 {
361         atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
362             "instruction isn't valid without a context");
363 }
364
365 ATF_TC_BODY(libbpfjit_copx_no_ctx, tc)
366 {
367         static struct bpf_insn insns[] = {
368                 BPF_STMT(BPF_MISC+BPF_COP, 0),
369                 BPF_STMT(BPF_RET+BPF_K, 7)
370         };
371
372         bpfjit_func_t code;
373
374         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
375
376         ATF_CHECK(!bpf_validate(insns, insn_count));
377
378         code = bpfjit_generate_code(NULL, insns, insn_count);
379         ATF_CHECK(code == NULL);
380 }
381
382 ATF_TC(libbpfjit_copx_ret_A);
383 ATF_TC_HEAD(libbpfjit_copx_ret_A, tc)
384 {
385         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
386             "that returns a content of the A register");
387 }
388
389 ATF_TC_BODY(libbpfjit_copx_ret_A, tc)
390 {
391         static struct bpf_insn insns[] = {
392                 BPF_STMT(BPF_LD+BPF_IMM, 13),
393                 BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
394                 BPF_STMT(BPF_MISC+BPF_COPX, 0),
395                 BPF_STMT(BPF_RET+BPF_A, 0)
396         };
397
398         bpfjit_func_t code;
399         uint8_t pkt[1] = { 0 };
400         bpf_args_t args = {
401                 .pkt = pkt,
402                 .buflen = sizeof(pkt),
403                 .wirelen = sizeof(pkt),
404         };
405
406         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
407
408         code = bpfjit_generate_code(&ctx, insns, insn_count);
409         ATF_REQUIRE(code != NULL);
410
411         ATF_CHECK(code(&ctx, &args) == 13);
412
413         bpfjit_free_code(code);
414 }
415
416 ATF_TC(libbpfjit_copx_ret_buflen);
417 ATF_TC_HEAD(libbpfjit_copx_ret_buflen, tc)
418 {
419         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
420             "that returns the buflen argument");
421 }
422
423 ATF_TC_BODY(libbpfjit_copx_ret_buflen, tc)
424 {
425         static struct bpf_insn insns[] = {
426                 BPF_STMT(BPF_LD+BPF_IMM, 13),
427                 BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
428                 BPF_STMT(BPF_MISC+BPF_COPX, 0),
429                 BPF_STMT(BPF_RET+BPF_A, 0)
430         };
431
432         bpfjit_func_t code;
433         uint8_t pkt[1] = { 0 };
434         bpf_args_t args = {
435                 .pkt = pkt,
436                 .buflen = sizeof(pkt),
437                 .wirelen = sizeof(pkt)
438         };
439
440         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
441
442         code = bpfjit_generate_code(&ctx, insns, insn_count);
443         ATF_REQUIRE(code != NULL);
444
445         ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
446
447         bpfjit_free_code(code);
448 }
449
450 ATF_TC(libbpfjit_copx_ret_wirelen);
451 ATF_TC_HEAD(libbpfjit_copx_ret_wirelen, tc)
452 {
453         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
454             "that returns the wirelen argument");
455 }
456
457 ATF_TC_BODY(libbpfjit_copx_ret_wirelen, tc)
458 {
459         static struct bpf_insn insns[] = {
460                 BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
461                 BPF_STMT(BPF_LD+BPF_IMM, 13),
462                 BPF_STMT(BPF_MISC+BPF_COPX, 0),
463                 BPF_STMT(BPF_RET+BPF_A, 0)
464         };
465
466         bpfjit_func_t code;
467         uint8_t pkt[1] = { 0 };
468         bpf_args_t args = {
469                 .pkt = pkt,
470                 .buflen = sizeof(pkt),
471                 .wirelen = sizeof(pkt)
472         };
473
474         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
475
476         code = bpfjit_generate_code(&ctx, insns, insn_count);
477         ATF_REQUIRE(code != NULL);
478
479         ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
480
481         bpfjit_free_code(code);
482 }
483
484 ATF_TC(libbpfjit_copx_ret_nfuncs);
485 ATF_TC_HEAD(libbpfjit_copx_ret_nfuncs, tc)
486 {
487         atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
488             "that returns nfuncs member of the context argument");
489 }
490
491 ATF_TC_BODY(libbpfjit_copx_ret_nfuncs, tc)
492 {
493         static struct bpf_insn insns[] = {
494                 BPF_STMT(BPF_LD+BPF_IMM, 13),
495                 BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
496                 BPF_STMT(BPF_MISC+BPF_COPX, 0),
497                 BPF_STMT(BPF_RET+BPF_A, 0)
498         };
499
500         bpfjit_func_t code;
501         uint8_t pkt[1] = { 0 };
502         bpf_args_t args = {
503                 .pkt = pkt,
504                 .buflen = sizeof(pkt),
505                 .wirelen = sizeof(pkt)
506         };
507
508         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
509
510         code = bpfjit_generate_code(&ctx, insns, insn_count);
511         ATF_REQUIRE(code != NULL);
512
513         ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
514
515         bpfjit_free_code(code);
516 }
517
518 ATF_TC(libbpfjit_copx_side_effect);
519 ATF_TC_HEAD(libbpfjit_copx_side_effect, tc)
520 {
521         atf_tc_set_md_var(tc, "descr",
522             "Test that ABC optimization doesn't skip BPF_COPX call");
523 }
524
525 ATF_TC_BODY(libbpfjit_copx_side_effect, tc)
526 {
527         static struct bpf_insn insns[] = {
528                 BPF_STMT(BPF_LD+BPF_IMM, 13),
529                 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
530                 BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
531                 BPF_STMT(BPF_MISC+BPF_COPX, 0),
532                 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
533                 BPF_STMT(BPF_RET+BPF_A, 0)
534         };
535
536         bpfjit_func_t code;
537         bool arg = false;
538         uint8_t pkt[1] = { 0 };
539         bpf_args_t args = {
540                 .pkt = pkt,
541                 .buflen = sizeof(pkt),
542                 .wirelen = sizeof(pkt),
543                 .mem = NULL,
544                 .arg = &arg
545         };
546
547         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
548
549         code = bpfjit_generate_code(&ctx, insns, insn_count);
550         ATF_REQUIRE(code != NULL);
551
552         ATF_CHECK(code(&ctx, &args) == 0);
553         ATF_CHECK(arg == true);
554
555         bpfjit_free_code(code);
556 }
557
558 ATF_TC(libbpfjit_copx_cop);
559 ATF_TC_HEAD(libbpfjit_copx_cop, tc)
560 {
561         atf_tc_set_md_var(tc, "descr",
562             "Test BPF_COPX call followed by BPF_COP call");
563 }
564
565 ATF_TC_BODY(libbpfjit_copx_cop, tc)
566 {
567         static struct bpf_insn insns[] = {
568                 BPF_STMT(BPF_LDX+BPF_IMM, 2),        /* X <- 2    */
569                 BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retWL     */
570                 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
571                 BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
572                 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
573                 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
574                 BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
575                 BPF_STMT(BPF_MISC+BPF_COP, 3),      /* retNF     */
576                 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
577                 BPF_STMT(BPF_RET+BPF_A, 0)
578         };
579
580         bpfjit_func_t code;
581         uint8_t pkt[1] = { 2 };
582         bpf_args_t args = {
583                 .pkt = pkt,
584                 .buflen = sizeof(pkt),
585                 .wirelen = sizeof(pkt),
586         };
587
588         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
589
590         code = bpfjit_generate_code(&ctx, insns, insn_count);
591         ATF_REQUIRE(code != NULL);
592
593         ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
594
595         bpfjit_free_code(code);
596 }
597
598 ATF_TC(libbpfjit_copx_invalid_index);
599 ATF_TC_HEAD(libbpfjit_copx_invalid_index, tc)
600 {
601         atf_tc_set_md_var(tc, "descr",
602             "Test that out-of-range BPF_COPX call fails at runtime");
603 }
604
605 ATF_TC_BODY(libbpfjit_copx_invalid_index, tc)
606 {
607         static struct bpf_insn insns[] = {
608                 BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
609                 BPF_STMT(BPF_MISC+BPF_COPX, 0),
610                 BPF_STMT(BPF_RET+BPF_K, 27)
611         };
612
613         bpfjit_func_t code;
614         uint8_t pkt[1] = { 0 };
615         bpf_args_t args = {
616                 .pkt = pkt,
617                 .buflen = sizeof(pkt),
618                 .wirelen = sizeof(pkt)
619         };
620
621         size_t insn_count = sizeof(insns) / sizeof(insns[0]);
622
623         code = bpfjit_generate_code(&ctx, insns, insn_count);
624         ATF_REQUIRE(code != NULL);
625
626         ATF_CHECK(code(&ctx, &args) == 0);
627
628         bpfjit_free_code(code);
629 }
630
631 ATF_TP_ADD_TCS(tp)
632 {
633
634         /*
635          * For every new test please also add a similar test
636          * to ../../net/bpfjit/t_cop.c
637          */
638         ATF_TP_ADD_TC(tp, libbpfjit_cop_no_ctx);
639         ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_A);
640         ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_buflen);
641         ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_wirelen);
642         ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_nfuncs);
643         ATF_TP_ADD_TC(tp, libbpfjit_cop_side_effect);
644         ATF_TP_ADD_TC(tp, libbpfjit_cop_copx);
645         ATF_TP_ADD_TC(tp, libbpfjit_cop_invalid_index);
646
647         ATF_TP_ADD_TC(tp, libbpfjit_copx_no_ctx);
648         ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_A);
649         ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_buflen);
650         ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_wirelen);
651         ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_nfuncs);
652         ATF_TP_ADD_TC(tp, libbpfjit_copx_side_effect);
653         ATF_TP_ADD_TC(tp, libbpfjit_copx_cop);
654         ATF_TP_ADD_TC(tp, libbpfjit_copx_invalid_index);
655
656         return atf_no_error();
657 }