#include <signal.h>
#include <limits.h>
#include <urcu/uatomic.h>
-#include "futex.h"
#include <urcu/compiler.h>
#include <lttng/urcu/urcu-ust.h>
#include <lttng/ust-libc-wrapper.h>
#include <lttng/ust-thread.h>
#include <lttng/ust-tracer.h>
+#include <lttng/ust-common.h>
#include <urcu/tls-compat.h>
+#include "lib/lttng-ust/futex.h"
#include "common/ustcomm.h"
#include "common/ust-fd.h"
#include "common/logging.h"
#include "common/macros.h"
-#include "tracepoint-internal.h"
+#include "common/tracepoint.h"
#include "lttng-tracer-core.h"
#include "common/compat/pthread.h"
#include "common/procname.h"
#include "common/ringbuffer/rb-init.h"
#include "lttng-ust-statedump.h"
-#include "clock.h"
-#include "common/ringbuffer/getcpu.h"
-#include "getenv.h"
-#include "ust-events-internal.h"
+#include "common/clock.h"
+#include "common/getenv.h"
+#include "lib/lttng-ust/events.h"
#include "context-internal.h"
#include "common/align.h"
-#include "lttng-counter-client.h"
-#include "lttng-rb-clients.h"
+#include "common/counter-clients/clients.h"
+#include "common/ringbuffer-clients/clients.h"
/*
* Has lttng ust comm constructor been called ?
};
/* Socket from app (connect) to session daemon (listen) for communication */
-struct sock_info global_apps = {
+static struct sock_info global_apps = {
.name = "global",
.global = 1,
/* TODO: allow global_apps_sock_path override */
-struct sock_info local_apps = {
+static struct sock_info local_apps = {
.name = "local",
.global = 0,
.root_handle = -1,
static char *get_map_shm(struct sock_info *sock_info);
-ssize_t lttng_ust_read(int fd, void *buf, size_t len)
-{
- ssize_t ret;
- size_t copied = 0, to_copy = len;
-
- do {
- ret = read(fd, buf + copied, to_copy);
- if (ret > 0) {
- copied += ret;
- to_copy -= ret;
- }
- } while ((ret > 0 && to_copy > 0)
- || (ret < 0 && errno == EINTR));
- if (ret > 0) {
- ret = copied;
- }
- return ret;
-}
/*
* Returns the HOME directory path. Caller MUST NOT free(3) the returned
* pointer.
}
/*
- * Force a read (imply TLS fixup for dlopen) of TLS variables.
+ * Force a read (imply TLS allocation for dlopen) of TLS variables.
*/
static
-void lttng_fixup_nest_count_tls(void)
+void lttng_nest_count_alloc_tls(void)
{
asm volatile ("" : : "m" (URCU_TLS(lttng_ust_nest_count)));
}
static
-void lttng_fixup_ust_mutex_nest_tls(void)
+void lttng_ust_mutex_nest_alloc_tls(void)
{
asm volatile ("" : : "m" (URCU_TLS(ust_mutex_nest)));
}
/*
- * Fixup lttng-ust urcu TLS.
+ * Allocate lttng-ust urcu TLS.
*/
static
-void lttng_fixup_lttng_ust_urcu_tls(void)
+void lttng_lttng_ust_urcu_alloc_tls(void)
{
(void) lttng_ust_urcu_read_ongoing();
}
-void lttng_ust_fixup_tls(void)
+void lttng_ust_alloc_tls(void)
{
- lttng_fixup_lttng_ust_urcu_tls();
- lttng_fixup_ringbuffer_tls();
- lttng_fixup_vtid_tls();
- lttng_fixup_nest_count_tls();
- lttng_fixup_procname_tls();
- lttng_fixup_ust_mutex_nest_tls();
- lttng_ust_fixup_perf_counter_tls();
- lttng_ust_fixup_fd_tracker_tls();
- lttng_fixup_cgroup_ns_tls();
- lttng_fixup_ipc_ns_tls();
- lttng_fixup_net_ns_tls();
- lttng_fixup_time_ns_tls();
- lttng_fixup_uts_ns_tls();
- lttng_ust_fixup_ring_buffer_client_discard_tls();
- lttng_ust_fixup_ring_buffer_client_discard_rt_tls();
- lttng_ust_fixup_ring_buffer_client_overwrite_tls();
- lttng_ust_fixup_ring_buffer_client_overwrite_rt_tls();
+ lttng_lttng_ust_urcu_alloc_tls();
+ lttng_ringbuffer_alloc_tls();
+ lttng_vtid_alloc_tls();
+ lttng_nest_count_alloc_tls();
+ lttng_procname_alloc_tls();
+ lttng_ust_mutex_nest_alloc_tls();
+ lttng_ust_perf_counter_alloc_tls();
+ lttng_ust_common_alloc_tls();
+ lttng_cgroup_ns_alloc_tls();
+ lttng_ipc_ns_alloc_tls();
+ lttng_net_ns_alloc_tls();
+ lttng_time_ns_alloc_tls();
+ lttng_uts_ns_alloc_tls();
+ lttng_ust_ring_buffer_client_discard_alloc_tls();
+ lttng_ust_ring_buffer_client_discard_rt_alloc_tls();
+ lttng_ust_ring_buffer_client_overwrite_alloc_tls();
+ lttng_ust_ring_buffer_client_overwrite_rt_alloc_tls();
}
/*
* ensure those are initialized before a signal handler nesting over
* this thread attempts to use them.
*/
- lttng_ust_fixup_tls();
+ lttng_ust_alloc_tls();
}
int lttng_get_notify_socket(void *owner)
}
static
-int register_to_sessiond(int socket, enum ustctl_socket_type type)
+int register_to_sessiond(int socket, enum lttng_ust_ctl_socket_type type)
{
return ustcomm_send_reg_msg(socket,
type,
return ret;
}
+static
+void prepare_cmd_reply(struct ustcomm_ust_reply *lur, uint32_t handle, uint32_t cmd, int ret)
+{
+ lur->handle = handle;
+ lur->cmd = cmd;
+ lur->ret_val = ret;
+ if (ret >= 0) {
+ lur->ret_code = LTTNG_UST_OK;
+ } else {
+ /*
+ * Use -LTTNG_UST_ERR as wildcard for UST internal
+ * error that are not caused by the transport, except if
+ * we already have a more precise error message to
+ * report.
+ */
+ if (ret > -LTTNG_UST_ERR) {
+ /* Translate code to UST error. */
+ switch (ret) {
+ case -EEXIST:
+ lur->ret_code = -LTTNG_UST_ERR_EXIST;
+ break;
+ case -EINVAL:
+ lur->ret_code = -LTTNG_UST_ERR_INVAL;
+ break;
+ case -ENOENT:
+ lur->ret_code = -LTTNG_UST_ERR_NOENT;
+ break;
+ case -EPERM:
+ lur->ret_code = -LTTNG_UST_ERR_PERM;
+ break;
+ case -ENOSYS:
+ lur->ret_code = -LTTNG_UST_ERR_NOSYS;
+ break;
+ default:
+ lur->ret_code = -LTTNG_UST_ERR;
+ break;
+ }
+ } else {
+ lur->ret_code = ret;
+ }
+ }
+}
+
static
int handle_message(struct sock_info *sock_info,
int sock, struct ustcomm_ust_msg *lum)
goto error;
}
+ switch (lum->cmd) {
+ case LTTNG_UST_ABI_FILTER:
+ case LTTNG_UST_ABI_EXCLUSION:
+ case LTTNG_UST_ABI_CHANNEL:
+ case LTTNG_UST_ABI_STREAM:
+ case LTTNG_UST_ABI_CONTEXT:
+ /*
+ * Those commands send additional payload after struct
+ * ustcomm_ust_msg, which makes it pretty much impossible to
+ * deal with "unknown command" errors without leaving the
+ * communication pipe in a out-of-sync state. This is part of
+ * the ABI between liblttng-ust-ctl and liblttng-ust, and
+ * should be fixed on the next breaking
+ * LTTNG_UST_ABI_MAJOR_VERSION protocol bump by indicating the
+ * total command message length as part of a message header so
+ * that the protocol can recover from invalid command errors.
+ */
+ break;
+
+ case LTTNG_UST_ABI_CAPTURE:
+ case LTTNG_UST_ABI_COUNTER:
+ case LTTNG_UST_ABI_COUNTER_GLOBAL:
+ case LTTNG_UST_ABI_COUNTER_CPU:
+ case LTTNG_UST_ABI_EVENT_NOTIFIER_CREATE:
+ case LTTNG_UST_ABI_EVENT_NOTIFIER_GROUP_CREATE:
+ /*
+ * Those commands expect a reply to the struct ustcomm_ust_msg
+ * before sending additional payload.
+ */
+ prepare_cmd_reply(&lur, lum->handle, lum->cmd, 0);
+
+ ret = send_reply(sock, &lur);
+ if (ret < 0) {
+ DBG("error sending reply");
+ goto error;
+ }
+ break;
+
+ default:
+ /*
+ * Other commands either don't send additional payload, or are
+ * unknown.
+ */
+ break;
+ }
+
switch (lum->cmd) {
case LTTNG_UST_ABI_REGISTER_DONE:
if (lum->handle == LTTNG_UST_ABI_ROOT_HANDLE)
break;
}
- lur.handle = lum->handle;
- lur.cmd = lum->cmd;
- lur.ret_val = ret;
- if (ret >= 0) {
- lur.ret_code = LTTNG_UST_OK;
- } else {
- /*
- * Use -LTTNG_UST_ERR as wildcard for UST internal
- * error that are not caused by the transport, except if
- * we already have a more precise error message to
- * report.
- */
- if (ret > -LTTNG_UST_ERR) {
- /* Translate code to UST error. */
- switch (ret) {
- case -EEXIST:
- lur.ret_code = -LTTNG_UST_ERR_EXIST;
- break;
- case -EINVAL:
- lur.ret_code = -LTTNG_UST_ERR_INVAL;
- break;
- case -ENOENT:
- lur.ret_code = -LTTNG_UST_ERR_NOENT;
- break;
- case -EPERM:
- lur.ret_code = -LTTNG_UST_ERR_PERM;
- break;
- case -ENOSYS:
- lur.ret_code = -LTTNG_UST_ERR_NOSYS;
- break;
- default:
- lur.ret_code = -LTTNG_UST_ERR;
- break;
- }
- } else {
- lur.ret_code = ret;
- }
- }
+ prepare_cmd_reply(&lur, lum->handle, lum->cmd, ret);
+
if (ret >= 0) {
switch (lum->cmd) {
case LTTNG_UST_ABI_TRACER_VERSION:
int sock, ret, prev_connect_failed = 0, has_waited = 0, fd;
long timeout;
- lttng_ust_fixup_tls();
+ lttng_ust_alloc_tls();
/*
* If available, add '-ust' to the end of this thread's
* process name
sock_info->root_handle = ret;
}
- ret = register_to_sessiond(sock_info->socket, USTCTL_SOCKET_CMD);
+ ret = register_to_sessiond(sock_info->socket, LTTNG_UST_CTL_SOCKET_CMD);
if (ret < 0) {
ERR("Error registering to %s ust cmd socket",
sock_info->name);
}
ret = register_to_sessiond(sock_info->notify_socket,
- USTCTL_SOCKET_NOTIFY);
+ LTTNG_UST_CTL_SOCKET_NOTIFY);
if (ret < 0) {
ERR("Error registering to %s ust notify socket",
sock_info->name);
* Weak symbol to call when the ust malloc wrapper is not loaded.
*/
__attribute__((weak))
-void lttng_ust_libc_wrapper_malloc_init(void)
+void lttng_ust_libc_wrapper_malloc_ctor(void)
{
}
+/*
+ * Use a symbol of the previous ABI to detect if liblttng-ust.so.0 is loaded in
+ * the current process.
+ */
+#define LTTNG_UST_SONAME_0_SYM "ltt_probe_register"
+
+static
+void lttng_ust_check_soname_0(void)
+{
+ if (!dlsym(RTLD_DEFAULT, LTTNG_UST_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_SONAME_0_SYM);
+}
+
+/*
+ * Expose a canary symbol of the previous ABI to ensure we catch uses of a
+ * liblttng-ust.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.
+ */
+void init_usterr(void);
+void init_usterr(void)
+{
+ 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__);
+}
+
/*
* sessiond monitoring thread: monitor presence of global and per-user
* sessiond by polling the application common named pipe.
*/
static
-void lttng_ust_init(void)
+void lttng_ust_ctor(void)
__attribute__((constructor));
static
-void lttng_ust_init(void)
+void lttng_ust_ctor(void)
{
struct timespec constructor_timeout;
sigset_t sig_all_blocked, orig_parent_mask;
return;
/*
- * Fixup interdependency between TLS fixup mutex (which happens
+ * Fixup interdependency between TLS allocation mutex (which happens
* to be the dynamic linker mutex) and ust_lock, taken within
* the ust lock.
*/
- lttng_ust_fixup_tls();
+ lttng_ust_alloc_tls();
lttng_ust_loaded = 1;
+ /*
+ * 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_check_soname_0();
+
/*
* We need to ensure that the liblttng-ust library is not unloaded to avoid
* the unloading of code used by the ust_listener_threads as we can not
handle = dlopen(LTTNG_UST_LIB_SONAME, RTLD_LAZY | RTLD_NODELETE);
if (!handle) {
ERR("dlopen of liblttng-ust shared library (%s).", LTTNG_UST_LIB_SONAME);
+ } else {
+ DBG("dlopened liblttng-ust shared library (%s).", LTTNG_UST_LIB_SONAME);
}
/*
* sessiond (otherwise leading to errors when trying to create
* sessiond before the init functions are completed).
*/
+
+ /*
+ * Both the logging and getenv lazy-initialization uses getenv()
+ * internally and thus needs to be explicitly initialized in
+ * liblttng-ust before we start any threads as an unsuspecting normally
+ * single threaded application using liblttng-ust could be using
+ * setenv() which is not thread-safe.
+ */
lttng_ust_logging_init();
- lttng_ust_getenv_init(); /* Needs lttng_ust_logging_init() to be completed. */
+ lttng_ust_getenv_init();
+
+ /* Call the liblttng-ust-common constructor. */
+ lttng_ust_common_ctor();
+
lttng_ust_tp_init();
- lttng_ust_init_fd_tracker();
- lttng_ust_clock_init();
- lttng_ust_getcpu_init();
lttng_ust_statedump_init();
lttng_ust_ring_buffer_clients_init();
lttng_ust_counter_clients_init();
/*
* Invoke ust malloc wrapper init before starting other threads.
*/
- lttng_ust_libc_wrapper_malloc_init();
+ lttng_ust_libc_wrapper_malloc_ctor();
timeout_mode = get_constructor_timeout(&constructor_timeout);
sigset_t all_sigs;
int ret;
- /* Fixup lttng-ust TLS. */
- lttng_ust_fixup_tls();
+ /* Allocate lttng-ust TLS. */
+ lttng_ust_alloc_tls();
if (URCU_TLS(lttng_ust_nest_count))
return;
* After fork, in the child, we need to cleanup all the leftover state,
* except the worker thread which already magically disappeared thanks
* to the weird Linux fork semantics. After tyding up, we call
- * lttng_ust_init() again to start over as a new PID.
+ * lttng_ust_ctor() again to start over as a new PID.
*
* This is meant for forks() that have tracing in the child between the
* fork and following exec call (if there is any).
lttng_ust_cleanup(0);
/* Release mutexes and reenable signals */
ust_after_fork_common(restore_sigset);
- lttng_ust_init();
+ lttng_ust_ctor();
}
void lttng_ust_after_setns(void)