Commit | Line | Data |
---|---|---|
9f36eaed MJ |
1 | /* SPDX-License-Identifier: MIT |
2 | * | |
80c2a69a | 3 | * lttng-bytecode-specialize.c |
07dfc1d0 | 4 | * |
80c2a69a | 5 | * LTTng modules bytecode code specializer. |
07dfc1d0 | 6 | * |
bbf3aef5 | 7 | * Copyright (C) 2010-2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
07dfc1d0 MD |
8 | */ |
9 | ||
3834b99f | 10 | #include <linux/slab.h> |
c570be0d MJ |
11 | #include <wrapper/compiler_attributes.h> |
12 | ||
80c2a69a | 13 | #include <lttng/lttng-bytecode.h> |
a071f25d | 14 | #include <lttng/align.h> |
437d5aa5 | 15 | #include <lttng/events-internal.h> |
07dfc1d0 | 16 | |
3834b99f MD |
17 | static ssize_t bytecode_reserve_data(struct bytecode_runtime *runtime, |
18 | size_t align, size_t len) | |
19 | { | |
20 | ssize_t ret; | |
21 | size_t padding = offset_align(runtime->data_len, align); | |
22 | size_t new_len = runtime->data_len + padding + len; | |
23 | size_t new_alloc_len = new_len; | |
24 | size_t old_alloc_len = runtime->data_alloc_len; | |
25 | ||
80c2a69a | 26 | if (new_len > INTERPRETER_MAX_DATA_LEN) |
3834b99f MD |
27 | return -EINVAL; |
28 | ||
29 | if (new_alloc_len > old_alloc_len) { | |
30 | char *newptr; | |
31 | ||
32 | new_alloc_len = | |
33 | max_t(size_t, 1U << get_count_order(new_alloc_len), old_alloc_len << 1); | |
34 | newptr = krealloc(runtime->data, new_alloc_len, GFP_KERNEL); | |
35 | if (!newptr) | |
36 | return -ENOMEM; | |
37 | runtime->data = newptr; | |
38 | /* We zero directly the memory from start of allocation. */ | |
39 | memset(&runtime->data[old_alloc_len], 0, new_alloc_len - old_alloc_len); | |
40 | runtime->data_alloc_len = new_alloc_len; | |
41 | } | |
42 | runtime->data_len += padding; | |
43 | ret = runtime->data_len; | |
44 | runtime->data_len += len; | |
45 | return ret; | |
46 | } | |
47 | ||
48 | static ssize_t bytecode_push_data(struct bytecode_runtime *runtime, | |
49 | const void *p, size_t align, size_t len) | |
50 | { | |
51 | ssize_t offset; | |
52 | ||
53 | offset = bytecode_reserve_data(runtime, align, len); | |
54 | if (offset < 0) | |
55 | return -ENOMEM; | |
56 | memcpy(&runtime->data[offset], p, len); | |
57 | return offset; | |
58 | } | |
59 | ||
60 | static int specialize_load_field(struct vstack_entry *stack_top, | |
61 | struct load_op *insn) | |
62 | { | |
63 | int ret; | |
64 | ||
65 | switch (stack_top->load.type) { | |
66 | case LOAD_OBJECT: | |
67 | break; | |
68 | case LOAD_ROOT_CONTEXT: | |
69 | case LOAD_ROOT_APP_CONTEXT: | |
70 | case LOAD_ROOT_PAYLOAD: | |
71 | default: | |
80c2a69a | 72 | dbg_printk("Bytecode warning: cannot load root, missing field name.\n"); |
3834b99f MD |
73 | ret = -EINVAL; |
74 | goto end; | |
75 | } | |
76 | switch (stack_top->load.object_type) { | |
77 | case OBJECT_TYPE_S8: | |
78 | dbg_printk("op load field s8\n"); | |
79 | stack_top->type = REG_S64; | |
8c36b138 | 80 | if (!stack_top->load.user) |
80c2a69a | 81 | insn->op = BYTECODE_OP_LOAD_FIELD_S8; |
3834b99f MD |
82 | break; |
83 | case OBJECT_TYPE_S16: | |
84 | dbg_printk("op load field s16\n"); | |
85 | stack_top->type = REG_S64; | |
8c36b138 | 86 | if (!stack_top->load.rev_bo && !stack_top->load.user) |
80c2a69a | 87 | insn->op = BYTECODE_OP_LOAD_FIELD_S16; |
3834b99f MD |
88 | break; |
89 | case OBJECT_TYPE_S32: | |
90 | dbg_printk("op load field s32\n"); | |
91 | stack_top->type = REG_S64; | |
8c36b138 | 92 | if (!stack_top->load.rev_bo && !stack_top->load.user) |
80c2a69a | 93 | insn->op = BYTECODE_OP_LOAD_FIELD_S32; |
3834b99f MD |
94 | break; |
95 | case OBJECT_TYPE_S64: | |
96 | dbg_printk("op load field s64\n"); | |
97 | stack_top->type = REG_S64; | |
8c36b138 | 98 | if (!stack_top->load.rev_bo && !stack_top->load.user) |
80c2a69a | 99 | insn->op = BYTECODE_OP_LOAD_FIELD_S64; |
3834b99f | 100 | break; |
29a574c3 FD |
101 | case OBJECT_TYPE_SIGNED_ENUM: |
102 | dbg_printk("op load field signed enumeration\n"); | |
8c36b138 MD |
103 | if (stack_top->load.user) { |
104 | printk(KERN_WARNING "LTTng: bytecode: user enum unsupported\n"); | |
105 | ret = -EINVAL; | |
106 | goto end; | |
107 | } | |
108 | stack_top->type = REG_S64; | |
29a574c3 | 109 | break; |
3834b99f MD |
110 | case OBJECT_TYPE_U8: |
111 | dbg_printk("op load field u8\n"); | |
112 | stack_top->type = REG_S64; | |
8c36b138 MD |
113 | if (!stack_top->load.user) |
114 | insn->op = BYTECODE_OP_LOAD_FIELD_U8; | |
3834b99f MD |
115 | break; |
116 | case OBJECT_TYPE_U16: | |
117 | dbg_printk("op load field u16\n"); | |
118 | stack_top->type = REG_S64; | |
8c36b138 | 119 | if (!stack_top->load.rev_bo && !stack_top->load.user) |
80c2a69a | 120 | insn->op = BYTECODE_OP_LOAD_FIELD_U16; |
3834b99f MD |
121 | break; |
122 | case OBJECT_TYPE_U32: | |
123 | dbg_printk("op load field u32\n"); | |
124 | stack_top->type = REG_S64; | |
8c36b138 | 125 | if (!stack_top->load.rev_bo && !stack_top->load.user) |
80c2a69a | 126 | insn->op = BYTECODE_OP_LOAD_FIELD_U32; |
3834b99f MD |
127 | break; |
128 | case OBJECT_TYPE_U64: | |
129 | dbg_printk("op load field u64\n"); | |
130 | stack_top->type = REG_S64; | |
8c36b138 | 131 | if (!stack_top->load.rev_bo && !stack_top->load.user) |
80c2a69a | 132 | insn->op = BYTECODE_OP_LOAD_FIELD_U64; |
3834b99f | 133 | break; |
29a574c3 FD |
134 | case OBJECT_TYPE_UNSIGNED_ENUM: |
135 | dbg_printk("op load field unsigned enumeration\n"); | |
8c36b138 MD |
136 | if (stack_top->load.user) { |
137 | printk(KERN_WARNING "LTTng: bytecode: user enum unsupported\n"); | |
138 | ret = -EINVAL; | |
139 | goto end; | |
140 | } | |
141 | stack_top->type = REG_U64; | |
29a574c3 | 142 | break; |
3834b99f | 143 | case OBJECT_TYPE_DOUBLE: |
80c2a69a | 144 | printk(KERN_WARNING "LTTng: bytecode: Double type unsupported\n\n"); |
3834b99f MD |
145 | ret = -EINVAL; |
146 | goto end; | |
147 | case OBJECT_TYPE_STRING: | |
148 | dbg_printk("op load field string\n"); | |
149 | stack_top->type = REG_STRING; | |
8c36b138 MD |
150 | if (!stack_top->load.user) |
151 | insn->op = BYTECODE_OP_LOAD_FIELD_STRING; | |
3834b99f MD |
152 | break; |
153 | case OBJECT_TYPE_STRING_SEQUENCE: | |
154 | dbg_printk("op load field string sequence\n"); | |
155 | stack_top->type = REG_STRING; | |
8c36b138 MD |
156 | if (!stack_top->load.user) |
157 | insn->op = BYTECODE_OP_LOAD_FIELD_SEQUENCE; | |
3834b99f MD |
158 | break; |
159 | case OBJECT_TYPE_DYNAMIC: | |
160 | ret = -EINVAL; | |
161 | goto end; | |
162 | case OBJECT_TYPE_SEQUENCE: | |
163 | case OBJECT_TYPE_ARRAY: | |
164 | case OBJECT_TYPE_STRUCT: | |
165 | case OBJECT_TYPE_VARIANT: | |
80c2a69a | 166 | printk(KERN_WARNING "LTTng: bytecode: Sequences, arrays, struct and variant cannot be loaded (nested types).\n"); |
3834b99f MD |
167 | ret = -EINVAL; |
168 | goto end; | |
169 | } | |
170 | return 0; | |
171 | ||
172 | end: | |
173 | return ret; | |
174 | } | |
175 | ||
176 | static int specialize_get_index_object_type(enum object_type *otype, | |
177 | int signedness, uint32_t elem_len) | |
178 | { | |
179 | switch (elem_len) { | |
180 | case 8: | |
181 | if (signedness) | |
182 | *otype = OBJECT_TYPE_S8; | |
183 | else | |
184 | *otype = OBJECT_TYPE_U8; | |
185 | break; | |
186 | case 16: | |
187 | if (signedness) | |
188 | *otype = OBJECT_TYPE_S16; | |
189 | else | |
190 | *otype = OBJECT_TYPE_U16; | |
191 | break; | |
192 | case 32: | |
193 | if (signedness) | |
194 | *otype = OBJECT_TYPE_S32; | |
195 | else | |
196 | *otype = OBJECT_TYPE_U32; | |
197 | break; | |
198 | case 64: | |
199 | if (signedness) | |
200 | *otype = OBJECT_TYPE_S64; | |
201 | else | |
202 | *otype = OBJECT_TYPE_U64; | |
203 | break; | |
204 | default: | |
205 | return -EINVAL; | |
206 | } | |
207 | return 0; | |
208 | } | |
209 | ||
210 | static int specialize_get_index(struct bytecode_runtime *runtime, | |
211 | struct load_op *insn, uint64_t index, | |
212 | struct vstack_entry *stack_top, | |
213 | int idx_len) | |
214 | { | |
215 | int ret; | |
80c2a69a | 216 | struct bytecode_get_index_data gid; |
3834b99f MD |
217 | ssize_t data_offset; |
218 | ||
219 | memset(&gid, 0, sizeof(gid)); | |
220 | switch (stack_top->load.type) { | |
221 | case LOAD_OBJECT: | |
222 | switch (stack_top->load.object_type) { | |
223 | case OBJECT_TYPE_ARRAY: | |
224 | { | |
437d5aa5 MD |
225 | const struct lttng_kernel_event_field *field; |
226 | const struct lttng_kernel_type_array *array_type; | |
227 | const struct lttng_kernel_type_integer *integer_type; | |
3834b99f MD |
228 | uint32_t elem_len, num_elems; |
229 | int signedness; | |
230 | ||
231 | field = stack_top->load.field; | |
437d5aa5 MD |
232 | array_type = lttng_kernel_get_type_array(field->type); |
233 | if (!lttng_kernel_type_is_bytewise_integer(array_type->elem_type)) { | |
ceabb767 MD |
234 | ret = -EINVAL; |
235 | goto end; | |
236 | } | |
437d5aa5 MD |
237 | integer_type = lttng_kernel_get_type_integer(array_type->elem_type); |
238 | num_elems = array_type->length; | |
ceabb767 MD |
239 | elem_len = integer_type->size; |
240 | signedness = integer_type->signedness; | |
3834b99f MD |
241 | if (index >= num_elems) { |
242 | ret = -EINVAL; | |
243 | goto end; | |
244 | } | |
245 | ret = specialize_get_index_object_type(&stack_top->load.object_type, | |
246 | signedness, elem_len); | |
247 | if (ret) | |
248 | goto end; | |
249 | gid.offset = index * (elem_len / CHAR_BIT); | |
250 | gid.array_len = num_elems * (elem_len / CHAR_BIT); | |
251 | gid.elem.type = stack_top->load.object_type; | |
252 | gid.elem.len = elem_len; | |
8c36b138 MD |
253 | stack_top->load.rev_bo = gid.elem.rev_bo = integer_type->reverse_byte_order; |
254 | stack_top->load.user = gid.elem.user = integer_type->user; | |
3834b99f MD |
255 | break; |
256 | } | |
257 | case OBJECT_TYPE_SEQUENCE: | |
258 | { | |
437d5aa5 MD |
259 | const struct lttng_kernel_event_field *field; |
260 | const struct lttng_kernel_type_sequence *sequence_type; | |
261 | const struct lttng_kernel_type_integer *integer_type; | |
3834b99f MD |
262 | uint32_t elem_len; |
263 | int signedness; | |
264 | ||
265 | field = stack_top->load.field; | |
437d5aa5 MD |
266 | sequence_type = lttng_kernel_get_type_sequence(field->type); |
267 | if (!lttng_kernel_type_is_bytewise_integer(sequence_type->elem_type)) { | |
ceabb767 MD |
268 | ret = -EINVAL; |
269 | goto end; | |
270 | } | |
437d5aa5 | 271 | integer_type = lttng_kernel_get_type_integer(sequence_type->elem_type); |
ceabb767 MD |
272 | elem_len = integer_type->size; |
273 | signedness = integer_type->signedness; | |
3834b99f MD |
274 | ret = specialize_get_index_object_type(&stack_top->load.object_type, |
275 | signedness, elem_len); | |
276 | if (ret) | |
277 | goto end; | |
278 | gid.offset = index * (elem_len / CHAR_BIT); | |
279 | gid.elem.type = stack_top->load.object_type; | |
280 | gid.elem.len = elem_len; | |
8c36b138 MD |
281 | stack_top->load.rev_bo = gid.elem.rev_bo = integer_type->reverse_byte_order; |
282 | stack_top->load.user = gid.elem.user = integer_type->user; | |
3834b99f MD |
283 | break; |
284 | } | |
285 | case OBJECT_TYPE_STRUCT: | |
286 | /* Only generated by the specialize phase. */ | |
c570be0d MJ |
287 | case OBJECT_TYPE_VARIANT: |
288 | lttng_fallthrough; | |
3834b99f | 289 | default: |
80c2a69a | 290 | printk(KERN_WARNING "LTTng: bytecode: Unexpected get index type %d", |
3834b99f MD |
291 | (int) stack_top->load.object_type); |
292 | ret = -EINVAL; | |
293 | goto end; | |
294 | } | |
295 | break; | |
296 | case LOAD_ROOT_CONTEXT: | |
297 | case LOAD_ROOT_APP_CONTEXT: | |
298 | case LOAD_ROOT_PAYLOAD: | |
80c2a69a | 299 | printk(KERN_WARNING "LTTng: bytecode: Index lookup for root field not implemented yet.\n"); |
3834b99f MD |
300 | ret = -EINVAL; |
301 | goto end; | |
302 | } | |
303 | data_offset = bytecode_push_data(runtime, &gid, | |
304 | __alignof__(gid), sizeof(gid)); | |
305 | if (data_offset < 0) { | |
306 | ret = -EINVAL; | |
307 | goto end; | |
308 | } | |
309 | switch (idx_len) { | |
310 | case 2: | |
311 | ((struct get_index_u16 *) insn->data)->index = data_offset; | |
312 | break; | |
313 | case 8: | |
314 | ((struct get_index_u64 *) insn->data)->index = data_offset; | |
315 | break; | |
316 | default: | |
317 | ret = -EINVAL; | |
318 | goto end; | |
319 | } | |
320 | ||
321 | return 0; | |
322 | ||
323 | end: | |
324 | return ret; | |
325 | } | |
326 | ||
437d5aa5 | 327 | static int specialize_context_lookup_name(struct lttng_kernel_ctx *ctx, |
2dfda770 | 328 | struct bytecode_runtime *bytecode, |
3834b99f MD |
329 | struct load_op *insn) |
330 | { | |
331 | uint16_t offset; | |
332 | const char *name; | |
333 | ||
334 | offset = ((struct get_symbol *) insn->data)->offset; | |
335 | name = bytecode->p.bc->bc.data + bytecode->p.bc->bc.reloc_offset + offset; | |
437d5aa5 | 336 | return lttng_kernel_get_context_index(ctx, name); |
3834b99f MD |
337 | } |
338 | ||
437d5aa5 | 339 | static int specialize_load_object(const struct lttng_kernel_event_field *field, |
3834b99f MD |
340 | struct vstack_load *load, bool is_context) |
341 | { | |
342 | load->type = LOAD_OBJECT; | |
1242217a | 343 | |
437d5aa5 | 344 | switch (field->type->type) { |
12bb2edb | 345 | case lttng_kernel_type_integer: |
8c36b138 MD |
346 | { |
347 | const struct lttng_kernel_type_integer *integer_type = lttng_kernel_get_type_integer(field->type); | |
348 | ||
349 | if (integer_type->signedness) | |
3834b99f MD |
350 | load->object_type = OBJECT_TYPE_S64; |
351 | else | |
352 | load->object_type = OBJECT_TYPE_U64; | |
8c36b138 MD |
353 | load->rev_bo = integer_type->reverse_byte_order; |
354 | load->user = integer_type->user; | |
3834b99f | 355 | break; |
8c36b138 | 356 | } |
437d5aa5 | 357 | case lttng_kernel_type_enum: |
3834b99f | 358 | { |
437d5aa5 MD |
359 | const struct lttng_kernel_type_enum *enum_type = lttng_kernel_get_type_enum(field->type); |
360 | const struct lttng_kernel_type_integer *integer_type = lttng_kernel_get_type_integer(enum_type->container_type); | |
3834b99f | 361 | |
437d5aa5 | 362 | if (integer_type->signedness) |
29a574c3 | 363 | load->object_type = OBJECT_TYPE_SIGNED_ENUM; |
3834b99f | 364 | else |
29a574c3 | 365 | load->object_type = OBJECT_TYPE_UNSIGNED_ENUM; |
8c36b138 MD |
366 | load->rev_bo = integer_type->reverse_byte_order; |
367 | load->user = integer_type->user; | |
3834b99f MD |
368 | break; |
369 | } | |
437d5aa5 MD |
370 | case lttng_kernel_type_array: |
371 | { | |
372 | const struct lttng_kernel_type_array *array_type = lttng_kernel_get_type_array(field->type); | |
8c36b138 | 373 | const struct lttng_kernel_type_integer *integer_type; |
437d5aa5 MD |
374 | |
375 | if (!lttng_kernel_type_is_bytewise_integer(array_type->elem_type)) { | |
80c2a69a | 376 | printk(KERN_WARNING "LTTng: bytecode: Array nesting only supports integer types.\n"); |
3834b99f MD |
377 | return -EINVAL; |
378 | } | |
8c36b138 | 379 | integer_type = lttng_kernel_get_type_integer(array_type->elem_type); |
3834b99f MD |
380 | if (is_context) { |
381 | load->object_type = OBJECT_TYPE_STRING; | |
8c36b138 | 382 | load->user = integer_type->user; |
3834b99f | 383 | } else { |
437d5aa5 | 384 | if (array_type->encoding == lttng_kernel_string_encoding_none) { |
3834b99f MD |
385 | load->object_type = OBJECT_TYPE_ARRAY; |
386 | load->field = field; | |
387 | } else { | |
388 | load->object_type = OBJECT_TYPE_STRING_SEQUENCE; | |
8c36b138 | 389 | load->user = integer_type->user; |
3834b99f MD |
390 | } |
391 | } | |
392 | break; | |
437d5aa5 MD |
393 | } |
394 | case lttng_kernel_type_sequence: | |
395 | { | |
396 | const struct lttng_kernel_type_sequence *sequence_type = lttng_kernel_get_type_sequence(field->type); | |
8c36b138 | 397 | const struct lttng_kernel_type_integer *integer_type; |
437d5aa5 MD |
398 | |
399 | if (!lttng_kernel_type_is_bytewise_integer(sequence_type->elem_type)) { | |
80c2a69a | 400 | printk(KERN_WARNING "LTTng: bytecode: Sequence nesting only supports integer types.\n"); |
3834b99f MD |
401 | return -EINVAL; |
402 | } | |
8c36b138 | 403 | integer_type = lttng_kernel_get_type_integer(sequence_type->elem_type); |
3834b99f MD |
404 | if (is_context) { |
405 | load->object_type = OBJECT_TYPE_STRING; | |
8c36b138 | 406 | load->user = integer_type->user; |
3834b99f | 407 | } else { |
437d5aa5 | 408 | if (sequence_type->encoding == lttng_kernel_string_encoding_none) { |
3834b99f MD |
409 | load->object_type = OBJECT_TYPE_SEQUENCE; |
410 | load->field = field; | |
411 | } else { | |
412 | load->object_type = OBJECT_TYPE_STRING_SEQUENCE; | |
8c36b138 | 413 | load->user = integer_type->user; |
3834b99f MD |
414 | } |
415 | } | |
416 | break; | |
437d5aa5 | 417 | } |
12bb2edb | 418 | case lttng_kernel_type_string: |
8c36b138 MD |
419 | { |
420 | const struct lttng_kernel_type_string *string_type = lttng_kernel_get_type_string(field->type); | |
421 | ||
3834b99f | 422 | load->object_type = OBJECT_TYPE_STRING; |
8c36b138 | 423 | load->user = string_type->user; |
3834b99f | 424 | break; |
8c36b138 | 425 | } |
437d5aa5 | 426 | case lttng_kernel_type_struct: |
80c2a69a | 427 | printk(KERN_WARNING "LTTng: bytecode: Structure type cannot be loaded.\n"); |
3834b99f | 428 | return -EINVAL; |
437d5aa5 | 429 | case lttng_kernel_type_variant: |
80c2a69a | 430 | printk(KERN_WARNING "LTTng: bytecode: Variant type cannot be loaded.\n"); |
ceabb767 | 431 | return -EINVAL; |
3834b99f | 432 | default: |
437d5aa5 | 433 | printk(KERN_WARNING "LTTng: bytecode: Unknown type: %d", (int) field->type->type); |
3834b99f MD |
434 | return -EINVAL; |
435 | } | |
436 | return 0; | |
437 | } | |
438 | ||
437d5aa5 | 439 | static int specialize_context_lookup(struct lttng_kernel_ctx *ctx, |
2dfda770 | 440 | struct bytecode_runtime *runtime, |
3834b99f MD |
441 | struct load_op *insn, |
442 | struct vstack_load *load) | |
443 | { | |
444 | int idx, ret; | |
437d5aa5 MD |
445 | const struct lttng_kernel_ctx_field *ctx_field; |
446 | const struct lttng_kernel_event_field *field; | |
80c2a69a | 447 | struct bytecode_get_index_data gid; |
3834b99f MD |
448 | ssize_t data_offset; |
449 | ||
2dfda770 | 450 | idx = specialize_context_lookup_name(ctx, runtime, insn); |
3834b99f MD |
451 | if (idx < 0) { |
452 | return -ENOENT; | |
453 | } | |
454 | ctx_field = <tng_static_ctx->fields[idx]; | |
437d5aa5 | 455 | field = ctx_field->event_field; |
3834b99f MD |
456 | ret = specialize_load_object(field, load, true); |
457 | if (ret) | |
458 | return ret; | |
459 | /* Specialize each get_symbol into a get_index. */ | |
80c2a69a | 460 | insn->op = BYTECODE_OP_GET_INDEX_U16; |
3834b99f MD |
461 | memset(&gid, 0, sizeof(gid)); |
462 | gid.ctx_index = idx; | |
463 | gid.elem.type = load->object_type; | |
60e8b0d6 | 464 | gid.elem.rev_bo = load->rev_bo; |
8c36b138 | 465 | gid.elem.user = load->user; |
03cb0cdd | 466 | gid.field = field; |
3834b99f MD |
467 | data_offset = bytecode_push_data(runtime, &gid, |
468 | __alignof__(gid), sizeof(gid)); | |
469 | if (data_offset < 0) { | |
470 | return -EINVAL; | |
471 | } | |
472 | ((struct get_index_u16 *) insn->data)->index = data_offset; | |
473 | return 0; | |
474 | } | |
475 | ||
437d5aa5 | 476 | static int specialize_payload_lookup(const struct lttng_kernel_event_desc *event_desc, |
3834b99f MD |
477 | struct bytecode_runtime *runtime, |
478 | struct load_op *insn, | |
479 | struct vstack_load *load) | |
480 | { | |
481 | const char *name; | |
482 | uint16_t offset; | |
3834b99f MD |
483 | unsigned int i, nr_fields; |
484 | bool found = false; | |
485 | uint32_t field_offset = 0; | |
437d5aa5 | 486 | const struct lttng_kernel_event_field *field; |
3834b99f | 487 | int ret; |
80c2a69a | 488 | struct bytecode_get_index_data gid; |
3834b99f MD |
489 | ssize_t data_offset; |
490 | ||
e69abdfd | 491 | nr_fields = event_desc->tp_class->nr_fields; |
3834b99f MD |
492 | offset = ((struct get_symbol *) insn->data)->offset; |
493 | name = runtime->p.bc->bc.data + runtime->p.bc->bc.reloc_offset + offset; | |
494 | for (i = 0; i < nr_fields; i++) { | |
e69abdfd | 495 | field = event_desc->tp_class->fields[i]; |
ceabb767 MD |
496 | if (field->nofilter) { |
497 | continue; | |
498 | } | |
3834b99f MD |
499 | if (!strcmp(field->name, name)) { |
500 | found = true; | |
501 | break; | |
502 | } | |
503 | /* compute field offset on stack */ | |
437d5aa5 | 504 | switch (field->type->type) { |
12bb2edb | 505 | case lttng_kernel_type_integer: |
437d5aa5 | 506 | case lttng_kernel_type_enum: |
3834b99f MD |
507 | field_offset += sizeof(int64_t); |
508 | break; | |
437d5aa5 MD |
509 | case lttng_kernel_type_array: |
510 | case lttng_kernel_type_sequence: | |
3834b99f MD |
511 | field_offset += sizeof(unsigned long); |
512 | field_offset += sizeof(void *); | |
513 | break; | |
12bb2edb | 514 | case lttng_kernel_type_string: |
3834b99f MD |
515 | field_offset += sizeof(void *); |
516 | break; | |
517 | default: | |
518 | ret = -EINVAL; | |
519 | goto end; | |
520 | } | |
521 | } | |
522 | if (!found) { | |
523 | ret = -EINVAL; | |
524 | goto end; | |
525 | } | |
526 | ||
527 | ret = specialize_load_object(field, load, false); | |
528 | if (ret) | |
529 | goto end; | |
530 | ||
531 | /* Specialize each get_symbol into a get_index. */ | |
80c2a69a | 532 | insn->op = BYTECODE_OP_GET_INDEX_U16; |
3834b99f MD |
533 | memset(&gid, 0, sizeof(gid)); |
534 | gid.offset = field_offset; | |
535 | gid.elem.type = load->object_type; | |
60e8b0d6 | 536 | gid.elem.rev_bo = load->rev_bo; |
8c36b138 | 537 | gid.elem.user = load->user; |
03cb0cdd | 538 | gid.field = field; |
3834b99f MD |
539 | data_offset = bytecode_push_data(runtime, &gid, |
540 | __alignof__(gid), sizeof(gid)); | |
541 | if (data_offset < 0) { | |
542 | ret = -EINVAL; | |
543 | goto end; | |
544 | } | |
545 | ((struct get_index_u16 *) insn->data)->index = data_offset; | |
546 | ret = 0; | |
547 | end: | |
548 | return ret; | |
549 | } | |
550 | ||
437d5aa5 | 551 | int lttng_bytecode_specialize(const struct lttng_kernel_event_desc *event_desc, |
3834b99f | 552 | struct bytecode_runtime *bytecode) |
07dfc1d0 MD |
553 | { |
554 | void *pc, *next_pc, *start_pc; | |
555 | int ret = -EINVAL; | |
556 | struct vstack _stack; | |
557 | struct vstack *stack = &_stack; | |
437d5aa5 | 558 | struct lttng_kernel_ctx *ctx = bytecode->p.ctx; |
07dfc1d0 MD |
559 | |
560 | vstack_init(stack); | |
561 | ||
3834b99f | 562 | start_pc = &bytecode->code[0]; |
07dfc1d0 MD |
563 | for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; |
564 | pc = next_pc) { | |
80c2a69a FD |
565 | switch (*(bytecode_opcode_t *) pc) { |
566 | case BYTECODE_OP_UNKNOWN: | |
07dfc1d0 | 567 | default: |
80c2a69a FD |
568 | printk(KERN_WARNING "LTTng: bytecode: unknown bytecode op %u\n", |
569 | (unsigned int) *(bytecode_opcode_t *) pc); | |
07dfc1d0 MD |
570 | ret = -EINVAL; |
571 | goto end; | |
572 | ||
80c2a69a FD |
573 | case BYTECODE_OP_RETURN: |
574 | case BYTECODE_OP_RETURN_S64: | |
07dfc1d0 MD |
575 | ret = 0; |
576 | goto end; | |
577 | ||
578 | /* binary */ | |
80c2a69a FD |
579 | case BYTECODE_OP_MUL: |
580 | case BYTECODE_OP_DIV: | |
581 | case BYTECODE_OP_MOD: | |
582 | case BYTECODE_OP_PLUS: | |
583 | case BYTECODE_OP_MINUS: | |
584 | printk(KERN_WARNING "LTTng: bytecode: unknown bytecode op %u\n", | |
585 | (unsigned int) *(bytecode_opcode_t *) pc); | |
07dfc1d0 MD |
586 | ret = -EINVAL; |
587 | goto end; | |
588 | ||
80c2a69a | 589 | case BYTECODE_OP_EQ: |
07dfc1d0 MD |
590 | { |
591 | struct binary_op *insn = (struct binary_op *) pc; | |
592 | ||
593 | switch(vstack_ax(stack)->type) { | |
594 | default: | |
80c2a69a | 595 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
596 | ret = -EINVAL; |
597 | goto end; | |
598 | ||
599 | case REG_STRING: | |
02aca193 | 600 | if (vstack_bx(stack)->type == REG_STAR_GLOB_STRING) |
80c2a69a | 601 | insn->op = BYTECODE_OP_EQ_STAR_GLOB_STRING; |
02aca193 | 602 | else |
80c2a69a | 603 | insn->op = BYTECODE_OP_EQ_STRING; |
02aca193 PP |
604 | break; |
605 | case REG_STAR_GLOB_STRING: | |
80c2a69a | 606 | insn->op = BYTECODE_OP_EQ_STAR_GLOB_STRING; |
07dfc1d0 MD |
607 | break; |
608 | case REG_S64: | |
609 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 610 | insn->op = BYTECODE_OP_EQ_S64; |
07dfc1d0 | 611 | else |
80c2a69a | 612 | insn->op = BYTECODE_OP_EQ_DOUBLE_S64; |
07dfc1d0 MD |
613 | break; |
614 | case REG_DOUBLE: | |
615 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 616 | insn->op = BYTECODE_OP_EQ_S64_DOUBLE; |
07dfc1d0 | 617 | else |
80c2a69a | 618 | insn->op = BYTECODE_OP_EQ_DOUBLE; |
07dfc1d0 MD |
619 | break; |
620 | } | |
621 | /* Pop 2, push 1 */ | |
622 | if (vstack_pop(stack)) { | |
623 | ret = -EINVAL; | |
624 | goto end; | |
625 | } | |
626 | vstack_ax(stack)->type = REG_S64; | |
627 | next_pc += sizeof(struct binary_op); | |
628 | break; | |
629 | } | |
630 | ||
80c2a69a | 631 | case BYTECODE_OP_NE: |
07dfc1d0 MD |
632 | { |
633 | struct binary_op *insn = (struct binary_op *) pc; | |
634 | ||
635 | switch(vstack_ax(stack)->type) { | |
636 | default: | |
80c2a69a | 637 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
638 | ret = -EINVAL; |
639 | goto end; | |
640 | ||
641 | case REG_STRING: | |
02aca193 | 642 | if (vstack_bx(stack)->type == REG_STAR_GLOB_STRING) |
80c2a69a | 643 | insn->op = BYTECODE_OP_NE_STAR_GLOB_STRING; |
02aca193 | 644 | else |
80c2a69a | 645 | insn->op = BYTECODE_OP_NE_STRING; |
02aca193 PP |
646 | break; |
647 | case REG_STAR_GLOB_STRING: | |
80c2a69a | 648 | insn->op = BYTECODE_OP_NE_STAR_GLOB_STRING; |
07dfc1d0 MD |
649 | break; |
650 | case REG_S64: | |
651 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 652 | insn->op = BYTECODE_OP_NE_S64; |
07dfc1d0 | 653 | else |
80c2a69a | 654 | insn->op = BYTECODE_OP_NE_DOUBLE_S64; |
07dfc1d0 MD |
655 | break; |
656 | case REG_DOUBLE: | |
657 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 658 | insn->op = BYTECODE_OP_NE_S64_DOUBLE; |
07dfc1d0 | 659 | else |
80c2a69a | 660 | insn->op = BYTECODE_OP_NE_DOUBLE; |
07dfc1d0 MD |
661 | break; |
662 | } | |
663 | /* Pop 2, push 1 */ | |
664 | if (vstack_pop(stack)) { | |
665 | ret = -EINVAL; | |
666 | goto end; | |
667 | } | |
668 | vstack_ax(stack)->type = REG_S64; | |
669 | next_pc += sizeof(struct binary_op); | |
670 | break; | |
671 | } | |
672 | ||
80c2a69a | 673 | case BYTECODE_OP_GT: |
07dfc1d0 MD |
674 | { |
675 | struct binary_op *insn = (struct binary_op *) pc; | |
676 | ||
677 | switch(vstack_ax(stack)->type) { | |
678 | default: | |
80c2a69a | 679 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
680 | ret = -EINVAL; |
681 | goto end; | |
682 | ||
02aca193 | 683 | case REG_STAR_GLOB_STRING: |
80c2a69a | 684 | printk(KERN_WARNING "LTTng: bytecode: invalid register type for '>' binary operator\n"); |
02aca193 PP |
685 | ret = -EINVAL; |
686 | goto end; | |
07dfc1d0 | 687 | case REG_STRING: |
80c2a69a | 688 | insn->op = BYTECODE_OP_GT_STRING; |
07dfc1d0 MD |
689 | break; |
690 | case REG_S64: | |
691 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 692 | insn->op = BYTECODE_OP_GT_S64; |
07dfc1d0 | 693 | else |
80c2a69a | 694 | insn->op = BYTECODE_OP_GT_DOUBLE_S64; |
07dfc1d0 MD |
695 | break; |
696 | case REG_DOUBLE: | |
697 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 698 | insn->op = BYTECODE_OP_GT_S64_DOUBLE; |
07dfc1d0 | 699 | else |
80c2a69a | 700 | insn->op = BYTECODE_OP_GT_DOUBLE; |
07dfc1d0 MD |
701 | break; |
702 | } | |
703 | /* Pop 2, push 1 */ | |
704 | if (vstack_pop(stack)) { | |
705 | ret = -EINVAL; | |
706 | goto end; | |
707 | } | |
708 | vstack_ax(stack)->type = REG_S64; | |
709 | next_pc += sizeof(struct binary_op); | |
710 | break; | |
711 | } | |
712 | ||
80c2a69a | 713 | case BYTECODE_OP_LT: |
07dfc1d0 MD |
714 | { |
715 | struct binary_op *insn = (struct binary_op *) pc; | |
716 | ||
717 | switch(vstack_ax(stack)->type) { | |
718 | default: | |
80c2a69a | 719 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
720 | ret = -EINVAL; |
721 | goto end; | |
722 | ||
02aca193 | 723 | case REG_STAR_GLOB_STRING: |
80c2a69a | 724 | printk(KERN_WARNING "LTTng: bytecode: invalid register type for '<' binary operator\n"); |
02aca193 PP |
725 | ret = -EINVAL; |
726 | goto end; | |
07dfc1d0 | 727 | case REG_STRING: |
80c2a69a | 728 | insn->op = BYTECODE_OP_LT_STRING; |
07dfc1d0 MD |
729 | break; |
730 | case REG_S64: | |
731 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 732 | insn->op = BYTECODE_OP_LT_S64; |
07dfc1d0 | 733 | else |
80c2a69a | 734 | insn->op = BYTECODE_OP_LT_DOUBLE_S64; |
07dfc1d0 MD |
735 | break; |
736 | case REG_DOUBLE: | |
737 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 738 | insn->op = BYTECODE_OP_LT_S64_DOUBLE; |
07dfc1d0 | 739 | else |
80c2a69a | 740 | insn->op = BYTECODE_OP_LT_DOUBLE; |
07dfc1d0 MD |
741 | break; |
742 | } | |
743 | /* Pop 2, push 1 */ | |
744 | if (vstack_pop(stack)) { | |
745 | ret = -EINVAL; | |
746 | goto end; | |
747 | } | |
748 | vstack_ax(stack)->type = REG_S64; | |
749 | next_pc += sizeof(struct binary_op); | |
750 | break; | |
751 | } | |
752 | ||
80c2a69a | 753 | case BYTECODE_OP_GE: |
07dfc1d0 MD |
754 | { |
755 | struct binary_op *insn = (struct binary_op *) pc; | |
756 | ||
757 | switch(vstack_ax(stack)->type) { | |
758 | default: | |
80c2a69a | 759 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
760 | ret = -EINVAL; |
761 | goto end; | |
762 | ||
02aca193 | 763 | case REG_STAR_GLOB_STRING: |
80c2a69a | 764 | printk(KERN_WARNING "LTTng: bytecode: invalid register type for '>=' binary operator\n"); |
02aca193 PP |
765 | ret = -EINVAL; |
766 | goto end; | |
07dfc1d0 | 767 | case REG_STRING: |
80c2a69a | 768 | insn->op = BYTECODE_OP_GE_STRING; |
07dfc1d0 MD |
769 | break; |
770 | case REG_S64: | |
771 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 772 | insn->op = BYTECODE_OP_GE_S64; |
07dfc1d0 | 773 | else |
80c2a69a | 774 | insn->op = BYTECODE_OP_GE_DOUBLE_S64; |
07dfc1d0 MD |
775 | break; |
776 | case REG_DOUBLE: | |
777 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 778 | insn->op = BYTECODE_OP_GE_S64_DOUBLE; |
07dfc1d0 | 779 | else |
80c2a69a | 780 | insn->op = BYTECODE_OP_GE_DOUBLE; |
07dfc1d0 MD |
781 | break; |
782 | } | |
783 | /* Pop 2, push 1 */ | |
784 | if (vstack_pop(stack)) { | |
785 | ret = -EINVAL; | |
786 | goto end; | |
787 | } | |
788 | vstack_ax(stack)->type = REG_S64; | |
789 | next_pc += sizeof(struct binary_op); | |
790 | break; | |
791 | } | |
80c2a69a | 792 | case BYTECODE_OP_LE: |
07dfc1d0 MD |
793 | { |
794 | struct binary_op *insn = (struct binary_op *) pc; | |
795 | ||
796 | switch(vstack_ax(stack)->type) { | |
797 | default: | |
80c2a69a | 798 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
799 | ret = -EINVAL; |
800 | goto end; | |
801 | ||
02aca193 | 802 | case REG_STAR_GLOB_STRING: |
80c2a69a | 803 | printk(KERN_WARNING "LTTng: bytecode: invalid register type for '<=' binary operator\n"); |
02aca193 PP |
804 | ret = -EINVAL; |
805 | goto end; | |
07dfc1d0 | 806 | case REG_STRING: |
80c2a69a | 807 | insn->op = BYTECODE_OP_LE_STRING; |
07dfc1d0 MD |
808 | break; |
809 | case REG_S64: | |
810 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 811 | insn->op = BYTECODE_OP_LE_S64; |
07dfc1d0 | 812 | else |
80c2a69a | 813 | insn->op = BYTECODE_OP_LE_DOUBLE_S64; |
07dfc1d0 MD |
814 | break; |
815 | case REG_DOUBLE: | |
816 | if (vstack_bx(stack)->type == REG_S64) | |
80c2a69a | 817 | insn->op = BYTECODE_OP_LE_S64_DOUBLE; |
07dfc1d0 | 818 | else |
80c2a69a | 819 | insn->op = BYTECODE_OP_LE_DOUBLE; |
07dfc1d0 MD |
820 | break; |
821 | } | |
822 | vstack_ax(stack)->type = REG_S64; | |
823 | next_pc += sizeof(struct binary_op); | |
824 | break; | |
825 | } | |
826 | ||
80c2a69a FD |
827 | case BYTECODE_OP_EQ_STRING: |
828 | case BYTECODE_OP_NE_STRING: | |
829 | case BYTECODE_OP_GT_STRING: | |
830 | case BYTECODE_OP_LT_STRING: | |
831 | case BYTECODE_OP_GE_STRING: | |
832 | case BYTECODE_OP_LE_STRING: | |
833 | case BYTECODE_OP_EQ_STAR_GLOB_STRING: | |
834 | case BYTECODE_OP_NE_STAR_GLOB_STRING: | |
835 | case BYTECODE_OP_EQ_S64: | |
836 | case BYTECODE_OP_NE_S64: | |
837 | case BYTECODE_OP_GT_S64: | |
838 | case BYTECODE_OP_LT_S64: | |
839 | case BYTECODE_OP_GE_S64: | |
840 | case BYTECODE_OP_LE_S64: | |
841 | case BYTECODE_OP_EQ_DOUBLE: | |
842 | case BYTECODE_OP_NE_DOUBLE: | |
843 | case BYTECODE_OP_GT_DOUBLE: | |
844 | case BYTECODE_OP_LT_DOUBLE: | |
845 | case BYTECODE_OP_GE_DOUBLE: | |
846 | case BYTECODE_OP_LE_DOUBLE: | |
847 | case BYTECODE_OP_EQ_DOUBLE_S64: | |
848 | case BYTECODE_OP_NE_DOUBLE_S64: | |
849 | case BYTECODE_OP_GT_DOUBLE_S64: | |
850 | case BYTECODE_OP_LT_DOUBLE_S64: | |
851 | case BYTECODE_OP_GE_DOUBLE_S64: | |
852 | case BYTECODE_OP_LE_DOUBLE_S64: | |
853 | case BYTECODE_OP_EQ_S64_DOUBLE: | |
854 | case BYTECODE_OP_NE_S64_DOUBLE: | |
855 | case BYTECODE_OP_GT_S64_DOUBLE: | |
856 | case BYTECODE_OP_LT_S64_DOUBLE: | |
857 | case BYTECODE_OP_GE_S64_DOUBLE: | |
858 | case BYTECODE_OP_LE_S64_DOUBLE: | |
859 | case BYTECODE_OP_BIT_RSHIFT: | |
860 | case BYTECODE_OP_BIT_LSHIFT: | |
861 | case BYTECODE_OP_BIT_AND: | |
862 | case BYTECODE_OP_BIT_OR: | |
863 | case BYTECODE_OP_BIT_XOR: | |
07dfc1d0 MD |
864 | { |
865 | /* Pop 2, push 1 */ | |
866 | if (vstack_pop(stack)) { | |
867 | ret = -EINVAL; | |
868 | goto end; | |
869 | } | |
870 | vstack_ax(stack)->type = REG_S64; | |
871 | next_pc += sizeof(struct binary_op); | |
872 | break; | |
873 | } | |
874 | ||
875 | /* unary */ | |
80c2a69a | 876 | case BYTECODE_OP_UNARY_PLUS: |
07dfc1d0 MD |
877 | { |
878 | struct unary_op *insn = (struct unary_op *) pc; | |
879 | ||
880 | switch(vstack_ax(stack)->type) { | |
881 | default: | |
80c2a69a | 882 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
883 | ret = -EINVAL; |
884 | goto end; | |
885 | ||
886 | case REG_S64: | |
80c2a69a | 887 | insn->op = BYTECODE_OP_UNARY_PLUS_S64; |
07dfc1d0 MD |
888 | break; |
889 | case REG_DOUBLE: | |
80c2a69a | 890 | insn->op = BYTECODE_OP_UNARY_PLUS_DOUBLE; |
07dfc1d0 MD |
891 | break; |
892 | } | |
893 | /* Pop 1, push 1 */ | |
894 | next_pc += sizeof(struct unary_op); | |
895 | break; | |
896 | } | |
897 | ||
80c2a69a | 898 | case BYTECODE_OP_UNARY_MINUS: |
07dfc1d0 MD |
899 | { |
900 | struct unary_op *insn = (struct unary_op *) pc; | |
901 | ||
902 | switch(vstack_ax(stack)->type) { | |
903 | default: | |
80c2a69a | 904 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
905 | ret = -EINVAL; |
906 | goto end; | |
907 | ||
908 | case REG_S64: | |
80c2a69a | 909 | insn->op = BYTECODE_OP_UNARY_MINUS_S64; |
07dfc1d0 MD |
910 | break; |
911 | case REG_DOUBLE: | |
80c2a69a | 912 | insn->op = BYTECODE_OP_UNARY_MINUS_DOUBLE; |
07dfc1d0 MD |
913 | break; |
914 | } | |
915 | /* Pop 1, push 1 */ | |
916 | next_pc += sizeof(struct unary_op); | |
917 | break; | |
918 | } | |
919 | ||
80c2a69a | 920 | case BYTECODE_OP_UNARY_NOT: |
07dfc1d0 MD |
921 | { |
922 | struct unary_op *insn = (struct unary_op *) pc; | |
923 | ||
924 | switch(vstack_ax(stack)->type) { | |
925 | default: | |
80c2a69a | 926 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
927 | ret = -EINVAL; |
928 | goto end; | |
929 | ||
930 | case REG_S64: | |
80c2a69a | 931 | insn->op = BYTECODE_OP_UNARY_NOT_S64; |
07dfc1d0 MD |
932 | break; |
933 | case REG_DOUBLE: | |
80c2a69a | 934 | insn->op = BYTECODE_OP_UNARY_NOT_DOUBLE; |
07dfc1d0 MD |
935 | break; |
936 | } | |
937 | /* Pop 1, push 1 */ | |
938 | next_pc += sizeof(struct unary_op); | |
939 | break; | |
940 | } | |
941 | ||
80c2a69a | 942 | case BYTECODE_OP_UNARY_BIT_NOT: |
e16c054b MD |
943 | { |
944 | /* Pop 1, push 1 */ | |
945 | next_pc += sizeof(struct unary_op); | |
946 | break; | |
947 | } | |
948 | ||
80c2a69a FD |
949 | case BYTECODE_OP_UNARY_PLUS_S64: |
950 | case BYTECODE_OP_UNARY_MINUS_S64: | |
951 | case BYTECODE_OP_UNARY_NOT_S64: | |
952 | case BYTECODE_OP_UNARY_PLUS_DOUBLE: | |
953 | case BYTECODE_OP_UNARY_MINUS_DOUBLE: | |
954 | case BYTECODE_OP_UNARY_NOT_DOUBLE: | |
07dfc1d0 MD |
955 | { |
956 | /* Pop 1, push 1 */ | |
957 | next_pc += sizeof(struct unary_op); | |
958 | break; | |
959 | } | |
960 | ||
961 | /* logical */ | |
80c2a69a FD |
962 | case BYTECODE_OP_AND: |
963 | case BYTECODE_OP_OR: | |
07dfc1d0 MD |
964 | { |
965 | /* Continue to next instruction */ | |
966 | /* Pop 1 when jump not taken */ | |
967 | if (vstack_pop(stack)) { | |
968 | ret = -EINVAL; | |
969 | goto end; | |
970 | } | |
971 | next_pc += sizeof(struct logical_op); | |
972 | break; | |
973 | } | |
974 | ||
975 | /* load field ref */ | |
80c2a69a | 976 | case BYTECODE_OP_LOAD_FIELD_REF: |
07dfc1d0 | 977 | { |
80c2a69a | 978 | printk(KERN_WARNING "LTTng: bytecode: Unknown field ref type\n"); |
07dfc1d0 MD |
979 | ret = -EINVAL; |
980 | goto end; | |
981 | } | |
982 | /* get context ref */ | |
80c2a69a | 983 | case BYTECODE_OP_GET_CONTEXT_REF: |
07dfc1d0 | 984 | { |
80c2a69a | 985 | printk(KERN_WARNING "LTTng: bytecode: Unknown get context ref type\n"); |
07dfc1d0 MD |
986 | ret = -EINVAL; |
987 | goto end; | |
988 | } | |
80c2a69a FD |
989 | case BYTECODE_OP_LOAD_FIELD_REF_STRING: |
990 | case BYTECODE_OP_LOAD_FIELD_REF_SEQUENCE: | |
991 | case BYTECODE_OP_GET_CONTEXT_REF_STRING: | |
992 | case BYTECODE_OP_LOAD_FIELD_REF_USER_STRING: | |
993 | case BYTECODE_OP_LOAD_FIELD_REF_USER_SEQUENCE: | |
07dfc1d0 MD |
994 | { |
995 | if (vstack_push(stack)) { | |
996 | ret = -EINVAL; | |
997 | goto end; | |
998 | } | |
999 | vstack_ax(stack)->type = REG_STRING; | |
1000 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); | |
1001 | break; | |
1002 | } | |
80c2a69a FD |
1003 | case BYTECODE_OP_LOAD_FIELD_REF_S64: |
1004 | case BYTECODE_OP_GET_CONTEXT_REF_S64: | |
07dfc1d0 MD |
1005 | { |
1006 | if (vstack_push(stack)) { | |
1007 | ret = -EINVAL; | |
1008 | goto end; | |
1009 | } | |
1010 | vstack_ax(stack)->type = REG_S64; | |
1011 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); | |
1012 | break; | |
1013 | } | |
80c2a69a FD |
1014 | case BYTECODE_OP_LOAD_FIELD_REF_DOUBLE: |
1015 | case BYTECODE_OP_GET_CONTEXT_REF_DOUBLE: | |
07dfc1d0 MD |
1016 | { |
1017 | if (vstack_push(stack)) { | |
1018 | ret = -EINVAL; | |
1019 | goto end; | |
1020 | } | |
1021 | vstack_ax(stack)->type = REG_DOUBLE; | |
1022 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); | |
1023 | break; | |
1024 | } | |
1025 | ||
1026 | /* load from immediate operand */ | |
80c2a69a | 1027 | case BYTECODE_OP_LOAD_STRING: |
07dfc1d0 MD |
1028 | { |
1029 | struct load_op *insn = (struct load_op *) pc; | |
1030 | ||
1031 | if (vstack_push(stack)) { | |
1032 | ret = -EINVAL; | |
1033 | goto end; | |
1034 | } | |
1035 | vstack_ax(stack)->type = REG_STRING; | |
1036 | next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; | |
1037 | break; | |
1038 | } | |
1039 | ||
80c2a69a | 1040 | case BYTECODE_OP_LOAD_STAR_GLOB_STRING: |
02aca193 PP |
1041 | { |
1042 | struct load_op *insn = (struct load_op *) pc; | |
1043 | ||
1044 | if (vstack_push(stack)) { | |
1045 | ret = -EINVAL; | |
1046 | goto end; | |
1047 | } | |
1048 | vstack_ax(stack)->type = REG_STAR_GLOB_STRING; | |
1049 | next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; | |
1050 | break; | |
1051 | } | |
1052 | ||
80c2a69a | 1053 | case BYTECODE_OP_LOAD_S64: |
07dfc1d0 MD |
1054 | { |
1055 | if (vstack_push(stack)) { | |
1056 | ret = -EINVAL; | |
1057 | goto end; | |
1058 | } | |
1059 | vstack_ax(stack)->type = REG_S64; | |
1060 | next_pc += sizeof(struct load_op) | |
1061 | + sizeof(struct literal_numeric); | |
1062 | break; | |
1063 | } | |
1064 | ||
80c2a69a | 1065 | case BYTECODE_OP_LOAD_DOUBLE: |
07dfc1d0 MD |
1066 | { |
1067 | if (vstack_push(stack)) { | |
1068 | ret = -EINVAL; | |
1069 | goto end; | |
1070 | } | |
1071 | vstack_ax(stack)->type = REG_DOUBLE; | |
1072 | next_pc += sizeof(struct load_op) | |
1073 | + sizeof(struct literal_double); | |
1074 | break; | |
1075 | } | |
1076 | ||
1077 | /* cast */ | |
80c2a69a | 1078 | case BYTECODE_OP_CAST_TO_S64: |
07dfc1d0 MD |
1079 | { |
1080 | struct cast_op *insn = (struct cast_op *) pc; | |
1081 | ||
1082 | switch (vstack_ax(stack)->type) { | |
1083 | default: | |
80c2a69a | 1084 | printk(KERN_WARNING "LTTng: bytecode: unknown register type\n"); |
07dfc1d0 MD |
1085 | ret = -EINVAL; |
1086 | goto end; | |
1087 | ||
1088 | case REG_STRING: | |
02aca193 | 1089 | case REG_STAR_GLOB_STRING: |
80c2a69a | 1090 | printk(KERN_WARNING "LTTng: bytecode: Cast op can only be applied to numeric or floating point registers\n"); |
07dfc1d0 MD |
1091 | ret = -EINVAL; |
1092 | goto end; | |
1093 | case REG_S64: | |
80c2a69a | 1094 | insn->op = BYTECODE_OP_CAST_NOP; |
07dfc1d0 MD |
1095 | break; |
1096 | case REG_DOUBLE: | |
80c2a69a | 1097 | insn->op = BYTECODE_OP_CAST_DOUBLE_TO_S64; |
07dfc1d0 MD |
1098 | break; |
1099 | } | |
1100 | /* Pop 1, push 1 */ | |
1101 | vstack_ax(stack)->type = REG_S64; | |
1102 | next_pc += sizeof(struct cast_op); | |
1103 | break; | |
1104 | } | |
80c2a69a | 1105 | case BYTECODE_OP_CAST_DOUBLE_TO_S64: |
07dfc1d0 MD |
1106 | { |
1107 | /* Pop 1, push 1 */ | |
1108 | vstack_ax(stack)->type = REG_S64; | |
1109 | next_pc += sizeof(struct cast_op); | |
1110 | break; | |
1111 | } | |
80c2a69a | 1112 | case BYTECODE_OP_CAST_NOP: |
07dfc1d0 MD |
1113 | { |
1114 | next_pc += sizeof(struct cast_op); | |
1115 | break; | |
1116 | } | |
1117 | ||
3834b99f MD |
1118 | /* |
1119 | * Instructions for recursive traversal through composed types. | |
1120 | */ | |
80c2a69a | 1121 | case BYTECODE_OP_GET_CONTEXT_ROOT: |
3834b99f MD |
1122 | { |
1123 | if (vstack_push(stack)) { | |
1124 | ret = -EINVAL; | |
1125 | goto end; | |
1126 | } | |
1127 | vstack_ax(stack)->type = REG_PTR; | |
1128 | vstack_ax(stack)->load.type = LOAD_ROOT_CONTEXT; | |
1129 | next_pc += sizeof(struct load_op); | |
1130 | break; | |
1131 | } | |
80c2a69a | 1132 | case BYTECODE_OP_GET_APP_CONTEXT_ROOT: |
3834b99f MD |
1133 | { |
1134 | if (vstack_push(stack)) { | |
1135 | ret = -EINVAL; | |
1136 | goto end; | |
1137 | } | |
1138 | vstack_ax(stack)->type = REG_PTR; | |
1139 | vstack_ax(stack)->load.type = LOAD_ROOT_APP_CONTEXT; | |
1140 | next_pc += sizeof(struct load_op); | |
1141 | break; | |
1142 | } | |
80c2a69a | 1143 | case BYTECODE_OP_GET_PAYLOAD_ROOT: |
3834b99f MD |
1144 | { |
1145 | if (vstack_push(stack)) { | |
1146 | ret = -EINVAL; | |
1147 | goto end; | |
1148 | } | |
1149 | vstack_ax(stack)->type = REG_PTR; | |
1150 | vstack_ax(stack)->load.type = LOAD_ROOT_PAYLOAD; | |
1151 | next_pc += sizeof(struct load_op); | |
1152 | break; | |
1153 | } | |
1154 | ||
80c2a69a | 1155 | case BYTECODE_OP_LOAD_FIELD: |
3834b99f MD |
1156 | { |
1157 | struct load_op *insn = (struct load_op *) pc; | |
1158 | ||
1159 | WARN_ON_ONCE(vstack_ax(stack)->type != REG_PTR); | |
1160 | /* Pop 1, push 1 */ | |
1161 | ret = specialize_load_field(vstack_ax(stack), insn); | |
1162 | if (ret) | |
1163 | goto end; | |
1164 | ||
1165 | next_pc += sizeof(struct load_op); | |
1166 | break; | |
1167 | } | |
1168 | ||
80c2a69a FD |
1169 | case BYTECODE_OP_LOAD_FIELD_S8: |
1170 | case BYTECODE_OP_LOAD_FIELD_S16: | |
1171 | case BYTECODE_OP_LOAD_FIELD_S32: | |
1172 | case BYTECODE_OP_LOAD_FIELD_S64: | |
1173 | case BYTECODE_OP_LOAD_FIELD_U8: | |
1174 | case BYTECODE_OP_LOAD_FIELD_U16: | |
1175 | case BYTECODE_OP_LOAD_FIELD_U32: | |
1176 | case BYTECODE_OP_LOAD_FIELD_U64: | |
3834b99f MD |
1177 | { |
1178 | /* Pop 1, push 1 */ | |
1179 | vstack_ax(stack)->type = REG_S64; | |
1180 | next_pc += sizeof(struct load_op); | |
1181 | break; | |
1182 | } | |
1183 | ||
80c2a69a FD |
1184 | case BYTECODE_OP_LOAD_FIELD_STRING: |
1185 | case BYTECODE_OP_LOAD_FIELD_SEQUENCE: | |
3834b99f MD |
1186 | { |
1187 | /* Pop 1, push 1 */ | |
1188 | vstack_ax(stack)->type = REG_STRING; | |
1189 | next_pc += sizeof(struct load_op); | |
1190 | break; | |
1191 | } | |
1192 | ||
80c2a69a | 1193 | case BYTECODE_OP_LOAD_FIELD_DOUBLE: |
3834b99f MD |
1194 | { |
1195 | /* Pop 1, push 1 */ | |
1196 | vstack_ax(stack)->type = REG_DOUBLE; | |
1197 | next_pc += sizeof(struct load_op); | |
1198 | break; | |
1199 | } | |
1200 | ||
80c2a69a | 1201 | case BYTECODE_OP_GET_SYMBOL: |
3834b99f MD |
1202 | { |
1203 | struct load_op *insn = (struct load_op *) pc; | |
1204 | ||
1205 | dbg_printk("op get symbol\n"); | |
1206 | switch (vstack_ax(stack)->load.type) { | |
1207 | case LOAD_OBJECT: | |
80c2a69a | 1208 | printk(KERN_WARNING "LTTng: bytecode: Nested fields not implemented yet.\n"); |
3834b99f MD |
1209 | ret = -EINVAL; |
1210 | goto end; | |
1211 | case LOAD_ROOT_CONTEXT: | |
1212 | /* Lookup context field. */ | |
2dfda770 | 1213 | ret = specialize_context_lookup(ctx, bytecode, insn, |
3834b99f MD |
1214 | &vstack_ax(stack)->load); |
1215 | if (ret) | |
1216 | goto end; | |
1217 | break; | |
1218 | case LOAD_ROOT_APP_CONTEXT: | |
1219 | ret = -EINVAL; | |
1220 | goto end; | |
1221 | case LOAD_ROOT_PAYLOAD: | |
1222 | /* Lookup event payload field. */ | |
2dfda770 | 1223 | ret = specialize_payload_lookup(event_desc, |
3834b99f MD |
1224 | bytecode, insn, |
1225 | &vstack_ax(stack)->load); | |
1226 | if (ret) | |
1227 | goto end; | |
1228 | break; | |
1229 | } | |
1230 | next_pc += sizeof(struct load_op) + sizeof(struct get_symbol); | |
1231 | break; | |
1232 | } | |
1233 | ||
80c2a69a | 1234 | case BYTECODE_OP_GET_SYMBOL_FIELD: |
3834b99f MD |
1235 | { |
1236 | /* Always generated by specialize phase. */ | |
1237 | ret = -EINVAL; | |
1238 | goto end; | |
1239 | } | |
1240 | ||
80c2a69a | 1241 | case BYTECODE_OP_GET_INDEX_U16: |
3834b99f MD |
1242 | { |
1243 | struct load_op *insn = (struct load_op *) pc; | |
1244 | struct get_index_u16 *index = (struct get_index_u16 *) insn->data; | |
1245 | ||
1246 | dbg_printk("op get index u16\n"); | |
1247 | /* Pop 1, push 1 */ | |
1248 | ret = specialize_get_index(bytecode, insn, index->index, | |
1249 | vstack_ax(stack), sizeof(*index)); | |
1250 | if (ret) | |
1251 | goto end; | |
1252 | next_pc += sizeof(struct load_op) + sizeof(struct get_index_u16); | |
1253 | break; | |
1254 | } | |
1255 | ||
80c2a69a | 1256 | case BYTECODE_OP_GET_INDEX_U64: |
3834b99f MD |
1257 | { |
1258 | struct load_op *insn = (struct load_op *) pc; | |
1259 | struct get_index_u64 *index = (struct get_index_u64 *) insn->data; | |
1260 | ||
1261 | dbg_printk("op get index u64\n"); | |
1262 | /* Pop 1, push 1 */ | |
1263 | ret = specialize_get_index(bytecode, insn, index->index, | |
1264 | vstack_ax(stack), sizeof(*index)); | |
1265 | if (ret) | |
1266 | goto end; | |
1267 | next_pc += sizeof(struct load_op) + sizeof(struct get_index_u64); | |
1268 | break; | |
1269 | } | |
1270 | ||
07dfc1d0 MD |
1271 | } |
1272 | } | |
1273 | end: | |
1274 | return ret; | |
1275 | } |