Detect unsupported use of .so.0 and .so.1 libraries within same process
[lttng-ust.git] / src / lib / lttng-ust-tracepoint / tracepoint.c
index 939af88872b75daf0bdc2b21502dab0ec1856869..12bc561c3342693cbdafbefac0a87612b5852981 100644 (file)
@@ -12,6 +12,7 @@
 #include <stdint.h>
 #include <stddef.h>
 #include <stdio.h>
+#include <dlfcn.h>
 
 #include <urcu/arch.h>
 #include <lttng/urcu/urcu-ust.h>
 #include "common/err-ptr.h"
 
 /* Test compiler support for weak symbols with hidden visibility. */
-int __tracepoint_test_symbol1 __attribute__((weak, visibility("hidden")));
-void *__tracepoint_test_symbol2 __attribute__((weak, visibility("hidden")));
+int lttng_ust_tracepoint_test_symbol1 __attribute__((weak, visibility("hidden")));
+void *lttng_ust_tracepoint_test_symbol2 __attribute__((weak, visibility("hidden")));
 struct {
        char a[24];
-} __tracepoint_test_symbol3 __attribute__((weak, visibility("hidden")));
+} lttng_ust_tracepoint_test_symbol3 __attribute__((weak, visibility("hidden")));
 
 /* Set to 1 to enable tracepoint debug output */
 static const int tracepoint_debug;
@@ -74,8 +75,8 @@ static CDS_LIST_HEAD(libs);
  * The tracepoint mutex protects the library tracepoints, the hash table, and
  * the library list.
  * All calls to the tracepoint API must be protected by the tracepoint mutex,
- * excepts calls to tracepoint_register_lib and
- * tracepoint_unregister_lib, which take the tracepoint mutex themselves.
+ * excepts calls to lttng_ust_tracepoint_module_register and
+ * lttng_ust_tracepoint_module_unregister, which take the tracepoint mutex themselves.
  */
 
 /*
@@ -607,8 +608,41 @@ static void tracepoint_release_queue_add_old_probes(void *old)
        }
 }
 
+/*
+ * Use a symbol of the previous ABI to detect if liblttng-ust-tracepoint.so.0
+ * is loaded in the current process.
+ */
+#define LTTNG_UST_TRACEPOINT_SONAME_0_SYM      "tracepoint_unregister_lib"
+
+static
+void lttng_ust_tracepoint_check_soname_0(void)
+{
+       if (!dlsym(RTLD_DEFAULT, LTTNG_UST_TRACEPOINT_SONAME_0_SYM))
+               return;
+
+       CRIT("Incompatible library ABIs detected within the same process. "
+               "The process is likely linked against different major soname of LTTng-UST which is unsupported. "
+               "The detection was triggered by lookup of ABI 0 symbol \"%s\" in the Global Symbol Table\n",
+               LTTNG_UST_TRACEPOINT_SONAME_0_SYM);
+}
+
+/*
+ * Expose a canary symbol of the previous ABI to ensure we catch uses of a
+ * liblttng-ust-tracepoint.so.0 dlopen'd after .so.1 has been loaded. Use a
+ * different symbol than the detection code to ensure we don't detect ourself.
+ */
+int tracepoint_register_lib(void *arg0 __attribute__((unused)), int arg1 __attribute__((unused)));
+int tracepoint_register_lib(void *arg0 __attribute__((unused)), int arg1 __attribute__((unused)))
+{
+       CRIT("Incompatible library ABIs detected within the same process. "
+               "The process is likely linked against different major soname of LTTng-UST which is unsupported. "
+               "The detection was triggered by canary symbol \"%s\"\n", __func__);
+
+       return -1;
+}
+
 /**
- * __tracepoint_probe_register -  Connect a probe to a tracepoint
+ * lttng_ust_tracepoint_provider_register -  Connect a probe to a tracepoint
  * @name: tracepoint provider name
  * @name: tracepoint event name
  * @probe: probe handler
@@ -617,12 +651,20 @@ static void tracepoint_release_queue_add_old_probes(void *old)
  * The probe address must at least be aligned on the architecture pointer size.
  * Called with the tracepoint mutex held.
  */
