2 * lttng-filter-validator.c
4 * LTTng UST filter bytecode validator.
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "lttng-filter.h"
28 #include <urcu/rculfhash.h>
29 #include "lttng-hash-helper.h"
32 * Number of merge points for hash table size. Hash table initialized to
33 * that size, and we do not resize, because we do not want to trigger
34 * RCU worker thread execution: fall-back on linear traversal if number
35 * of merge points exceeds this value.
37 #define DEFAULT_NR_MERGE_POINTS 128
38 #define MIN_NR_BUCKETS 128
39 #define MAX_NR_BUCKETS 128
41 /* merge point table node */
43 struct cds_lfht_node node
;
45 /* Context at merge point */
47 unsigned long target_pc
;
50 static unsigned long lttng_hash_seed
;
51 static unsigned int lttng_hash_seed_ready
;
54 int lttng_hash_match(struct cds_lfht_node
*node
, const void *key
)
56 struct lfht_mp_node
*mp_node
=
57 caa_container_of(node
, struct lfht_mp_node
, node
);
58 unsigned long key_pc
= (unsigned long) key
;
60 if (mp_node
->target_pc
== key_pc
)
67 int merge_points_compare(const struct vstack
*stacka
,
68 const struct vstack
*stackb
)
72 if (stacka
->top
!= stackb
->top
)
74 len
= stacka
->top
+ 1;
76 for (i
= 0; i
< len
; i
++) {
77 if (stacka
->e
[i
].type
!= REG_UNKNOWN
78 && stackb
->e
[i
].type
!= REG_UNKNOWN
79 && stacka
->e
[i
].type
!= stackb
->e
[i
].type
)
86 int merge_point_add_check(struct cds_lfht
*ht
, unsigned long target_pc
,
87 const struct vstack
*stack
)
89 struct lfht_mp_node
*node
;
90 unsigned long hash
= lttng_hash_mix((const char *) target_pc
,
93 struct cds_lfht_node
*ret
;
95 dbg_printf("Filter: adding merge point at offset %lu, hash %lu\n",
97 node
= zmalloc(sizeof(struct lfht_mp_node
));
100 node
->target_pc
= target_pc
;
101 memcpy(&node
->stack
, stack
, sizeof(node
->stack
));
102 ret
= cds_lfht_add_unique(ht
, hash
, lttng_hash_match
,
103 (const char *) target_pc
, &node
->node
);
104 if (ret
!= &node
->node
) {
105 struct lfht_mp_node
*ret_mp
=
106 caa_container_of(ret
, struct lfht_mp_node
, node
);
108 /* Key already present */
109 dbg_printf("Filter: compare merge points for offset %lu, hash %lu\n",
112 if (merge_points_compare(stack
, &ret_mp
->stack
)) {
113 ERR("Merge points differ for offset %lu\n",
122 * Binary comparators use top of stack and top of stack -1.
123 * Return 0 if typing is known to match, 1 if typing is dynamic
124 * (unknown), negative error value on error.
127 int bin_op_compare_check(struct vstack
*stack
, const char *str
)
129 if (unlikely(!vstack_ax(stack
) || !vstack_bx(stack
)))
132 switch (vstack_ax(stack
)->type
) {
139 switch (vstack_bx(stack
)->type
) {
154 switch (vstack_bx(stack
)->type
) {
174 ERR("type mismatch for '%s' binary operator\n", str
);
178 ERR("empty stack for '%s' binary operator\n", str
);
182 ERR("unknown type for '%s' binary operator\n", str
);
187 * Validate bytecode range overflow within the validation pass.
188 * Called for each instruction encountered.
191 int bytecode_validate_overflow(struct bytecode_runtime
*bytecode
,
192 char *start_pc
, char *pc
)
196 switch (*(filter_opcode_t
*) pc
) {
197 case FILTER_OP_UNKNOWN
:
200 ERR("unknown bytecode op %u\n",
201 (unsigned int) *(filter_opcode_t
*) pc
);
206 case FILTER_OP_RETURN
:
208 if (unlikely(pc
+ sizeof(struct return_op
)
209 > start_pc
+ bytecode
->len
)) {
220 case FILTER_OP_MINUS
:
221 case FILTER_OP_RSHIFT
:
222 case FILTER_OP_LSHIFT
:
223 case FILTER_OP_BIN_AND
:
224 case FILTER_OP_BIN_OR
:
225 case FILTER_OP_BIN_XOR
:
227 ERR("unsupported bytecode op %u\n",
228 (unsigned int) *(filter_opcode_t
*) pc
);
239 case FILTER_OP_EQ_STRING
:
240 case FILTER_OP_NE_STRING
:
241 case FILTER_OP_GT_STRING
:
242 case FILTER_OP_LT_STRING
:
243 case FILTER_OP_GE_STRING
:
244 case FILTER_OP_LE_STRING
:
245 case FILTER_OP_EQ_S64
:
246 case FILTER_OP_NE_S64
:
247 case FILTER_OP_GT_S64
:
248 case FILTER_OP_LT_S64
:
249 case FILTER_OP_GE_S64
:
250 case FILTER_OP_LE_S64
:
251 case FILTER_OP_EQ_DOUBLE
:
252 case FILTER_OP_NE_DOUBLE
:
253 case FILTER_OP_GT_DOUBLE
:
254 case FILTER_OP_LT_DOUBLE
:
255 case FILTER_OP_GE_DOUBLE
:
256 case FILTER_OP_LE_DOUBLE
:
257 case FILTER_OP_EQ_DOUBLE_S64
:
258 case FILTER_OP_NE_DOUBLE_S64
:
259 case FILTER_OP_GT_DOUBLE_S64
:
260 case FILTER_OP_LT_DOUBLE_S64
:
261 case FILTER_OP_GE_DOUBLE_S64
:
262 case FILTER_OP_LE_DOUBLE_S64
:
263 case FILTER_OP_EQ_S64_DOUBLE
:
264 case FILTER_OP_NE_S64_DOUBLE
:
265 case FILTER_OP_GT_S64_DOUBLE
:
266 case FILTER_OP_LT_S64_DOUBLE
:
267 case FILTER_OP_GE_S64_DOUBLE
:
268 case FILTER_OP_LE_S64_DOUBLE
:
270 if (unlikely(pc
+ sizeof(struct binary_op
)
271 > start_pc
+ bytecode
->len
)) {
278 case FILTER_OP_UNARY_PLUS
:
279 case FILTER_OP_UNARY_MINUS
:
280 case FILTER_OP_UNARY_NOT
:
281 case FILTER_OP_UNARY_PLUS_S64
:
282 case FILTER_OP_UNARY_MINUS_S64
:
283 case FILTER_OP_UNARY_NOT_S64
:
284 case FILTER_OP_UNARY_PLUS_DOUBLE
:
285 case FILTER_OP_UNARY_MINUS_DOUBLE
:
286 case FILTER_OP_UNARY_NOT_DOUBLE
:
288 if (unlikely(pc
+ sizeof(struct unary_op
)
289 > start_pc
+ bytecode
->len
)) {
299 if (unlikely(pc
+ sizeof(struct logical_op
)
300 > start_pc
+ bytecode
->len
)) {
307 case FILTER_OP_LOAD_FIELD_REF
:
309 ERR("Unknown field ref type\n");
313 /* get context ref */
314 case FILTER_OP_GET_CONTEXT_REF
:
315 case FILTER_OP_LOAD_FIELD_REF_STRING
:
316 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
317 case FILTER_OP_LOAD_FIELD_REF_S64
:
318 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
319 case FILTER_OP_GET_CONTEXT_REF_STRING
:
320 case FILTER_OP_GET_CONTEXT_REF_S64
:
321 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
323 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct field_ref
)
324 > start_pc
+ bytecode
->len
)) {
330 /* load from immediate operand */
331 case FILTER_OP_LOAD_STRING
:
333 struct load_op
*insn
= (struct load_op
*) pc
;
334 uint32_t str_len
, maxlen
;
336 if (unlikely(pc
+ sizeof(struct load_op
)
337 > start_pc
+ bytecode
->len
)) {
342 maxlen
= start_pc
+ bytecode
->len
- pc
- sizeof(struct load_op
);
343 str_len
= strnlen(insn
->data
, maxlen
);
344 if (unlikely(str_len
>= maxlen
)) {
345 /* Final '\0' not found within range */
351 case FILTER_OP_LOAD_S64
:
353 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct literal_numeric
)
354 > start_pc
+ bytecode
->len
)) {
360 case FILTER_OP_LOAD_DOUBLE
:
362 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct literal_double
)
363 > start_pc
+ bytecode
->len
)) {
369 case FILTER_OP_CAST_TO_S64
:
370 case FILTER_OP_CAST_DOUBLE_TO_S64
:
371 case FILTER_OP_CAST_NOP
:
373 if (unlikely(pc
+ sizeof(struct cast_op
)
374 > start_pc
+ bytecode
->len
)) {
386 unsigned long delete_all_nodes(struct cds_lfht
*ht
)
388 struct cds_lfht_iter iter
;
389 struct lfht_mp_node
*node
;
390 unsigned long nr_nodes
= 0;
392 cds_lfht_for_each_entry(ht
, &iter
, node
, node
) {
395 ret
= cds_lfht_del(ht
, cds_lfht_iter_get_node(&iter
));
397 /* note: this hash table is never used concurrently */
410 int validate_instruction_context(struct bytecode_runtime
*bytecode
,
411 struct vstack
*stack
,
417 switch (*(filter_opcode_t
*) pc
) {
418 case FILTER_OP_UNKNOWN
:
421 ERR("unknown bytecode op %u\n",
422 (unsigned int) *(filter_opcode_t
*) pc
);
427 case FILTER_OP_RETURN
:
437 case FILTER_OP_MINUS
:
438 case FILTER_OP_RSHIFT
:
439 case FILTER_OP_LSHIFT
:
440 case FILTER_OP_BIN_AND
:
441 case FILTER_OP_BIN_OR
:
442 case FILTER_OP_BIN_XOR
:
444 ERR("unsupported bytecode op %u\n",
445 (unsigned int) *(filter_opcode_t
*) pc
);
452 ret
= bin_op_compare_check(stack
, "==");
459 ret
= bin_op_compare_check(stack
, "!=");
466 ret
= bin_op_compare_check(stack
, ">");
473 ret
= bin_op_compare_check(stack
, "<");
480 ret
= bin_op_compare_check(stack
, ">=");
487 ret
= bin_op_compare_check(stack
, "<=");
493 case FILTER_OP_EQ_STRING
:
494 case FILTER_OP_NE_STRING
:
495 case FILTER_OP_GT_STRING
:
496 case FILTER_OP_LT_STRING
:
497 case FILTER_OP_GE_STRING
:
498 case FILTER_OP_LE_STRING
:
500 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
501 ERR("Empty stack\n");
505 if (vstack_ax(stack
)->type
!= REG_STRING
506 || vstack_bx(stack
)->type
!= REG_STRING
) {
507 ERR("Unexpected register type for string comparator\n");
514 case FILTER_OP_EQ_S64
:
515 case FILTER_OP_NE_S64
:
516 case FILTER_OP_GT_S64
:
517 case FILTER_OP_LT_S64
:
518 case FILTER_OP_GE_S64
:
519 case FILTER_OP_LE_S64
:
521 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
522 ERR("Empty stack\n");
526 if (vstack_ax(stack
)->type
!= REG_S64
527 || vstack_bx(stack
)->type
!= REG_S64
) {
528 ERR("Unexpected register type for s64 comparator\n");
535 case FILTER_OP_EQ_DOUBLE
:
536 case FILTER_OP_NE_DOUBLE
:
537 case FILTER_OP_GT_DOUBLE
:
538 case FILTER_OP_LT_DOUBLE
:
539 case FILTER_OP_GE_DOUBLE
:
540 case FILTER_OP_LE_DOUBLE
:
542 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
543 ERR("Empty stack\n");
547 if (vstack_ax(stack
)->type
!= REG_DOUBLE
&& vstack_bx(stack
)->type
!= REG_DOUBLE
) {
548 ERR("Double operator should have two double registers\n");
555 case FILTER_OP_EQ_DOUBLE_S64
:
556 case FILTER_OP_NE_DOUBLE_S64
:
557 case FILTER_OP_GT_DOUBLE_S64
:
558 case FILTER_OP_LT_DOUBLE_S64
:
559 case FILTER_OP_GE_DOUBLE_S64
:
560 case FILTER_OP_LE_DOUBLE_S64
:
562 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
563 ERR("Empty stack\n");
567 if (vstack_ax(stack
)->type
!= REG_S64
&& vstack_bx(stack
)->type
!= REG_DOUBLE
) {
568 ERR("Double-S64 operator has unexpected register types\n");
575 case FILTER_OP_EQ_S64_DOUBLE
:
576 case FILTER_OP_NE_S64_DOUBLE
:
577 case FILTER_OP_GT_S64_DOUBLE
:
578 case FILTER_OP_LT_S64_DOUBLE
:
579 case FILTER_OP_GE_S64_DOUBLE
:
580 case FILTER_OP_LE_S64_DOUBLE
:
582 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
583 ERR("Empty stack\n");
587 if (vstack_ax(stack
)->type
!= REG_DOUBLE
&& vstack_bx(stack
)->type
!= REG_S64
) {
588 ERR("S64-Double operator has unexpected register types\n");
596 case FILTER_OP_UNARY_PLUS
:
597 case FILTER_OP_UNARY_MINUS
:
598 case FILTER_OP_UNARY_NOT
:
600 if (!vstack_ax(stack
)) {
601 ERR("Empty stack\n");
605 switch (vstack_ax(stack
)->type
) {
607 ERR("unknown register type\n");
612 ERR("Unary op can only be applied to numeric or floating point registers\n");
625 case FILTER_OP_UNARY_PLUS_S64
:
626 case FILTER_OP_UNARY_MINUS_S64
:
627 case FILTER_OP_UNARY_NOT_S64
:
629 if (!vstack_ax(stack
)) {
630 ERR("Empty stack\n");
634 if (vstack_ax(stack
)->type
!= REG_S64
) {
635 ERR("Invalid register type\n");
642 case FILTER_OP_UNARY_PLUS_DOUBLE
:
643 case FILTER_OP_UNARY_MINUS_DOUBLE
:
644 case FILTER_OP_UNARY_NOT_DOUBLE
:
646 if (!vstack_ax(stack
)) {
647 ERR("Empty stack\n");
651 if (vstack_ax(stack
)->type
!= REG_DOUBLE
) {
652 ERR("Invalid register type\n");
663 struct logical_op
*insn
= (struct logical_op
*) pc
;
665 if (!vstack_ax(stack
)) {
666 ERR("Empty stack\n");
670 if (vstack_ax(stack
)->type
!= REG_S64
671 && vstack_ax(stack
)->type
!= REG_UNKNOWN
) {
672 ERR("Logical comparator expects S64 or dynamic register\n");
677 dbg_printf("Validate jumping to bytecode offset %u\n",
678 (unsigned int) insn
->skip_offset
);
679 if (unlikely(start_pc
+ insn
->skip_offset
<= pc
)) {
680 ERR("Loops are not allowed in bytecode\n");
688 case FILTER_OP_LOAD_FIELD_REF
:
690 ERR("Unknown field ref type\n");
694 case FILTER_OP_LOAD_FIELD_REF_STRING
:
695 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
697 struct load_op
*insn
= (struct load_op
*) pc
;
698 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
700 dbg_printf("Validate load field ref offset %u type string\n",
704 case FILTER_OP_LOAD_FIELD_REF_S64
:
706 struct load_op
*insn
= (struct load_op
*) pc
;
707 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
709 dbg_printf("Validate load field ref offset %u type s64\n",
713 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
715 struct load_op
*insn
= (struct load_op
*) pc
;
716 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
718 dbg_printf("Validate load field ref offset %u type double\n",
723 /* load from immediate operand */
724 case FILTER_OP_LOAD_STRING
:
729 case FILTER_OP_LOAD_S64
:
734 case FILTER_OP_LOAD_DOUBLE
:
739 case FILTER_OP_CAST_TO_S64
:
740 case FILTER_OP_CAST_DOUBLE_TO_S64
:
742 struct cast_op
*insn
= (struct cast_op
*) pc
;
744 if (!vstack_ax(stack
)) {
745 ERR("Empty stack\n");
749 switch (vstack_ax(stack
)->type
) {
751 ERR("unknown register type\n");
756 ERR("Cast op can only be applied to numeric or floating point registers\n");
766 if (insn
->op
== FILTER_OP_CAST_DOUBLE_TO_S64
) {
767 if (vstack_ax(stack
)->type
!= REG_DOUBLE
) {
768 ERR("Cast expects double\n");
775 case FILTER_OP_CAST_NOP
:
780 /* get context ref */
781 case FILTER_OP_GET_CONTEXT_REF
:
783 struct load_op
*insn
= (struct load_op
*) pc
;
784 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
786 dbg_printf("Validate get context ref offset %u type dynamic\n",
790 case FILTER_OP_GET_CONTEXT_REF_STRING
:
792 struct load_op
*insn
= (struct load_op
*) pc
;
793 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
795 dbg_printf("Validate get context ref offset %u type string\n",
799 case FILTER_OP_GET_CONTEXT_REF_S64
:
801 struct load_op
*insn
= (struct load_op
*) pc
;
802 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
804 dbg_printf("Validate get context ref offset %u type s64\n",
808 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
810 struct load_op
*insn
= (struct load_op
*) pc
;
811 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
813 dbg_printf("Validate get context ref offset %u type double\n",
829 int validate_instruction_all_contexts(struct bytecode_runtime
*bytecode
,
830 struct cds_lfht
*merge_points
,
831 struct vstack
*stack
,
836 unsigned long target_pc
= pc
- start_pc
;
837 struct cds_lfht_iter iter
;
838 struct cds_lfht_node
*node
;
839 struct lfht_mp_node
*mp_node
;
842 /* Validate the context resulting from the previous instruction */
843 ret
= validate_instruction_context(bytecode
, stack
, start_pc
, pc
);
847 /* Validate merge points */
848 hash
= lttng_hash_mix((const char *) target_pc
, sizeof(target_pc
),
850 cds_lfht_lookup(merge_points
, hash
, lttng_hash_match
,
851 (const char *) target_pc
, &iter
);
852 node
= cds_lfht_iter_get_node(&iter
);
854 mp_node
= caa_container_of(node
, struct lfht_mp_node
, node
);
856 dbg_printf("Filter: validate merge point at offset %lu\n",
858 if (merge_points_compare(stack
, &mp_node
->stack
)) {
859 ERR("Merge points differ for offset %lu\n",
863 /* Once validated, we can remove the merge point */
864 dbg_printf("Filter: remove merge point at offset %lu\n",
866 ret
= cds_lfht_del(merge_points
, node
);
874 * >0: going to next insn.
875 * 0: success, stop iteration.
879 int exec_insn(struct bytecode_runtime
*bytecode
,
880 struct cds_lfht
*merge_points
,
881 struct vstack
*stack
,
886 char *next_pc
= *_next_pc
;
888 switch (*(filter_opcode_t
*) pc
) {
889 case FILTER_OP_UNKNOWN
:
892 ERR("unknown bytecode op %u\n",
893 (unsigned int) *(filter_opcode_t
*) pc
);
898 case FILTER_OP_RETURN
:
900 if (!vstack_ax(stack
)) {
901 ERR("Empty stack\n");
914 case FILTER_OP_MINUS
:
915 case FILTER_OP_RSHIFT
:
916 case FILTER_OP_LSHIFT
:
917 case FILTER_OP_BIN_AND
:
918 case FILTER_OP_BIN_OR
:
919 case FILTER_OP_BIN_XOR
:
921 ERR("unsupported bytecode op %u\n",
922 (unsigned int) *(filter_opcode_t
*) pc
);
933 case FILTER_OP_EQ_STRING
:
934 case FILTER_OP_NE_STRING
:
935 case FILTER_OP_GT_STRING
:
936 case FILTER_OP_LT_STRING
:
937 case FILTER_OP_GE_STRING
:
938 case FILTER_OP_LE_STRING
:
939 case FILTER_OP_EQ_S64
:
940 case FILTER_OP_NE_S64
:
941 case FILTER_OP_GT_S64
:
942 case FILTER_OP_LT_S64
:
943 case FILTER_OP_GE_S64
:
944 case FILTER_OP_LE_S64
:
945 case FILTER_OP_EQ_DOUBLE
:
946 case FILTER_OP_NE_DOUBLE
:
947 case FILTER_OP_GT_DOUBLE
:
948 case FILTER_OP_LT_DOUBLE
:
949 case FILTER_OP_GE_DOUBLE
:
950 case FILTER_OP_LE_DOUBLE
:
951 case FILTER_OP_EQ_DOUBLE_S64
:
952 case FILTER_OP_NE_DOUBLE_S64
:
953 case FILTER_OP_GT_DOUBLE_S64
:
954 case FILTER_OP_LT_DOUBLE_S64
:
955 case FILTER_OP_GE_DOUBLE_S64
:
956 case FILTER_OP_LE_DOUBLE_S64
:
957 case FILTER_OP_EQ_S64_DOUBLE
:
958 case FILTER_OP_NE_S64_DOUBLE
:
959 case FILTER_OP_GT_S64_DOUBLE
:
960 case FILTER_OP_LT_S64_DOUBLE
:
961 case FILTER_OP_GE_S64_DOUBLE
:
962 case FILTER_OP_LE_S64_DOUBLE
:
965 if (vstack_pop(stack
)) {
969 if (!vstack_ax(stack
)) {
970 ERR("Empty stack\n");
974 vstack_ax(stack
)->type
= REG_S64
;
975 next_pc
+= sizeof(struct binary_op
);
980 case FILTER_OP_UNARY_PLUS
:
981 case FILTER_OP_UNARY_MINUS
:
984 if (!vstack_ax(stack
)) {
985 ERR("Empty stack\n");
989 vstack_ax(stack
)->type
= REG_UNKNOWN
;
990 next_pc
+= sizeof(struct unary_op
);
994 case FILTER_OP_UNARY_PLUS_S64
:
995 case FILTER_OP_UNARY_MINUS_S64
:
996 case FILTER_OP_UNARY_NOT
:
997 case FILTER_OP_UNARY_NOT_S64
:
998 case FILTER_OP_UNARY_NOT_DOUBLE
:
1001 if (!vstack_ax(stack
)) {
1002 ERR("Empty stack\n");
1006 vstack_ax(stack
)->type
= REG_S64
;
1007 next_pc
+= sizeof(struct unary_op
);
1011 case FILTER_OP_UNARY_PLUS_DOUBLE
:
1012 case FILTER_OP_UNARY_MINUS_DOUBLE
:
1015 if (!vstack_ax(stack
)) {
1016 ERR("Empty stack\n");
1020 vstack_ax(stack
)->type
= REG_DOUBLE
;
1021 next_pc
+= sizeof(struct unary_op
);
1029 struct logical_op
*insn
= (struct logical_op
*) pc
;
1032 /* Add merge point to table */
1033 merge_ret
= merge_point_add_check(merge_points
,
1034 insn
->skip_offset
, stack
);
1039 /* Continue to next instruction */
1040 /* Pop 1 when jump not taken */
1041 if (vstack_pop(stack
)) {
1045 next_pc
+= sizeof(struct logical_op
);
1049 /* load field ref */
1050 case FILTER_OP_LOAD_FIELD_REF
:
1052 ERR("Unknown field ref type\n");
1056 /* get context ref */
1057 case FILTER_OP_GET_CONTEXT_REF
:
1059 if (vstack_push(stack
)) {
1063 vstack_ax(stack
)->type
= REG_UNKNOWN
;
1064 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1067 case FILTER_OP_LOAD_FIELD_REF_STRING
:
1068 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
1069 case FILTER_OP_GET_CONTEXT_REF_STRING
:
1071 if (vstack_push(stack
)) {
1075 vstack_ax(stack
)->type
= REG_STRING
;
1076 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1079 case FILTER_OP_LOAD_FIELD_REF_S64
:
1080 case FILTER_OP_GET_CONTEXT_REF_S64
:
1082 if (vstack_push(stack
)) {
1086 vstack_ax(stack
)->type
= REG_S64
;
1087 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1090 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
1091 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
1093 if (vstack_push(stack
)) {
1097 vstack_ax(stack
)->type
= REG_DOUBLE
;
1098 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1102 /* load from immediate operand */
1103 case FILTER_OP_LOAD_STRING
:
1105 struct load_op
*insn
= (struct load_op
*) pc
;
1107 if (vstack_push(stack
)) {
1111 vstack_ax(stack
)->type
= REG_STRING
;
1112 next_pc
+= sizeof(struct load_op
) + strlen(insn
->data
) + 1;
1116 case FILTER_OP_LOAD_S64
:
1118 if (vstack_push(stack
)) {
1122 vstack_ax(stack
)->type
= REG_S64
;
1123 next_pc
+= sizeof(struct load_op
)
1124 + sizeof(struct literal_numeric
);
1128 case FILTER_OP_LOAD_DOUBLE
:
1130 if (vstack_push(stack
)) {
1134 vstack_ax(stack
)->type
= REG_DOUBLE
;
1135 next_pc
+= sizeof(struct load_op
)
1136 + sizeof(struct literal_double
);
1140 case FILTER_OP_CAST_TO_S64
:
1141 case FILTER_OP_CAST_DOUBLE_TO_S64
:
1144 if (!vstack_ax(stack
)) {
1145 ERR("Empty stack\n");
1149 vstack_ax(stack
)->type
= REG_S64
;
1150 next_pc
+= sizeof(struct cast_op
);
1153 case FILTER_OP_CAST_NOP
:
1155 next_pc
+= sizeof(struct cast_op
);
1161 *_next_pc
= next_pc
;
1166 * Never called concurrently (hash seed is shared).
1168 int lttng_filter_validate_bytecode(struct bytecode_runtime
*bytecode
)
1170 struct cds_lfht
*merge_points
;
1171 char *pc
, *next_pc
, *start_pc
;
1173 struct vstack stack
;
1175 vstack_init(&stack
);
1177 if (!lttng_hash_seed_ready
) {
1178 lttng_hash_seed
= time(NULL
);
1179 lttng_hash_seed_ready
= 1;
1182 * Note: merge_points hash table used by single thread, and
1183 * never concurrently resized. Therefore, we can use it without
1184 * holding RCU read-side lock and free nodes without using
1187 merge_points
= cds_lfht_new(DEFAULT_NR_MERGE_POINTS
,
1188 MIN_NR_BUCKETS
, MAX_NR_BUCKETS
,
1190 if (!merge_points
) {
1191 ERR("Error allocating hash table for bytecode validation\n");
1194 start_pc
= &bytecode
->data
[0];
1195 for (pc
= next_pc
= start_pc
; pc
- start_pc
< bytecode
->len
;
1197 ret
= bytecode_validate_overflow(bytecode
, start_pc
, pc
);
1200 ERR("filter bytecode overflow\n");
1203 dbg_printf("Validating op %s (%u)\n",
1204 print_op((unsigned int) *(filter_opcode_t
*) pc
),
1205 (unsigned int) *(filter_opcode_t
*) pc
);
1208 * For each instruction, validate the current context
1209 * (traversal of entire execution flow), and validate
1210 * all merge points targeting this instruction.
1212 ret
= validate_instruction_all_contexts(bytecode
, merge_points
,
1213 &stack
, start_pc
, pc
);
1216 ret
= exec_insn(bytecode
, merge_points
, &stack
, &next_pc
, pc
);
1221 if (delete_all_nodes(merge_points
)) {
1223 ERR("Unexpected merge points\n");
1227 if (cds_lfht_destroy(merge_points
, NULL
)) {
1228 ERR("Error destroying hash table\n");