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