-int __tracepoint_probe_register(const char *provider_name, const char *event_name,
+int lttng_ust_tracepoint_provider_register(const char *provider_name, const char *event_name,
                void (*probe)(void), void *data, const char *signature)
 {
        void *old;
        int ret = 0;
 
+       /*
+        * Check if we find a symbol of the previous ABI in the current process
+        * as different ABIs of liblttng-ust can't co-exist in a process. If we
+        * do so, emit a critical log message which will also abort if the
+        * LTTNG_UST_ABORT_ON_CRITICAL environment variable is set.
+        */
+       lttng_ust_tracepoint_check_soname_0();
+
        DBG("Registering probe to tracepoint \"%s:%s\"", provider_name, event_name);
 
        pthread_mutex_lock(&tracepoint_mutex);
@@ -640,7 +682,7 @@ end:
 }
 
 /*
- * Caller needs to invoke __tracepoint_probe_release_queue() after
+ * Caller needs to invoke lttng_ust_tracepoint_probe_release_queue() after
  * calling lttng_ust_tp_probe_register_queue_release() one or multiple
  * times to ensure it does not leak memory.
  */
@@ -690,7 +732,7 @@ static void *tracepoint_remove_probe(const char *provider_name, const char *even
  * @probe: probe function pointer
  * @probe: probe data pointer
  */
-int __tracepoint_probe_unregister(const char *provider_name, const char *event_name,
+int lttng_ust_tracepoint_provider_unregister(const char *provider_name, const char *event_name,
                void (*probe)(void), void *data)
 {
        void *old;
@@ -712,7 +754,7 @@ end:
 }
 
 /*
- * Caller needs to invoke __tracepoint_probe_release_queue() after
+ * Caller needs to invoke lttng_ust_tracepoint_probe_release_queue() after
  * calling lttng_ust_tp_probe_unregister_queue_release() one or multiple
  * times to ensure it does not leak memory.
  */
@@ -877,9 +919,9 @@ static void new_tracepoints(struct lttng_ust_tracepoint * const *start,
  * against recent liblttng-ust headers require a recent liblttng-ust
  * runtime for those tracepoints to be taken into account.
  */
-int tracepoint_register_lib(struct lttng_ust_tracepoint * const *tracepoints_start,
+int lttng_ust_tracepoint_module_register(struct lttng_ust_tracepoint * const *tracepoints_start,
                             int tracepoints_count);
-int tracepoint_register_lib(struct lttng_ust_tracepoint * const *tracepoints_start,
+int lttng_ust_tracepoint_module_register(struct lttng_ust_tracepoint * const *tracepoints_start,
                             int tracepoints_count)
 {
        struct tracepoint_lib *pl, *iter;
@@ -932,8 +974,8 @@ lib_added:
        return 0;
 }
 
-int tracepoint_unregister_lib(struct lttng_ust_tracepoint * const *tracepoints_start);
-int tracepoint_unregister_lib(struct lttng_ust_tracepoint * const *tracepoints_start)
+int lttng_ust_tracepoint_module_unregister(struct lttng_ust_tracepoint * const *tracepoints_start);
+int lttng_ust_tracepoint_module_unregister(struct lttng_ust_tracepoint * const *tracepoints_start)
 {
        struct tracepoint_lib *lib;
 
@@ -968,15 +1010,15 @@ int tracepoint_unregister_lib(struct lttng_ust_tracepoint * const *tracepoints_s
 static void check_weak_hidden(void)
 {
        DBG("Your compiler treats weak symbols with hidden visibility for integer objects as %s between compile units part of the same module.",
-               &__tracepoint_test_symbol1 == lttng_ust_tp_check_weak_hidden1() ?
+               &lttng_ust_tracepoint_test_symbol1 == lttng_ust_tp_check_weak_hidden1() ?
                        "SAME address" :
                        "DIFFERENT addresses");
        DBG("Your compiler treats weak symbols with hidden visibility for pointer objects as %s between compile units part of the same module.",
-               &__tracepoint_test_symbol2 == lttng_ust_tp_check_weak_hidden2() ?
+               &lttng_ust_tracepoint_test_symbol2 == lttng_ust_tp_check_weak_hidden2() ?
                        "SAME address" :
                        "DIFFERENT addresses");
        DBG("Your compiler treats weak symbols with hidden visibility for 24-byte structure objects as %s between compile units part of the same module.",
-               &__tracepoint_test_symbol3 == lttng_ust_tp_check_weak_hidden3() ?
+               &lttng_ust_tracepoint_test_symbol3 == lttng_ust_tp_check_weak_hidden3() ?
                        "SAME address" :
                        "DIFFERENT addresses");
 }
@@ -998,24 +1040,24 @@ void lttng_ust_tp_exit(void)
 /*
  * Create the wrapper symbols.
  */
-#undef tp_rcu_read_lock
-#undef tp_rcu_read_unlock
-#undef tp_rcu_dereference
+#undef lttng_ust_tp_rcu_read_lock
+#undef lttng_ust_tp_rcu_read_unlock
+#undef lttng_ust_tp_rcu_dereference
 
-void tp_rcu_read_lock(void);
-void tp_rcu_read_lock(void)
+void lttng_ust_tp_rcu_read_lock(void);
+void lttng_ust_tp_rcu_read_lock(void)
 {
        lttng_ust_urcu_read_lock();
 }
 
-void tp_rcu_read_unlock(void);
-void tp_rcu_read_unlock(void)
+void lttng_ust_tp_rcu_read_unlock(void);
+void lttng_ust_tp_rcu_read_unlock(void)
 {
        lttng_ust_urcu_read_unlock();
 }
 
-void *tp_rcu_dereference_sym(void *p);
-void *tp_rcu_dereference_sym(void *p)
+void *lttng_ust_tp_rcu_dereference_sym(void *p);
+void *lttng_ust_tp_rcu_dereference_sym(void *p)
 {
        return lttng_ust_rcu_dereference(p);
 }
@@ -1023,16 +1065,16 @@ void *tp_rcu_dereference_sym(void *p)
 /*
  * Programs that have threads that survive after they exit, and therefore call
  * library destructors, should disable the tracepoint destructors by calling
- * tp_disable_destructors(). This will leak the tracepoint
+ * lttng_ust_tp_disable_destructors(). This will leak the tracepoint
  * instrumentation library shared object, leaving its teardown to the operating
  * system process teardown.
  *
  * To access and/or modify this value, users need to use a combination of
  * dlopen(3) and dlsym(3) to get an handle on the
- * tp_disable_destructors and tp_get_destructors_state symbols below.
+ * lttng_ust_tp_disable_destructors and lttng_ust_tp_get_destructors_state symbols below.
  */
-void tp_disable_destructors(void);
-void tp_disable_destructors(void)
+void lttng_ust_tp_disable_destructors(void);
+void lttng_ust_tp_disable_destructors(void)
 {
        uatomic_set(&tracepoint_destructors_state, 0);
 }
@@ -1041,8 +1083,8 @@ void tp_disable_destructors(void)
  * Returns 1 if the destructors are enabled and should be executed.
  * Returns 0 if the destructors are disabled.
  */
-int tp_get_destructors_state(void);
-int tp_get_destructors_state(void)
+int lttng_ust_tp_get_destructors_state(void);
+int lttng_ust_tp_get_destructors_state(void)
 {
        return uatomic_read(&tracepoint_destructors_state);
 }
This page took 0.02792 seconds and 4 git commands to generate.