tracepoint: move "probe" test outside of loop
[lttng-ust.git] / liblttng-ust / tracepoint.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2008-2011 Mathieu Desnoyers
3 * Copyright (C) 2009 Pierre-Marc Fournier
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Ported to userspace by Pierre-Marc Fournier.
20 */
21
22#define _LGPL_SOURCE
23#include <errno.h>
24#include <stdint.h>
25#include <stddef.h>
26#include <stdio.h>
27
28#include <urcu/arch.h>
29#include <urcu-bp.h>
30#include <urcu/hlist.h>
31#include <urcu/uatomic.h>
32#include <urcu/compiler.h>
33
34#include <lttng/tracepoint.h>
35#include <lttng/ust-abi.h> /* for LTTNG_UST_SYM_NAME_LEN */
36
37#include <usterr-signal-safe.h>
38#include <helper.h>
39
40#include "tracepoint-internal.h"
41#include "lttng-tracer-core.h"
42#include "jhash.h"
43#include "error.h"
44
45/* Set to 1 to enable tracepoint debug output */
46static const int tracepoint_debug;
47static int initialized;
48static void (*new_tracepoint_cb)(struct tracepoint *);
49
50/*
51 * tracepoint_mutex nests inside UST mutex.
52 *
53 * Note about interaction with fork/clone: UST does not hold the
54 * tracepoint mutex across fork/clone because it is either:
55 * - nested within UST mutex, in which case holding the UST mutex across
56 * fork/clone suffice,
57 * - taken by a library constructor, which should never race with a
58 * fork/clone if the application is expected to continue running with
59 * the same memory layout (no following exec()).
60 */
61static pthread_mutex_t tracepoint_mutex = PTHREAD_MUTEX_INITIALIZER;
62
63/*
64 * libraries that contain tracepoints (struct tracepoint_lib).
65 * Protected by tracepoint mutex.
66 */
67static CDS_LIST_HEAD(libs);
68
69/*
70 * The tracepoint mutex protects the library tracepoints, the hash table, and
71 * the library list.
72 * All calls to the tracepoint API must be protected by the tracepoint mutex,
73 * excepts calls to tracepoint_register_lib and
74 * tracepoint_unregister_lib, which take the tracepoint mutex themselves.
75 */
76
77/*
78 * Tracepoint hash table, containing the active tracepoints.
79 * Protected by tracepoint mutex.
80 */
81#define TRACEPOINT_HASH_BITS 12
82#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
83static struct cds_hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
84
85static CDS_LIST_HEAD(old_probes);
86static int need_update;
87
88/*
89 * Note about RCU :
90 * It is used to to delay the free of multiple probes array until a quiescent
91 * state is reached.
92 * Tracepoint entries modifications are protected by the tracepoint mutex.
93 */
94struct tracepoint_entry {
95 struct cds_hlist_node hlist;
96 struct tracepoint_probe *probes;
97 int refcount; /* Number of times armed. 0 if disarmed. */
98 const char *signature;
99 char name[0];
100};
101
102struct tp_probes {
103 union {
104 struct cds_list_head list;
105 /* Field below only used for call_rcu scheme */
106 /* struct rcu_head head; */
107 } u;
108 struct tracepoint_probe probes[0];
109};
110
111static void *allocate_probes(int count)
112{
113 struct tp_probes *p = zmalloc(count * sizeof(struct tracepoint_probe)
114 + sizeof(struct tp_probes));
115 return p == NULL ? NULL : p->probes;
116}
117
118static void release_probes(void *old)
119{
120 if (old) {
121 struct tp_probes *tp_probes = caa_container_of(old,
122 struct tp_probes, probes[0]);
123 synchronize_rcu();
124 free(tp_probes);
125 }
126}
127
128static void debug_print_probes(struct tracepoint_entry *entry)
129{
130 int i;
131
132 if (!tracepoint_debug || !entry->probes)
133 return;
134
135 for (i = 0; entry->probes[i].func; i++)
136 DBG("Probe %d : %p", i, entry->probes[i].func);
137}
138
139static void *
140tracepoint_entry_add_probe(struct tracepoint_entry *entry,
141 void (*probe)(void), void *data)
142{
143 int nr_probes = 0;
144 struct tracepoint_probe *old, *new;
145
146 if (!probe) {
147 WARN_ON(1);
148 return ERR_PTR(-EINVAL);
149 }
150 debug_print_probes(entry);
151 old = entry->probes;
152 if (old) {
153 /* (N -> N+1), (N != 0, 1) probes */
154 for (nr_probes = 0; old[nr_probes].func; nr_probes++)
155 if (old[nr_probes].func == probe &&
156 old[nr_probes].data == data)
157 return ERR_PTR(-EEXIST);
158 }
159 /* + 2 : one for new probe, one for NULL func */
160 new = allocate_probes(nr_probes + 2);
161 if (new == NULL)
162 return ERR_PTR(-ENOMEM);
163 if (old)
164 memcpy(new, old, nr_probes * sizeof(struct tracepoint_probe));
165 new[nr_probes].func = probe;
166 new[nr_probes].data = data;
167 new[nr_probes + 1].func = NULL;
168 entry->refcount = nr_probes + 1;
169 entry->probes = new;
170 debug_print_probes(entry);
171 return old;
172}
173
174static void *
175tracepoint_entry_remove_probe(struct tracepoint_entry *entry,
176 void (*probe)(void), void *data)
177{
178 int nr_probes = 0, nr_del = 0, i;
179 struct tracepoint_probe *old, *new;
180
181 old = entry->probes;
182
183 if (!old)
184 return ERR_PTR(-ENOENT);
185
186 debug_print_probes(entry);
187 /* (N -> M), (N > 1, M >= 0) probes */
188 if (probe) {
189 for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
190 if (old[nr_probes].func == probe &&
191 old[nr_probes].data == data)
192 nr_del++;
193 }
194 } else {
195 nr_del = nr_probes;
196 }
197
198 if (nr_probes - nr_del == 0) {
199 /* N -> 0, (N > 1) */
200 entry->probes = NULL;
201 entry->refcount = 0;
202 debug_print_probes(entry);
203 return old;
204 } else {
205 int j = 0;
206 /* N -> M, (N > 1, M > 0) */
207 /* + 1 for NULL */
208 new = allocate_probes(nr_probes - nr_del + 1);
209 if (new == NULL)
210 return ERR_PTR(-ENOMEM);
211 for (i = 0; old[i].func; i++)
212 if (old[i].func != probe || old[i].data != data)
213 new[j++] = old[i];
214 new[nr_probes - nr_del].func = NULL;
215 entry->refcount = nr_probes - nr_del;
216 entry->probes = new;
217 }
218 debug_print_probes(entry);
219 return old;
220}
221
222/*
223 * Get tracepoint if the tracepoint is present in the tracepoint hash table.
224 * Must be called with tracepoint mutex held.
225 * Returns NULL if not present.
226 */
227static struct tracepoint_entry *get_tracepoint(const char *name)
228{
229 struct cds_hlist_head *head;
230 struct cds_hlist_node *node;
231 struct tracepoint_entry *e;
232 size_t name_len = strlen(name);
233 uint32_t hash;
234
235 if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
236 WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
237 name_len = LTTNG_UST_SYM_NAME_LEN - 1;
238 }
239 hash = jhash(name, name_len, 0);
240 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
241 cds_hlist_for_each_entry(e, node, head, hlist) {
242 if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1))
243 return e;
244 }
245 return NULL;
246}
247
248/*
249 * Add the tracepoint to the tracepoint hash table. Must be called with
250 * tracepoint mutex held.
251 */
252static struct tracepoint_entry *add_tracepoint(const char *name,
253 const char *signature)
254{
255 struct cds_hlist_head *head;
256 struct cds_hlist_node *node;
257 struct tracepoint_entry *e;
258 size_t name_len = strlen(name);
259 uint32_t hash;
260
261 if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
262 WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
263 name_len = LTTNG_UST_SYM_NAME_LEN - 1;
264 }
265 hash = jhash(name, name_len, 0);
266 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
267 cds_hlist_for_each_entry(e, node, head, hlist) {
268 if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) {
269 DBG("tracepoint %s busy", name);
270 return ERR_PTR(-EEXIST); /* Already there */
271 }
272 }
273 /*
274 * Using zmalloc here to allocate a variable length element. Could
275 * cause some memory fragmentation if overused.
276 */
277 e = zmalloc(sizeof(struct tracepoint_entry) + name_len + 1);
278 if (!e)
279 return ERR_PTR(-ENOMEM);
280 memcpy(&e->name[0], name, name_len + 1);
281 e->name[name_len] = '\0';
282 e->probes = NULL;
283 e->refcount = 0;
284 e->signature = signature;
285 cds_hlist_add_head(&e->hlist, head);
286 return e;
287}
288
289/*
290 * Remove the tracepoint from the tracepoint hash table. Must be called with
291 * tracepoint mutex held.
292 */
293static void remove_tracepoint(struct tracepoint_entry *e)
294{
295 cds_hlist_del(&e->hlist);
296 free(e);
297}
298
299/*
300 * Sets the probe callback corresponding to one tracepoint.
301 */
302static void set_tracepoint(struct tracepoint_entry **entry,
303 struct tracepoint *elem, int active)
304{
305 WARN_ON(strncmp((*entry)->name, elem->name, LTTNG_UST_SYM_NAME_LEN - 1) != 0);
306 /*
307 * Check that signatures match before connecting a probe to a
308 * tracepoint. Warn the user if they don't.
309 */
310 if (strcmp(elem->signature, (*entry)->signature) != 0) {
311 static int warned = 0;
312
313 /* Only print once, don't flood console. */
314 if (!warned) {
315 WARN("Tracepoint signature mismatch, not enabling one or more tracepoints. Ensure that the tracepoint probes prototypes match the application.");
316 WARN("Tracepoint \"%s\" signatures: call: \"%s\" vs probe: \"%s\".",
317 elem->name, elem->signature, (*entry)->signature);
318 warned = 1;
319 }
320 /* Don't accept connecting non-matching signatures. */
321 return;
322 }
323
324 /*
325 * rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new
326 * probe callbacks array is consistent before setting a pointer to it.
327 * This array is referenced by __DO_TRACE from
328 * include/linux/tracepoints.h. A matching cmm_smp_read_barrier_depends()
329 * is used.
330 */
331 rcu_assign_pointer(elem->probes, (*entry)->probes);
332 elem->state = active;
333}
334
335/*
336 * Disable a tracepoint and its probe callback.
337 * Note: only waiting an RCU period after setting elem->call to the empty
338 * function insures that the original callback is not used anymore. This insured
339 * by preempt_disable around the call site.
340 */
341static void disable_tracepoint(struct tracepoint *elem)
342{
343 elem->state = 0;
344 rcu_assign_pointer(elem->probes, NULL);
345}
346
347/**
348 * tracepoint_update_probe_range - Update a probe range
349 * @begin: beginning of the range
350 * @end: end of the range
351 *
352 * Updates the probe callback corresponding to a range of tracepoints.
353 */
354static
355void tracepoint_update_probe_range(struct tracepoint * const *begin,
356 struct tracepoint * const *end)
357{
358 struct tracepoint * const *iter;
359 struct tracepoint_entry *mark_entry;
360
361 for (iter = begin; iter < end; iter++) {
362 if (!*iter)
363 continue; /* skip dummy */
364 if (!(*iter)->name) {
365 disable_tracepoint(*iter);
366 continue;
367 }
368 mark_entry = get_tracepoint((*iter)->name);
369 if (mark_entry) {
370 set_tracepoint(&mark_entry, *iter,
371 !!mark_entry->refcount);
372 } else {
373 disable_tracepoint(*iter);
374 }
375 }
376}
377
378static void lib_update_tracepoints(void)
379{
380 struct tracepoint_lib *lib;
381
382 cds_list_for_each_entry(lib, &libs, list) {
383 tracepoint_update_probe_range(lib->tracepoints_start,
384 lib->tracepoints_start + lib->tracepoints_count);
385 }
386}
387
388/*
389 * Update probes, removing the faulty probes.
390 */
391static void tracepoint_update_probes(void)
392{
393 /* tracepoints registered from libraries and executable. */
394 lib_update_tracepoints();
395}
396
397static struct tracepoint_probe *
398tracepoint_add_probe(const char *name, void (*probe)(void), void *data,
399 const char *signature)
400{
401 struct tracepoint_entry *entry;
402 struct tracepoint_probe *old;
403
404 entry = get_tracepoint(name);
405 if (!entry) {
406 entry = add_tracepoint(name, signature);
407 if (IS_ERR(entry))
408 return (struct tracepoint_probe *)entry;
409 }
410 old = tracepoint_entry_add_probe(entry, probe, data);
411 if (IS_ERR(old) && !entry->refcount)
412 remove_tracepoint(entry);
413 return old;
414}
415
416/**
417 * __tracepoint_probe_register - Connect a probe to a tracepoint
418 * @name: tracepoint name
419 * @probe: probe handler
420 *
421 * Returns 0 if ok, error value on error.
422 * The probe address must at least be aligned on the architecture pointer size.
423 * Called with the tracepoint mutex held.
424 */
425int __tracepoint_probe_register(const char *name, void (*probe)(void),
426 void *data, const char *signature)
427{
428 void *old;
429 int ret = 0;
430
431 DBG("Registering probe to tracepoint %s", name);
432
433 pthread_mutex_lock(&tracepoint_mutex);
434 old = tracepoint_add_probe(name, probe, data, signature);
435 if (IS_ERR(old)) {
436 ret = PTR_ERR(old);
437 goto end;
438 }
439
440 tracepoint_update_probes(); /* may update entry */
441 release_probes(old);
442end:
443 pthread_mutex_unlock(&tracepoint_mutex);
444 return ret;
445}
446
447static void *tracepoint_remove_probe(const char *name, void (*probe)(void),
448 void *data)
449{
450 struct tracepoint_entry *entry;
451 void *old;
452
453 entry = get_tracepoint(name);
454 if (!entry)
455 return ERR_PTR(-ENOENT);
456 old = tracepoint_entry_remove_probe(entry, probe, data);
457 if (IS_ERR(old))
458 return old;
459 if (!entry->refcount)
460 remove_tracepoint(entry);
461 return old;
462}
463
464/**
465 * tracepoint_probe_unregister - Disconnect a probe from a tracepoint
466 * @name: tracepoint name
467 * @probe: probe function pointer
468 * @probe: probe data pointer
469 */
470int __tracepoint_probe_unregister(const char *name, void (*probe)(void),
471 void *data)
472{
473 void *old;
474 int ret = 0;
475
476 DBG("Un-registering probe from tracepoint %s", name);
477
478 pthread_mutex_lock(&tracepoint_mutex);
479 old = tracepoint_remove_probe(name, probe, data);
480 if (IS_ERR(old)) {
481 ret = PTR_ERR(old);
482 goto end;
483 }
484 tracepoint_update_probes(); /* may update entry */
485 release_probes(old);
486end:
487 pthread_mutex_unlock(&tracepoint_mutex);
488 return ret;
489}
490
491static void tracepoint_add_old_probes(void *old)
492{
493 need_update = 1;
494 if (old) {
495 struct tp_probes *tp_probes = caa_container_of(old,
496 struct tp_probes, probes[0]);
497 cds_list_add(&tp_probes->u.list, &old_probes);
498 }
499}
500
501/**
502 * tracepoint_probe_register_noupdate - register a probe but not connect
503 * @name: tracepoint name
504 * @probe: probe handler
505 *
506 * caller must call tracepoint_probe_update_all()
507 */
508int tracepoint_probe_register_noupdate(const char *name, void (*probe)(void),
509 void *data, const char *signature)
510{
511 void *old;
512 int ret = 0;
513
514 pthread_mutex_lock(&tracepoint_mutex);
515 old = tracepoint_add_probe(name, probe, data, signature);
516 if (IS_ERR(old)) {
517 ret = PTR_ERR(old);
518 goto end;
519 }
520 tracepoint_add_old_probes(old);
521end:
522 pthread_mutex_unlock(&tracepoint_mutex);
523 return ret;
524}
525
526/**
527 * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect
528 * @name: tracepoint name
529 * @probe: probe function pointer
530 *
531 * caller must call tracepoint_probe_update_all()
532 * Called with the tracepoint mutex held.
533 */
534int tracepoint_probe_unregister_noupdate(const char *name, void (*probe)(void),
535 void *data)
536{
537 void *old;
538 int ret = 0;
539
540 DBG("Un-registering probe from tracepoint %s", name);
541
542 pthread_mutex_lock(&tracepoint_mutex);
543 old = tracepoint_remove_probe(name, probe, data);
544 if (IS_ERR(old)) {
545 ret = PTR_ERR(old);
546 goto end;
547 }
548 tracepoint_add_old_probes(old);
549end:
550 pthread_mutex_unlock(&tracepoint_mutex);
551 return ret;
552}
553
554/**
555 * tracepoint_probe_update_all - update tracepoints
556 */
557void tracepoint_probe_update_all(void)
558{
559 CDS_LIST_HEAD(release_probes);
560 struct tp_probes *pos, *next;
561
562 pthread_mutex_lock(&tracepoint_mutex);
563 if (!need_update) {
564 goto end;
565 }
566 if (!cds_list_empty(&old_probes))
567 cds_list_replace_init(&old_probes, &release_probes);
568 need_update = 0;
569
570 tracepoint_update_probes();
571 cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) {
572 cds_list_del(&pos->u.list);
573 synchronize_rcu();
574 free(pos);
575 }
576end:
577 pthread_mutex_unlock(&tracepoint_mutex);
578}
579
580void tracepoint_set_new_tracepoint_cb(void (*cb)(struct tracepoint *))
581{
582 new_tracepoint_cb = cb;
583}
584
585static void new_tracepoints(struct tracepoint * const *start, struct tracepoint * const *end)
586{
587 if (new_tracepoint_cb) {
588 struct tracepoint * const *t;
589
590 for (t = start; t < end; t++) {
591 if (*t)
592 new_tracepoint_cb(*t);
593 }
594 }
595}
596
597static
598void lib_disable_tracepoints(struct tracepoint * const *begin,
599 struct tracepoint * const *end)
600{
601 struct tracepoint * const *iter;
602
603 for (iter = begin; iter < end; iter++) {
604 if (!*iter)
605 continue; /* skip dummy */
606 disable_tracepoint(*iter);
607 }
608
609}
610
611int tracepoint_register_lib(struct tracepoint * const *tracepoints_start,
612 int tracepoints_count)
613{
614 struct tracepoint_lib *pl, *iter;
615
616 init_tracepoint();
617
618 pl = (struct tracepoint_lib *) zmalloc(sizeof(struct tracepoint_lib));
619
620 pl->tracepoints_start = tracepoints_start;
621 pl->tracepoints_count = tracepoints_count;
622
623 pthread_mutex_lock(&tracepoint_mutex);
624 /*
625 * We sort the libs by struct lib pointer address.
626 */
627 cds_list_for_each_entry_reverse(iter, &libs, list) {
628 BUG_ON(iter == pl); /* Should never be in the list twice */
629 if (iter < pl) {
630 /* We belong to the location right after iter. */
631 cds_list_add(&pl->list, &iter->list);
632 goto lib_added;
633 }
634 }
635 /* We should be added at the head of the list */
636 cds_list_add(&pl->list, &libs);
637lib_added:
638 new_tracepoints(tracepoints_start, tracepoints_start + tracepoints_count);
639
640 /* TODO: update just the loaded lib */
641 lib_update_tracepoints();
642 pthread_mutex_unlock(&tracepoint_mutex);
643
644 DBG("just registered a tracepoints section from %p and having %d tracepoints",
645 tracepoints_start, tracepoints_count);
646 if (ust_debug()) {
647 int i;
648
649 for (i = 0; i < tracepoints_count; i++) {
650 DBG("registered tracepoint: %s", tracepoints_start[i]->name);
651 }
652 }
653
654 return 0;
655}
656
657int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start)
658{
659 struct tracepoint_lib *lib;
660 int tracepoints_count;
661
662 pthread_mutex_lock(&tracepoint_mutex);
663 cds_list_for_each_entry(lib, &libs, list) {
664 if (lib->tracepoints_start == tracepoints_start) {
665 struct tracepoint_lib *lib2free = lib;
666
667 cds_list_del(&lib->list);
668 tracepoints_count = lib->tracepoints_count;
669 free(lib2free);
670 goto found;
671 }
672 }
673 goto end;
674found:
675 /*
676 * Force tracepoint disarm for all tracepoints of this lib.
677 * This takes care of destructor of library that would leave a
678 * LD_PRELOAD wrapper override function enabled for tracing, but
679 * the session teardown would not be able to reach the
680 * tracepoint anymore to disable it.
681 */
682 lib_disable_tracepoints(tracepoints_start,
683 tracepoints_start + tracepoints_count);
684 DBG("just unregistered a tracepoints section from %p",
685 tracepoints_start);
686end:
687 pthread_mutex_unlock(&tracepoint_mutex);
688 return 0;
689}
690
691void init_tracepoint(void)
692{
693 if (uatomic_xchg(&initialized, 1) == 1)
694 return;
695 init_usterr();
696}
697
698void exit_tracepoint(void)
699{
700 initialized = 0;
701}
702
703/*
704 * Create the wrapper symbols.
705 */
706#undef tp_rcu_read_lock_bp
707#undef tp_rcu_read_unlock_bp
708#undef tp_rcu_dereference_bp
709
710void tp_rcu_read_lock_bp(void)
711{
712 rcu_read_lock_bp();
713}
714
715void tp_rcu_read_unlock_bp(void)
716{
717 rcu_read_unlock_bp();
718}
719
720void *tp_rcu_dereference_sym_bp(void *p)
721{
722 return rcu_dereference_bp(p);
723}
This page took 0.025642 seconds and 4 git commands to generate.