xref: /freebsd/contrib/netbsd-tests/lib/libbpfjit/t_cop.c (revision cddbc3b40812213ff00041f79174cac0be360a2a)
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 }
658