#include <urcu/compiler.h>
#include <lttng/tracepoint.h>
+#include <lttng/ust-abi.h> /* for LTTNG_UST_SYM_NAME_LEN */
#include <usterr-signal-safe.h>
#include <helper.h>
struct tp_probes {
union {
struct cds_list_head list;
+ /* Field below only used for call_rcu scheme */
+ /* struct rcu_head head; */
} u;
struct tracepoint_probe probes[0];
};
struct cds_hlist_head *head;
struct cds_hlist_node *node;
struct tracepoint_entry *e;
- uint32_t hash = jhash(name, strlen(name), 0);
+ size_t name_len = strlen(name);
+ uint32_t hash;
+ if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
+ WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
+ name_len = LTTNG_UST_SYM_NAME_LEN - 1;
+ }
+ hash = jhash(name, name_len, 0);
head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
cds_hlist_for_each_entry(e, node, head, hlist) {
- if (!strcmp(name, e->name))
+ if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1))
return e;
}
return NULL;
struct cds_hlist_head *head;
struct cds_hlist_node *node;
struct tracepoint_entry *e;
- size_t name_len = strlen(name) + 1;
- uint32_t hash = jhash(name, name_len-1, 0);
+ size_t name_len = strlen(name);
+ uint32_t hash;
+ if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
+ WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
+ name_len = LTTNG_UST_SYM_NAME_LEN - 1;
+ }
+ hash = jhash(name, name_len, 0);
head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
cds_hlist_for_each_entry(e, node, head, hlist) {
- if (!strcmp(name, e->name)) {
+ if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) {
DBG("tracepoint %s busy", name);
return ERR_PTR(-EEXIST); /* Already there */
}
* Using zmalloc here to allocate a variable length element. Could
* cause some memory fragmentation if overused.
*/
- e = zmalloc(sizeof(struct tracepoint_entry) + name_len);
+ e = zmalloc(sizeof(struct tracepoint_entry) + name_len + 1);
if (!e)
return ERR_PTR(-ENOMEM);
- memcpy(&e->name[0], name, name_len);
+ memcpy(&e->name[0], name, name_len + 1);
+ e->name[name_len] = '\0';
e->probes = NULL;
e->refcount = 0;
cds_hlist_add_head(&e->hlist, head);
static void set_tracepoint(struct tracepoint_entry **entry,
struct tracepoint *elem, int active)
{
- WARN_ON(strcmp((*entry)->name, elem->name) != 0);
+ WARN_ON(strncmp((*entry)->name, elem->name, LTTNG_UST_SYM_NAME_LEN - 1) != 0);
/*
* rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new
}
}
+static
+void lib_disable_tracepoints(struct tracepoint * const *begin,
+ struct tracepoint * const *end)
+{
+ struct tracepoint * const *iter;
+
+ for (iter = begin; iter < end; iter++) {
+ if (!*iter)
+ continue; /* skip dummy */
+ disable_tracepoint(*iter);
+ }
+
+}
+
int tracepoint_register_lib(struct tracepoint * const *tracepoints_start,
int tracepoints_count)
{
int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start)
{
struct tracepoint_lib *lib;
+ int tracepoints_count;
ust_lock();
cds_list_for_each_entry(lib, &libs, list) {
if (lib->tracepoints_start == tracepoints_start) {
struct tracepoint_lib *lib2free = lib;
+
cds_list_del(&lib->list);
+ tracepoints_count = lib->tracepoints_count;
free(lib2free);
- break;
+ goto found;
}
}
+ goto end;
+found:
+ /*
+ * Force tracepoint disarm for all tracepoints of this lib.
+ * This takes care of destructor of library that would leave a
+ * LD_PRELOAD wrapper override function enabled for tracing, but
+ * the session teardown would not be able to reach the
+ * tracepoint anymore to disable it.
+ */
+ lib_disable_tracepoints(tracepoints_start,
+ tracepoints_start + tracepoints_count);
+ DBG("just unregistered a tracepoints section from %p",
+ tracepoints_start);
+end:
ust_unlock();
-
return 0;
}