Merge branch 'master' of git://git.lttng.org/lttng-tools
[lttng-tools.git] / src / bin / lttng-sessiond / event.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #include <errno.h>
20 #include <urcu/list.h>
21 #include <string.h>
22
23 #include <lttng/lttng.h>
24 #include <common/error.h>
25 #include <common/sessiond-comm/sessiond-comm.h>
26
27 #include "channel.h"
28 #include "event.h"
29 #include "kernel.h"
30 #include "ust-ctl.h"
31 #include "ust-app.h"
32 #include "trace-kernel.h"
33 #include "trace-ust.h"
34
35 /*
36 * Setup a lttng_event used to enable *all* syscall tracing.
37 */
38 static void init_syscalls_kernel_event(struct lttng_event *event)
39 {
40 event->name[0] = '\0';
41 /*
42 * We use LTTNG_EVENT* here since the trace kernel creation will make the
43 * right changes for the kernel.
44 */
45 event->type = LTTNG_EVENT_SYSCALL;
46 }
47
48 /*
49 * Disable kernel tracepoint event for a channel from the kernel session.
50 */
51 int event_kernel_disable_tracepoint(struct ltt_kernel_session *ksession,
52 struct ltt_kernel_channel *kchan, char *event_name)
53 {
54 int ret;
55 struct ltt_kernel_event *kevent;
56
57 kevent = trace_kernel_get_event_by_name(event_name, kchan);
58 if (kevent == NULL) {
59 ret = LTTCOMM_NO_EVENT;
60 goto error;
61 }
62
63 ret = kernel_disable_event(kevent);
64 if (ret < 0) {
65 ret = LTTCOMM_KERN_DISABLE_FAIL;
66 goto error;
67 }
68
69 DBG("Kernel event %s disable for channel %s.",
70 kevent->event->name, kchan->channel->name);
71
72 ret = LTTCOMM_OK;
73
74 error:
75 return ret;
76 }
77
78 /*
79 * Disable kernel tracepoint events for a channel from the kernel session.
80 */
81 int event_kernel_disable_all_tracepoints(struct ltt_kernel_session *ksession,
82 struct ltt_kernel_channel *kchan)
83 {
84 int ret;
85 struct ltt_kernel_event *kevent;
86
87 /* For each event in the kernel session */
88 cds_list_for_each_entry(kevent, &kchan->events_list.head, list) {
89 ret = kernel_disable_event(kevent);
90 if (ret < 0) {
91 /* We continue disabling the rest */
92 continue;
93 }
94 }
95 ret = LTTCOMM_OK;
96 return ret;
97 }
98
99 /*
100 * Disable kernel syscall events for a channel from the kernel session.
101 */
102 int event_kernel_disable_all_syscalls(struct ltt_kernel_session *ksession,
103 struct ltt_kernel_channel *kchan)
104 {
105 ERR("Cannot disable syscall tracing for existing session. Please destroy session instead.");
106 return LTTCOMM_OK; /* Return OK so disable all succeeds */
107 }
108
109 /*
110 * Disable all kernel event for a channel from the kernel session.
111 */
112 int event_kernel_disable_all(struct ltt_kernel_session *ksession,
113 struct ltt_kernel_channel *kchan)
114 {
115 int ret;
116
117 ret = event_kernel_disable_all_tracepoints(ksession, kchan);
118 if (ret != LTTCOMM_OK)
119 return ret;
120 ret = event_kernel_disable_all_syscalls(ksession, kchan);
121 return ret;
122 }
123
124 /*
125 * Enable kernel tracepoint event for a channel from the kernel session.
126 */
127 int event_kernel_enable_tracepoint(struct ltt_kernel_session *ksession,
128 struct ltt_kernel_channel *kchan, struct lttng_event *event)
129 {
130 int ret;
131 struct ltt_kernel_event *kevent;
132
133 kevent = trace_kernel_get_event_by_name(event->name, kchan);
134 if (kevent == NULL) {
135 ret = kernel_create_event(event, kchan);
136 if (ret < 0) {
137 if (ret == -EEXIST) {
138 ret = LTTCOMM_KERN_EVENT_EXIST;
139 } else {
140 ret = LTTCOMM_KERN_ENABLE_FAIL;
141 }
142 goto end;
143 }
144 } else if (kevent->enabled == 0) {
145 ret = kernel_enable_event(kevent);
146 if (ret < 0) {
147 ret = LTTCOMM_KERN_ENABLE_FAIL;
148 goto end;
149 }
150 } else {
151 /* At this point, the event is considered enabled */
152 ret = LTTCOMM_KERN_EVENT_EXIST;
153 goto end;
154 }
155
156 ret = LTTCOMM_OK;
157 end:
158 return ret;
159 }
160
161 /*
162 * Enable all kernel tracepoint events of a channel of the kernel session.
163 */
164 int event_kernel_enable_all_tracepoints(struct ltt_kernel_session *ksession,
165 struct ltt_kernel_channel *kchan, int kernel_tracer_fd)
166 {
167 int size, i, ret;
168 struct ltt_kernel_event *kevent;
169 struct lttng_event *event_list = NULL;
170
171 /* For each event in the kernel session */
172 cds_list_for_each_entry(kevent, &kchan->events_list.head, list) {
173 if (kevent->enabled == 0) {
174 ret = kernel_enable_event(kevent);
175 if (ret < 0) {
176 /* Enable failed but still continue */
177 continue;
178 }
179 }
180 }
181
182 size = kernel_list_events(kernel_tracer_fd, &event_list);
183 if (size < 0) {
184 ret = LTTCOMM_KERN_LIST_FAIL;
185 goto end;
186 }
187
188 for (i = 0; i < size; i++) {
189 kevent = trace_kernel_get_event_by_name(event_list[i].name, kchan);
190 if (kevent == NULL) {
191 /* Default event type for enable all */
192 event_list[i].type = LTTNG_EVENT_TRACEPOINT;
193 /* Enable each single tracepoint event */
194 ret = kernel_create_event(&event_list[i], kchan);
195 if (ret < 0) {
196 /* Ignore error here and continue */
197 }
198 }
199 }
200 free(event_list);
201
202 ret = LTTCOMM_OK;
203 end:
204 return ret;
205
206 }
207
208 /*
209 * Enable all kernel tracepoint events of a channel of the kernel session.
210 */
211 int event_kernel_enable_all_syscalls(struct ltt_kernel_session *ksession,
212 struct ltt_kernel_channel *kchan, int kernel_tracer_fd)
213 {
214 int ret;
215 struct lttng_event event;
216
217 init_syscalls_kernel_event(&event);
218
219 DBG("Enabling all syscall tracing");
220
221 ret = kernel_create_event(&event, kchan);
222 if (ret < 0) {
223 if (ret == -EEXIST) {
224 ret = LTTCOMM_KERN_EVENT_EXIST;
225 } else {
226 ret = LTTCOMM_KERN_ENABLE_FAIL;
227 }
228 goto end;
229 }
230
231 ret = LTTCOMM_OK;
232 end:
233 return ret;
234 }
235
236 /*
237 * Enable all kernel events of a channel of the kernel session.
238 */
239 int event_kernel_enable_all(struct ltt_kernel_session *ksession,
240 struct ltt_kernel_channel *kchan, int kernel_tracer_fd)
241 {
242 int ret;
243
244 ret = event_kernel_enable_all_tracepoints(ksession, kchan, kernel_tracer_fd);
245 if (ret != LTTCOMM_OK) {
246 goto end;
247 }
248 ret = event_kernel_enable_all_syscalls(ksession, kchan, kernel_tracer_fd);
249 end:
250 return ret;
251 }
252
253 /*
254 * ============================
255 * UST : The Ultimate Frontier!
256 * ============================
257 */
258
259 /*
260 * Enable all UST tracepoints for a channel from a UST session.
261 */
262 int event_ust_enable_all_tracepoints(struct ltt_ust_session *usess, int domain,
263 struct ltt_ust_channel *uchan)
264 {
265 int ret, i;
266 size_t size;
267 struct lttng_ht_iter iter;
268 struct ltt_ust_event *uevent = NULL;
269 struct lttng_event *events = NULL;
270
271 switch (domain) {
272 case LTTNG_DOMAIN_UST:
273 {
274 /* Enable existing events */
275 cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
276 node.node) {
277 if (uevent->enabled == 0) {
278 ret = ust_app_enable_event_glb(usess, uchan, uevent);
279 if (ret < 0) {
280 continue;
281 }
282 uevent->enabled = 1;
283 }
284 }
285
286 /* Get all UST available events */
287 size = ust_app_list_events(&events);
288 if (size < 0) {
289 ret = LTTCOMM_UST_LIST_FAIL;
290 goto error;
291 }
292
293 for (i = 0; i < size; i++) {
294 /*
295 * Check if event exist and if so, continue since it was enable
296 * previously.
297 */
298 uevent = trace_ust_find_event_by_name(uchan->events,
299 events[i].name);
300 if (uevent != NULL) {
301 ret = ust_app_enable_event_pid(usess, uchan, uevent,
302 events[i].pid);
303 if (ret < 0) {
304 if (ret != -EEXIST) {
305 ret = LTTCOMM_UST_ENABLE_FAIL;
306 goto error;
307 }
308 }
309 continue;
310 }
311
312 /* Create ust event */
313 uevent = trace_ust_create_event(&events[i]);
314 if (uevent == NULL) {
315 ret = LTTCOMM_FATAL;
316 goto error_destroy;
317 }
318
319 /* Create event for the specific PID */
320 ret = ust_app_enable_event_pid(usess, uchan, uevent,
321 events[i].pid);
322 if (ret < 0) {
323 if (ret == -EEXIST) {
324 ret = LTTCOMM_UST_EVENT_EXIST;
325 goto error;
326 } else {
327 ret = LTTCOMM_UST_ENABLE_FAIL;
328 goto error_destroy;
329 }
330 }
331
332 uevent->enabled = 1;
333 /* Add ltt ust event to channel */
334 rcu_read_lock();
335 lttng_ht_add_unique_str(uchan->events, &uevent->node);
336 rcu_read_unlock();
337 }
338
339 free(events);
340 break;
341 }
342 #if 0
343 case LTTNG_DOMAIN_UST_EXEC_NAME:
344 case LTTNG_DOMAIN_UST_PID:
345 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
346 #endif
347 default:
348 ret = LTTCOMM_UND;
349 goto error;
350 }
351
352 return LTTCOMM_OK;
353
354 error_destroy:
355 trace_ust_destroy_event(uevent);
356
357 error:
358 free(events);
359 return ret;
360 }
361
362 /*
363 * Enable UST tracepoint event for a channel from a UST session.
364 */
365 int event_ust_enable_tracepoint(struct ltt_ust_session *usess, int domain,
366 struct ltt_ust_channel *uchan, struct lttng_event *event)
367 {
368 int ret = LTTCOMM_OK, to_create = 0;
369 struct ltt_ust_event *uevent;
370
371 uevent = trace_ust_find_event_by_name(uchan->events, event->name);
372 if (uevent == NULL) {
373 uevent = trace_ust_create_event(event);
374 if (uevent == NULL) {
375 ret = LTTCOMM_FATAL;
376 goto error;
377 }
378 /* Valid to set it after the goto error since uevent is still NULL */
379 to_create = 1;
380 }
381
382 if (uevent->enabled) {
383 /* It's already enabled so everything is OK */
384 goto end;
385 }
386
387 uevent->enabled = 1;
388
389 switch (domain) {
390 case LTTNG_DOMAIN_UST:
391 {
392 if (to_create) {
393 /* Create event on all UST registered apps for session */
394 ret = ust_app_create_event_glb(usess, uchan, uevent);
395 } else {
396 /* Enable event on all UST registered apps for session */
397 ret = ust_app_enable_event_glb(usess, uchan, uevent);
398 }
399
400 if (ret < 0) {
401 if (ret == -EEXIST) {
402 ret = LTTCOMM_UST_EVENT_EXIST;
403 goto end;
404 } else {
405 ret = LTTCOMM_UST_ENABLE_FAIL;
406 goto error;
407 }
408 }
409 break;
410 }
411 #if 0
412 case LTTNG_DOMAIN_UST_EXEC_NAME:
413 case LTTNG_DOMAIN_UST_PID:
414 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
415 #endif
416 default:
417 ret = LTTCOMM_UND;
418 goto end;
419 }
420
421 if (to_create) {
422 rcu_read_lock();
423 /* Add ltt ust event to channel */
424 lttng_ht_add_unique_str(uchan->events, &uevent->node);
425 rcu_read_unlock();
426 }
427
428 DBG("Event UST %s %s in channel %s", uevent->attr.name,
429 to_create ? "created" : "enabled", uchan->name);
430
431 ret = LTTCOMM_OK;
432
433 end:
434 return ret;
435
436 error:
437 /*
438 * Only destroy event on creation time (not enabling time) because if the
439 * event is found in the channel (to_create == 0), it means that at some
440 * point the enable_event worked and it's thus valid to keep it alive.
441 * Destroying it also implies that we also destroy it's shadow copy to sync
442 * everyone up.
443 */
444 if (to_create) {
445 /* In this code path, the uevent was not added to the hash table */
446 trace_ust_destroy_event(uevent);
447 }
448 return ret;
449 }
450
451 /*
452 * Disable UST tracepoint of a channel from a UST session.
453 */
454 int event_ust_disable_tracepoint(struct ltt_ust_session *usess, int domain,
455 struct ltt_ust_channel *uchan, char *event_name)
456 {
457 int ret;
458 struct ltt_ust_event *uevent;
459
460 uevent = trace_ust_find_event_by_name(uchan->events, event_name);
461 if (uevent == NULL) {
462 ret = LTTCOMM_UST_EVENT_NOT_FOUND;
463 goto error;
464 }
465
466 if (uevent->enabled == 0) {
467 /* It's already enabled so everything is OK */
468 ret = LTTCOMM_OK;
469 goto end;
470 }
471
472 switch (domain) {
473 case LTTNG_DOMAIN_UST:
474 ret = ust_app_disable_event_glb(usess, uchan, uevent);
475 if (ret < 0 && ret != -EEXIST) {
476 ret = LTTCOMM_UST_DISABLE_FAIL;
477 goto error;
478 }
479 break;
480 #if 0
481 case LTTNG_DOMAIN_UST_EXEC_NAME:
482 case LTTNG_DOMAIN_UST_PID:
483 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
484 #endif
485 default:
486 ret = LTTCOMM_UND;
487 goto error;
488 }
489
490 uevent->enabled = 0;
491 ret = LTTCOMM_OK;
492
493 end:
494 DBG2("Event UST %s disabled in channel %s", uevent->attr.name,
495 uchan->name);
496
497 error:
498 return ret;
499 }
500
501 /*
502 * Disable all UST tracepoints for a channel from a UST session.
503 */
504 int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess, int domain,
505 struct ltt_ust_channel *uchan)
506 {
507 int ret, i;
508 size_t size;
509 struct lttng_ht_iter iter;
510 struct ltt_ust_event *uevent = NULL;
511 struct lttng_event *events = NULL;
512
513 switch (domain) {
514 case LTTNG_DOMAIN_UST:
515 {
516 /* Disabling existing events */
517 cds_lfht_for_each_entry(uchan->events->ht, &iter.iter, uevent,
518 node.node) {
519 if (uevent->enabled == 1) {
520 ret = ust_app_disable_event_glb(usess, uchan, uevent);
521 if (ret < 0) {
522 continue;
523 }
524 uevent->enabled = 0;
525 }
526 }
527
528 /* Get all UST available events */
529 size = ust_app_list_events(&events);
530 if (size < 0) {
531 ret = LTTCOMM_UST_LIST_FAIL;
532 goto error;
533 }
534
535 for (i = 0; i < size; i++) {
536 uevent = trace_ust_find_event_by_name(uchan->events,
537 events[i].name);
538 if (uevent != NULL && uevent->enabled == 1) {
539 ret = ust_app_disable_event_pid(usess, uchan, uevent,
540 events[i].pid);
541 if (ret < 0 && ret != -EEXIST) {
542 ret = LTTCOMM_UST_DISABLE_FAIL;
543 goto error;
544 }
545 uevent->enabled = 0;
546 continue;
547 }
548 }
549
550 free(events);
551 break;
552 }
553 #if 0
554 case LTTNG_DOMAIN_UST_EXEC_NAME:
555 case LTTNG_DOMAIN_UST_PID:
556 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
557 #endif
558 default:
559 ret = LTTCOMM_UND;
560 goto error;
561 }
562
563 return LTTCOMM_OK;
564
565 error:
566 free(events);
567 return ret;
568 }
This page took 0.041234 seconds and 5 git commands to generate.