ust-fd: Add close_range declaration
[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/urcu-bp.h>
30#include <urcu/hlist.h>
31#include <urcu/uatomic.h>
32#include <urcu/compiler.h>
33#include <urcu/system.h>
34
35#include <lttng/tracepoint.h>
36#include <lttng/ust-abi.h> /* for LTTNG_UST_SYM_NAME_LEN */
37
38#include <usterr-signal-safe.h>
39#include <helper.h>
40
41#include "tracepoint-internal.h"
42#include "lttng-tracer-core.h"
43#include "jhash.h"
44#include "error.h"
45
46/* Test compiler support for weak symbols with hidden visibility. */
47int __tracepoint_test_symbol1 __attribute__((weak, visibility("hidden")));
48void *__tracepoint_test_symbol2 __attribute__((weak, visibility("hidden")));
49struct {
50 char a[24];
51} __tracepoint_test_symbol3 __attribute__((weak, visibility("hidden")));
52
53/* Set to 1 to enable tracepoint debug output */
54static const int tracepoint_debug;
55static int initialized;
56
57/*
58 * If tracepoint_destructors_state = 1, tracepoint destructors are
59 * enabled. They are disabled otherwise.
60 */
61static int tracepoint_destructors_state = 1;
62
63/*
64 * Expose the now deprecated symbol __tracepoints__disable_destructors for
65 * backward compatibility of applications built against old versions of
66 * lttng-ust. We need to keep __tracepoints__disable_destructors up to date
67 * within the new destructor disabling API because old applications read this
68 * symbol directly.
69 */
70int __tracepoints__disable_destructors __attribute__((weak));
71
72static void (*new_tracepoint_cb)(struct lttng_ust_tracepoint *);
73
74/*
75 * tracepoint_mutex nests inside UST mutex.
76 *
77 * Note about interaction with fork/clone: UST does not hold the
78 * tracepoint mutex across fork/clone because it is either:
79 * - nested within UST mutex, in which case holding the UST mutex across
80 * fork/clone suffice,
81 * - taken by a library constructor, which should never race with a
82 * fork/clone if the application is expected to continue running with
83 * the same memory layout (no following exec()).
84 */
85static pthread_mutex_t tracepoint_mutex = PTHREAD_MUTEX_INITIALIZER;
86
87/*
88 * libraries that contain tracepoints (struct tracepoint_lib).
89 * Protected by tracepoint mutex.
90 */
91static CDS_LIST_HEAD(libs);
92
93/*
94 * The tracepoint mutex protects the library tracepoints, the hash table, and
95 * the library list.
96 * All calls to the tracepoint API must be protected by the tracepoint mutex,
97 * excepts calls to tracepoint_register_lib and
98 * tracepoint_unregister_lib, which take the tracepoint mutex themselves.
99 */
100
101/*
102 * Tracepoint hash table, containing the active tracepoints.
103 * Protected by tracepoint mutex.
104 */
105#define TRACEPOINT_HASH_BITS 12
106#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
107static struct cds_hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
108
109static CDS_LIST_HEAD(old_probes);
110static int need_update;
111
112static CDS_LIST_HEAD(release_queue);
113static int release_queue_need_update;
114
115/*
116 * Note about RCU :
117 * It is used to to delay the free of multiple probes array until a quiescent
118 * state is reached.
119 * Tracepoint entries modifications are protected by the tracepoint mutex.
120 */
121struct tracepoint_entry {
122 struct cds_hlist_node hlist;
123 struct lttng_ust_tracepoint_probe *probes;
124 int refcount; /* Number of times armed. 0 if disarmed. */
125 int callsite_refcount; /* how many libs use this tracepoint */
126 char *signature;
127 char *name;
128};
129
130struct tp_probes {
131 union {
132 struct cds_list_head list;
133 /* Field below only used for call_rcu scheme */
134 /* struct rcu_head head; */
135 } u;
136 struct lttng_ust_tracepoint_probe probes[0];
137};
138
139/*
140 * Callsite hash table, containing the tracepoint call sites.
141 * Protected by tracepoint mutex.
142 */
143#define CALLSITE_HASH_BITS 12
144#define CALLSITE_TABLE_SIZE (1 << CALLSITE_HASH_BITS)
145static struct cds_hlist_head callsite_table[CALLSITE_TABLE_SIZE];
146
147struct callsite_entry {
148 struct cds_hlist_node hlist; /* hash table node */
149 struct cds_list_head node; /* lib list of callsites node */
150 struct lttng_ust_tracepoint *tp;
151 bool tp_entry_callsite_ref; /* Has a tp_entry took a ref on this callsite */
152};
153
154/* coverity[+alloc] */
155static void *allocate_probes(int count)
156{
157 struct tp_probes *p =
158 zmalloc(count * sizeof(struct lttng_ust_tracepoint_probe)
159 + sizeof(struct tp_probes));
160 return p == NULL ? NULL : p->probes;
161}
162
163/* coverity[+free : arg-0] */
164static void release_probes(void *old)
165{
166 if (old) {
167 struct tp_probes *tp_probes = caa_container_of(old,
168 struct tp_probes, probes[0]);
169 urcu_bp_synchronize_rcu();
170 free(tp_probes);
171 }
172}
173
174static void debug_print_probes(struct tracepoint_entry *entry)
175{
176 int i;
177
178 if (!tracepoint_debug || !entry->probes)
179 return;
180
181 for (i = 0; entry->probes[i].func; i++)
182 DBG("Probe %d : %p", i, entry->probes[i].func);
183}
184
185static void *
186tracepoint_entry_add_probe(struct tracepoint_entry *entry,
187 void (*probe)(void), void *data)
188{
189 int nr_probes = 0;
190 struct lttng_ust_tracepoint_probe *old, *new;
191
192 if (!probe) {
193 WARN_ON(1);
194 return ERR_PTR(-EINVAL);
195 }
196 debug_print_probes(entry);
197 old = entry->probes;
198 if (old) {
199 /* (N -> N+1), (N != 0, 1) probes */
200 for (nr_probes = 0; old[nr_probes].func; nr_probes++)
201 if (old[nr_probes].func == probe &&
202 old[nr_probes].data == data)
203 return ERR_PTR(-EEXIST);
204 }
205 /* + 2 : one for new probe, one for NULL func */
206 new = allocate_probes(nr_probes + 2);
207 if (new == NULL)
208 return ERR_PTR(-ENOMEM);
209 if (old)
210 memcpy(new, old,
211 nr_probes * sizeof(struct lttng_ust_tracepoint_probe));
212 new[nr_probes].func = probe;
213 new[nr_probes].data = data;
214 new[nr_probes + 1].func = NULL;
215 entry->refcount = nr_probes + 1;
216 entry->probes = new;
217 debug_print_probes(entry);
218 return old;
219}
220
221static void *
222tracepoint_entry_remove_probe(struct tracepoint_entry *entry,
223 void (*probe)(void), void *data)
224{
225 int nr_probes = 0, nr_del = 0, i;
226 struct lttng_ust_tracepoint_probe *old, *new;
227
228 old = entry->probes;
229
230 if (!old)
231 return ERR_PTR(-ENOENT);
232
233 debug_print_probes(entry);
234 /* (N -> M), (N > 1, M >= 0) probes */
235 if (probe) {
236 for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
237 if (old[nr_probes].func == probe &&
238 old[nr_probes].data == data)
239 nr_del++;
240 }
241 }
242
243 if (nr_probes - nr_del == 0) {
244 /* N -> 0, (N > 1) */
245 entry->probes = NULL;
246 entry->refcount = 0;
247 debug_print_probes(entry);
248 return old;
249 } else {
250 int j = 0;
251 /* N -> M, (N > 1, M > 0) */
252 /* + 1 for NULL */
253 new = allocate_probes(nr_probes - nr_del + 1);
254 if (new == NULL)
255 return ERR_PTR(-ENOMEM);
256 for (i = 0; old[i].func; i++)
257 if (old[i].func != probe || old[i].data != data)
258 new[j++] = old[i];
259 new[nr_probes - nr_del].func = NULL;
260 entry->refcount = nr_probes - nr_del;
261 entry->probes = new;
262 }
263 debug_print_probes(entry);
264 return old;
265}
266
267/*
268 * Get tracepoint if the tracepoint is present in the tracepoint hash table.
269 * Must be called with tracepoint mutex held.
270 * Returns NULL if not present.
271 */
272static struct tracepoint_entry *get_tracepoint(const char *name)
273{
274 struct cds_hlist_head *head;
275 struct cds_hlist_node *node;
276 struct tracepoint_entry *e;
277 size_t name_len = strlen(name);
278 uint32_t hash;
279
280 if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
281 WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
282 name_len = LTTNG_UST_SYM_NAME_LEN - 1;
283 }
284 hash = jhash(name, name_len, 0);
285 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
286 cds_hlist_for_each_entry(e, node, head, hlist) {
287 if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1))
288 return e;
289 }
290 return NULL;
291}
292
293/*
294 * Add the tracepoint to the tracepoint hash table. Must be called with
295 * tracepoint mutex held.
296 */
297static struct tracepoint_entry *add_tracepoint(const char *name,
298 const char *signature)
299{
300 struct cds_hlist_head *head;
301 struct cds_hlist_node *node;
302 struct tracepoint_entry *e;
303 size_t name_len = strlen(name);
304 size_t sig_len = strlen(signature);
305 size_t sig_off, name_off;
306 uint32_t hash;
307
308 if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
309 WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
310 name_len = LTTNG_UST_SYM_NAME_LEN - 1;
311 }
312 hash = jhash(name, name_len, 0);
313 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
314 cds_hlist_for_each_entry(e, node, head, hlist) {
315 if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) {
316 DBG("tracepoint %s busy", name);
317 return ERR_PTR(-EEXIST); /* Already there */
318 }
319 }
320
321 /*
322 * Using zmalloc here to allocate a variable length elements: name and
323 * signature. Could cause some memory fragmentation if overused.
324 */
325 name_off = sizeof(struct tracepoint_entry);
326 sig_off = name_off + name_len + 1;
327
328 e = zmalloc(sizeof(struct tracepoint_entry) + name_len + 1 + sig_len + 1);
329 if (!e)
330 return ERR_PTR(-ENOMEM);
331 e->name = (char *) e + name_off;
332 memcpy(e->name, name, name_len + 1);
333 e->name[name_len] = '\0';
334
335 e->signature = (char *) e + sig_off;
336 memcpy(e->signature, signature, sig_len + 1);
337 e->signature[sig_len] = '\0';
338
339 e->probes = NULL;
340 e->refcount = 0;
341 e->callsite_refcount = 0;
342
343 cds_hlist_add_head(&e->hlist, head);
344 return e;
345}
346
347/*
348 * Remove the tracepoint from the tracepoint hash table. Must be called with
349 * tracepoint mutex held.
350 */
351static void remove_tracepoint(struct tracepoint_entry *e)
352{
353 cds_hlist_del(&e->hlist);
354 free(e);
355}
356
357/*
358 * Sets the probe callback corresponding to one tracepoint.
359 */
360static void set_tracepoint(struct tracepoint_entry **entry,
361 struct lttng_ust_tracepoint *elem, int active)
362{
363 WARN_ON(strncmp((*entry)->name, elem->name, LTTNG_UST_SYM_NAME_LEN - 1) != 0);
364 /*
365 * Check that signatures match before connecting a probe to a
366 * tracepoint. Warn the user if they don't.
367 */
368 if (strcmp(elem->signature, (*entry)->signature) != 0) {
369 static int warned = 0;
370
371 /* Only print once, don't flood console. */
372 if (!warned) {
373 WARN("Tracepoint signature mismatch, not enabling one or more tracepoints. Ensure that the tracepoint probes prototypes match the application.");
374 WARN("Tracepoint \"%s\" signatures: call: \"%s\" vs probe: \"%s\".",
375 elem->name, elem->signature, (*entry)->signature);
376 warned = 1;
377 }
378 /* Don't accept connecting non-matching signatures. */
379 return;
380 }
381
382 /*
383 * rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new
384 * probe callbacks array is consistent before setting a pointer to it.
385 * This array is referenced by __DO_TRACE from
386 * include/linux/tracepoints.h. A matching cmm_smp_read_barrier_depends()
387 * is used.
388 */
389 rcu_assign_pointer(elem->probes, (*entry)->probes);
390 CMM_STORE_SHARED(elem->state, active);
391}
392
393/*
394 * Disable a tracepoint and its probe callback.
395 * Note: only waiting an RCU period after setting elem->call to the empty
396 * function insures that the original callback is not used anymore. This insured
397 * by preempt_disable around the call site.
398 */
399static void disable_tracepoint(struct lttng_ust_tracepoint *elem)
400{
401 CMM_STORE_SHARED(elem->state, 0);
402 rcu_assign_pointer(elem->probes, NULL);
403}
404
405/*
406 * Add the callsite to the callsite hash table. Must be called with
407 * tracepoint mutex held.
408 */
409static void add_callsite(struct tracepoint_lib * lib, struct lttng_ust_tracepoint *tp)
410{
411 struct cds_hlist_head *head;
412 struct callsite_entry *e;
413 const char *name = tp->name;
414 size_t name_len = strlen(name);
415 uint32_t hash;
416 struct tracepoint_entry *tp_entry;
417
418 if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
419 WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
420 name_len = LTTNG_UST_SYM_NAME_LEN - 1;
421 }
422 hash = jhash(name, name_len, 0);
423 head = &callsite_table[hash & (CALLSITE_TABLE_SIZE - 1)];
424 e = zmalloc(sizeof(struct callsite_entry));
425 if (!e) {
426 PERROR("Unable to add callsite for tracepoint \"%s\"", name);
427 return;
428 }
429 cds_hlist_add_head(&e->hlist, head);
430 e->tp = tp;
431 cds_list_add(&e->node, &lib->callsites);
432
433 tp_entry = get_tracepoint(name);
434 if (!tp_entry)
435 return;
436 tp_entry->callsite_refcount++;
437 e->tp_entry_callsite_ref = true;
438}
439
440/*
441 * Remove the callsite from the callsite hash table and from lib
442 * callsite list. Must be called with tracepoint mutex held.
443 */
444static void remove_callsite(struct callsite_entry *e)
445{
446 struct tracepoint_entry *tp_entry;
447
448 tp_entry = get_tracepoint(e->tp->name);
449 if (tp_entry) {
450 if (e->tp_entry_callsite_ref)
451 tp_entry->callsite_refcount--;
452 if (tp_entry->callsite_refcount == 0)
453 disable_tracepoint(e->tp);
454 }
455 cds_hlist_del(&e->hlist);
456 cds_list_del(&e->node);
457 free(e);
458}
459
460/*
461 * Enable/disable all callsites based on the state of a specific
462 * tracepoint entry.
463 * Must be called with tracepoint mutex held.
464 */
465static void tracepoint_sync_callsites(const char *name)
466{
467 struct cds_hlist_head *head;
468 struct cds_hlist_node *node;
469 struct callsite_entry *e;
470 size_t name_len = strlen(name);
471 uint32_t hash;
472 struct tracepoint_entry *tp_entry;
473
474 tp_entry = get_tracepoint(name);
475 if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
476 WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
477 name_len = LTTNG_UST_SYM_NAME_LEN - 1;
478 }
479 hash = jhash(name, name_len, 0);
480 head = &callsite_table[hash & (CALLSITE_TABLE_SIZE - 1)];
481 cds_hlist_for_each_entry(e, node, head, hlist) {
482 struct lttng_ust_tracepoint *tp = e->tp;
483
484 if (strncmp(name, tp->name, LTTNG_UST_SYM_NAME_LEN - 1))
485 continue;
486 if (tp_entry) {
487 if (!e->tp_entry_callsite_ref) {
488 tp_entry->callsite_refcount++;
489 e->tp_entry_callsite_ref = true;
490 }
491 set_tracepoint(&tp_entry, tp,
492 !!tp_entry->refcount);
493 } else {
494 disable_tracepoint(tp);
495 e->tp_entry_callsite_ref = false;
496 }
497 }
498}
499
500/**
501 * tracepoint_update_probe_range - Update a probe range
502 * @begin: beginning of the range
503 * @end: end of the range
504 *
505 * Updates the probe callback corresponding to a range of tracepoints.
506 */
507static
508void tracepoint_update_probe_range(struct lttng_ust_tracepoint * const *begin,
509 struct lttng_ust_tracepoint * const *end)
510{
511 struct lttng_ust_tracepoint * const *iter;
512 struct tracepoint_entry *mark_entry;
513
514 for (iter = begin; iter < end; iter++) {
515 if (!*iter)
516 continue; /* skip dummy */
517 if (!(*iter)->name) {
518 disable_tracepoint(*iter);
519 continue;
520 }
521 mark_entry = get_tracepoint((*iter)->name);
522 if (mark_entry) {
523 set_tracepoint(&mark_entry, *iter,
524 !!mark_entry->refcount);
525 } else {
526 disable_tracepoint(*iter);
527 }
528 }
529}
530
531static void lib_update_tracepoints(struct tracepoint_lib *lib)
532{
533 tracepoint_update_probe_range(lib->tracepoints_start,
534 lib->tracepoints_start + lib->tracepoints_count);
535}
536
537static void lib_register_callsites(struct tracepoint_lib *lib)
538{
539 struct lttng_ust_tracepoint * const *begin;
540 struct lttng_ust_tracepoint * const *end;
541 struct lttng_ust_tracepoint * const *iter;
542
543 begin = lib->tracepoints_start;
544 end = lib->tracepoints_start + lib->tracepoints_count;
545
546 for (iter = begin; iter < end; iter++) {
547 if (!*iter)
548 continue; /* skip dummy */
549 if (!(*iter)->name) {
550 continue;
551 }
552 add_callsite(lib, *iter);
553 }
554}
555
556static void lib_unregister_callsites(struct tracepoint_lib *lib)
557{
558 struct callsite_entry *callsite, *tmp;
559
560 cds_list_for_each_entry_safe(callsite, tmp, &lib->callsites, node)
561 remove_callsite(callsite);
562}
563
564/*
565 * Update probes, removing the faulty probes.
566 */
567static void tracepoint_update_probes(void)
568{
569 struct tracepoint_lib *lib;
570
571 /* tracepoints registered from libraries and executable. */
572 cds_list_for_each_entry(lib, &libs, list)
573 lib_update_tracepoints(lib);
574}
575
576static struct lttng_ust_tracepoint_probe *
577tracepoint_add_probe(const char *name, void (*probe)(void), void *data,
578 const char *signature)
579{
580 struct tracepoint_entry *entry;
581 struct lttng_ust_tracepoint_probe *old;
582
583 entry = get_tracepoint(name);
584 if (entry) {
585 if (strcmp(entry->signature, signature) != 0) {
586 ERR("Tracepoint and probe signature do not match.");
587 return ERR_PTR(-EINVAL);
588 }
589 } else {
590 entry = add_tracepoint(name, signature);
591 if (IS_ERR(entry))
592 return (struct lttng_ust_tracepoint_probe *)entry;
593 }
594 old = tracepoint_entry_add_probe(entry, probe, data);
595 if (IS_ERR(old) && !entry->refcount)
596 remove_tracepoint(entry);
597 return old;
598}
599
600static void tracepoint_release_queue_add_old_probes(void *old)
601{
602 release_queue_need_update = 1;
603 if (old) {
604 struct tp_probes *tp_probes = caa_container_of(old,
605 struct tp_probes, probes[0]);
606 cds_list_add(&tp_probes->u.list, &release_queue);
607 }
608}
609
610/**
611 * __tracepoint_probe_register - Connect a probe to a tracepoint
612 * @name: tracepoint name
613 * @probe: probe handler
614 *
615 * Returns 0 if ok, error value on error.
616 * The probe address must at least be aligned on the architecture pointer size.
617 * Called with the tracepoint mutex held.
618 */
619int __tracepoint_probe_register(const char *name, void (*probe)(void),
620 void *data, const char *signature)
621{
622 void *old;
623 int ret = 0;
624
625 DBG("Registering probe to tracepoint %s", name);
626
627 pthread_mutex_lock(&tracepoint_mutex);
628 old = tracepoint_add_probe(name, probe, data, signature);
629 if (IS_ERR(old)) {
630 ret = PTR_ERR(old);
631 goto end;
632 }
633
634 tracepoint_sync_callsites(name);
635 release_probes(old);
636end:
637 pthread_mutex_unlock(&tracepoint_mutex);
638 return ret;
639}
640
641/*
642 * Caller needs to invoke __tracepoint_probe_release_queue() after
643 * calling __tracepoint_probe_register_queue_release() one or multiple
644 * times to ensure it does not leak memory.
645 */
646int __tracepoint_probe_register_queue_release(const char *name,
647 void (*probe)(void), void *data, const char *signature)
648{
649 void *old;
650 int ret = 0;
651
652 DBG("Registering probe to tracepoint %s. Queuing release.", name);
653
654 pthread_mutex_lock(&tracepoint_mutex);
655 old = tracepoint_add_probe(name, probe, data, signature);
656 if (IS_ERR(old)) {
657 ret = PTR_ERR(old);
658 goto end;
659 }
660
661 tracepoint_sync_callsites(name);
662 tracepoint_release_queue_add_old_probes(old);
663end:
664 pthread_mutex_unlock(&tracepoint_mutex);
665 return ret;
666}
667
668static void *tracepoint_remove_probe(const char *name, void (*probe)(void),
669 void *data)
670{
671 struct tracepoint_entry *entry;
672 void *old;
673
674 entry = get_tracepoint(name);
675 if (!entry)
676 return ERR_PTR(-ENOENT);
677 old = tracepoint_entry_remove_probe(entry, probe, data);
678 if (IS_ERR(old))
679 return old;
680 if (!entry->refcount)
681 remove_tracepoint(entry);
682 return old;
683}
684
685/**
686 * tracepoint_probe_unregister - Disconnect a probe from a tracepoint
687 * @name: tracepoint name
688 * @probe: probe function pointer
689 * @probe: probe data pointer
690 */
691int __tracepoint_probe_unregister(const char *name, void (*probe)(void),
692 void *data)
693{
694 void *old;
695 int ret = 0;
696
697 DBG("Un-registering probe from tracepoint %s", name);
698
699 pthread_mutex_lock(&tracepoint_mutex);
700 old = tracepoint_remove_probe(name, probe, data);
701 if (IS_ERR(old)) {
702 ret = PTR_ERR(old);
703 goto end;
704 }
705 tracepoint_sync_callsites(name);
706 release_probes(old);
707end:
708 pthread_mutex_unlock(&tracepoint_mutex);
709 return ret;
710}
711
712/*
713 * Caller needs to invoke __tracepoint_probe_release_queue() after
714 * calling __tracepoint_probe_unregister_queue_release() one or multiple
715 * times to ensure it does not leak memory.
716 */
717int __tracepoint_probe_unregister_queue_release(const char *name,
718 void (*probe)(void), void *data)
719{
720 void *old;
721 int ret = 0;
722
723 DBG("Un-registering probe from tracepoint %s. Queuing release.", name);
724
725 pthread_mutex_lock(&tracepoint_mutex);
726 old = tracepoint_remove_probe(name, probe, data);
727 if (IS_ERR(old)) {
728 ret = PTR_ERR(old);
729 goto end;
730 }
731 tracepoint_sync_callsites(name);
732 tracepoint_release_queue_add_old_probes(old);
733end:
734 pthread_mutex_unlock(&tracepoint_mutex);
735 return ret;
736}
737
738void __tracepoint_probe_prune_release_queue(void)
739{
740 CDS_LIST_HEAD(release_probes);
741 struct tp_probes *pos, *next;
742
743 DBG("Release queue of unregistered tracepoint probes.");
744
745 pthread_mutex_lock(&tracepoint_mutex);
746 if (!release_queue_need_update)
747 goto end;
748 if (!cds_list_empty(&release_queue))
749 cds_list_replace_init(&release_queue, &release_probes);
750 release_queue_need_update = 0;
751
752 /* Wait for grace period between all sync_callsites and free. */
753 urcu_bp_synchronize_rcu();
754
755 cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) {
756 cds_list_del(&pos->u.list);
757 free(pos);
758 }
759end:
760 pthread_mutex_unlock(&tracepoint_mutex);
761}
762
763static void tracepoint_add_old_probes(void *old)
764{
765 need_update = 1;
766 if (old) {
767 struct tp_probes *tp_probes = caa_container_of(old,
768 struct tp_probes, probes[0]);
769 cds_list_add(&tp_probes->u.list, &old_probes);
770 }
771}
772
773/**
774 * tracepoint_probe_register_noupdate - register a probe but not connect
775 * @name: tracepoint name
776 * @probe: probe handler
777 *
778 * caller must call tracepoint_probe_update_all()
779 */
780int tracepoint_probe_register_noupdate(const char *name, void (*probe)(void),
781 void *data, const char *signature)
782{
783 void *old;
784 int ret = 0;
785
786 pthread_mutex_lock(&tracepoint_mutex);
787 old = tracepoint_add_probe(name, probe, data, signature);
788 if (IS_ERR(old)) {
789 ret = PTR_ERR(old);
790 goto end;
791 }
792 tracepoint_add_old_probes(old);
793end:
794 pthread_mutex_unlock(&tracepoint_mutex);
795 return ret;
796}
797
798/**
799 * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect
800 * @name: tracepoint name
801 * @probe: probe function pointer
802 *
803 * caller must call tracepoint_probe_update_all()
804 * Called with the tracepoint mutex held.
805 */
806int tracepoint_probe_unregister_noupdate(const char *name, void (*probe)(void),
807 void *data)
808{
809 void *old;
810 int ret = 0;
811
812 DBG("Un-registering probe from tracepoint %s", name);
813
814 pthread_mutex_lock(&tracepoint_mutex);
815 old = tracepoint_remove_probe(name, probe, data);
816 if (IS_ERR(old)) {
817 ret = PTR_ERR(old);
818 goto end;
819 }
820 tracepoint_add_old_probes(old);
821end:
822 pthread_mutex_unlock(&tracepoint_mutex);
823 return ret;
824}
825
826/**
827 * tracepoint_probe_update_all - update tracepoints
828 */
829void tracepoint_probe_update_all(void)
830{
831 CDS_LIST_HEAD(release_probes);
832 struct tp_probes *pos, *next;
833
834 pthread_mutex_lock(&tracepoint_mutex);
835 if (!need_update) {
836 goto end;
837 }
838 if (!cds_list_empty(&old_probes))
839 cds_list_replace_init(&old_probes, &release_probes);
840 need_update = 0;
841
842 tracepoint_update_probes();
843 /* Wait for grace period between update_probes and free. */
844 urcu_bp_synchronize_rcu();
845 cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) {
846 cds_list_del(&pos->u.list);
847 free(pos);
848 }
849end:
850 pthread_mutex_unlock(&tracepoint_mutex);
851}
852
853void tracepoint_set_new_tracepoint_cb(void (*cb)(struct lttng_ust_tracepoint *))
854{
855 new_tracepoint_cb = cb;
856}
857
858static void new_tracepoints(struct lttng_ust_tracepoint * const *start,
859 struct lttng_ust_tracepoint * const *end)
860{
861 if (new_tracepoint_cb) {
862 struct lttng_ust_tracepoint * const *t;
863
864 for (t = start; t < end; t++) {
865 if (*t)
866 new_tracepoint_cb(*t);
867 }
868 }
869}
870
871int tracepoint_register_lib(struct lttng_ust_tracepoint * const *tracepoints_start,
872 int tracepoints_count)
873{
874 struct tracepoint_lib *pl, *iter;
875
876 init_tracepoint();
877
878 pl = (struct tracepoint_lib *) zmalloc(sizeof(struct tracepoint_lib));
879 if (!pl) {
880 PERROR("Unable to register tracepoint lib");
881 return -1;
882 }
883 pl->tracepoints_start = tracepoints_start;
884 pl->tracepoints_count = tracepoints_count;
885 CDS_INIT_LIST_HEAD(&pl->callsites);
886
887 pthread_mutex_lock(&tracepoint_mutex);
888 /*
889 * We sort the libs by struct lib pointer address.
890 */
891 cds_list_for_each_entry_reverse(iter, &libs, list) {
892 BUG_ON(iter == pl); /* Should never be in the list twice */
893 if (iter < pl) {
894 /* We belong to the location right after iter. */
895 cds_list_add(&pl->list, &iter->list);
896 goto lib_added;
897 }
898 }
899 /* We should be added at the head of the list */
900 cds_list_add(&pl->list, &libs);
901lib_added:
902 new_tracepoints(tracepoints_start, tracepoints_start + tracepoints_count);
903 lib_register_callsites(pl);
904 lib_update_tracepoints(pl);
905 pthread_mutex_unlock(&tracepoint_mutex);
906
907 DBG("just registered a tracepoints section from %p and having %d tracepoints",
908 tracepoints_start, tracepoints_count);
909 if (ust_debug()) {
910 int i;
911
912 for (i = 0; i < tracepoints_count; i++) {
913 DBG("registered tracepoint: %s", tracepoints_start[i]->name);
914 }
915 }
916
917 return 0;
918}
919
920int tracepoint_unregister_lib(struct lttng_ust_tracepoint * const *tracepoints_start)
921{
922 struct tracepoint_lib *lib;
923
924 pthread_mutex_lock(&tracepoint_mutex);
925 cds_list_for_each_entry(lib, &libs, list) {
926 if (lib->tracepoints_start != tracepoints_start)
927 continue;
928
929 cds_list_del(&lib->list);
930 /*
931 * Unregistering a callsite also decreases the
932 * callsite reference count of the corresponding
933 * tracepoint, and disables the tracepoint if
934 * the reference count drops to zero.
935 */
936 lib_unregister_callsites(lib);
937 DBG("just unregistered a tracepoints section from %p",
938 lib->tracepoints_start);
939 free(lib);
940 break;
941 }
942 pthread_mutex_unlock(&tracepoint_mutex);
943 return 0;
944}
945
946/*
947 * Report in debug message whether the compiler correctly supports weak
948 * hidden symbols. This test checks that the address associated with two
949 * weak symbols with hidden visibility is the same when declared within
950 * two compile units part of the same module.
951 */
952static void check_weak_hidden(void)
953{
954 DBG("Your compiler treats weak symbols with hidden visibility for integer objects as %s between compile units part of the same module.",
955 &__tracepoint_test_symbol1 == lttng_ust_tp_check_weak_hidden1() ?
956 "SAME address" :
957 "DIFFERENT addresses");
958 DBG("Your compiler treats weak symbols with hidden visibility for pointer objects as %s between compile units part of the same module.",
959 &__tracepoint_test_symbol2 == lttng_ust_tp_check_weak_hidden2() ?
960 "SAME address" :
961 "DIFFERENT addresses");
962 DBG("Your compiler treats weak symbols with hidden visibility for 24-byte structure objects as %s between compile units part of the same module.",
963 &__tracepoint_test_symbol3 == lttng_ust_tp_check_weak_hidden3() ?
964 "SAME address" :
965 "DIFFERENT addresses");
966}
967
968void init_tracepoint(void)
969{
970 if (uatomic_xchg(&initialized, 1) == 1)
971 return;
972 init_usterr();
973 check_weak_hidden();
974}
975
976void exit_tracepoint(void)
977{
978 initialized = 0;
979}
980
981/*
982 * Create the wrapper symbols.
983 */
984#undef tp_rcu_read_lock_bp
985#undef tp_rcu_read_unlock_bp
986#undef tp_rcu_dereference_bp
987
988void tp_rcu_read_lock_bp(void)
989{
990 urcu_bp_read_lock();
991}
992
993void tp_rcu_read_unlock_bp(void)
994{
995 urcu_bp_read_unlock();
996}
997
998void *tp_rcu_dereference_sym_bp(void *p)
999{
1000 return urcu_bp_dereference(p);
1001}
1002
1003/*
1004 * Programs that have threads that survive after they exit, and therefore call
1005 * library destructors, should disable the tracepoint destructors by calling
1006 * tp_disable_destructors(). This will leak the tracepoint
1007 * instrumentation library shared object, leaving its teardown to the operating
1008 * system process teardown.
1009 *
1010 * To access and/or modify this value, users need to use a combination of
1011 * dlopen(3) and dlsym(3) to get an handle on the
1012 * tp_disable_destructors and tp_get_destructors_state symbols below.
1013 */
1014void tp_disable_destructors(void)
1015{
1016 uatomic_set(&tracepoint_destructors_state, 0);
1017}
1018
1019/*
1020 * Returns 1 if the destructors are enabled and should be executed.
1021 * Returns 0 if the destructors are disabled.
1022 */
1023int tp_get_destructors_state(void)
1024{
1025 return uatomic_read(&tracepoint_destructors_state);
1026}
This page took 0.025988 seconds and 4 git commands to generate.