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
!= stackb
->e
[i
].type
)
84 int merge_point_add_check(struct cds_lfht
*ht
, unsigned long target_pc
,
85 const struct vstack
*stack
)
87 struct lfht_mp_node
*node
;
88 unsigned long hash
= lttng_hash_mix((const void *) target_pc
,
91 struct cds_lfht_node
*ret
;
93 dbg_printf("Filter: adding merge point at offset %lu, hash %lu\n",
95 node
= zmalloc(sizeof(struct lfht_mp_node
));
98 node
->target_pc
= target_pc
;
99 memcpy(&node
->stack
, stack
, sizeof(node
->stack
));
100 ret
= cds_lfht_add_unique(ht
, hash
, lttng_hash_match
,
101 (const void *) target_pc
, &node
->node
);
102 if (ret
!= &node
->node
) {
103 struct lfht_mp_node
*ret_mp
=
104 caa_container_of(ret
, struct lfht_mp_node
, node
);
106 /* Key already present */
107 dbg_printf("Filter: compare merge points for offset %lu, hash %lu\n",
110 if (merge_points_compare(stack
, &ret_mp
->stack
)) {
111 ERR("Merge points differ for offset %lu\n",
120 * Binary comparators use top of stack and top of stack -1.
123 int bin_op_compare_check(struct vstack
*stack
, const char *str
)
125 if (unlikely(!vstack_ax(stack
) || !vstack_bx(stack
)))
128 switch (vstack_ax(stack
)->type
) {
133 switch (vstack_bx(stack
)->type
) {
146 switch (vstack_bx(stack
)->type
) {
165 ERR("type mismatch for '%s' binary operator\n", str
);
170 * Validate bytecode range overflow within the validation pass.
171 * Called for each instruction encountered.
174 int bytecode_validate_overflow(struct bytecode_runtime
*bytecode
,
175 void *start_pc
, void *pc
)
179 switch (*(filter_opcode_t
*) pc
) {
180 case FILTER_OP_UNKNOWN
:
183 ERR("unknown bytecode op %u\n",
184 (unsigned int) *(filter_opcode_t
*) pc
);
189 case FILTER_OP_RETURN
:
191 if (unlikely(pc
+ sizeof(struct return_op
)
192 > start_pc
+ bytecode
->len
)) {
203 case FILTER_OP_MINUS
:
204 case FILTER_OP_RSHIFT
:
205 case FILTER_OP_LSHIFT
:
206 case FILTER_OP_BIN_AND
:
207 case FILTER_OP_BIN_OR
:
208 case FILTER_OP_BIN_XOR
:
210 ERR("unsupported bytecode op %u\n",
211 (unsigned int) *(filter_opcode_t
*) pc
);
222 case FILTER_OP_EQ_STRING
:
223 case FILTER_OP_NE_STRING
:
224 case FILTER_OP_GT_STRING
:
225 case FILTER_OP_LT_STRING
:
226 case FILTER_OP_GE_STRING
:
227 case FILTER_OP_LE_STRING
:
228 case FILTER_OP_EQ_S64
:
229 case FILTER_OP_NE_S64
:
230 case FILTER_OP_GT_S64
:
231 case FILTER_OP_LT_S64
:
232 case FILTER_OP_GE_S64
:
233 case FILTER_OP_LE_S64
:
234 case FILTER_OP_EQ_DOUBLE
:
235 case FILTER_OP_NE_DOUBLE
:
236 case FILTER_OP_GT_DOUBLE
:
237 case FILTER_OP_LT_DOUBLE
:
238 case FILTER_OP_GE_DOUBLE
:
239 case FILTER_OP_LE_DOUBLE
:
240 case FILTER_OP_EQ_DOUBLE_S64
:
241 case FILTER_OP_NE_DOUBLE_S64
:
242 case FILTER_OP_GT_DOUBLE_S64
:
243 case FILTER_OP_LT_DOUBLE_S64
:
244 case FILTER_OP_GE_DOUBLE_S64
:
245 case FILTER_OP_LE_DOUBLE_S64
:
246 case FILTER_OP_EQ_S64_DOUBLE
:
247 case FILTER_OP_NE_S64_DOUBLE
:
248 case FILTER_OP_GT_S64_DOUBLE
:
249 case FILTER_OP_LT_S64_DOUBLE
:
250 case FILTER_OP_GE_S64_DOUBLE
:
251 case FILTER_OP_LE_S64_DOUBLE
:
253 if (unlikely(pc
+ sizeof(struct binary_op
)
254 > start_pc
+ bytecode
->len
)) {
261 case FILTER_OP_UNARY_PLUS
:
262 case FILTER_OP_UNARY_MINUS
:
263 case FILTER_OP_UNARY_NOT
:
264 case FILTER_OP_UNARY_PLUS_S64
:
265 case FILTER_OP_UNARY_MINUS_S64
:
266 case FILTER_OP_UNARY_NOT_S64
:
267 case FILTER_OP_UNARY_PLUS_DOUBLE
:
268 case FILTER_OP_UNARY_MINUS_DOUBLE
:
269 case FILTER_OP_UNARY_NOT_DOUBLE
:
271 if (unlikely(pc
+ sizeof(struct unary_op
)
272 > start_pc
+ bytecode
->len
)) {
282 if (unlikely(pc
+ sizeof(struct logical_op
)
283 > start_pc
+ bytecode
->len
)) {
290 case FILTER_OP_LOAD_FIELD_REF
:
292 ERR("Unknown field ref type\n");
296 /* get context ref */
297 case FILTER_OP_GET_CONTEXT_REF
:
299 ERR("Unknown field ref type\n");
303 case FILTER_OP_LOAD_FIELD_REF_STRING
:
304 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
305 case FILTER_OP_LOAD_FIELD_REF_S64
:
306 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
307 case FILTER_OP_GET_CONTEXT_REF_STRING
:
308 case FILTER_OP_GET_CONTEXT_REF_S64
:
309 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
311 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct field_ref
)
312 > start_pc
+ bytecode
->len
)) {
318 /* load from immediate operand */
319 case FILTER_OP_LOAD_STRING
:
321 struct load_op
*insn
= (struct load_op
*) pc
;
322 uint32_t str_len
, maxlen
;
324 if (unlikely(pc
+ sizeof(struct load_op
)
325 > start_pc
+ bytecode
->len
)) {
330 maxlen
= start_pc
+ bytecode
->len
- pc
- sizeof(struct load_op
);
331 str_len
= strnlen(insn
->data
, maxlen
);
332 if (unlikely(str_len
>= maxlen
)) {
333 /* Final '\0' not found within range */
339 case FILTER_OP_LOAD_S64
:
341 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct literal_numeric
)
342 > start_pc
+ bytecode
->len
)) {
348 case FILTER_OP_LOAD_DOUBLE
:
350 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct literal_double
)
351 > start_pc
+ bytecode
->len
)) {
357 case FILTER_OP_CAST_TO_S64
:
358 case FILTER_OP_CAST_DOUBLE_TO_S64
:
359 case FILTER_OP_CAST_NOP
:
361 if (unlikely(pc
+ sizeof(struct cast_op
)
362 > start_pc
+ bytecode
->len
)) {
374 unsigned long delete_all_nodes(struct cds_lfht
*ht
)
376 struct cds_lfht_iter iter
;
377 struct lfht_mp_node
*node
;
378 unsigned long nr_nodes
= 0;
380 cds_lfht_for_each_entry(ht
, &iter
, node
, node
) {
383 ret
= cds_lfht_del(ht
, cds_lfht_iter_get_node(&iter
));
385 /* note: this hash table is never used concurrently */
398 int validate_instruction_context(struct bytecode_runtime
*bytecode
,
399 struct vstack
*stack
,
405 switch (*(filter_opcode_t
*) pc
) {
406 case FILTER_OP_UNKNOWN
:
409 ERR("unknown bytecode op %u\n",
410 (unsigned int) *(filter_opcode_t
*) pc
);
415 case FILTER_OP_RETURN
:
425 case FILTER_OP_MINUS
:
426 case FILTER_OP_RSHIFT
:
427 case FILTER_OP_LSHIFT
:
428 case FILTER_OP_BIN_AND
:
429 case FILTER_OP_BIN_OR
:
430 case FILTER_OP_BIN_XOR
:
432 ERR("unsupported bytecode op %u\n",
433 (unsigned int) *(filter_opcode_t
*) pc
);
440 ret
= bin_op_compare_check(stack
, "==");
447 ret
= bin_op_compare_check(stack
, "!=");
454 ret
= bin_op_compare_check(stack
, ">");
461 ret
= bin_op_compare_check(stack
, "<");
468 ret
= bin_op_compare_check(stack
, ">=");
475 ret
= bin_op_compare_check(stack
, "<=");
481 case FILTER_OP_EQ_STRING
:
482 case FILTER_OP_NE_STRING
:
483 case FILTER_OP_GT_STRING
:
484 case FILTER_OP_LT_STRING
:
485 case FILTER_OP_GE_STRING
:
486 case FILTER_OP_LE_STRING
:
488 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
489 ERR("Empty stack\n");
493 if (vstack_ax(stack
)->type
!= REG_STRING
494 || vstack_bx(stack
)->type
!= REG_STRING
) {
495 ERR("Unexpected register type for string comparator\n");
502 case FILTER_OP_EQ_S64
:
503 case FILTER_OP_NE_S64
:
504 case FILTER_OP_GT_S64
:
505 case FILTER_OP_LT_S64
:
506 case FILTER_OP_GE_S64
:
507 case FILTER_OP_LE_S64
:
509 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
510 ERR("Empty stack\n");
514 if (vstack_ax(stack
)->type
!= REG_S64
515 || vstack_bx(stack
)->type
!= REG_S64
) {
516 ERR("Unexpected register type for s64 comparator\n");
523 case FILTER_OP_EQ_DOUBLE
:
524 case FILTER_OP_NE_DOUBLE
:
525 case FILTER_OP_GT_DOUBLE
:
526 case FILTER_OP_LT_DOUBLE
:
527 case FILTER_OP_GE_DOUBLE
:
528 case FILTER_OP_LE_DOUBLE
:
530 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
531 ERR("Empty stack\n");
535 if (vstack_ax(stack
)->type
!= REG_DOUBLE
&& vstack_bx(stack
)->type
!= REG_DOUBLE
) {
536 ERR("Double operator should have two double registers\n");
543 case FILTER_OP_EQ_DOUBLE_S64
:
544 case FILTER_OP_NE_DOUBLE_S64
:
545 case FILTER_OP_GT_DOUBLE_S64
:
546 case FILTER_OP_LT_DOUBLE_S64
:
547 case FILTER_OP_GE_DOUBLE_S64
:
548 case FILTER_OP_LE_DOUBLE_S64
:
550 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
551 ERR("Empty stack\n");
555 if (vstack_ax(stack
)->type
!= REG_S64
&& vstack_bx(stack
)->type
!= REG_DOUBLE
) {
556 ERR("Double-S64 operator has unexpected register types\n");
563 case FILTER_OP_EQ_S64_DOUBLE
:
564 case FILTER_OP_NE_S64_DOUBLE
:
565 case FILTER_OP_GT_S64_DOUBLE
:
566 case FILTER_OP_LT_S64_DOUBLE
:
567 case FILTER_OP_GE_S64_DOUBLE
:
568 case FILTER_OP_LE_S64_DOUBLE
:
570 if (!vstack_ax(stack
) || !vstack_bx(stack
)) {
571 ERR("Empty stack\n");
575 if (vstack_ax(stack
)->type
!= REG_DOUBLE
&& vstack_bx(stack
)->type
!= REG_S64
) {
576 ERR("S64-Double operator has unexpected register types\n");
584 case FILTER_OP_UNARY_PLUS
:
585 case FILTER_OP_UNARY_MINUS
:
586 case FILTER_OP_UNARY_NOT
:
588 if (!vstack_ax(stack
)) {
589 ERR("Empty stack\n");
593 switch (vstack_ax(stack
)->type
) {
595 ERR("unknown register type\n");
600 ERR("Unary op can only be applied to numeric or floating point registers\n");
611 case FILTER_OP_UNARY_PLUS_S64
:
612 case FILTER_OP_UNARY_MINUS_S64
:
613 case FILTER_OP_UNARY_NOT_S64
:
615 if (!vstack_ax(stack
)) {
616 ERR("Empty stack\n");
620 if (vstack_ax(stack
)->type
!= REG_S64
) {
621 ERR("Invalid register type\n");
628 case FILTER_OP_UNARY_PLUS_DOUBLE
:
629 case FILTER_OP_UNARY_MINUS_DOUBLE
:
630 case FILTER_OP_UNARY_NOT_DOUBLE
:
632 if (!vstack_ax(stack
)) {
633 ERR("Empty stack\n");
637 if (vstack_ax(stack
)->type
!= REG_DOUBLE
) {
638 ERR("Invalid register type\n");
649 struct logical_op
*insn
= (struct logical_op
*) pc
;
651 if (!vstack_ax(stack
)) {
652 ERR("Empty stack\n");
656 if (vstack_ax(stack
)->type
!= REG_S64
) {
657 ERR("Logical comparator expects S64 register\n");
662 dbg_printf("Validate jumping to bytecode offset %u\n",
663 (unsigned int) insn
->skip_offset
);
664 if (unlikely(start_pc
+ insn
->skip_offset
<= pc
)) {
665 ERR("Loops are not allowed in bytecode\n");
673 case FILTER_OP_LOAD_FIELD_REF
:
675 ERR("Unknown field ref type\n");
679 case FILTER_OP_LOAD_FIELD_REF_STRING
:
680 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
682 struct load_op
*insn
= (struct load_op
*) pc
;
683 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
685 dbg_printf("Validate load field ref offset %u type string\n",
689 case FILTER_OP_LOAD_FIELD_REF_S64
:
691 struct load_op
*insn
= (struct load_op
*) pc
;
692 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
694 dbg_printf("Validate load field ref offset %u type s64\n",
698 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
700 struct load_op
*insn
= (struct load_op
*) pc
;
701 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
703 dbg_printf("Validate load field ref offset %u type double\n",
708 /* load from immediate operand */
709 case FILTER_OP_LOAD_STRING
:
714 case FILTER_OP_LOAD_S64
:
719 case FILTER_OP_LOAD_DOUBLE
:
724 case FILTER_OP_CAST_TO_S64
:
725 case FILTER_OP_CAST_DOUBLE_TO_S64
:
727 struct cast_op
*insn
= (struct cast_op
*) pc
;
729 if (!vstack_ax(stack
)) {
730 ERR("Empty stack\n");
734 switch (vstack_ax(stack
)->type
) {
736 ERR("unknown register type\n");
741 ERR("Cast op can only be applied to numeric or floating point registers\n");
749 if (insn
->op
== FILTER_OP_CAST_DOUBLE_TO_S64
) {
750 if (vstack_ax(stack
)->type
!= REG_DOUBLE
) {
751 ERR("Cast expects double\n");
758 case FILTER_OP_CAST_NOP
:
763 /* get context ref */
764 case FILTER_OP_GET_CONTEXT_REF
:
766 ERR("Unknown get context ref type\n");
770 case FILTER_OP_GET_CONTEXT_REF_STRING
:
772 struct load_op
*insn
= (struct load_op
*) pc
;
773 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
775 dbg_printf("Validate get context ref offset %u type string\n",
779 case FILTER_OP_GET_CONTEXT_REF_S64
:
781 struct load_op
*insn
= (struct load_op
*) pc
;
782 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
784 dbg_printf("Validate get context ref offset %u type s64\n",
788 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
790 struct load_op
*insn
= (struct load_op
*) pc
;
791 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
793 dbg_printf("Validate get context ref offset %u type double\n",
809 int validate_instruction_all_contexts(struct bytecode_runtime
*bytecode
,
810 struct cds_lfht
*merge_points
,
811 struct vstack
*stack
,
816 unsigned long target_pc
= pc
- start_pc
;
817 struct cds_lfht_iter iter
;
818 struct cds_lfht_node
*node
;
819 struct lfht_mp_node
*mp_node
;
822 /* Validate the context resulting from the previous instruction */
823 ret
= validate_instruction_context(bytecode
, stack
, start_pc
, pc
);
827 /* Validate merge points */
828 hash
= lttng_hash_mix((const void *) target_pc
, sizeof(target_pc
),
830 cds_lfht_lookup(merge_points
, hash
, lttng_hash_match
,
831 (const void *) target_pc
, &iter
);
832 node
= cds_lfht_iter_get_node(&iter
);
834 mp_node
= caa_container_of(node
, struct lfht_mp_node
, node
);
836 dbg_printf("Filter: validate merge point at offset %lu\n",
838 if (merge_points_compare(stack
, &mp_node
->stack
)) {
839 ERR("Merge points differ for offset %lu\n",
843 /* Once validated, we can remove the merge point */
844 dbg_printf("Filter: remove merge point at offset %lu\n",
846 ret
= cds_lfht_del(merge_points
, node
);
854 * >0: going to next insn.
855 * 0: success, stop iteration.
859 int exec_insn(struct bytecode_runtime
*bytecode
,
860 struct cds_lfht
*merge_points
,
861 struct vstack
*stack
,
866 void *next_pc
= *_next_pc
;
868 switch (*(filter_opcode_t
*) pc
) {
869 case FILTER_OP_UNKNOWN
:
872 ERR("unknown bytecode op %u\n",
873 (unsigned int) *(filter_opcode_t
*) pc
);
878 case FILTER_OP_RETURN
:
880 if (!vstack_ax(stack
)) {
881 ERR("Empty stack\n");
894 case FILTER_OP_MINUS
:
895 case FILTER_OP_RSHIFT
:
896 case FILTER_OP_LSHIFT
:
897 case FILTER_OP_BIN_AND
:
898 case FILTER_OP_BIN_OR
:
899 case FILTER_OP_BIN_XOR
:
901 ERR("unsupported bytecode op %u\n",
902 (unsigned int) *(filter_opcode_t
*) pc
);
913 case FILTER_OP_EQ_STRING
:
914 case FILTER_OP_NE_STRING
:
915 case FILTER_OP_GT_STRING
:
916 case FILTER_OP_LT_STRING
:
917 case FILTER_OP_GE_STRING
:
918 case FILTER_OP_LE_STRING
:
919 case FILTER_OP_EQ_S64
:
920 case FILTER_OP_NE_S64
:
921 case FILTER_OP_GT_S64
:
922 case FILTER_OP_LT_S64
:
923 case FILTER_OP_GE_S64
:
924 case FILTER_OP_LE_S64
:
925 case FILTER_OP_EQ_DOUBLE
:
926 case FILTER_OP_NE_DOUBLE
:
927 case FILTER_OP_GT_DOUBLE
:
928 case FILTER_OP_LT_DOUBLE
:
929 case FILTER_OP_GE_DOUBLE
:
930 case FILTER_OP_LE_DOUBLE
:
931 case FILTER_OP_EQ_DOUBLE_S64
:
932 case FILTER_OP_NE_DOUBLE_S64
:
933 case FILTER_OP_GT_DOUBLE_S64
:
934 case FILTER_OP_LT_DOUBLE_S64
:
935 case FILTER_OP_GE_DOUBLE_S64
:
936 case FILTER_OP_LE_DOUBLE_S64
:
937 case FILTER_OP_EQ_S64_DOUBLE
:
938 case FILTER_OP_NE_S64_DOUBLE
:
939 case FILTER_OP_GT_S64_DOUBLE
:
940 case FILTER_OP_LT_S64_DOUBLE
:
941 case FILTER_OP_GE_S64_DOUBLE
:
942 case FILTER_OP_LE_S64_DOUBLE
:
945 if (vstack_pop(stack
)) {
949 if (!vstack_ax(stack
)) {
950 ERR("Empty stack\n");
954 vstack_ax(stack
)->type
= REG_S64
;
955 next_pc
+= sizeof(struct binary_op
);
960 case FILTER_OP_UNARY_PLUS
:
961 case FILTER_OP_UNARY_MINUS
:
962 case FILTER_OP_UNARY_NOT
:
963 case FILTER_OP_UNARY_PLUS_S64
:
964 case FILTER_OP_UNARY_MINUS_S64
:
965 case FILTER_OP_UNARY_NOT_S64
:
968 if (!vstack_ax(stack
)) {
969 ERR("Empty stack\n");
973 vstack_ax(stack
)->type
= REG_S64
;
974 next_pc
+= sizeof(struct unary_op
);
978 case FILTER_OP_UNARY_PLUS_DOUBLE
:
979 case FILTER_OP_UNARY_MINUS_DOUBLE
:
980 case FILTER_OP_UNARY_NOT_DOUBLE
:
983 if (!vstack_ax(stack
)) {
984 ERR("Empty stack\n");
988 vstack_ax(stack
)->type
= REG_DOUBLE
;
989 next_pc
+= sizeof(struct unary_op
);
997 struct logical_op
*insn
= (struct logical_op
*) pc
;
1000 /* Add merge point to table */
1001 merge_ret
= merge_point_add_check(merge_points
,
1002 insn
->skip_offset
, stack
);
1007 /* Continue to next instruction */
1008 /* Pop 1 when jump not taken */
1009 if (vstack_pop(stack
)) {
1013 next_pc
+= sizeof(struct logical_op
);
1017 /* load field ref */
1018 case FILTER_OP_LOAD_FIELD_REF
:
1020 ERR("Unknown field ref type\n");
1024 /* get context ref */
1025 case FILTER_OP_GET_CONTEXT_REF
:
1027 ERR("Unknown get context ref type\n");
1031 case FILTER_OP_LOAD_FIELD_REF_STRING
:
1032 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
1033 case FILTER_OP_GET_CONTEXT_REF_STRING
:
1035 if (vstack_push(stack
)) {
1039 vstack_ax(stack
)->type
= REG_STRING
;
1040 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1043 case FILTER_OP_LOAD_FIELD_REF_S64
:
1044 case FILTER_OP_GET_CONTEXT_REF_S64
:
1046 if (vstack_push(stack
)) {
1050 vstack_ax(stack
)->type
= REG_S64
;
1051 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1054 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
1055 case FILTER_OP_GET_CONTEXT_REF_DOUBLE
:
1057 if (vstack_push(stack
)) {
1061 vstack_ax(stack
)->type
= REG_DOUBLE
;
1062 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
1066 /* load from immediate operand */
1067 case FILTER_OP_LOAD_STRING
:
1069 struct load_op
*insn
= (struct load_op
*) pc
;
1071 if (vstack_push(stack
)) {
1075 vstack_ax(stack
)->type
= REG_STRING
;
1076 next_pc
+= sizeof(struct load_op
) + strlen(insn
->data
) + 1;
1080 case FILTER_OP_LOAD_S64
:
1082 if (vstack_push(stack
)) {
1086 vstack_ax(stack
)->type
= REG_S64
;
1087 next_pc
+= sizeof(struct load_op
)
1088 + sizeof(struct literal_numeric
);
1092 case FILTER_OP_LOAD_DOUBLE
:
1094 if (vstack_push(stack
)) {
1098 vstack_ax(stack
)->type
= REG_DOUBLE
;
1099 next_pc
+= sizeof(struct load_op
)
1100 + sizeof(struct literal_double
);
1104 case FILTER_OP_CAST_TO_S64
:
1105 case FILTER_OP_CAST_DOUBLE_TO_S64
:
1108 if (!vstack_ax(stack
)) {
1109 ERR("Empty stack\n");
1113 vstack_ax(stack
)->type
= REG_S64
;
1114 next_pc
+= sizeof(struct cast_op
);
1117 case FILTER_OP_CAST_NOP
:
1119 next_pc
+= sizeof(struct cast_op
);
1125 *_next_pc
= next_pc
;
1130 * Never called concurrently (hash seed is shared).
1132 int lttng_filter_validate_bytecode(struct bytecode_runtime
*bytecode
)
1134 struct cds_lfht
*merge_points
;
1135 void *pc
, *next_pc
, *start_pc
;
1137 struct vstack stack
;
1139 vstack_init(&stack
);
1141 if (!lttng_hash_seed_ready
) {
1142 lttng_hash_seed
= time(NULL
);
1143 lttng_hash_seed_ready
= 1;
1146 * Note: merge_points hash table used by single thread, and
1147 * never concurrently resized. Therefore, we can use it without
1148 * holding RCU read-side lock and free nodes without using
1151 merge_points
= cds_lfht_new(DEFAULT_NR_MERGE_POINTS
,
1152 MIN_NR_BUCKETS
, MAX_NR_BUCKETS
,
1154 if (!merge_points
) {
1155 ERR("Error allocating hash table for bytecode validation\n");
1158 start_pc
= &bytecode
->data
[0];
1159 for (pc
= next_pc
= start_pc
; pc
- start_pc
< bytecode
->len
;
1161 ret
= bytecode_validate_overflow(bytecode
, start_pc
, pc
);
1164 ERR("filter bytecode overflow\n");
1167 dbg_printf("Validating op %s (%u)\n",
1168 print_op((unsigned int) *(filter_opcode_t
*) pc
),
1169 (unsigned int) *(filter_opcode_t
*) pc
);
1172 * For each instruction, validate the current context
1173 * (traversal of entire execution flow), and validate
1174 * all merge points targeting this instruction.
1176 ret
= validate_instruction_all_contexts(bytecode
, merge_points
,
1177 &stack
, start_pc
, pc
);
1180 ret
= exec_insn(bytecode
, merge_points
, &stack
, &next_pc
, pc
);
1185 if (delete_all_nodes(merge_points
)) {
1187 ERR("Unexpected merge points\n");
1191 if (cds_lfht_destroy(merge_points
, NULL
)) {
1192 ERR("Error destroying hash table\n");