2 * lttng-filter-validator.c
4 * LTTng UST filter bytecode validator.
6 * Copyright (C) 2010-2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 #include "lttng-filter.h"
32 #include <urcu/rculfhash.h>
33 #include "lttng-hash-helper.h"
34 #include "string-utils.h"
37 * Number of merge points for hash table size. Hash table initialized to
38 * that size, and we do not resize, because we do not want to trigger
39 * RCU worker thread execution: fall-back on linear traversal if number
40 * of merge points exceeds this value.
42 #define DEFAULT_NR_MERGE_POINTS 128
43 #define MIN_NR_BUCKETS 128
44 #define MAX_NR_BUCKETS 128
46 /* merge point table node */
48 struct cds_lfht_node node
;
50 /* Context at merge point */
52 unsigned long target_pc
;
55 static unsigned long lttng_hash_seed
;
56 static unsigned int lttng_hash_seed_ready
;
59 int lttng_hash_match(struct cds_lfht_node
*node
, const void *key
)
61 struct lfht_mp_node
*mp_node
=
62 caa_container_of(node
, struct lfht_mp_node
, node
);
63 unsigned long key_pc
= (unsigned long) key
;
65 if (mp_node
->target_pc
== key_pc
)
72 int merge_points_compare(const struct vstack
*stacka
,
73 const struct vstack
*stackb
)
77 if (stacka
->top
!= stackb
->top
)
79 len
= stacka
->top
+ 1;
81 for (i
= 0; i
< len
; i
++) {
82 if (stacka
->e
[i
].type
!= REG_UNKNOWN
83 && stackb
->e
[i
].type
!= REG_UNKNOWN
84 && stacka
->e
[i
].type
!= stackb
->e
[i
].type
)
91 int merge_point_add_check(struct cds_lfht
*ht
, unsigned long target_pc
,
92 const struct vstack
*stack
)
94 struct lfht_mp_node
*node
;
95 unsigned long hash
= lttng_hash_mix((const char *) target_pc
,
98 struct cds_lfht_node
*ret
;
100 dbg_printf("Filter: adding merge point at offset %lu, hash %lu\n",
102 node
= zmalloc(sizeof(struct lfht_mp_node
));
105 node
->target_pc
= target_pc
;
106 memcpy(&node
->stack
, stack
, sizeof(node
->stack
));
107 ret
= cds_lfht_add_unique(ht
, hash
, lttng_hash_match
,
108 (const char *) target_pc
, &node
->node
);
109 if (ret
!= &node
->node
) {
110 struct lfht_mp_node
*ret_mp
=
111 caa_container_of(ret
, struct lfht_mp_node
, node
);
113 /* Key already present */
114 dbg_printf("Filter: compare merge points for offset %lu, hash %lu\n",
117 if (merge_points_compare(stack
, &ret_mp
->stack
)) {
118 ERR("Merge points differ for offset %lu\n",
127 * Binary comparators use top of stack and top of stack -1.
128 * Return 0 if typing is known to match, 1 if typing is dynamic
129 * (unknown), negative error value on error.
132 int bin_op_compare_check(struct vstack
*stack
, filter_opcode_t opcode
,
135 if (unlikely(!vstack_ax(stack
) || !vstack_bx(stack
)))
138 switch (vstack_ax(stack
)->type
) {
145 switch (vstack_bx(stack
)->type
) {
153 case REG_STAR_GLOB_STRING
:
154 if (opcode
!= FILTER_OP_EQ
&& opcode
!= FILTER_OP_NE
) {
163 case REG_STAR_GLOB_STRING
:
164 switch (vstack_bx(stack
)->type
) {
171 if (opcode
!= FILTER_OP_EQ
&& opcode
!= FILTER_OP_NE
) {
175 case REG_STAR_GLOB_STRING
:
183 switch (vstack_bx(stack
)->type
) {
190 case REG_STAR_GLOB_STRING
:
204 ERR("type mismatch for '%s' binary operator\n", str
);
208 ERR("empty stack for '%s' binary operator\n", str
);
212 ERR("unknown type for '%s' binary operator\n", str
);
217 * Validate bytecode range overflow within the validation pass.
218 * Called for each instruction encountered.
221 int bytecode_validate_overflow(struct bytecode_runtime
*bytecode
,
222 char *start_pc
, char *pc
)
226 switch (*(filter_opcode_t
*) pc
) {
227 case FILTER_OP_UNKNOWN
:
230 ERR("unknown bytecode op %u\n",
231 (unsigned int) *(filter_opcode_t
*) pc
);
236 case FILTER_OP_RETURN
:
238 if (unlikely(pc
+ sizeof(struct return_op
)
239 > start_pc
+ bytecode
->len
)) {
250 case FILTER_OP_MINUS
:
251 case FILTER_OP_RSHIFT
:
252 case FILTER_OP_LSHIFT
:
253 case FILTER_OP_BIN_AND
:
254 case FILTER_OP_BIN_OR
:
255 case FILTER_OP_BIN_XOR
:
257 ERR("unsupported bytecode op %u\n",
258 (unsigned int) *(filter_opcode_t
*) pc
);
269 case FILTER_OP_EQ_STRING
:
270 case FILTER_OP_NE_STRING
:
271 case FILTER_OP_GT_STRING
:
272 case FILTER_OP_LT_STRING
:
273 case FILTER_OP_GE_STRING
:
274 case FILTER_OP_LE_STRING
:
275 case FILTER_OP_EQ_STAR_GLOB_STRING
:
276 case FILTER_OP_NE_STAR_GLOB_STRING
:
277 case FILTER_OP_EQ_S64
:
278 case FILTER_OP_NE_S64
:
279 case FILTER_OP_GT_S64
:
280 case FILTER_OP_LT_S64
:
281 case FILTER_OP_GE_S64
:
282 case FILTER_OP_LE_S64
:
283 case FILTER_OP_EQ_DOUBLE
:
284 case FILTER_OP_NE_DOUBLE
:
285 case FILTER_OP_GT_DOUBLE
:
286 case FILTER_OP_LT_DOUBLE
:
287 case FILTER_OP_GE_DOUBLE
:
288 case FILTER_OP_LE_DOUBLE
:
289 case FILTER_OP_EQ_DOUBLE_S64
:
290 case FILTER_OP_NE_DOUBLE_S64
:
291 case FILTER_OP_GT_DOUBLE_S64
:
292 case FILTER_OP_LT_DOUBLE_S64
:
293 case FILTER_OP_GE_DOUBLE_S64
:
294 case FILTER_OP_LE_DOUBLE_S64
:
295 case FILTER_OP_EQ_S64_DOUBLE
:
296 case FILTER_OP_NE_S64_DOUBLE
:
297 case FILTER_OP_GT_S64_DOUBLE
:
298 case FILTER_OP_LT_S64_DOUBLE
:
299 case FILTER_OP_GE_S64_DOUBLE
:
300 case FILTER_OP_LE_S64_DOUBLE
:
302 if (unlikely(pc
+ sizeof(struct binary_op
)
303 > start_pc
+ bytecode
->len
)) {
310 case FILTER_OP_UNARY_PLUS
:
311 case FILTER_OP_UNARY_MINUS
:
312 case FILTER_OP_UNARY_NOT
:
313 case FILTER_OP_UNARY_PLUS_S64
:
314 case FILTER_OP_UNARY_MINUS_S64
:
315 case FILTER_OP_UNARY_NOT_S64
:
316 case FILTER_OP_UNARY_PLUS_DOUBLE
:
317 case FILTER_OP_UNARY_MINUS_DOUBLE
:
318 case FILTER_OP_UNARY_NOT_DOUBLE
:
320 if (unlikely(pc
+ sizeof(struct unary_op
)
321 > start_pc
+ bytecode
->len
)) {
331 if (unlikely(pc
+ sizeof(struct logical_op
)
332 > start_pc
+ bytecode
->len
)) {
339 case FILTER_OP_LOAD_FIELD_REF
:
341 ERR("Unknown field ref type\n");
345 /* get context ref */
346 case FILTER_OP_GET_CONTEXT_REF
:
347 case FILTER_OP_LOAD_FIELD_REF_STRING
:
348 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
349 case FILTER_OP_LOAD_FIELD_REF_S64
:
350 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
351 case FILTER_OP_GET_CONTEXT_REF_STRING
:
352 case FILTER_OP_GET_CONTEXT_REF_S64
:
353 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
355 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct field_ref
)
356 > start_pc
+ bytecode
->len
)) {
362 /* load from immediate operand */
363 case FILTER_OP_LOAD_STRING
:
364 case FILTER_OP_LOAD_STAR_GLOB_STRING
:
366 struct load_op
*insn
= (struct load_op
*) pc
;
367 uint32_t str_len
, maxlen
;
369 if (unlikely(pc
+ sizeof(struct load_op
)
370 > start_pc
+ bytecode
->len
)) {
375 maxlen
= start_pc
+ bytecode
->len
- pc
- sizeof(struct load_op
);
376 str_len
= strnlen(insn
->data
, maxlen
);
377 if (unlikely(str_len
>= maxlen
)) {
378 /* Final '\0' not found within range */
384 case FILTER_OP_LOAD_S64
:
386 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct literal_numeric
)
387 > start_pc
+ bytecode
->len
)) {
393 case FILTER_OP_LOAD_DOUBLE
:
395 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct literal_double
)
396 > start_pc
+ bytecode
->len
)) {
402 case FILTER_OP_CAST_TO_S64
:
403 case FILTER_OP_CAST_DOUBLE_TO_S64
:
404 case FILTER_OP_CAST_NOP
:
406 if (unlikely(pc
+ sizeof(struct cast_op
)
407 > start_pc
+ bytecode
->len
)) {
419 unsigned long delete_all_nodes(struct cds_lfht
*ht
)
421 struct cds_lfht_iter iter
;
422 struct lfht_mp_node
*node
;
423 unsigned long nr_nodes
= 0;
425 cds_lfht_for_each_entry(ht
, &iter
, node
, node
) {
428 ret
= cds_lfht_del(ht
, cds_lfht_iter_get_node(&iter
));
430 /* note: this hash table is never used concurrently */
443 int validate_instruction_context(struct bytecode_runtime
*bytecode
,
444 struct vstack
*stack
,
449 const filter_opcode_t opcode
= *(filter_opcode_t
*) pc
;
452 case FILTER_OP_UNKNOWN
:
455 ERR("unknown bytecode op %u\n",
456 (unsigned int) *(filter_opcode_t
*) pc
);
461 case FILTER_OP_RETURN
:
471 case FILTER_OP_MINUS
:
472 case FILTER_OP_RSHIFT
:
473 case FILTER_OP_LSHIFT
:
474 case FILTER_OP_BIN_AND
:
475 case FILTER_OP_BIN_OR
:
476 case FILTER_OP_BIN_XOR
:
478 ERR("unsupported bytecode op %u\n",
479 (unsigned int) opcode
);
486 ret
= bin_op_compare_check(stack
, opcode
, "==");
493 ret
= bin_op_compare_check(stack
, opcode
, "!=");
500 ret
= bin_op_compare_check(stack
, opcode
, ">");
507 ret
= bin_op_compare_check(stack
, opcode
, "<");
514 ret
= bin_op_compare_check(stack
, opcode
, ">=");
521 ret
= bin_op_compare_check(stack
, opcode
, "<=");
527 case FILTER_OP_EQ_STRING
:
528 case FILTER_OP_NE_STRING
:
529 case FILTER_OP_GT_STRING
:
530 case FILTER_OP_LT_STRING
:
531 case FILTER_OP_GE_STRING
:
532 case FILTER_OP_LE_STRING
:
534 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
535 ERR("Empty stack\n");
539 if (vstack_ax(stack
)->type
!= REG_STRING
540 || vstack_bx(stack
)->type
!= REG_STRING
) {
541 ERR("Unexpected register type for string comparator\n");
548 case FILTER_OP_EQ_STAR_GLOB_STRING
:
549 case FILTER_OP_NE_STAR_GLOB_STRING
:
551 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
552 ERR("Empty stack\n");
556 if (vstack_ax(stack
)->type
!= REG_STAR_GLOB_STRING
557 && vstack_bx(stack
)->type
!= REG_STAR_GLOB_STRING
) {
558 ERR("Unexpected register type for globbing pattern comparator\n");
565 case FILTER_OP_EQ_S64
:
566 case FILTER_OP_NE_S64
:
567 case FILTER_OP_GT_S64
:
568 case FILTER_OP_LT_S64
:
569 case FILTER_OP_GE_S64
:
570 case FILTER_OP_LE_S64
:
572 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
573 ERR("Empty stack\n");
577 if (vstack_ax(stack
)->type
!= REG_S64
578 || vstack_bx(stack
)->type
!= REG_S64
) {
579 ERR("Unexpected register type for s64 comparator\n");
586 case FILTER_OP_EQ_DOUBLE
:
587 case FILTER_OP_NE_DOUBLE
:
588 case FILTER_OP_GT_DOUBLE
:
589 case FILTER_OP_LT_DOUBLE
:
590 case FILTER_OP_GE_DOUBLE
:
591 case FILTER_OP_LE_DOUBLE
:
593 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
594 ERR("Empty stack\n");
598 if (vstack_ax(stack
)->type
!= REG_DOUBLE
&& vstack_bx(stack
)->type
!= REG_DOUBLE
) {
599 ERR("Double operator should have two double registers\n");
606 case FILTER_OP_EQ_DOUBLE_S64
:
607 case FILTER_OP_NE_DOUBLE_S64
:
608 case FILTER_OP_GT_DOUBLE_S64
:
609 case FILTER_OP_LT_DOUBLE_S64
:
610 case FILTER_OP_GE_DOUBLE_S64
:
611 case FILTER_OP_LE_DOUBLE_S64
:
613 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
614 ERR("Empty stack\n");
618 if (vstack_ax(stack
)->type
!= REG_S64
&& vstack_bx(stack
)->type
!= REG_DOUBLE
) {
619 ERR("Double-S64 operator has unexpected register types\n");
626 case FILTER_OP_EQ_S64_DOUBLE
:
627 case FILTER_OP_NE_S64_DOUBLE
:
628 case FILTER_OP_GT_S64_DOUBLE
:
629 case FILTER_OP_LT_S64_DOUBLE
:
630 case FILTER_OP_GE_S64_DOUBLE
:
631 case FILTER_OP_LE_S64_DOUBLE
:
633 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
634 ERR("Empty stack\n");
638 if (vstack_ax(stack
)->type
!= REG_DOUBLE
&& vstack_bx(stack
)->type
!= REG_S64
) {
639 ERR("S64-Double operator has unexpected register types\n");
647 case FILTER_OP_UNARY_PLUS
:
648 case FILTER_OP_UNARY_MINUS
:
649 case FILTER_OP_UNARY_NOT
:
651 if (!vstack_ax(stack
)) {
652 ERR("Empty stack\n");
656 switch (vstack_ax(stack
)->type
) {
658 ERR("unknown register type\n");
663 case REG_STAR_GLOB_STRING
:
664 ERR("Unary op can only be applied to numeric or floating point registers\n");
677 case FILTER_OP_UNARY_PLUS_S64
:
678 case FILTER_OP_UNARY_MINUS_S64
:
679 case FILTER_OP_UNARY_NOT_S64
:
681 if (!vstack_ax(stack
)) {
682 ERR("Empty stack\n");
686 if (vstack_ax(stack
)->type
!= REG_S64
) {
687 ERR("Invalid register type\n");
694 case FILTER_OP_UNARY_PLUS_DOUBLE
:
695 case FILTER_OP_UNARY_MINUS_DOUBLE
:
696 case FILTER_OP_UNARY_NOT_DOUBLE
:
698 if (!vstack_ax(stack
)) {
699 ERR("Empty stack\n");
703 if (vstack_ax(stack
)->type
!= REG_DOUBLE
) {
704 ERR("Invalid register type\n");
715 struct logical_op
*insn
= (struct logical_op
*) pc
;
717 if (!vstack_ax(stack
)) {
718 ERR("Empty stack\n");
722 if (vstack_ax(stack
)->type
!= REG_S64
723 && vstack_ax(stack
)->type
!= REG_UNKNOWN
) {
724 ERR("Logical comparator expects S64 or dynamic register\n");
729 dbg_printf("Validate jumping to bytecode offset %u\n",
730 (unsigned int) insn
->skip_offset
);
731 if (unlikely(start_pc
+ insn
->skip_offset
<= pc
)) {
732 ERR("Loops are not allowed in bytecode\n");
740 case FILTER_OP_LOAD_FIELD_REF
:
742 ERR("Unknown field ref type\n");
746 case FILTER_OP_LOAD_FIELD_REF_STRING
:
747 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
749 struct load_op
*insn
= (struct load_op
*) pc
;
750 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
752 dbg_printf("Validate load field ref offset %u type string\n",
756 case FILTER_OP_LOAD_FIELD_REF_S64
:
758 struct load_op
*insn
= (struct load_op
*) pc
;
759 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
761 dbg_printf("Validate load field ref offset %u type s64\n",
765 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
767 struct load_op
*insn
= (struct load_op
*) pc
;
768 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
770 dbg_printf("Validate load field ref offset %u type double\n",
775 /* load from immediate operand */
776 case FILTER_OP_LOAD_STRING
:
777 case FILTER_OP_LOAD_STAR_GLOB_STRING
:
782 case FILTER_OP_LOAD_S64
:
787 case FILTER_OP_LOAD_DOUBLE
:
792 case FILTER_OP_CAST_TO_S64
:
793 case FILTER_OP_CAST_DOUBLE_TO_S64
:
795 struct cast_op
*insn
= (struct cast_op
*) pc
;
797 if (!vstack_ax(stack
)) {
798 ERR("Empty stack\n");
802 switch (vstack_ax(stack
)->type
) {
804 ERR("unknown register type\n");
809 case REG_STAR_GLOB_STRING
:
810 ERR("Cast op can only be applied to numeric or floating point registers\n");
820 if (insn
->op
== FILTER_OP_CAST_DOUBLE_TO_S64
) {
821 if (vstack_ax(stack
)->type
!= REG_DOUBLE
) {
822 ERR("Cast expects double\n");
829 case FILTER_OP_CAST_NOP
:
834 /* get context ref */
835 case FILTER_OP_GET_CONTEXT_REF
:
837 struct load_op
*insn
= (struct load_op
*) pc
;
838 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
840 dbg_printf("Validate get context ref offset %u type dynamic\n",
844 case FILTER_OP_GET_CONTEXT_REF_STRING
:
846 struct load_op
*insn
= (struct load_op
*) pc
;
847 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
849 dbg_printf("Validate get context ref offset %u type string\n",
853 case FILTER_OP_GET_CONTEXT_REF_S64
:
855 struct load_op
*insn
= (struct load_op
*) pc
;
856 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
858 dbg_printf("Validate get context ref offset %u type s64\n",
862 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
864 struct load_op
*insn
= (struct load_op
*) pc
;
865 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
867 dbg_printf("Validate get context ref offset %u type double\n",
883 int validate_instruction_all_contexts(struct bytecode_runtime
*bytecode
,
884 struct cds_lfht
*merge_points
,
885 struct vstack
*stack
,
890 unsigned long target_pc
= pc
- start_pc
;
891 struct cds_lfht_iter iter
;
892 struct cds_lfht_node
*node
;
893 struct lfht_mp_node
*mp_node
;
896 /* Validate the context resulting from the previous instruction */
897 ret
= validate_instruction_context(bytecode
, stack
, start_pc
, pc
);
901 /* Validate merge points */
902 hash
= lttng_hash_mix((const char *) target_pc
, sizeof(target_pc
),
904 cds_lfht_lookup(merge_points
, hash
, lttng_hash_match
,
905 (const char *) target_pc
, &iter
);
906 node
= cds_lfht_iter_get_node(&iter
);
908 mp_node
= caa_container_of(node
, struct lfht_mp_node
, node
);
910 dbg_printf("Filter: validate merge point at offset %lu\n",
912 if (merge_points_compare(stack
, &mp_node
->stack
)) {
913 ERR("Merge points differ for offset %lu\n",
917 /* Once validated, we can remove the merge point */
918 dbg_printf("Filter: remove merge point at offset %lu\n",
920 ret
= cds_lfht_del(merge_points
, node
);
928 * >0: going to next insn.
929 * 0: success, stop iteration.
933 int exec_insn(struct bytecode_runtime
*bytecode
,
934 struct cds_lfht
*merge_points
,
935 struct vstack
*stack
,
940 char *next_pc
= *_next_pc
;
942 switch (*(filter_opcode_t
*) pc
) {
943 case FILTER_OP_UNKNOWN
:
946 ERR("unknown bytecode op %u\n",
947 (unsigned int) *(filter_opcode_t
*) pc
);
952 case FILTER_OP_RETURN
:
954 if (!vstack_ax(stack
)) {
955 ERR("Empty stack\n");
968 case FILTER_OP_MINUS
:
969 case FILTER_OP_RSHIFT
:
970 case FILTER_OP_LSHIFT
:
971 case FILTER_OP_BIN_AND
:
972 case FILTER_OP_BIN_OR
:
973 case FILTER_OP_BIN_XOR
:
975 ERR("unsupported bytecode op %u\n",
976 (unsigned int) *(filter_opcode_t
*) pc
);
987 case FILTER_OP_EQ_STRING
:
988 case FILTER_OP_NE_STRING
:
989 case FILTER_OP_GT_STRING
:
990 case FILTER_OP_LT_STRING
:
991 case FILTER_OP_GE_STRING
:
992 case FILTER_OP_LE_STRING
:
993 case FILTER_OP_EQ_STAR_GLOB_STRING
:
994 case FILTER_OP_NE_STAR_GLOB_STRING
:
995 case FILTER_OP_EQ_S64
:
996 case FILTER_OP_NE_S64
:
997 case FILTER_OP_GT_S64
:
998 case FILTER_OP_LT_S64
:
999 case FILTER_OP_GE_S64
:
1000 case FILTER_OP_LE_S64
:
1001 case FILTER_OP_EQ_DOUBLE
:
1002 case FILTER_OP_NE_DOUBLE
:
1003 case FILTER_OP_GT_DOUBLE
:
1004 case FILTER_OP_LT_DOUBLE
:
1005 case FILTER_OP_GE_DOUBLE
:
1006 case FILTER_OP_LE_DOUBLE
:
1007 case FILTER_OP_EQ_DOUBLE_S64
:
1008 case FILTER_OP_NE_DOUBLE_S64
:
1009 case FILTER_OP_GT_DOUBLE_S64
:
1010 case FILTER_OP_LT_DOUBLE_S64
:
1011 case FILTER_OP_GE_DOUBLE_S64
:
1012 case FILTER_OP_LE_DOUBLE_S64
:
1013 case FILTER_OP_EQ_S64_DOUBLE
:
1014 case FILTER_OP_NE_S64_DOUBLE
:
1015 case FILTER_OP_GT_S64_DOUBLE
:
1016 case FILTER_OP_LT_S64_DOUBLE
:
1017 case FILTER_OP_GE_S64_DOUBLE
:
1018 case FILTER_OP_LE_S64_DOUBLE
:
1021 if (vstack_pop(stack
)) {
1025 if (!vstack_ax(stack
)) {
1026 ERR("Empty stack\n");
1030 vstack_ax(stack
)->type
= REG_S64
;
1031 next_pc
+= sizeof(struct binary_op
);
1036 case FILTER_OP_UNARY_PLUS
:
1037 case FILTER_OP_UNARY_MINUS
:
1040 if (!vstack_ax(stack
)) {
1041 ERR("Empty stack\n");
1045 vstack_ax(stack
)->type
= REG_UNKNOWN
;
1046 next_pc
+= sizeof(struct unary_op
);
1050 case FILTER_OP_UNARY_PLUS_S64
:
1051 case FILTER_OP_UNARY_MINUS_S64
:
1052 case FILTER_OP_UNARY_NOT
:
1053 case FILTER_OP_UNARY_NOT_S64
:
1054 case FILTER_OP_UNARY_NOT_DOUBLE
:
1057 if (!vstack_ax(stack
)) {
1058 ERR("Empty stack\n");
1062 vstack_ax(stack
)->type
= REG_S64
;
1063 next_pc
+= sizeof(struct unary_op
);
1067 case FILTER_OP_UNARY_PLUS_DOUBLE
:
1068 case FILTER_OP_UNARY_MINUS_DOUBLE
:
1071 if (!vstack_ax(stack
)) {
1072 ERR("Empty stack\n");
1076 vstack_ax(stack
)->type
= REG_DOUBLE
;
1077 next_pc
+= sizeof(struct unary_op
);
1085 struct logical_op
*insn
= (struct logical_op
*) pc
;
1088 /* Add merge point to table */
1089 merge_ret
= merge_point_add_check(merge_points
,
1090 insn
->skip_offset
, stack
);
1095 /* Continue to next instruction */
1096 /* Pop 1 when jump not taken */
1097 if (vstack_pop(stack
)) {
1101 next_pc
+= sizeof(struct logical_op
);
1105 /* load field ref */
1106 case FILTER_OP_LOAD_FIELD_REF
:
1108 ERR("Unknown field ref type\n");
1112 /* get context ref */
1113 case FILTER_OP_GET_CONTEXT_REF
:
1115 if (vstack_push(stack
)) {
1119 vstack_ax(stack
)->type
= REG_UNKNOWN
;
1120 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1123 case FILTER_OP_LOAD_FIELD_REF_STRING
:
1124 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
1125 case FILTER_OP_GET_CONTEXT_REF_STRING
:
1127 if (vstack_push(stack
)) {
1131 vstack_ax(stack
)->type
= REG_STRING
;
1132 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1135 case FILTER_OP_LOAD_FIELD_REF_S64
:
1136 case FILTER_OP_GET_CONTEXT_REF_S64
:
1138 if (vstack_push(stack
)) {
1142 vstack_ax(stack
)->type
= REG_S64
;
1143 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1146 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
1147 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
1149 if (vstack_push(stack
)) {
1153 vstack_ax(stack
)->type
= REG_DOUBLE
;
1154 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1158 /* load from immediate operand */
1159 case FILTER_OP_LOAD_STRING
:
1161 struct load_op
*insn
= (struct load_op
*) pc
;
1163 if (vstack_push(stack
)) {
1167 vstack_ax(stack
)->type
= REG_STRING
;
1168 next_pc
+= sizeof(struct load_op
) + strlen(insn
->data
) + 1;
1172 case FILTER_OP_LOAD_STAR_GLOB_STRING
:
1174 struct load_op
*insn
= (struct load_op
*) pc
;
1176 if (vstack_push(stack
)) {
1180 vstack_ax(stack
)->type
= REG_STAR_GLOB_STRING
;
1181 next_pc
+= sizeof(struct load_op
) + strlen(insn
->data
) + 1;
1185 case FILTER_OP_LOAD_S64
:
1187 if (vstack_push(stack
)) {
1191 vstack_ax(stack
)->type
= REG_S64
;
1192 next_pc
+= sizeof(struct load_op
)
1193 + sizeof(struct literal_numeric
);
1197 case FILTER_OP_LOAD_DOUBLE
:
1199 if (vstack_push(stack
)) {
1203 vstack_ax(stack
)->type
= REG_DOUBLE
;
1204 next_pc
+= sizeof(struct load_op
)
1205 + sizeof(struct literal_double
);
1209 case FILTER_OP_CAST_TO_S64
:
1210 case FILTER_OP_CAST_DOUBLE_TO_S64
:
1213 if (!vstack_ax(stack
)) {
1214 ERR("Empty stack\n");
1218 vstack_ax(stack
)->type
= REG_S64
;
1219 next_pc
+= sizeof(struct cast_op
);
1222 case FILTER_OP_CAST_NOP
:
1224 next_pc
+= sizeof(struct cast_op
);
1230 *_next_pc
= next_pc
;
1235 * Never called concurrently (hash seed is shared).
1237 int lttng_filter_validate_bytecode(struct bytecode_runtime
*bytecode
)
1239 struct cds_lfht
*merge_points
;
1240 char *pc
, *next_pc
, *start_pc
;
1242 struct vstack stack
;
1244 vstack_init(&stack
);
1246 if (!lttng_hash_seed_ready
) {
1247 lttng_hash_seed
= time(NULL
);
1248 lttng_hash_seed_ready
= 1;
1251 * Note: merge_points hash table used by single thread, and
1252 * never concurrently resized. Therefore, we can use it without
1253 * holding RCU read-side lock and free nodes without using
1256 merge_points
= cds_lfht_new(DEFAULT_NR_MERGE_POINTS
,
1257 MIN_NR_BUCKETS
, MAX_NR_BUCKETS
,
1259 if (!merge_points
) {
1260 ERR("Error allocating hash table for bytecode validation\n");
1263 start_pc
= &bytecode
->data
[0];
1264 for (pc
= next_pc
= start_pc
; pc
- start_pc
< bytecode
->len
;
1266 ret
= bytecode_validate_overflow(bytecode
, start_pc
, pc
);
1269 ERR("filter bytecode overflow\n");
1272 dbg_printf("Validating op %s (%u)\n",
1273 print_op((unsigned int) *(filter_opcode_t
*) pc
),
1274 (unsigned int) *(filter_opcode_t
*) pc
);
1277 * For each instruction, validate the current context
1278 * (traversal of entire execution flow), and validate
1279 * all merge points targeting this instruction.
1281 ret
= validate_instruction_all_contexts(bytecode
, merge_points
,
1282 &stack
, start_pc
, pc
);
1285 ret
= exec_insn(bytecode
, merge_points
, &stack
, &next_pc
, pc
);
1290 if (delete_all_nodes(merge_points
)) {
1292 ERR("Unexpected merge points\n");
1296 if (cds_lfht_destroy(merge_points
, NULL
)) {
1297 ERR("Error destroying hash table\n");