Commit | Line | Data |
---|---|---|
748b5f7b SM |
1 | /* |
2 | * Copyright 2020 EfficiOS, Inc. | |
3 | * | |
4 | * SPDX-License-Identifier: LGPL-2.1-only | |
5 | * | |
6 | */ | |
7 | ||
8 | #include "event-expr-to-bytecode.h" | |
9 | ||
10 | #include <stdio.h> | |
11 | #include <lttng/event-expr.h> | |
12 | #include <common/bytecode/bytecode.h> | |
13 | #include <common/error.h> | |
14 | ||
15 | static | |
16 | int event_expr_to_bytecode_recursive(const struct lttng_event_expr *expr, | |
17 | struct lttng_bytecode_alloc **bytecode, | |
18 | struct lttng_bytecode_alloc **bytecode_reloc) | |
19 | { | |
20 | int status; | |
21 | enum lttng_event_expr_status event_expr_status; | |
22 | ||
23 | switch (lttng_event_expr_get_type(expr)) { | |
24 | case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: | |
25 | { | |
26 | const char *name; | |
27 | ||
28 | status = bytecode_push_get_payload_root(bytecode); | |
29 | if (status) { | |
30 | ERR("Failed to get payload root from bytecode"); | |
31 | goto end; | |
32 | } | |
33 | ||
34 | name = lttng_event_expr_event_payload_field_get_name(expr); | |
35 | if (!name) { | |
36 | ERR("Failed to get payload field name from event expression"); | |
37 | status = -1; | |
38 | goto end; | |
39 | } | |
40 | ||
41 | status = bytecode_push_get_symbol(bytecode, bytecode_reloc, name); | |
42 | if (status) { | |
43 | ERR("Failed to push 'get symbol %s' in bytecode", name); | |
44 | goto end; | |
45 | } | |
46 | ||
47 | break; | |
48 | } | |
49 | case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: | |
50 | { | |
51 | const char *name; | |
52 | ||
53 | status = bytecode_push_get_context_root(bytecode); | |
54 | if (status) { | |
55 | ERR("Failed to get context root from bytecode"); | |
56 | goto end; | |
57 | } | |
58 | ||
59 | name = lttng_event_expr_channel_context_field_get_name(expr); | |
60 | if (!name) { | |
61 | ERR("Failed to get channel context field name from event expression"); | |
62 | status = -1; | |
63 | goto end; | |
64 | } | |
65 | ||
66 | status = bytecode_push_get_symbol(bytecode, bytecode_reloc, name); | |
67 | if (status) { | |
68 | ERR("Failed to push 'get symbol %s' in bytecode", name); | |
69 | goto end; | |
70 | } | |
71 | ||
72 | break; | |
73 | } | |
74 | case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: | |
75 | { | |
76 | int ret; | |
77 | char *name = NULL; | |
78 | const char *provider_name, *type_name; | |
79 | ||
80 | status = bytecode_push_get_app_context_root(bytecode); | |
81 | if (status) { | |
82 | ERR("Failed to get application context root from bytecode"); | |
83 | goto end; | |
84 | } | |
85 | ||
86 | provider_name = lttng_event_expr_app_specific_context_field_get_provider_name( | |
87 | expr); | |
88 | if (!provider_name) { | |
89 | ERR("Failed to get application context provider name from event expression"); | |
90 | status = -1; | |
91 | goto end; | |
92 | } | |
93 | ||
94 | type_name = lttng_event_expr_app_specific_context_field_get_type_name( | |
95 | expr); | |
96 | if (!type_name) { | |
97 | ERR("Failed to get application context type name from event expression"); | |
98 | status = -1; | |
99 | goto end; | |
100 | } | |
101 | ||
102 | /* | |
103 | * Reconstitute the app context field name from its two parts. | |
104 | */ | |
105 | ret = asprintf(&name, "%s:%s", provider_name, type_name); | |
106 | if (ret < 0) { | |
107 | PERROR("Failed to format application specific context: provider_name = '%s', type_name = '%s'", | |
108 | provider_name, type_name); | |
109 | status = -1; | |
110 | goto end; | |
111 | } | |
112 | ||
113 | status = bytecode_push_get_symbol( | |
114 | bytecode, bytecode_reloc, name); | |
115 | free(name); | |
116 | if (status) { | |
a3088f1a JG |
117 | ERR("Failed to push 'get symbol %s:%s' in bytecode", |
118 | provider_name, type_name); | |
748b5f7b SM |
119 | goto end; |
120 | } | |
121 | ||
122 | break; | |
123 | } | |
124 | case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: | |
125 | { | |
126 | unsigned int index; | |
127 | const struct lttng_event_expr *parent; | |
128 | ||
129 | parent = lttng_event_expr_array_field_element_get_parent_expr( | |
130 | expr); | |
131 | if (!parent) { | |
132 | ERR("Failed to get parent expression from array event expression"); | |
133 | status = -1; | |
134 | goto end; | |
135 | } | |
136 | ||
137 | status = event_expr_to_bytecode_recursive( | |
138 | parent, bytecode, bytecode_reloc); | |
139 | if (status) { | |
140 | goto end; | |
141 | } | |
142 | ||
143 | event_expr_status = lttng_event_expr_array_field_element_get_index( | |
144 | expr, &index); | |
145 | if (event_expr_status != LTTNG_EVENT_EXPR_STATUS_OK) { | |
146 | ERR("Failed to get array field element index from event expression"); | |
147 | status = -1; | |
148 | goto end; | |
149 | } | |
150 | ||
151 | status = bytecode_push_get_index_u64(bytecode, index); | |
152 | if (status) { | |
153 | ERR("Failed to push 'get index %u' in bytecode", index); | |
154 | goto end; | |
155 | } | |
156 | ||
157 | break; | |
158 | } | |
159 | default: | |
160 | abort(); | |
161 | } | |
162 | ||
163 | status = 0; | |
164 | end: | |
165 | return status; | |
166 | } | |
167 | ||
168 | LTTNG_HIDDEN | |
169 | int lttng_event_expr_to_bytecode(const struct lttng_event_expr *expr, | |
170 | struct lttng_bytecode **bytecode_out) | |
171 | { | |
172 | int status; | |
173 | struct return_op ret_insn; | |
174 | struct lttng_bytecode_alloc *bytecode = NULL; | |
175 | struct lttng_bytecode_alloc *bytecode_reloc = NULL; | |
176 | ||
177 | status = bytecode_init(&bytecode); | |
178 | if (status) { | |
179 | ERR("Failed to initialize bytecode"); | |
180 | goto end; | |
181 | } | |
182 | ||
183 | status = bytecode_init(&bytecode_reloc); | |
184 | if (status) { | |
185 | ERR("Failed to initialize relocation bytecode"); | |
186 | goto end; | |
187 | } | |
188 | ||
189 | status = event_expr_to_bytecode_recursive( | |
190 | expr, &bytecode, &bytecode_reloc); | |
191 | if (status) { | |
192 | /* Errors already logged. */ | |
193 | goto end; | |
194 | } | |
195 | ||
196 | ret_insn.op = BYTECODE_OP_RETURN; | |
197 | bytecode_push(&bytecode, &ret_insn, 1, sizeof(ret_insn)); | |
198 | ||
199 | /* Append symbol table to bytecode. */ | |
200 | bytecode->b.reloc_table_offset = bytecode_get_len(&bytecode->b); | |
201 | status = bytecode_push(&bytecode, bytecode_reloc->b.data, 1, | |
202 | bytecode_get_len(&bytecode_reloc->b)); | |
203 | if (status) { | |
204 | ERR("Failed to push symbol table to bytecode"); | |
205 | goto end; | |
206 | } | |
207 | ||
208 | /* Copy the `lttng_bytecode` out of the `lttng_bytecode_alloc`. */ | |
209 | *bytecode_out = lttng_bytecode_copy(&bytecode->b); | |
210 | if (!*bytecode_out) { | |
211 | status = -1; | |
212 | goto end; | |
213 | } | |
214 | ||
215 | end: | |
216 | if (bytecode) { | |
217 | free(bytecode); | |
218 | } | |
219 | ||
220 | if (bytecode_reloc) { | |
221 | free(bytecode_reloc); | |
222 | } | |
223 | ||
224 | return status; | |
225 | } |