Filter: split passes into separate components
[lttng-ust.git] / liblttng-ust / lttng-filter.c
1 /*
2 * lttng-filter.c
3 *
4 * LTTng UST filter code.
5 *
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include "lttng-filter.h"
24
25 static const char *opnames[] = {
26 [ FILTER_OP_UNKNOWN ] = "UNKNOWN",
27
28 [ FILTER_OP_RETURN ] = "RETURN",
29
30 /* binary */
31 [ FILTER_OP_MUL ] = "MUL",
32 [ FILTER_OP_DIV ] = "DIV",
33 [ FILTER_OP_MOD ] = "MOD",
34 [ FILTER_OP_PLUS ] = "PLUS",
35 [ FILTER_OP_MINUS ] = "MINUS",
36 [ FILTER_OP_RSHIFT ] = "RSHIFT",
37 [ FILTER_OP_LSHIFT ] = "LSHIFT",
38 [ FILTER_OP_BIN_AND ] = "BIN_AND",
39 [ FILTER_OP_BIN_OR ] = "BIN_OR",
40 [ FILTER_OP_BIN_XOR ] = "BIN_XOR",
41
42 /* binary comparators */
43 [ FILTER_OP_EQ ] = "EQ",
44 [ FILTER_OP_NE ] = "NE",
45 [ FILTER_OP_GT ] = "GT",
46 [ FILTER_OP_LT ] = "LT",
47 [ FILTER_OP_GE ] = "GE",
48 [ FILTER_OP_LE ] = "LE",
49
50 /* string binary comparators */
51 [ FILTER_OP_EQ_STRING ] = "EQ_STRING",
52 [ FILTER_OP_NE_STRING ] = "NE_STRING",
53 [ FILTER_OP_GT_STRING ] = "GT_STRING",
54 [ FILTER_OP_LT_STRING ] = "LT_STRING",
55 [ FILTER_OP_GE_STRING ] = "GE_STRING",
56 [ FILTER_OP_LE_STRING ] = "LE_STRING",
57
58 /* s64 binary comparators */
59 [ FILTER_OP_EQ_S64 ] = "EQ_S64",
60 [ FILTER_OP_NE_S64 ] = "NE_S64",
61 [ FILTER_OP_GT_S64 ] = "GT_S64",
62 [ FILTER_OP_LT_S64 ] = "LT_S64",
63 [ FILTER_OP_GE_S64 ] = "GE_S64",
64 [ FILTER_OP_LE_S64 ] = "LE_S64",
65
66 /* double binary comparators */
67 [ FILTER_OP_EQ_DOUBLE ] = "EQ_DOUBLE",
68 [ FILTER_OP_NE_DOUBLE ] = "NE_DOUBLE",
69 [ FILTER_OP_GT_DOUBLE ] = "GT_DOUBLE",
70 [ FILTER_OP_LT_DOUBLE ] = "LT_DOUBLE",
71 [ FILTER_OP_GE_DOUBLE ] = "GE_DOUBLE",
72 [ FILTER_OP_LE_DOUBLE ] = "LE_DOUBLE",
73
74
75 /* unary */
76 [ FILTER_OP_UNARY_PLUS ] = "UNARY_PLUS",
77 [ FILTER_OP_UNARY_MINUS ] = "UNARY_MINUS",
78 [ FILTER_OP_UNARY_NOT ] = "UNARY_NOT",
79 [ FILTER_OP_UNARY_PLUS_S64 ] = "UNARY_PLUS_S64",
80 [ FILTER_OP_UNARY_MINUS_S64 ] = "UNARY_MINUS_S64",
81 [ FILTER_OP_UNARY_NOT_S64 ] = "UNARY_NOT_S64",
82 [ FILTER_OP_UNARY_PLUS_DOUBLE ] = "UNARY_PLUS_DOUBLE",
83 [ FILTER_OP_UNARY_MINUS_DOUBLE ] = "UNARY_MINUS_DOUBLE",
84 [ FILTER_OP_UNARY_NOT_DOUBLE ] = "UNARY_NOT_DOUBLE",
85
86 /* logical */
87 [ FILTER_OP_AND ] = "AND",
88 [ FILTER_OP_OR ] = "OR",
89
90 /* load */
91 [ FILTER_OP_LOAD_FIELD_REF ] = "LOAD_FIELD_REF",
92 [ FILTER_OP_LOAD_FIELD_REF_STRING ] = "LOAD_FIELD_REF_STRING",
93 [ FILTER_OP_LOAD_FIELD_REF_SEQUENCE ] = "LOAD_FIELD_REF_SEQUENCE",
94 [ FILTER_OP_LOAD_FIELD_REF_S64 ] = "LOAD_FIELD_REF_S64",
95 [ FILTER_OP_LOAD_FIELD_REF_DOUBLE ] = "LOAD_FIELD_REF_DOUBLE",
96
97 [ FILTER_OP_LOAD_STRING ] = "LOAD_STRING",
98 [ FILTER_OP_LOAD_S64 ] = "LOAD_S64",
99 [ FILTER_OP_LOAD_DOUBLE ] = "LOAD_DOUBLE",
100
101 /* cast */
102 [ FILTER_OP_CAST_TO_S64 ] = "CAST_TO_S64",
103 [ FILTER_OP_CAST_DOUBLE_TO_S64 ] = "CAST_DOUBLE_TO_S64",
104 [ FILTER_OP_CAST_NOP ] = "CAST_NOP",
105 };
106
107 const char *print_op(enum filter_op op)
108 {
109 if (op >= NR_FILTER_OPS)
110 return "UNKNOWN";
111 else
112 return opnames[op];
113 }
114
115 static
116 int apply_field_reloc(struct ltt_event *event,
117 struct bytecode_runtime *runtime,
118 uint32_t runtime_len,
119 uint32_t reloc_offset,
120 const char *field_name)
121 {
122 const struct lttng_event_desc *desc;
123 const struct lttng_event_field *fields, *field = NULL;
124 unsigned int nr_fields, i;
125 struct field_ref *field_ref;
126 struct load_op *op;
127 uint32_t field_offset = 0;
128
129 dbg_printf("Apply reloc: %u %s\n", reloc_offset, field_name);
130
131 /* Ensure that the reloc is within the code */
132 if (runtime_len - reloc_offset < sizeof(uint16_t))
133 return -EINVAL;
134
135 /* Lookup event by name */
136 desc = event->desc;
137 if (!desc)
138 return -EINVAL;
139 fields = desc->fields;
140 if (!fields)
141 return -EINVAL;
142 nr_fields = desc->nr_fields;
143 for (i = 0; i < nr_fields; i++) {
144 if (!strcmp(fields[i].name, field_name)) {
145 field = &fields[i];
146 break;
147 }
148 /* compute field offset */
149 switch (fields[i].type.atype) {
150 case atype_integer:
151 case atype_enum:
152 field_offset += sizeof(int64_t);
153 break;
154 case atype_array:
155 case atype_sequence:
156 field_offset += sizeof(unsigned long);
157 field_offset += sizeof(void *);
158 break;
159 case atype_string:
160 field_offset += sizeof(void *);
161 break;
162 case atype_float:
163 field_offset += sizeof(double);
164 break;
165 default:
166 return -EINVAL;
167 }
168 }
169 if (!field)
170 return -EINVAL;
171
172 /* Check if field offset is too large for 16-bit offset */
173 if (field_offset > FILTER_BYTECODE_MAX_LEN)
174 return -EINVAL;
175
176 /* set type */
177 op = (struct load_op *) &runtime->data[reloc_offset];
178 field_ref = (struct field_ref *) op->data;
179 switch (field->type.atype) {
180 case atype_integer:
181 case atype_enum:
182 op->op = FILTER_OP_LOAD_FIELD_REF_S64;
183 break;
184 case atype_array:
185 case atype_sequence:
186 op->op = FILTER_OP_LOAD_FIELD_REF_SEQUENCE;
187 break;
188 case atype_string:
189 op->op = FILTER_OP_LOAD_FIELD_REF_STRING;
190 break;
191 case atype_float:
192 op->op = FILTER_OP_LOAD_FIELD_REF_DOUBLE;
193 break;
194 default:
195 return -EINVAL;
196 }
197 /* set offset */
198 field_ref->offset = (uint16_t) field_offset;
199 return 0;
200 }
201
202 /*
203 * Take a bytecode with reloc table and link it to an event to create a
204 * bytecode runtime.
205 */
206 static
207 int _lttng_filter_event_link_bytecode(struct ltt_event *event,
208 struct lttng_ust_filter_bytecode *filter_bytecode)
209 {
210 int ret, offset, next_offset;
211 struct bytecode_runtime *runtime = NULL;
212 size_t runtime_alloc_len;
213
214 if (!filter_bytecode)
215 return 0;
216 /* Even is not connected to any description */
217 if (!event->desc)
218 return 0;
219 /* Bytecode already linked */
220 if (event->filter || event->filter_data)
221 return 0;
222
223 dbg_printf("Linking\n");
224
225 /* We don't need the reloc table in the runtime */
226 runtime_alloc_len = sizeof(*runtime) + filter_bytecode->reloc_offset;
227 runtime = zmalloc(runtime_alloc_len);
228 if (!runtime) {
229 ret = -ENOMEM;
230 goto link_error;
231 }
232 runtime->len = filter_bytecode->reloc_offset;
233 /* copy original bytecode */
234 memcpy(runtime->data, filter_bytecode->data, runtime->len);
235 /*
236 * apply relocs. Those are a uint16_t (offset in bytecode)
237 * followed by a string (field name).
238 */
239 for (offset = filter_bytecode->reloc_offset;
240 offset < filter_bytecode->len;
241 offset = next_offset) {
242 uint16_t reloc_offset =
243 *(uint16_t *) &filter_bytecode->data[offset];
244 const char *field_name =
245 (const char *) &filter_bytecode->data[offset + sizeof(uint16_t)];
246
247 ret = apply_field_reloc(event, runtime, runtime->len, reloc_offset, field_name);
248 if (ret) {
249 goto link_error;
250 }
251 next_offset = offset + sizeof(uint16_t) + strlen(field_name) + 1;
252 }
253 /* Validate bytecode */
254 ret = lttng_filter_validate_bytecode(runtime);
255 if (ret) {
256 goto link_error;
257 }
258 /* Specialize bytecode */
259 ret = lttng_filter_specialize_bytecode(runtime);
260 if (ret) {
261 goto link_error;
262 }
263 event->filter_data = runtime;
264 event->filter = lttng_filter_interpret_bytecode;
265 return 0;
266
267 link_error:
268 event->filter = lttng_filter_false;
269 free(runtime);
270 return ret;
271 }
272
273 void lttng_filter_event_link_bytecode(struct ltt_event *event,
274 struct lttng_ust_filter_bytecode *filter_bytecode)
275 {
276 int ret;
277
278 ret = _lttng_filter_event_link_bytecode(event, filter_bytecode);
279 if (ret) {
280 fprintf(stderr, "[lttng filter] error linking event bytecode\n");
281 }
282 }
283
284 /*
285 * Link bytecode to all events for a wildcard. Skips events that already
286 * have a bytecode linked.
287 * We do not set each event's filter_bytecode field, because they do not
288 * own the filter_bytecode: the wildcard owns it.
289 */
290 void lttng_filter_wildcard_link_bytecode(struct session_wildcard *wildcard)
291 {
292 struct ltt_event *event;
293 int ret;
294
295 if (!wildcard->filter_bytecode)
296 return;
297
298 cds_list_for_each_entry(event, &wildcard->events, wildcard_list) {
299 if (event->filter)
300 continue;
301 ret = _lttng_filter_event_link_bytecode(event,
302 wildcard->filter_bytecode);
303 if (ret) {
304 fprintf(stderr, "[lttng filter] error linking wildcard bytecode\n");
305 }
306
307 }
308 return;
309 }
310
311 /*
312 * Need to attach filter to an event before starting tracing for the
313 * session. We own the filter_bytecode if we return success.
314 */
315 int lttng_filter_event_attach_bytecode(struct ltt_event *event,
316 struct lttng_ust_filter_bytecode *filter_bytecode)
317 {
318 if (event->chan->session->been_active)
319 return -EPERM;
320 if (event->filter_bytecode)
321 return -EEXIST;
322 event->filter_bytecode = filter_bytecode;
323 return 0;
324 }
325
326 /*
327 * Need to attach filter to a wildcard before starting tracing for the
328 * session. We own the filter_bytecode if we return success.
329 */
330 int lttng_filter_wildcard_attach_bytecode(struct session_wildcard *wildcard,
331 struct lttng_ust_filter_bytecode *filter_bytecode)
332 {
333 if (wildcard->chan->session->been_active)
334 return -EPERM;
335 if (wildcard->filter_bytecode)
336 return -EEXIST;
337 wildcard->filter_bytecode = filter_bytecode;
338 return 0;
339 }
This page took 0.036543 seconds and 5 git commands to generate.