Patches 1&2 merged into lttng-ust master. ----- On Jul 4, 2016, at 6:53 PM, Mathieu Desnoyers mathieu.desnoy...@efficios.com wrote:
> Track library load and unload, with the following new events: > > lttng_ust_lib:load > lttng_ust_lib:build_id > lttng_ust_lib:debug_link > lttng_ust_lib:unload > > This takes care of correctly tracing the mapping of direct dependencies > of dlopen'd libraries, which was not appropriately done by tracing just > dlopen events. > > Fixes: #1035 > > Signed-off-by: Mathieu Desnoyers <mathieu.desnoy...@efficios.com> > --- > include/lttng/ust-events.h | 2 + > liblttng-ust-dl/lttng-ust-dl.c | 15 +- > liblttng-ust/Makefile.am | 2 + > liblttng-ust/lttng-ust-elf.c | 1 + > liblttng-ust/lttng-ust-statedump.c | 395 +++++++++++++++++++++++++++++++------ > 5 files changed, 350 insertions(+), 65 deletions(-) > > diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h > index 9f6aa06..309206d 100644 > --- a/include/lttng/ust-events.h > +++ b/include/lttng/ust-events.h > @@ -722,6 +722,8 @@ struct cds_list_head *_lttng_get_sessions(void); > struct lttng_enum *lttng_ust_enum_get(struct lttng_session *session, > const char *enum_name); > > +void lttng_ust_dl_update(void *ip); > + > /* For backward compatibility. Leave those exported symbols in place. */ > extern struct lttng_ctx *lttng_static_ctx; > void lttng_context_init(void); > diff --git a/liblttng-ust-dl/lttng-ust-dl.c b/liblttng-ust-dl/lttng-ust-dl.c > index e457e7a..81b5bec 100644 > --- a/liblttng-ust-dl/lttng-ust-dl.c > +++ b/liblttng-ust-dl/lttng-ust-dl.c > @@ -1,6 +1,7 @@ > /* > * Copyright (C) 2013 Paul Woegerer <paul.woege...@mentor.com> > * Copyright (C) 2015 Antoine Busque <abus...@efficios.com> > + * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoy...@efficios.com> > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -26,6 +27,7 @@ > > #include <lttng/ust-dlfcn.h> > #include <lttng/ust-elf.h> > +#include <lttng/ust-events.h> > #include <helper.h> > #include "usterr-signal-safe.h" > > @@ -135,19 +137,21 @@ void *dlopen(const char *filename, int flag) > > ret = dlinfo(handle, RTLD_DI_LINKMAP, &p); > if (ret != -1 && p != NULL && p->l_addr != 0) { > - lttng_ust_dl_dlopen((void *) p->l_addr, p->l_name, > + lttng_ust_dl_dlopen((void *) p->l_addr, > + p->l_name, > LTTNG_UST_CALLER_IP()); > } > } > - > + lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); > return handle; > } > > int dlclose(void *handle) > { > + int ret; > + > if (__tracepoint_ptrs_registered) { > struct link_map *p = NULL; > - int ret; > > ret = dlinfo(handle, RTLD_DI_LINKMAP, &p); > if (ret != -1 && p != NULL && p->l_addr != 0) { > @@ -156,6 +160,7 @@ int dlclose(void *handle) > (void *) p->l_addr); > } > } > - > - return _lttng_ust_dl_libc_dlclose(handle); > + ret = _lttng_ust_dl_libc_dlclose(handle); > + lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); > + return ret; > } > diff --git a/liblttng-ust/Makefile.am b/liblttng-ust/Makefile.am > index 05929be..a2a32b4 100644 > --- a/liblttng-ust/Makefile.am > +++ b/liblttng-ust/Makefile.am > @@ -43,6 +43,8 @@ liblttng_ust_runtime_la_SOURCES = \ > lttng-ust-statedump.c \ > lttng-ust-statedump.h \ > lttng-ust-statedump-provider.h \ > + ust_lib.c \ > + ust_lib.h \ > tracepoint-internal.h \ > clock.h \ > compat.h \ > diff --git a/liblttng-ust/lttng-ust-elf.c b/liblttng-ust/lttng-ust-elf.c > index 5f27920..e5b8a08 100644 > --- a/liblttng-ust/lttng-ust-elf.c > +++ b/liblttng-ust/lttng-ust-elf.c > @@ -25,6 +25,7 @@ > #include <sys/stat.h> > #include <fcntl.h> > #include <unistd.h> > +#include <stdbool.h> > #include "lttng-tracer-core.h" > > #define BUF_LEN 4096 > diff --git a/liblttng-ust/lttng-ust-statedump.c > b/liblttng-ust/lttng-ust-statedump.c > index bcb168b..c8e508c 100644 > --- a/liblttng-ust/lttng-ust-statedump.c > +++ b/liblttng-ust/lttng-ust-statedump.c > @@ -1,6 +1,7 @@ > /* > * Copyright (C) 2013 Paul Woegerer <paul_woege...@mentor.com> > * Copyright (C) 2015 Antoine Busque <abus...@efficios.com> > + * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoy...@efficios.com> > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -24,27 +25,32 @@ > #include <stdio.h> > #include <stdint.h> > #include <stdlib.h> > +#include <stdbool.h> > #include <sys/types.h> > #include <unistd.h> > > #include <lttng/ust-elf.h> > +#include <helper.h> > #include "lttng-tracer-core.h" > #include "lttng-ust-statedump.h" > +#include "jhash.h" > > #define TRACEPOINT_DEFINE > +#include "ust_lib.h" /* Only define. */ > + > #define TRACEPOINT_CREATE_PROBES > #define TP_SESSION_CHECK > -#include "lttng-ust-statedump-provider.h" > +#include "lttng-ust-statedump-provider.h" /* Define and create probes. */ > > struct dl_iterate_data { > - void *owner; > int exec_found; > + bool first; > + bool cancel; > }; > > struct bin_info_data { > - void *owner; > void *base_addr_ptr; > - const char *resolved_path; > + char resolved_path[PATH_MAX]; > char *dbg_file; > uint8_t *build_id; > uint64_t memsz; > @@ -56,14 +62,143 @@ struct bin_info_data { > uint8_t has_debug_link; > }; > > +struct lttng_ust_dl_node { > + struct bin_info_data bin_data; > + struct cds_hlist_node node; > + bool traced; > + bool marked; > +}; > + > +#define UST_DL_STATE_HASH_BITS 8 > +#define UST_DL_STATE_TABLE_SIZE (1 << UST_DL_STATE_HASH_BITS) > +struct cds_hlist_head dl_state_table[UST_DL_STATE_TABLE_SIZE]; > + > typedef void (*tracepoint_cb)(struct lttng_session *session, void *priv); > > +static > +struct lttng_ust_dl_node *alloc_dl_node(const struct bin_info_data *bin_data) > +{ > + struct lttng_ust_dl_node *e; > + > + e = zmalloc(sizeof(struct lttng_ust_dl_node)); > + if (!e) > + return NULL; > + if (bin_data->dbg_file) { > + e->bin_data.dbg_file = strdup(bin_data->dbg_file); > + if (!e->bin_data.dbg_file) > + goto error; > + } > + if (bin_data->build_id) { > + e->bin_data.build_id = zmalloc(bin_data->build_id_len); > + if (!e->bin_data.build_id) > + goto error; > + memcpy(e->bin_data.build_id, bin_data->build_id, > + bin_data->build_id_len); > + } > + e->bin_data.base_addr_ptr = bin_data->base_addr_ptr; > + memcpy(e->bin_data.resolved_path, bin_data->resolved_path, PATH_MAX); > + e->bin_data.memsz = bin_data->memsz; > + e->bin_data.build_id_len = bin_data->build_id_len; > + e->bin_data.vdso = bin_data->vdso; > + e->bin_data.crc = bin_data->crc; > + e->bin_data.is_pic = bin_data->is_pic; > + e->bin_data.has_build_id = bin_data->has_build_id; > + e->bin_data.has_debug_link = bin_data->has_debug_link; > + return e; > + > +error: > + free(e->bin_data.build_id); > + free(e->bin_data.dbg_file); > + free(e); > + return NULL; > +} > + > +static > +void free_dl_node(struct lttng_ust_dl_node *e) > +{ > + free(e->bin_data.build_id); > + free(e->bin_data.dbg_file); > + free(e); > +} > + > +/* Return 0 if same, nonzero if not. */ > +static > +int compare_bin_data(const struct bin_info_data *a, > + const struct bin_info_data *b) > +{ > + if (a->base_addr_ptr != b->base_addr_ptr) > + return -1; > + if (strcmp(a->resolved_path, b->resolved_path) != 0) > + return -1; > + if (a->dbg_file && !b->dbg_file) > + return -1; > + if (!a->dbg_file && b->dbg_file) > + return -1; > + if (a->dbg_file && strcmp(a->dbg_file, b->dbg_file) != 0) > + return -1; > + if (a->build_id && !b->build_id) > + return -1; > + if (!a->build_id && b->build_id) > + return -1; > + if (a->build_id_len != b->build_id_len) > + return -1; > + if (a->build_id && > + memcmp(a->build_id, b->build_id, a->build_id_len) != 0) > + return -1; > + if (a->memsz != b->memsz) > + return -1; > + if (a->vdso != b->vdso) > + return -1; > + if (a->crc != b->crc) > + return -1; > + if (a->is_pic != b->is_pic) > + return -1; > + if (a->has_build_id != b->has_build_id) > + return -1; > + if (a->has_debug_link != b->has_debug_link) > + return -1; > + return 0; > +} > + > +static > +struct lttng_ust_dl_node *find_or_create_dl_node(struct bin_info_data > *bin_data) > +{ > + struct cds_hlist_head *head; > + struct lttng_ust_dl_node *e; > + unsigned int hash; > + bool found = false; > + > + hash = jhash(&bin_data->base_addr_ptr, > + sizeof(bin_data->base_addr_ptr), 0); > + head = &dl_state_table[hash & (UST_DL_STATE_TABLE_SIZE - 1)]; > + cds_hlist_for_each_entry_2(e, head, node) { > + if (compare_bin_data(&e->bin_data, bin_data) != 0) > + continue; > + found = true; > + break; > + } > + if (!found) { > + /* Create */ > + e = alloc_dl_node(bin_data); > + if (!e) > + return NULL; > + cds_hlist_add_head(&e->node, head); > + } > + return e; > +} > + > +static > +void remove_dl_node(struct lttng_ust_dl_node *e) > +{ > + cds_hlist_del(&e->node); > +} > + > /* > * Trace statedump event into all sessions owned by the caller thread > * for which statedump is pending. > */ > static > -int trace_statedump_event(tracepoint_cb tp_cb, void *owner, void *priv) > +void trace_statedump_event(tracepoint_cb tp_cb, void *owner, void *priv) > { > struct cds_list_head *sessionsp; > struct lttng_session *session; > @@ -76,7 +211,6 @@ int trace_statedump_event(tracepoint_cb tp_cb, void *owner, > void *priv) > continue; > tp_cb(session, priv); > } > - return 0; > } > > static > @@ -165,9 +299,22 @@ end: > } > > static > -int trace_baddr(struct bin_info_data *bin_data) > +void trace_baddr(struct bin_info_data *bin_data, void *owner) > +{ > + trace_statedump_event(trace_bin_info_cb, owner, bin_data); > + > + if (bin_data->has_build_id) > + trace_statedump_event(trace_build_id_cb, owner, bin_data); > + > + if (bin_data->has_debug_link) > + trace_statedump_event(trace_debug_link_cb, owner, bin_data); > +} > + > +static > +int extract_baddr(struct bin_info_data *bin_data) > { > int ret = 0; > + struct lttng_ust_dl_node *e; > > if (!bin_data->vdso) { > ret = get_elf_info(bin_data); > @@ -180,73 +327,146 @@ int trace_baddr(struct bin_info_data *bin_data) > bin_data->has_debug_link = 0; > } > > - ret = trace_statedump_event(trace_bin_info_cb, bin_data->owner, > - bin_data); > - if (ret) { > + e = find_or_create_dl_node(bin_data); > + if (!e) { > + ret = -1; > goto end; > } > - > - if (bin_data->has_build_id) { > - ret = trace_statedump_event( > - trace_build_id_cb, bin_data->owner, bin_data); > - free(bin_data->build_id); > - if (ret) { > - goto end; > - } > - } > - > - if (bin_data->has_debug_link) { > - ret = trace_statedump_event( > - trace_debug_link_cb, bin_data->owner, bin_data); > - free(bin_data->dbg_file); > - if (ret) { > - goto end; > - } > - } > - > + e->marked = true; > end: > + free(bin_data->build_id); > + bin_data->build_id = NULL; > + free(bin_data->dbg_file); > + bin_data->dbg_file = NULL; > return ret; > } > > static > -int trace_statedump_start(void *owner) > +void trace_statedump_start(void *owner) > { > - return trace_statedump_event(trace_start_cb, owner, NULL); > + trace_statedump_event(trace_start_cb, owner, NULL); > } > > static > -int trace_statedump_end(void *owner) > +void trace_statedump_end(void *owner) > { > - return trace_statedump_event(trace_end_cb, owner, NULL); > + trace_statedump_event(trace_end_cb, owner, NULL); > } > > static > -int extract_bin_info_events(struct dl_phdr_info *info, size_t size, void > *_data) > +void iter_begin(struct dl_iterate_data *data) > { > - int j, ret = 0; > - struct dl_iterate_data *data = _data; > + unsigned int i; > > /* > * UST lock nests within dynamic loader lock. > * > - * Hold this lock across handling of the entire module to > + * Hold this lock across handling of the module listing to > * protect memory allocation at early process start, due to > * interactions with libc-wrapper lttng malloc instrumentation. > */ > if (ust_lock()) { > - goto end; > + data->cancel = true; > + return; > } > > + /* Ensure all entries are unmarked. */ > + for (i = 0; i < UST_DL_STATE_TABLE_SIZE; i++) { > + struct cds_hlist_head *head; > + struct lttng_ust_dl_node *e; > + > + head = &dl_state_table[i]; > + cds_hlist_for_each_entry_2(e, head, node) > + assert(!e->marked); > + } > +} > + > +static > +void trace_lib_load(const struct bin_info_data *bin_data, void *ip) > +{ > + tracepoint(lttng_ust_lib, load, > + ip, bin_data->base_addr_ptr, bin_data->resolved_path, > + bin_data->memsz, bin_data->has_build_id, > + bin_data->has_debug_link); > + > + if (bin_data->has_build_id) { > + tracepoint(lttng_ust_lib, build_id, > + ip, bin_data->base_addr_ptr, bin_data->build_id, > + bin_data->build_id_len); > + } > + > + if (bin_data->has_debug_link) { > + tracepoint(lttng_ust_lib, debug_link, > + ip, bin_data->base_addr_ptr, bin_data->dbg_file, > + bin_data->crc); > + } > +} > + > +static > +void trace_lib_unload(const struct bin_info_data *bin_data, void *ip) > +{ > + tracepoint(lttng_ust_lib, unload, ip, bin_data->base_addr_ptr); > +} > + > +static > +void iter_end(struct dl_iterate_data *data, void *ip) > +{ > + unsigned int i; > + > + /* > + * Iterate on hash table. > + * For each marked, traced, do nothing. > + * For each marked, not traced, trace lib open event. traced = true. > + * For each unmarked, traced, trace lib close event. remove node. > + * For each unmarked, not traced, remove node. > + */ > + for (i = 0; i < UST_DL_STATE_TABLE_SIZE; i++) { > + struct cds_hlist_head *head; > + struct lttng_ust_dl_node *e; > + > + head = &dl_state_table[i]; > + cds_hlist_for_each_entry_2(e, head, node) { > + if (e->marked) { > + if (!e->traced) { > + trace_lib_load(&e->bin_data, ip); > + e->traced = true; > + } > + } else { > + if (e->traced) > + trace_lib_unload(&e->bin_data, ip); > + remove_dl_node(e); > + free_dl_node(e); > + } > + e->marked = false; > + } > + } > + ust_unlock(); > +} > + > +static > +int extract_bin_info_events(struct dl_phdr_info *info, size_t size, void > *_data) > +{ > + int j, ret = 0; > + struct dl_iterate_data *data = _data; > + > + if (data->first) { > + iter_begin(data); > + data->first = false; > + } > + > + if (data->cancel) > + goto end; > + > for (j = 0; j < info->dlpi_phnum; j++) { > struct bin_info_data bin_data; > - char resolved_path[PATH_MAX]; > - void *base_addr_ptr; > > if (info->dlpi_phdr[j].p_type != PT_LOAD) > continue; > > + memset(&bin_data, 0, sizeof(bin_data)); > + > /* Calculate virtual memory address of the loadable segment */ > - base_addr_ptr = (void *) info->dlpi_addr + > + bin_data.base_addr_ptr = (void *) info->dlpi_addr + > info->dlpi_phdr[j].p_vaddr; > > if ((info->dlpi_name == NULL || info->dlpi_name[0] == 0)) { > @@ -264,15 +484,16 @@ int extract_bin_info_events(struct dl_phdr_info *info, > size_t size, void *_data) > * executable's full path. > */ > path_len = readlink("/proc/self/exe", > - resolved_path, > + bin_data.resolved_path, > PATH_MAX - 1); > if (path_len <= 0) > break; > > - resolved_path[path_len] = '\0'; > + bin_data.resolved_path[path_len] = '\0'; > bin_data.vdso = 0; > } else { > - snprintf(resolved_path, PATH_MAX - 1, "[vdso]"); > + snprintf(bin_data.resolved_path, > + PATH_MAX - 1, "[vdso]"); > bin_data.vdso = 1; > } > } else { > @@ -281,8 +502,10 @@ int extract_bin_info_events(struct dl_phdr_info *info, > size_t size, void *_data) > * the path to the binary really exists. If not, > * treat as vdso and use dlpi_name as 'path'. > */ > - if (!realpath(info->dlpi_name, resolved_path)) { > - snprintf(resolved_path, PATH_MAX - 1, "[%s]", > + if (!realpath(info->dlpi_name, > + bin_data.resolved_path)) { > + snprintf(bin_data.resolved_path, > + PATH_MAX - 1, "[%s]", > info->dlpi_name); > bin_data.vdso = 1; > } else { > @@ -290,39 +513,73 @@ int extract_bin_info_events(struct dl_phdr_info *info, > size_t size, void *_data) > } > } > > - bin_data.owner = data->owner; > - bin_data.base_addr_ptr = base_addr_ptr; > - bin_data.resolved_path = resolved_path; > - ret = trace_baddr(&bin_data); > + ret = extract_baddr(&bin_data); > break; > } > end: > - ust_unlock(); > return ret; > } > > -/* > - * Generate a statedump of base addresses of all shared objects loaded > - * by the traced application, as well as for the application's > - * executable itself. > - */ > static > -int do_baddr_statedump(void *owner) > +void ust_dl_table_statedump(void *owner) > +{ > + unsigned int i; > + > + if (ust_lock()) > + goto end; > + > + /* Statedump each traced table entry into session for owner. */ > + for (i = 0; i < UST_DL_STATE_TABLE_SIZE; i++) { > + struct cds_hlist_head *head; > + struct lttng_ust_dl_node *e; > + > + head = &dl_state_table[i]; > + cds_hlist_for_each_entry_2(e, head, node) { > + if (e->traced) > + trace_baddr(&e->bin_data, owner); > + } > + } > + > +end: > + ust_unlock(); > +} > + > +void lttng_ust_dl_update(void *ip) > { > struct dl_iterate_data data; > > if (getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP")) > - return 0; > + return; > > - data.owner = owner; > data.exec_found = 0; > + data.first = true; > + data.cancel = false; > /* > * Iterate through the list of currently loaded shared objects and > - * generate events for loadable segments using > + * generate tables entries for loadable segments using > * extract_bin_info_events. > + * Removed libraries are detected by mark-and-sweep: marking is > + * done in the iteration over libraries, and sweeping is > + * performed by iter_end(). > */ > dl_iterate_phdr(extract_bin_info_events, &data); > + if (data.first) > + iter_begin(&data); > + iter_end(&data, ip); > +} > > +/* > + * Generate a statedump of base addresses of all shared objects loaded > + * by the traced application, as well as for the application's > + * executable itself. > + */ > +static > +int do_baddr_statedump(void *owner) > +{ > + if (getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP")) > + return 0; > + lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); > + ust_dl_table_statedump(owner); > return 0; > } > > @@ -348,6 +605,23 @@ void lttng_ust_statedump_init(void) > __tracepoints__init(); > __tracepoints__ptrs_init(); > __lttng_events_init__lttng_ust_statedump(); > + lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); > +} > + > +static > +void ust_dl_state_destroy(void) > +{ > + unsigned int i; > + > + for (i = 0; i < UST_DL_STATE_TABLE_SIZE; i++) { > + struct cds_hlist_head *head; > + struct lttng_ust_dl_node *e, *tmp; > + > + head = &dl_state_table[i]; > + cds_hlist_for_each_entry_safe_2(e, tmp, head, node) > + free_dl_node(e); > + CDS_INIT_HLIST_HEAD(head); > + } > } > > void lttng_ust_statedump_destroy(void) > @@ -355,4 +629,5 @@ void lttng_ust_statedump_destroy(void) > __lttng_events_exit__lttng_ust_statedump(); > __tracepoints__ptrs_destroy(); > __tracepoints__destroy(); > + ust_dl_state_destroy(); > } > -- > 2.1.4 -- Mathieu Desnoyers EfficiOS Inc. http://www.efficios.com _______________________________________________ lttng-dev mailing list lttng-dev@lists.lttng.org https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev