Commit | Line | Data |
---|---|---|
54012638 | 1 | /* |
ab5be9fa | 2 | * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca> |
54012638 | 3 | * |
ab5be9fa | 4 | * SPDX-License-Identifier: GPL-2.0-only |
54012638 | 5 | * |
54012638 DG |
6 | */ |
7 | ||
6c1c0768 | 8 | #define _LGPL_SOURCE |
54012638 DG |
9 | #include <stdio.h> |
10 | #include <stdlib.h> | |
11 | #include <string.h> | |
c363b55d | 12 | #include <unistd.h> |
54012638 | 13 | |
dcabc190 FD |
14 | #include <lttng/event.h> |
15 | #include <lttng/lttng-error.h> | |
16 | #include <lttng/userspace-probe.h> | |
17 | #include <lttng/userspace-probe-internal.h> | |
d3a684ee JR |
18 | #include <lttng/event-rule/event-rule.h> |
19 | #include <lttng/event-rule/event-rule-internal.h> | |
20 | #include <lttng/event-rule/kprobe.h> | |
21 | #include <lttng/event-rule/kprobe-internal.h> | |
22 | #include <lttng/event-rule/kretprobe.h> | |
23 | #include <lttng/event-rule/kretprobe-internal.h> | |
24 | #include <lttng/event-rule/syscall.h> | |
25 | #include <lttng/event-rule/syscall-internal.h> | |
26 | #include <lttng/event-rule/tracepoint.h> | |
27 | #include <lttng/event-rule/tracepoint-internal.h> | |
28 | #include <lttng/event-rule/uprobe-internal.h> | |
990570ed DG |
29 | #include <common/common.h> |
30 | #include <common/defaults.h> | |
82b69413 | 31 | #include <common/trace-chunk.h> |
1e307fab | 32 | |
00e2e675 | 33 | #include "consumer.h" |
62499ad6 | 34 | #include "trace-kernel.h" |
e9404c27 JG |
35 | #include "lttng-sessiond.h" |
36 | #include "notification-thread-commands.h" | |
54012638 | 37 | |
19e70852 | 38 | /* |
050349bb | 39 | * Find the channel name for the given kernel session. |
19e70852 | 40 | */ |
62499ad6 | 41 | struct ltt_kernel_channel *trace_kernel_get_channel_by_name( |
df4f5a87 | 42 | const char *name, struct ltt_kernel_session *session) |
19e70852 DG |
43 | { |
44 | struct ltt_kernel_channel *chan; | |
45 | ||
0525e9ae DG |
46 | assert(session); |
47 | assert(name); | |
19e70852 | 48 | |
85076754 MD |
49 | /* |
50 | * If we receive an empty string for channel name, it means the | |
51 | * default channel name is requested. | |
52 | */ | |
53 | if (name[0] == '\0') | |
54 | name = DEFAULT_CHANNEL_NAME; | |
55 | ||
54d01ffb DG |
56 | DBG("Trying to find channel %s", name); |
57 | ||
19e70852 DG |
58 | cds_list_for_each_entry(chan, &session->channel_list.head, list) { |
59 | if (strcmp(name, chan->channel->name) == 0) { | |
60 | DBG("Found channel by name %s", name); | |
61 | return chan; | |
62 | } | |
63 | } | |
64 | ||
19e70852 DG |
65 | return NULL; |
66 | } | |
67 | ||
00a62084 MD |
68 | /* |
69 | * Find the event for the given channel. | |
70 | */ | |
71 | struct ltt_kernel_event *trace_kernel_find_event( | |
72 | char *name, struct ltt_kernel_channel *channel, | |
73 | enum lttng_event_type type, | |
74 | struct lttng_filter_bytecode *filter) | |
75 | { | |
76 | struct ltt_kernel_event *ev; | |
77 | int found = 0; | |
78 | ||
79 | assert(name); | |
80 | assert(channel); | |
81 | ||
82 | cds_list_for_each_entry(ev, &channel->events_list.head, list) { | |
83 | if (type != LTTNG_EVENT_ALL && ev->type != type) { | |
84 | continue; | |
85 | } | |
86 | if (strcmp(name, ev->event->name)) { | |
87 | continue; | |
88 | } | |
89 | if ((ev->filter && !filter) || (!ev->filter && filter)) { | |
90 | continue; | |
91 | } | |
92 | if (ev->filter && filter) { | |
93 | if (ev->filter->len != filter->len || | |
94 | memcmp(ev->filter->data, filter->data, | |
95 | filter->len) != 0) { | |
96 | continue; | |
97 | } | |
98 | } | |
99 | found = 1; | |
100 | break; | |
101 | } | |
102 | if (found) { | |
103 | DBG("Found event %s for channel %s", name, | |
104 | channel->channel->name); | |
105 | return ev; | |
106 | } else { | |
107 | return NULL; | |
108 | } | |
109 | } | |
110 | ||
19e70852 | 111 | /* |
050349bb | 112 | * Find the event name for the given channel. |
19e70852 | 113 | */ |
62499ad6 | 114 | struct ltt_kernel_event *trace_kernel_get_event_by_name( |
d0ae4ea8 MD |
115 | char *name, struct ltt_kernel_channel *channel, |
116 | enum lttng_event_type type) | |
19e70852 DG |
117 | { |
118 | struct ltt_kernel_event *ev; | |
00a62084 | 119 | int found = 0; |
19e70852 | 120 | |
0525e9ae DG |
121 | assert(name); |
122 | assert(channel); | |
19e70852 DG |
123 | |
124 | cds_list_for_each_entry(ev, &channel->events_list.head, list) { | |
00a62084 | 125 | if (type != LTTNG_EVENT_ALL && ev->type != type) { |
d0ae4ea8 | 126 | continue; |
19e70852 | 127 | } |
00a62084 MD |
128 | if (strcmp(name, ev->event->name)) { |
129 | continue; | |
130 | } | |
131 | found = 1; | |
132 | break; | |
133 | } | |
134 | if (found) { | |
135 | DBG("Found event %s for channel %s", name, | |
136 | channel->channel->name); | |
137 | return ev; | |
138 | } else { | |
139 | return NULL; | |
19e70852 | 140 | } |
19e70852 DG |
141 | } |
142 | ||
d3a684ee JR |
143 | struct ltt_kernel_token_event_rule *trace_kernel_find_trigger_by_token( |
144 | struct ltt_kernel_token_event_rule_list *list, | |
145 | uint64_t token) | |
146 | { | |
147 | struct ltt_kernel_token_event_rule *token_event_rule; | |
148 | int found = 0; | |
149 | ||
150 | assert(list); | |
151 | ||
152 | cds_list_for_each_entry(token_event_rule, &list->head, list) { | |
153 | if (token_event_rule->token == token) { | |
154 | found = 1; | |
155 | } | |
156 | break; | |
157 | } | |
158 | if (found) { | |
159 | DBG("Found token event rule %" PRIu64, token); | |
160 | return token_event_rule; | |
161 | } else { | |
162 | return NULL; | |
163 | } | |
164 | } | |
165 | ||
54012638 | 166 | /* |
050349bb | 167 | * Allocate and initialize a kernel session data structure. |
54012638 | 168 | * |
050349bb | 169 | * Return pointer to structure or NULL. |
54012638 | 170 | */ |
dec56f6c | 171 | struct ltt_kernel_session *trace_kernel_create_session(void) |
54012638 | 172 | { |
a4b92340 | 173 | struct ltt_kernel_session *lks = NULL; |
54012638 DG |
174 | |
175 | /* Allocate a new ltt kernel session */ | |
ba7f0ae5 | 176 | lks = zmalloc(sizeof(struct ltt_kernel_session)); |
54012638 | 177 | if (lks == NULL) { |
df0f840b | 178 | PERROR("create kernel session zmalloc"); |
a4b92340 | 179 | goto alloc_error; |
54012638 DG |
180 | } |
181 | ||
182 | /* Init data structure */ | |
03550b58 MD |
183 | lks->fd = -1; |
184 | lks->metadata_stream_fd = -1; | |
54012638 DG |
185 | lks->channel_count = 0; |
186 | lks->stream_count_global = 0; | |
187 | lks->metadata = NULL; | |
188 | CDS_INIT_LIST_HEAD(&lks->channel_list.head); | |
189 | ||
55c9e7ca JR |
190 | lks->tracker_list_pid = lttng_tracker_list_create(); |
191 | if (!lks->tracker_list_pid) { | |
192 | goto error; | |
193 | } | |
194 | lks->tracker_list_vpid = lttng_tracker_list_create(); | |
195 | if (!lks->tracker_list_vpid) { | |
196 | goto error; | |
197 | } | |
198 | lks->tracker_list_uid = lttng_tracker_list_create(); | |
199 | if (!lks->tracker_list_uid) { | |
200 | goto error; | |
201 | } | |
202 | lks->tracker_list_vuid = lttng_tracker_list_create(); | |
203 | if (!lks->tracker_list_vuid) { | |
204 | goto error; | |
205 | } | |
206 | lks->tracker_list_gid = lttng_tracker_list_create(); | |
207 | if (!lks->tracker_list_gid) { | |
208 | goto error; | |
209 | } | |
210 | lks->tracker_list_vgid = lttng_tracker_list_create(); | |
211 | if (!lks->tracker_list_vgid) { | |
212 | goto error; | |
213 | } | |
00e2e675 DG |
214 | lks->consumer = consumer_create_output(CONSUMER_DST_LOCAL); |
215 | if (lks->consumer == NULL) { | |
216 | goto error; | |
217 | } | |
218 | ||
54012638 DG |
219 | return lks; |
220 | ||
221 | error: | |
55c9e7ca JR |
222 | lttng_tracker_list_destroy(lks->tracker_list_pid); |
223 | lttng_tracker_list_destroy(lks->tracker_list_vpid); | |
224 | lttng_tracker_list_destroy(lks->tracker_list_uid); | |
225 | lttng_tracker_list_destroy(lks->tracker_list_vuid); | |
226 | lttng_tracker_list_destroy(lks->tracker_list_gid); | |
227 | lttng_tracker_list_destroy(lks->tracker_list_vgid); | |
a4b92340 DG |
228 | free(lks); |
229 | ||
230 | alloc_error: | |
54012638 DG |
231 | return NULL; |
232 | } | |
233 | ||
234 | /* | |
050349bb | 235 | * Allocate and initialize a kernel channel data structure. |
54012638 | 236 | * |
050349bb | 237 | * Return pointer to structure or NULL. |
54012638 | 238 | */ |
00e2e675 | 239 | struct ltt_kernel_channel *trace_kernel_create_channel( |
fdd9eb17 | 240 | struct lttng_channel *chan) |
54012638 | 241 | { |
54012638 | 242 | struct ltt_kernel_channel *lkc; |
61a5b6b1 | 243 | struct lttng_channel_extended *extended = NULL; |
54012638 | 244 | |
0525e9ae DG |
245 | assert(chan); |
246 | ||
ba7f0ae5 | 247 | lkc = zmalloc(sizeof(struct ltt_kernel_channel)); |
f3ed775e | 248 | if (lkc == NULL) { |
df0f840b | 249 | PERROR("ltt_kernel_channel zmalloc"); |
54012638 DG |
250 | goto error; |
251 | } | |
252 | ||
ba7f0ae5 | 253 | lkc->channel = zmalloc(sizeof(struct lttng_channel)); |
f3ed775e | 254 | if (lkc->channel == NULL) { |
df0f840b | 255 | PERROR("lttng_channel zmalloc"); |
e9404c27 JG |
256 | goto error; |
257 | } | |
258 | ||
259 | extended = zmalloc(sizeof(struct lttng_channel_extended)); | |
260 | if (!extended) { | |
261 | PERROR("lttng_channel_channel zmalloc"); | |
f3ed775e DG |
262 | goto error; |
263 | } | |
264 | memcpy(lkc->channel, chan, sizeof(struct lttng_channel)); | |
e9404c27 JG |
265 | memcpy(extended, chan->attr.extended.ptr, sizeof(struct lttng_channel_extended)); |
266 | lkc->channel->attr.extended.ptr = extended; | |
267 | extended = NULL; | |
54012638 | 268 | |
85076754 MD |
269 | /* |
270 | * If we receive an empty string for channel name, it means the | |
271 | * default channel name is requested. | |
272 | */ | |
273 | if (chan->name[0] == '\0') { | |
274 | strncpy(lkc->channel->name, DEFAULT_CHANNEL_NAME, | |
275 | sizeof(lkc->channel->name)); | |
276 | } | |
bd722d76 | 277 | lkc->channel->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; |
85076754 | 278 | |
03550b58 | 279 | lkc->fd = -1; |
54012638 | 280 | lkc->stream_count = 0; |
cbbbb275 | 281 | lkc->event_count = 0; |
d36b8583 | 282 | lkc->enabled = 1; |
753873bf | 283 | lkc->published_to_notification_thread = false; |
54012638 DG |
284 | /* Init linked list */ |
285 | CDS_INIT_LIST_HEAD(&lkc->events_list.head); | |
286 | CDS_INIT_LIST_HEAD(&lkc->stream_list.head); | |
645328ae | 287 | CDS_INIT_LIST_HEAD(&lkc->ctx_list); |
54012638 DG |
288 | |
289 | return lkc; | |
290 | ||
291 | error: | |
e9404c27 JG |
292 | if (lkc) { |
293 | free(lkc->channel); | |
294 | } | |
295 | free(extended); | |
296 | free(lkc); | |
54012638 DG |
297 | return NULL; |
298 | } | |
299 | ||
645328ae DG |
300 | /* |
301 | * Allocate and init a kernel context object. | |
302 | * | |
303 | * Return the allocated object or NULL on error. | |
304 | */ | |
305 | struct ltt_kernel_context *trace_kernel_create_context( | |
306 | struct lttng_kernel_context *ctx) | |
307 | { | |
308 | struct ltt_kernel_context *kctx; | |
309 | ||
310 | kctx = zmalloc(sizeof(*kctx)); | |
311 | if (!kctx) { | |
312 | PERROR("zmalloc kernel context"); | |
313 | goto error; | |
314 | } | |
315 | ||
316 | if (ctx) { | |
317 | memcpy(&kctx->ctx, ctx, sizeof(kctx->ctx)); | |
318 | } | |
df3c77c8 JG |
319 | error: |
320 | return kctx; | |
321 | } | |
645328ae | 322 | |
df3c77c8 JG |
323 | /* |
324 | * Allocate and init a kernel context object from an existing kernel context | |
325 | * object. | |
326 | * | |
327 | * Return the allocated object or NULL on error. | |
328 | */ | |
329 | struct ltt_kernel_context *trace_kernel_copy_context( | |
330 | struct ltt_kernel_context *kctx) | |
331 | { | |
332 | struct ltt_kernel_context *kctx_copy; | |
333 | ||
334 | assert(kctx); | |
335 | kctx_copy = zmalloc(sizeof(*kctx_copy)); | |
336 | if (!kctx_copy) { | |
337 | PERROR("zmalloc ltt_kernel_context"); | |
338 | goto error; | |
339 | } | |
340 | ||
341 | memcpy(kctx_copy, kctx, sizeof(*kctx_copy)); | |
342 | memset(&kctx_copy->list, 0, sizeof(kctx_copy->list)); | |
7b9445b3 | 343 | |
645328ae | 344 | error: |
df3c77c8 | 345 | return kctx_copy; |
645328ae DG |
346 | } |
347 | ||
54012638 | 348 | /* |
050349bb | 349 | * Allocate and initialize a kernel event. Set name and event type. |
a969e101 | 350 | * We own filter_expression, and filter. |
54012638 | 351 | * |
050349bb | 352 | * Return pointer to structure or NULL. |
54012638 | 353 | */ |
71a3bb01 FD |
354 | enum lttng_error_code trace_kernel_create_event( |
355 | struct lttng_event *ev, char *filter_expression, | |
356 | struct lttng_filter_bytecode *filter, | |
357 | struct ltt_kernel_event **kernel_event) | |
54012638 | 358 | { |
71a3bb01 | 359 | enum lttng_error_code ret; |
54012638 | 360 | struct lttng_kernel_event *attr; |
71a3bb01 | 361 | struct ltt_kernel_event *local_kernel_event; |
dcabc190 | 362 | struct lttng_userspace_probe_location *userspace_probe_location = NULL; |
54012638 | 363 | |
0525e9ae DG |
364 | assert(ev); |
365 | ||
71a3bb01 | 366 | local_kernel_event = zmalloc(sizeof(struct ltt_kernel_event)); |
ba7f0ae5 | 367 | attr = zmalloc(sizeof(struct lttng_kernel_event)); |
71a3bb01 | 368 | if (local_kernel_event == NULL || attr == NULL) { |
df0f840b | 369 | PERROR("kernel event zmalloc"); |
71a3bb01 | 370 | ret = LTTNG_ERR_NOMEM; |
54012638 DG |
371 | goto error; |
372 | } | |
373 | ||
f3ed775e | 374 | switch (ev->type) { |
7d29a247 | 375 | case LTTNG_EVENT_PROBE: |
e6ddca71 | 376 | attr->instrumentation = LTTNG_KERNEL_KPROBE; |
7d29a247 DG |
377 | attr->u.kprobe.addr = ev->attr.probe.addr; |
378 | attr->u.kprobe.offset = ev->attr.probe.offset; | |
f3ed775e | 379 | strncpy(attr->u.kprobe.symbol_name, |
dbbb3ec5 DG |
380 | ev->attr.probe.symbol_name, LTTNG_KERNEL_SYM_NAME_LEN); |
381 | attr->u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | |
f3ed775e | 382 | break; |
dcabc190 FD |
383 | case LTTNG_EVENT_USERSPACE_PROBE: |
384 | { | |
87597c2c JG |
385 | const struct lttng_userspace_probe_location* location = NULL; |
386 | const struct lttng_userspace_probe_location_lookup_method *lookup = NULL; | |
dcabc190 FD |
387 | |
388 | location = lttng_event_get_userspace_probe_location(ev); | |
389 | if (!location) { | |
390 | ret = LTTNG_ERR_PROBE_LOCATION_INVAL; | |
391 | goto error; | |
392 | } | |
393 | ||
394 | /* | |
395 | * From this point on, the specific term 'uprobe' is used | |
396 | * instead of the generic 'userspace probe' because it's the | |
397 | * technology used at the moment for this instrumentation. | |
398 | * LTTng currently implements userspace probes using uprobes. | |
399 | * In the interactions with the kernel tracer, we use the | |
400 | * uprobe term. | |
401 | */ | |
402 | attr->instrumentation = LTTNG_KERNEL_UPROBE; | |
403 | ||
404 | /* | |
405 | * Only the elf lookup method is supported at the moment. | |
406 | */ | |
407 | lookup = lttng_userspace_probe_location_get_lookup_method( | |
408 | location); | |
409 | if (!lookup) { | |
410 | ret = LTTNG_ERR_PROBE_LOCATION_INVAL; | |
411 | goto error; | |
412 | } | |
413 | ||
414 | /* | |
415 | * From the kernel tracer's perspective, all userspace probe | |
416 | * event types are all the same: a file and an offset. | |
417 | */ | |
418 | switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) { | |
419 | case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF: | |
420 | /* Get the file descriptor on the target binary. */ | |
421 | attr->u.uprobe.fd = | |
422 | lttng_userspace_probe_location_function_get_binary_fd(location); | |
423 | ||
424 | /* | |
425 | * Save a reference to the probe location used during | |
426 | * the listing of events. Close its FD since it won't | |
427 | * be needed for listing. | |
428 | */ | |
429 | userspace_probe_location = | |
430 | lttng_userspace_probe_location_copy(location); | |
431 | ret = lttng_userspace_probe_location_function_set_binary_fd( | |
432 | userspace_probe_location, -1); | |
433 | if (ret) { | |
434 | goto error; | |
435 | } | |
436 | break; | |
437 | case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: | |
438 | /* Get the file descriptor on the target binary. */ | |
439 | attr->u.uprobe.fd = | |
440 | lttng_userspace_probe_location_tracepoint_get_binary_fd(location); | |
441 | ||
442 | /* | |
443 | * Save a reference to the probe location used during the listing of | |
444 | * events. Close its FD since it won't be needed for listing. | |
445 | */ | |
446 | userspace_probe_location = | |
447 | lttng_userspace_probe_location_copy(location); | |
448 | ret = lttng_userspace_probe_location_tracepoint_set_binary_fd( | |
449 | userspace_probe_location, -1); | |
450 | if (ret) { | |
451 | goto error; | |
452 | } | |
453 | break; | |
454 | default: | |
455 | DBG("Unsupported lookup method type"); | |
456 | ret = LTTNG_ERR_PROBE_LOCATION_INVAL; | |
457 | goto error; | |
458 | } | |
459 | break; | |
460 | } | |
f3ed775e | 461 | case LTTNG_EVENT_FUNCTION: |
8f0d098b MD |
462 | attr->instrumentation = LTTNG_KERNEL_KRETPROBE; |
463 | attr->u.kretprobe.addr = ev->attr.probe.addr; | |
464 | attr->u.kretprobe.offset = ev->attr.probe.offset; | |
8f0d098b | 465 | strncpy(attr->u.kretprobe.symbol_name, |
dbbb3ec5 DG |
466 | ev->attr.probe.symbol_name, LTTNG_KERNEL_SYM_NAME_LEN); |
467 | attr->u.kretprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | |
8f0d098b MD |
468 | break; |
469 | case LTTNG_EVENT_FUNCTION_ENTRY: | |
f3ed775e DG |
470 | attr->instrumentation = LTTNG_KERNEL_FUNCTION; |
471 | strncpy(attr->u.ftrace.symbol_name, | |
dbbb3ec5 DG |
472 | ev->attr.ftrace.symbol_name, LTTNG_KERNEL_SYM_NAME_LEN); |
473 | attr->u.ftrace.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | |
f3ed775e | 474 | break; |
e6ddca71 DG |
475 | case LTTNG_EVENT_TRACEPOINT: |
476 | attr->instrumentation = LTTNG_KERNEL_TRACEPOINT; | |
f3ed775e | 477 | break; |
a54bd42d MD |
478 | case LTTNG_EVENT_SYSCALL: |
479 | attr->instrumentation = LTTNG_KERNEL_SYSCALL; | |
0133c199 | 480 | break; |
7a3d1328 MD |
481 | case LTTNG_EVENT_ALL: |
482 | attr->instrumentation = LTTNG_KERNEL_ALL; | |
483 | break; | |
f3ed775e DG |
484 | default: |
485 | ERR("Unknown kernel instrumentation type (%d)", ev->type); | |
71a3bb01 | 486 | ret = LTTNG_ERR_INVALID; |
f3ed775e DG |
487 | goto error; |
488 | } | |
489 | ||
490 | /* Copy event name */ | |
dbbb3ec5 DG |
491 | strncpy(attr->name, ev->name, LTTNG_KERNEL_SYM_NAME_LEN); |
492 | attr->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | |
f3ed775e | 493 | |
54012638 | 494 | /* Setting up a kernel event */ |
71a3bb01 FD |
495 | local_kernel_event->fd = -1; |
496 | local_kernel_event->event = attr; | |
497 | local_kernel_event->enabled = 1; | |
498 | local_kernel_event->filter_expression = filter_expression; | |
499 | local_kernel_event->filter = filter; | |
dcabc190 | 500 | local_kernel_event->userspace_probe_location = userspace_probe_location; |
54012638 | 501 | |
71a3bb01 FD |
502 | *kernel_event = local_kernel_event; |
503 | ||
504 | return LTTNG_OK; | |
54012638 DG |
505 | |
506 | error: | |
a969e101 MD |
507 | free(filter_expression); |
508 | free(filter); | |
71a3bb01 | 509 | free(local_kernel_event); |
a2c0da86 | 510 | free(attr); |
71a3bb01 | 511 | return ret; |
54012638 DG |
512 | } |
513 | ||
d3a684ee JR |
514 | /* |
515 | * Allocate and initialize a kernel token event rule. | |
516 | * | |
517 | * Return pointer to structure or NULL. | |
518 | */ | |
519 | enum lttng_error_code trace_kernel_create_token_event_rule( | |
520 | struct lttng_event_rule *event_rule, | |
521 | uint64_t token, | |
522 | struct ltt_kernel_token_event_rule **kernel_token_event_rule) | |
523 | { | |
524 | enum lttng_error_code ret = LTTNG_OK; | |
525 | struct ltt_kernel_token_event_rule *local_kernel_token_event_rule; | |
526 | ||
527 | assert(kernel_token_event_rule); | |
528 | ||
529 | local_kernel_token_event_rule = zmalloc(sizeof(struct ltt_kernel_token_event_rule)); | |
530 | if (local_kernel_token_event_rule == NULL) { | |
531 | PERROR("Failed to allocate ltt_kernel_token_event_rule structure"); | |
532 | ret = LTTNG_ERR_NOMEM; | |
533 | goto error; | |
534 | } | |
535 | ||
536 | local_kernel_token_event_rule->fd = -1; | |
537 | local_kernel_token_event_rule->enabled = 1; | |
538 | local_kernel_token_event_rule->token = token; | |
539 | ||
540 | /* Get the reference of the event rule */ | |
541 | if (!lttng_event_rule_get(event_rule)) { | |
542 | assert(0); | |
543 | } | |
544 | ||
545 | local_kernel_token_event_rule->event_rule = event_rule; | |
546 | /* The event rule still own the filter and bytecode */ | |
547 | local_kernel_token_event_rule->filter = lttng_event_rule_get_filter_bytecode(event_rule); | |
548 | ||
549 | DBG3("[trace] Kernel token event rule %" PRIu64 " allocated", local_kernel_token_event_rule->token); | |
550 | error: | |
551 | *kernel_token_event_rule = local_kernel_token_event_rule; | |
552 | return ret; | |
553 | ||
554 | } | |
555 | ||
556 | /* | |
557 | * Initialize a kernel trigger from an event rule. | |
558 | */ | |
559 | enum lttng_error_code trace_kernel_init_trigger_from_event_rule(const struct lttng_event_rule *rule, | |
560 | struct lttng_kernel_trigger *kernel_trigger) | |
561 | { | |
562 | enum lttng_error_code ret; | |
563 | enum lttng_event_rule_status status; | |
564 | const char *name = NULL; | |
565 | ||
566 | /* TODO: do this for now but have disucssion on if this could be the | |
567 | * responsability of the event_rule itself ala | |
568 | * "lttng_even_rule_generate_kernel_trigger" | |
569 | */ | |
570 | switch (lttng_event_rule_get_type(rule)) { | |
571 | case LTTNG_EVENT_RULE_TYPE_KPROBE: | |
572 | kernel_trigger->instrumentation = LTTNG_KERNEL_KPROBE; | |
573 | kernel_trigger->u.kprobe.addr = lttng_event_rule_kprobe_get_address(rule); | |
574 | kernel_trigger->u.kprobe.offset = lttng_event_rule_kprobe_get_offset(rule); | |
575 | strncpy(kernel_trigger->u.kprobe.symbol_name, | |
576 | lttng_event_rule_kprobe_get_symbol_name(rule), LTTNG_KERNEL_SYM_NAME_LEN); | |
577 | kernel_trigger->u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | |
578 | (void) lttng_event_rule_kprobe_get_name(rule, &name); | |
579 | ret = LTTNG_OK; | |
580 | break; | |
581 | case LTTNG_EVENT_RULE_TYPE_UPROBE: | |
582 | { | |
583 | const struct lttng_userspace_probe_location* location = NULL; | |
584 | const struct lttng_userspace_probe_location_lookup_method *lookup = NULL; | |
585 | ||
586 | status = lttng_event_rule_uprobe_get_location(rule, &location); | |
587 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
588 | ret = LTTNG_ERR_PROBE_LOCATION_INVAL; | |
589 | goto error; | |
590 | } | |
591 | ||
592 | kernel_trigger->instrumentation = LTTNG_KERNEL_UPROBE; | |
593 | ||
594 | /* | |
595 | * Only the elf lookup method is supported at the moment. | |
596 | */ | |
597 | lookup = lttng_userspace_probe_location_get_lookup_method( | |
598 | location); | |
599 | if (!lookup) { | |
600 | ret = LTTNG_ERR_PROBE_LOCATION_INVAL; | |
601 | goto error; | |
602 | } | |
603 | ||
604 | /* | |
605 | * From the kernel tracer's perspective, all userspace probe | |
606 | * event types are all the same: a file and an offset. | |
607 | */ | |
608 | switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) { | |
609 | case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF: | |
610 | /* Get the file descriptor on the target binary. */ | |
611 | kernel_trigger->u.uprobe.fd = | |
612 | lttng_userspace_probe_location_function_get_binary_fd(location); | |
613 | ||
614 | break; | |
615 | case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: | |
616 | /* Get the file descriptor on the target binary. */ | |
617 | kernel_trigger->u.uprobe.fd = | |
618 | lttng_userspace_probe_location_tracepoint_get_binary_fd(location); | |
619 | break; | |
620 | default: | |
621 | DBG("Unsupported lookup method type"); | |
622 | ret = LTTNG_ERR_PROBE_LOCATION_INVAL; | |
623 | goto error; | |
624 | } | |
625 | ||
626 | (void) lttng_event_rule_uprobe_get_name(rule, &name); | |
627 | ||
628 | ret = LTTNG_OK; | |
629 | break; | |
630 | } | |
631 | case LTTNG_EVENT_RULE_TYPE_KRETPROBE: | |
632 | assert("Not supported" && 0); | |
633 | kernel_trigger->instrumentation = LTTNG_KERNEL_KRETPROBE; | |
634 | kernel_trigger->u.kretprobe.addr = lttng_event_rule_kretprobe_get_address(rule); | |
635 | kernel_trigger->u.kretprobe.offset = lttng_event_rule_kretprobe_get_offset(rule); | |
636 | strncpy(kernel_trigger->u.kretprobe.symbol_name, | |
637 | lttng_event_rule_kretprobe_get_symbol_name(rule), LTTNG_KERNEL_SYM_NAME_LEN); | |
638 | kernel_trigger->u.kretprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | |
639 | (void) lttng_event_rule_kretprobe_get_name(rule, &name); | |
640 | ret = LTTNG_OK; | |
641 | break; | |
642 | case LTTNG_EVENT_RULE_TYPE_TRACEPOINT: | |
643 | /* TODO: assert his is a kernel domain event-rule */ | |
644 | kernel_trigger->instrumentation = LTTNG_KERNEL_TRACEPOINT; | |
645 | (void) lttng_event_rule_tracepoint_get_pattern(rule, &name); | |
646 | ret = LTTNG_OK; | |
647 | break; | |
648 | case LTTNG_EVENT_RULE_TYPE_SYSCALL: | |
649 | kernel_trigger->instrumentation = LTTNG_KERNEL_SYSCALL; | |
650 | (void) lttng_event_rule_syscall_get_pattern(rule, &name); | |
651 | ret = LTTNG_OK; | |
652 | break; | |
653 | default: | |
654 | ERR("Unknown kernel event rule instrumentation type (%d)", lttng_event_rule_get_type(rule)); | |
655 | ret = LTTNG_ERR_INVALID; | |
656 | goto error; | |
657 | } | |
658 | ||
659 | /* | |
660 | * WTF is LTTNG_EVENT_ALL??? and LTTNG_EVENT_FUNTION_ENTRY????? | |
661 | */ | |
662 | ||
663 | /* Copy event name */ | |
664 | strncpy(kernel_trigger->name, name, LTTNG_KERNEL_SYM_NAME_LEN); | |
665 | kernel_trigger->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; | |
666 | ||
667 | error: | |
668 | return ret; | |
669 | } | |
54012638 | 670 | /* |
050349bb | 671 | * Allocate and initialize a kernel metadata. |
54012638 | 672 | * |
050349bb | 673 | * Return pointer to structure or NULL. |
54012638 | 674 | */ |
a4b92340 | 675 | struct ltt_kernel_metadata *trace_kernel_create_metadata(void) |
54012638 | 676 | { |
54012638 | 677 | struct ltt_kernel_metadata *lkm; |
f3ed775e | 678 | struct lttng_channel *chan; |
54012638 | 679 | |
ba7f0ae5 DG |
680 | lkm = zmalloc(sizeof(struct ltt_kernel_metadata)); |
681 | chan = zmalloc(sizeof(struct lttng_channel)); | |
f3ed775e | 682 | if (lkm == NULL || chan == NULL) { |
df0f840b | 683 | PERROR("kernel metadata zmalloc"); |
54012638 DG |
684 | goto error; |
685 | } | |
686 | ||
687 | /* Set default attributes */ | |
f3ed775e | 688 | chan->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; |
3e230f92 | 689 | chan->attr.subbuf_size = default_get_metadata_subbuf_size(); |
b389abbe | 690 | chan->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM; |
6bb9e85f MD |
691 | chan->attr.switch_timer_interval = DEFAULT_KERNEL_CHANNEL_SWITCH_TIMER; |
692 | chan->attr.read_timer_interval = DEFAULT_KERNEL_CHANNEL_READ_TIMER; | |
7d452e12 | 693 | chan->attr.output = DEFAULT_KERNEL_CHANNEL_OUTPUT; |
54012638 DG |
694 | |
695 | /* Init metadata */ | |
03550b58 | 696 | lkm->fd = -1; |
f3ed775e | 697 | lkm->conf = chan; |
54012638 DG |
698 | |
699 | return lkm; | |
700 | ||
701 | error: | |
a2c0da86 MD |
702 | free(lkm); |
703 | free(chan); | |
54012638 DG |
704 | return NULL; |
705 | } | |
706 | ||
707 | /* | |
050349bb DG |
708 | * Allocate and initialize a kernel stream. The stream is set to ACTIVE_FD by |
709 | * default. | |
54012638 | 710 | * |
050349bb | 711 | * Return pointer to structure or NULL. |
54012638 | 712 | */ |
00e2e675 DG |
713 | struct ltt_kernel_stream *trace_kernel_create_stream(const char *name, |
714 | unsigned int count) | |
54012638 | 715 | { |
00e2e675 | 716 | int ret; |
54012638 DG |
717 | struct ltt_kernel_stream *lks; |
718 | ||
0525e9ae DG |
719 | assert(name); |
720 | ||
ba7f0ae5 | 721 | lks = zmalloc(sizeof(struct ltt_kernel_stream)); |
54012638 | 722 | if (lks == NULL) { |
df0f840b | 723 | PERROR("kernel stream zmalloc"); |
54012638 DG |
724 | goto error; |
725 | } | |
726 | ||
00e2e675 | 727 | /* Set name */ |
535b8ff4 | 728 | ret = snprintf(lks->name, sizeof(lks->name), "%s_%u", name, count); |
00e2e675 DG |
729 | if (ret < 0) { |
730 | PERROR("snprintf stream name"); | |
731 | goto error; | |
732 | } | |
733 | lks->name[sizeof(lks->name) - 1] = '\0'; | |
734 | ||
54012638 | 735 | /* Init stream */ |
03550b58 | 736 | lks->fd = -1; |
54012638 | 737 | lks->state = 0; |
ffe60014 | 738 | lks->cpu = count; |
54012638 DG |
739 | |
740 | return lks; | |
741 | ||
742 | error: | |
743 | return NULL; | |
744 | } | |
c363b55d | 745 | |
050349bb DG |
746 | /* |
747 | * Cleanup kernel stream structure. | |
748 | */ | |
62499ad6 | 749 | void trace_kernel_destroy_stream(struct ltt_kernel_stream *stream) |
c363b55d | 750 | { |
0525e9ae DG |
751 | assert(stream); |
752 | ||
33a2b854 | 753 | DBG("[trace] Closing stream fd %d", stream->fd); |
c363b55d | 754 | /* Close kernel fd */ |
03550b58 | 755 | if (stream->fd >= 0) { |
c617c0c6 MD |
756 | int ret; |
757 | ||
03550b58 MD |
758 | ret = close(stream->fd); |
759 | if (ret) { | |
760 | PERROR("close"); | |
761 | } | |
799e2c4f | 762 | } |
c363b55d DG |
763 | /* Remove from stream list */ |
764 | cds_list_del(&stream->list); | |
f9815039 | 765 | |
c363b55d DG |
766 | free(stream); |
767 | } | |
768 | ||
050349bb DG |
769 | /* |
770 | * Cleanup kernel event structure. | |
771 | */ | |
62499ad6 | 772 | void trace_kernel_destroy_event(struct ltt_kernel_event *event) |
c363b55d | 773 | { |
0525e9ae DG |
774 | assert(event); |
775 | ||
87eb4ab8 | 776 | if (event->fd >= 0) { |
c617c0c6 MD |
777 | int ret; |
778 | ||
87eb4ab8 MD |
779 | DBG("[trace] Closing event fd %d", event->fd); |
780 | /* Close kernel fd */ | |
799e2c4f MD |
781 | ret = close(event->fd); |
782 | if (ret) { | |
783 | PERROR("close"); | |
784 | } | |
87eb4ab8 MD |
785 | } else { |
786 | DBG("[trace] Tearing down event (no associated fd)"); | |
787 | } | |
c363b55d DG |
788 | |
789 | /* Remove from event list */ | |
790 | cds_list_del(&event->list); | |
f9815039 | 791 | |
00a62084 MD |
792 | free(event->filter_expression); |
793 | free(event->filter); | |
794 | ||
f9815039 | 795 | free(event->event); |
c363b55d DG |
796 | free(event); |
797 | } | |
798 | ||
d3a684ee JR |
799 | /* |
800 | * Cleanup kernel event structure. | |
801 | */ | |
802 | void trace_kernel_destroy_token_event_rule(struct ltt_kernel_token_event_rule *event) | |
803 | { | |
804 | /* TODO: review in depth to ensure adequate disposing */ | |
805 | assert(event); | |
806 | ||
807 | /* Remove from event list */ | |
808 | cds_list_del(&event->list); | |
809 | ||
810 | if (event->fd >= 0) { | |
811 | int ret; | |
812 | ||
813 | DBG("[trace] Closing ,token event rule fd %d", event->fd); | |
814 | /* Close kernel fd */ | |
815 | ret = close(event->fd); | |
816 | if (ret) { | |
817 | PERROR("close"); | |
818 | } | |
819 | } else { | |
820 | DBG("[trace] Tearing down token event rule (no associated fd)"); | |
821 | } | |
822 | ||
823 | lttng_event_rule_put(event->event_rule); | |
824 | free(event); | |
825 | } | |
645328ae DG |
826 | /* |
827 | * Cleanup kernel context structure. | |
828 | */ | |
829 | void trace_kernel_destroy_context(struct ltt_kernel_context *ctx) | |
830 | { | |
831 | assert(ctx); | |
832 | ||
ba985c3a JG |
833 | if (ctx->in_list) { |
834 | cds_list_del(&ctx->list); | |
835 | } | |
645328ae DG |
836 | free(ctx); |
837 | } | |
838 | ||
050349bb DG |
839 | /* |
840 | * Cleanup kernel channel structure. | |
841 | */ | |
62499ad6 | 842 | void trace_kernel_destroy_channel(struct ltt_kernel_channel *channel) |
c363b55d | 843 | { |
af9737e9 DG |
844 | struct ltt_kernel_stream *stream, *stmp; |
845 | struct ltt_kernel_event *event, *etmp; | |
645328ae | 846 | struct ltt_kernel_context *ctx, *ctmp; |
799e2c4f | 847 | int ret; |
e9404c27 | 848 | enum lttng_error_code status; |
c363b55d | 849 | |
0525e9ae DG |
850 | assert(channel); |
851 | ||
33a2b854 | 852 | DBG("[trace] Closing channel fd %d", channel->fd); |
c363b55d | 853 | /* Close kernel fd */ |
03550b58 MD |
854 | if (channel->fd >= 0) { |
855 | ret = close(channel->fd); | |
856 | if (ret) { | |
857 | PERROR("close"); | |
858 | } | |
799e2c4f | 859 | } |
c363b55d DG |
860 | |
861 | /* For each stream in the channel list */ | |
af9737e9 | 862 | cds_list_for_each_entry_safe(stream, stmp, &channel->stream_list.head, list) { |
62499ad6 | 863 | trace_kernel_destroy_stream(stream); |
c363b55d DG |
864 | } |
865 | ||
866 | /* For each event in the channel list */ | |
af9737e9 | 867 | cds_list_for_each_entry_safe(event, etmp, &channel->events_list.head, list) { |
62499ad6 | 868 | trace_kernel_destroy_event(event); |
c363b55d DG |
869 | } |
870 | ||
645328ae DG |
871 | /* For each context in the channel list */ |
872 | cds_list_for_each_entry_safe(ctx, ctmp, &channel->ctx_list, list) { | |
873 | trace_kernel_destroy_context(ctx); | |
874 | } | |
875 | ||
c363b55d DG |
876 | /* Remove from channel list */ |
877 | cds_list_del(&channel->list); | |
f9815039 | 878 | |
753873bf JR |
879 | if (notification_thread_handle |
880 | && channel->published_to_notification_thread) { | |
63aaa3dc JG |
881 | status = notification_thread_command_remove_channel( |
882 | notification_thread_handle, | |
e1f3997a | 883 | channel->key, LTTNG_DOMAIN_KERNEL); |
63aaa3dc JG |
884 | assert(status == LTTNG_OK); |
885 | } | |
e9404c27 | 886 | free(channel->channel->attr.extended.ptr); |
f9815039 | 887 | free(channel->channel); |
c363b55d DG |
888 | free(channel); |
889 | } | |
890 | ||
050349bb DG |
891 | /* |
892 | * Cleanup kernel metadata structure. | |
893 | */ | |
62499ad6 | 894 | void trace_kernel_destroy_metadata(struct ltt_kernel_metadata *metadata) |
c363b55d | 895 | { |
0525e9ae DG |
896 | assert(metadata); |
897 | ||
33a2b854 | 898 | DBG("[trace] Closing metadata fd %d", metadata->fd); |
c363b55d | 899 | /* Close kernel fd */ |
03550b58 | 900 | if (metadata->fd >= 0) { |
c617c0c6 MD |
901 | int ret; |
902 | ||
03550b58 MD |
903 | ret = close(metadata->fd); |
904 | if (ret) { | |
905 | PERROR("close"); | |
906 | } | |
799e2c4f | 907 | } |
c363b55d | 908 | |
f9815039 | 909 | free(metadata->conf); |
c363b55d DG |
910 | free(metadata); |
911 | } | |
912 | ||
050349bb | 913 | /* |
62499ad6 | 914 | * Cleanup kernel session structure |
36b588ed MD |
915 | * |
916 | * Should *NOT* be called with RCU read-side lock held. | |
050349bb | 917 | */ |
62499ad6 | 918 | void trace_kernel_destroy_session(struct ltt_kernel_session *session) |
c363b55d | 919 | { |
af9737e9 | 920 | struct ltt_kernel_channel *channel, *ctmp; |
799e2c4f | 921 | int ret; |
c363b55d | 922 | |
0525e9ae DG |
923 | assert(session); |
924 | ||
33a2b854 | 925 | DBG("[trace] Closing session fd %d", session->fd); |
c363b55d | 926 | /* Close kernel fds */ |
03550b58 MD |
927 | if (session->fd >= 0) { |
928 | ret = close(session->fd); | |
929 | if (ret) { | |
930 | PERROR("close"); | |
931 | } | |
799e2c4f | 932 | } |
f9815039 | 933 | |
03550b58 | 934 | if (session->metadata_stream_fd >= 0) { |
70dc1c34 | 935 | DBG("[trace] Closing metadata stream fd %d", session->metadata_stream_fd); |
799e2c4f MD |
936 | ret = close(session->metadata_stream_fd); |
937 | if (ret) { | |
938 | PERROR("close"); | |
939 | } | |
70dc1c34 | 940 | } |
c363b55d | 941 | |
d36b8583 | 942 | if (session->metadata != NULL) { |
62499ad6 | 943 | trace_kernel_destroy_metadata(session->metadata); |
d36b8583 | 944 | } |
c363b55d | 945 | |
af9737e9 | 946 | cds_list_for_each_entry_safe(channel, ctmp, &session->channel_list.head, list) { |
62499ad6 | 947 | trace_kernel_destroy_channel(channel); |
c363b55d | 948 | } |
d070c424 | 949 | } |
c363b55d | 950 | |
d070c424 MD |
951 | /* Free elements needed by destroy notifiers. */ |
952 | void trace_kernel_free_session(struct ltt_kernel_session *session) | |
953 | { | |
00e2e675 | 954 | /* Wipe consumer output object */ |
6addfa37 | 955 | consumer_output_put(session->consumer); |
00e2e675 | 956 | |
55c9e7ca JR |
957 | lttng_tracker_list_destroy(session->tracker_list_pid); |
958 | lttng_tracker_list_destroy(session->tracker_list_vpid); | |
959 | lttng_tracker_list_destroy(session->tracker_list_uid); | |
960 | lttng_tracker_list_destroy(session->tracker_list_vuid); | |
961 | lttng_tracker_list_destroy(session->tracker_list_gid); | |
962 | lttng_tracker_list_destroy(session->tracker_list_vgid); | |
963 | ||
c363b55d DG |
964 | free(session); |
965 | } |