SoW-2019-0002: Dynamic Snapshot
[lttng-tools.git] / src / common / event-rule-kprobe.c
1 /*
2 * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #include <lttng/constant.h>
19 #include <lttng/event-rule/event-rule-internal.h>
20 #include <lttng/event-rule/kprobe-internal.h>
21 #include <common/macros.h>
22 #include <common/error.h>
23 #include <common/runas.h>
24 #include <assert.h>
25 #include <stdio.h>
26 #include <ctype.h>
27
28 #define IS_KPROBE_EVENT_RULE(rule) ( \
29 lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_KPROBE \
30 )
31
32 #if (LTTNG_SYMBOL_NAME_LEN == 256)
33 #define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
34 #endif
35
36 static
37 void lttng_event_rule_kprobe_destroy(struct lttng_event_rule *rule)
38 {
39 struct lttng_event_rule_kprobe *kprobe;
40
41 kprobe = container_of(rule, struct lttng_event_rule_kprobe,
42 parent);
43
44 free(kprobe->name);
45 free(kprobe->probe.symbol_name);
46 free(kprobe);
47 }
48
49 static
50 bool lttng_event_rule_kprobe_validate(
51 const struct lttng_event_rule *rule)
52 {
53 bool valid = false;
54 struct lttng_event_rule_kprobe *kprobe;
55
56 if (!rule) {
57 goto end;
58 }
59
60 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
61
62 /* Required field */
63 if (!kprobe->name) {
64 ERR("Invalid name event rule: a name must be set.");
65 goto end;
66 }
67 if (kprobe->probe.set == LTTNG_DOMAIN_NONE) {
68 ERR("Invalid kprobe event rule: a source must be set.");
69 goto end;
70 }
71
72 valid = true;
73 end:
74 return valid;
75 }
76
77 static
78 int lttng_event_rule_kprobe_serialize(
79 const struct lttng_event_rule *rule,
80 struct lttng_dynamic_buffer *buf,
81 int *fd_to_send)
82 {
83 int ret;
84 size_t name_len, probe_symbol_name_len;
85 struct lttng_event_rule_kprobe *kprobe;
86 struct lttng_event_rule_kprobe_comm kprobe_comm;
87
88 if (!rule || !IS_KPROBE_EVENT_RULE(rule)) {
89 ret = -1;
90 goto end;
91 }
92
93 DBG("Serializing kprobe event rule");
94 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
95
96 name_len = strlen(kprobe->name) + 1;
97
98 if (kprobe->probe.symbol_name != NULL) {
99 probe_symbol_name_len = strlen(kprobe->probe.symbol_name) + 1;
100 } else {
101 probe_symbol_name_len = 0;
102 }
103
104 kprobe_comm.name_len = name_len;
105 kprobe_comm.probe_symbol_name_len = probe_symbol_name_len;
106 kprobe_comm.probe_address = kprobe->probe.address;
107 kprobe_comm.probe_offset = kprobe->probe.offset;
108
109 ret = lttng_dynamic_buffer_append(
110 buf, &kprobe_comm, sizeof(kprobe_comm));
111 if (ret) {
112 goto end;
113 }
114 ret = lttng_dynamic_buffer_append(buf, kprobe->name, name_len);
115 if (ret) {
116 goto end;
117 }
118 ret = lttng_dynamic_buffer_append(
119 buf, kprobe->probe.symbol_name, probe_symbol_name_len);
120 if (ret) {
121 goto end;
122 }
123
124 if (fd_to_send) {
125 /* Nothing to send */
126 *fd_to_send = -1;
127 }
128 end:
129 return ret;
130 }
131
132 static
133 bool lttng_event_rule_kprobe_is_equal(const struct lttng_event_rule *_a,
134 const struct lttng_event_rule *_b)
135 {
136 bool is_equal = false;
137 struct lttng_event_rule_kprobe *a, *b;
138
139 a = container_of(_a, struct lttng_event_rule_kprobe, parent);
140 b = container_of(_b, struct lttng_event_rule_kprobe, parent);
141
142 /* Quick checks */
143 if (!!a->name != !!b->name) {
144 goto end;
145 }
146
147 if (!!a->probe.symbol_name != !!b->probe.symbol_name) {
148 goto end;
149 }
150
151 /* Long check */
152 /* kprobe is invalid if this is not true */
153 /* TODO: validate that a kprobe MUST have a name */
154 assert(a->name);
155 assert(b->name);
156 if (strcmp(a->name, b->name)) {
157 goto end;
158 }
159
160 if (a->probe.symbol_name) {
161 /* Both have symbol name due to previous checks */
162 if (strcmp(a->probe.symbol_name, b->probe.symbol_name)) {
163 goto end;
164 }
165 }
166
167 if (a->probe.offset != b->probe.offset) {
168 goto end;
169 }
170
171 if (a->probe.address != b->probe.address) {
172 goto end;
173 }
174
175 is_equal = true;
176 end:
177 return is_equal;
178 }
179
180 static
181 enum lttng_error_code lttng_event_rule_kprobe_populate(struct lttng_event_rule *rule, uid_t uid, gid_t gid)
182 {
183 /* Nothing to do */
184 return LTTNG_OK;
185 }
186
187 static const char *lttng_event_rule_kprobe_get_filter(
188 const struct lttng_event_rule *rule)
189 {
190 /* Not supported */
191 return NULL;
192 }
193
194 static const struct lttng_filter_bytecode *
195 lttng_event_rule_kprobe_get_filter_bytecode(const struct lttng_event_rule *rule)
196 {
197 /* Not supported */
198 return NULL;
199 }
200
201 static
202 struct lttng_event_exclusion *lttng_event_rule_kprobe_generate_exclusions(struct lttng_event_rule *rule)
203 {
204 /* Not supported */
205 return NULL;
206 }
207
208 struct lttng_event_rule *lttng_event_rule_kprobe_create()
209 {
210 struct lttng_event_rule_kprobe *rule;
211
212 rule = zmalloc(sizeof(struct lttng_event_rule_kprobe));
213 if (!rule) {
214 return NULL;
215 }
216
217 lttng_event_rule_init(&rule->parent, LTTNG_EVENT_RULE_TYPE_KPROBE);
218 rule->parent.validate = lttng_event_rule_kprobe_validate;
219 rule->parent.serialize = lttng_event_rule_kprobe_serialize;
220 rule->parent.equal = lttng_event_rule_kprobe_is_equal;
221 rule->parent.destroy = lttng_event_rule_kprobe_destroy;
222 rule->parent.populate = lttng_event_rule_kprobe_populate;
223 rule->parent.get_filter = lttng_event_rule_kprobe_get_filter;
224 rule->parent.get_filter_bytecode = lttng_event_rule_kprobe_get_filter_bytecode;
225 rule->parent.generate_exclusions = lttng_event_rule_kprobe_generate_exclusions;
226 return &rule->parent;
227 }
228
229 LTTNG_HIDDEN
230 ssize_t lttng_event_rule_kprobe_create_from_buffer(
231 const struct lttng_buffer_view *view,
232 struct lttng_event_rule **_event_rule)
233 {
234 ssize_t ret, offset = 0;
235 enum lttng_event_rule_status status;
236 const struct lttng_event_rule_kprobe_comm *kprobe_comm;
237 const char *name;
238 const char *probe_symbol_name = NULL;
239 struct lttng_buffer_view current_view;
240 struct lttng_event_rule *rule = NULL;
241 struct lttng_event_rule_kprobe *kprobe = NULL;
242
243 if (!_event_rule) {
244 ret = -1;
245 goto end;
246 }
247
248 if (view->size < sizeof(*kprobe_comm)) {
249 ERR("Failed to initialize from malformed event rule kprobe: buffer too short to contain header");
250 ret = -1;
251 goto end;
252 }
253
254 current_view = lttng_buffer_view_from_view(
255 view, offset, sizeof(*kprobe_comm));
256 kprobe_comm = (typeof(kprobe_comm)) current_view.data;
257 if (!kprobe_comm) {
258 ret = -1;
259 goto end;
260 }
261
262 rule = lttng_event_rule_kprobe_create();
263 if (!rule) {
264 ERR("Failed to create event rule kprobe");
265 ret = -1;
266 goto end;
267 }
268
269 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
270
271 /* Skip to payload */
272 offset += current_view.size;
273 /* Map the name */
274 current_view = lttng_buffer_view_from_view(
275 view, offset, kprobe_comm->name_len);
276 name = current_view.data;
277 if (!name) {
278 ret = -1;
279 goto end;
280 }
281
282 if (kprobe_comm->name_len == 1 ||
283 name[kprobe_comm->name_len - 1] != '\0' ||
284 strlen(name) != kprobe_comm->name_len - 1) {
285 /*
286 * Check that the name is not NULL, is NULL-terminated, and
287 * does not contain a NULL before the last byte.
288 */
289 ret = -1;
290 goto end;
291 }
292
293 /* Skip after the name */
294 offset += kprobe_comm->name_len;
295 if (!kprobe_comm->probe_symbol_name_len) {
296 goto skip_probe_symbol_name;
297 }
298
299 /* Map the probe_symbol_name */
300 current_view = lttng_buffer_view_from_view(
301 view, offset, kprobe_comm->probe_symbol_name_len);
302 probe_symbol_name = current_view.data;
303 if (!probe_symbol_name) {
304 ret = -1;
305 goto end;
306 }
307
308 if (kprobe_comm->probe_symbol_name_len == 1 ||
309 probe_symbol_name[kprobe_comm->probe_symbol_name_len -
310 1] != '\0' ||
311 strlen(probe_symbol_name) !=
312 kprobe_comm->probe_symbol_name_len -
313 1) {
314 /*
315 * Check that the filter expression is not NULL, is
316 * NULL-terminated, and does not contain a NULL before the last
317 * byte.
318 */
319 ret = -1;
320 goto end;
321 }
322
323 /* Skip after the pattern */
324 offset += kprobe_comm->probe_symbol_name_len;
325
326 skip_probe_symbol_name:
327
328 status = lttng_event_rule_kprobe_set_name(rule, name);
329 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
330 ERR("Failed to set event rule kprobe name");
331 ret = -1;
332 goto end;
333 }
334 kprobe->probe.offset = kprobe_comm->probe_offset;
335 kprobe->probe.address = kprobe_comm->probe_address;
336 if (probe_symbol_name) {
337 kprobe->probe.symbol_name = strdup(probe_symbol_name);
338 if (!kprobe->probe.symbol_name) {
339 ERR("Failed to set event rule kprobe probe symbol name");
340 ret = -1;
341 goto end;
342 }
343 }
344
345 *_event_rule = rule;
346 rule = NULL;
347 ret = offset;
348 end:
349 lttng_event_rule_destroy(rule);
350 return ret;
351 }
352
353 enum lttng_event_rule_status lttng_event_rule_kprobe_set_source(
354 struct lttng_event_rule *rule, const char *source)
355 {
356 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
357 int match;
358 char s_hex[19];
359 char name[LTTNG_SYMBOL_NAME_LEN];
360 struct lttng_event_rule_kprobe *kprobe;
361
362 /* TODO: support multiple call for this, we must free the symbol name if
363 * that happens !!!
364 */
365
366 if (!source || !IS_KPROBE_EVENT_RULE(rule) || !rule) {
367 status = LTTNG_EVENT_RULE_STATUS_INVALID;
368 goto end;
369 }
370
371 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
372
373 /* Check for symbol+offset */
374 match = sscanf(source, "%18s[^'+']+%18s", name, s_hex);
375 if (match == 2) {
376 /* TODO double validate termination handling of this */
377 kprobe->probe.symbol_name =
378 strndup(name, LTTNG_SYMBOL_NAME_LEN);
379 if (!kprobe->probe.symbol_name) {
380 status = LTTNG_EVENT_RULE_STATUS_ERROR;
381 goto end;
382 }
383 if (*s_hex == '\0') {
384 status = LTTNG_EVENT_RULE_STATUS_INVALID;
385 goto end;
386 }
387 kprobe->probe.offset = strtoul(s_hex, NULL, 0);
388 kprobe->probe.address = 0;
389 kprobe->probe.set = true;
390 goto end;
391 }
392
393 /* Check for symbol */
394 if (isalpha(name[0]) || name[0] == '_') {
395 match = sscanf(source,
396 "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
397 "s",
398 name);
399 if (match == 1) {
400 /* TODO double validate termination handling of this */
401 kprobe->probe.symbol_name =
402 strndup(name, LTTNG_SYMBOL_NAME_LEN);
403 if (!kprobe->probe.symbol_name) {
404 status = LTTNG_EVENT_RULE_STATUS_ERROR;
405 goto end;
406 }
407 kprobe->probe.offset = 0;
408 kprobe->probe.address = 0;
409 kprobe->probe.set = true;
410 goto end;
411 }
412 }
413
414 /* Check for address */
415 match = sscanf(source, "%18s", s_hex);
416 if (match > 0) {
417 if (*s_hex == '\0') {
418 status = LTTNG_EVENT_RULE_STATUS_INVALID;
419 goto end;
420 }
421 kprobe->probe.address = strtoul(s_hex, NULL, 0);
422 kprobe->probe.offset = 0;
423 kprobe->probe.symbol_name = NULL;
424 kprobe->probe.set = true;
425 goto end;
426 }
427
428 /* No match */
429 status = LTTNG_EVENT_RULE_STATUS_INVALID;
430
431 end:
432 return status;
433 }
434
435 enum lttng_event_rule_status lttng_event_rule_kprobe_set_name(
436 struct lttng_event_rule *rule, const char *name)
437 {
438 char *name_copy = NULL;
439 struct lttng_event_rule_kprobe *kprobe;
440 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
441
442 if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !name ||
443 strlen(name) == 0) {
444 status = LTTNG_EVENT_RULE_STATUS_INVALID;
445 goto end;
446 }
447
448 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
449 name_copy = strdup(name);
450 if (!name_copy) {
451 status = LTTNG_EVENT_RULE_STATUS_ERROR;
452 goto end;
453 }
454
455 if (kprobe->name) {
456 free(kprobe->name);
457 }
458
459 kprobe->name = name_copy;
460 name_copy = NULL;
461 end:
462 return status;
463 }
464
465 enum lttng_event_rule_status lttng_event_rule_kprobe_get_name(
466 const struct lttng_event_rule *rule, const char **name)
467 {
468 struct lttng_event_rule_kprobe *kprobe;
469 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
470
471 if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !name) {
472 status = LTTNG_EVENT_RULE_STATUS_INVALID;
473 goto end;
474 }
475
476 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
477 if (!kprobe->name) {
478 status = LTTNG_EVENT_RULE_STATUS_UNSET;
479 goto end;
480 }
481
482 *name = kprobe->name;
483 end:
484 return status;
485 }
486
487 LTTNG_HIDDEN
488 uint64_t lttng_event_rule_kprobe_get_address(
489 const struct lttng_event_rule *rule)
490 {
491 struct lttng_event_rule_kprobe *kprobe;
492
493 assert(rule && IS_KPROBE_EVENT_RULE(rule));
494
495 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
496
497 return kprobe->probe.address;
498 }
499
500 LTTNG_HIDDEN
501 uint64_t lttng_event_rule_kprobe_get_offset(
502 const struct lttng_event_rule *rule)
503 {
504 struct lttng_event_rule_kprobe *kprobe;
505
506 assert(rule && IS_KPROBE_EVENT_RULE(rule));
507
508 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
509 return kprobe->probe.offset;
510 }
511
512 LTTNG_HIDDEN
513 const char *lttng_event_rule_kprobe_get_symbol_name(
514 const struct lttng_event_rule *rule)
515 {
516 struct lttng_event_rule_kprobe *kprobe;
517
518 assert(rule && IS_KPROBE_EVENT_RULE(rule));
519
520 kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
521 return kprobe->probe.symbol_name;
522 }
This page took 0.04044 seconds and 5 git commands to generate.