X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-baddr.c;h=42ae630d99eadd1132025599f13c4505dd697a81;hb=f02baefb3ba4d5493816d63f65625ba4269224d2;hp=aa66dccfe8a243b4e9f948644c0ec5283731e119;hpb=76b82fc001c026d676057dd5772db3eb55f9b0ba;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-baddr.c b/liblttng-ust/lttng-ust-baddr.c index aa66dccf..42ae630d 100644 --- a/liblttng-ust/lttng-ust-baddr.c +++ b/liblttng-ust/lttng-ust-baddr.c @@ -16,8 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _LGPL_SOURCE #define _GNU_SOURCE -#include #include #include @@ -29,26 +29,76 @@ #include #include #include -#include "usterr.h" +#include +#include "lttng-tracer-core.h" #include "lttng-ust-baddr.h" #define TRACEPOINT_DEFINE +#define TRACEPOINT_CREATE_PROBES +#define TP_SESSION_CHECK #include "ust_baddr_statedump.h" +struct extract_data { + void *owner; + void *exec_baddr; /* executable base address */ +}; + +/* + * Trace baddr into all sessions for which statedump is pending owned by + * the caller thread. + */ static -int extract_soinfo_events(struct dl_phdr_info *info, size_t size, void *data) +int trace_baddr(void *base_addr_ptr, + const char *resolved_path, + int vdso, + void *owner) { - int j; - int num_loadable_segment = 0; - void *owner = data; struct cds_list_head *sessionsp; + struct lttng_session *session; + struct stat sostat; + + if (vdso || stat(resolved_path, &sostat)) { + sostat.st_size = 0; + sostat.st_mtime = -1; + } + /* + * UST lock nests within dynamic loader lock. + */ + if (ust_lock()) { + /* + * Stop iteration on headers if need to exit. + */ + ust_unlock(); + return 1; + } + + sessionsp = _lttng_get_sessions(); + cds_list_for_each_entry(session, sessionsp, node) { + if (session->owner != owner) + continue; + if (!session->statedump_pending) + continue; + tracepoint(ust_baddr_statedump, soinfo, + session, base_addr_ptr, + resolved_path, sostat.st_size, + sostat.st_mtime); + } + ust_unlock(); + return 0; +} + +static +int extract_soinfo_events(struct dl_phdr_info *info, size_t size, void *_data) +{ + int j; + struct extract_data *data = _data; + void *owner = data->owner; for (j = 0; j < info->dlpi_phnum; j++) { char resolved_path[PATH_MAX]; - struct stat sostat; void *base_addr_ptr; - struct lttng_session *session; + int vdso = 0; if (info->dlpi_phdr[j].p_type != PT_LOAD) continue; @@ -57,53 +107,40 @@ int extract_soinfo_events(struct dl_phdr_info *info, size_t size, void *data) base_addr_ptr = (void *) info->dlpi_addr + info->dlpi_phdr[j].p_vaddr; - num_loadable_segment += 1; if ((info->dlpi_name == NULL || info->dlpi_name[0] == 0) - && num_loadable_segment == 1) { + && !data->exec_baddr) { /* - * If the iterated element is the executable itself we - * have to use Dl_info to determine its full path + * Only the first phdr encountered is considered + * as the program executable. The following + * could be e.g. vdso. Don't mistakenly dump + * them as being the program executable. */ - Dl_info dl_info = { 0 }; - if (!dladdr(base_addr_ptr, &dl_info)) - return 0; - if (!realpath(dl_info.dli_fname, resolved_path)) - return 0; + data->exec_baddr = base_addr_ptr; + /* + * Deal with program executable outside of phdr + * iteration. + */ + break; + } + if (info->dlpi_name == NULL || info->dlpi_name[0] == 0) { + /* Found vDSO. */ + snprintf(resolved_path, PATH_MAX - 1, "[vdso]"); + vdso = 1; } else { /* * For regular dl_phdr_info entries we have to check if - * the path to the shared object really exists + * the path to the shared object really exists. */ if (!realpath(info->dlpi_name, resolved_path)) { - /* Found vDSO, put the 'path' into brackets */ + /* Path unknown, put the 'path' into brackets */ snprintf(resolved_path, PATH_MAX - 1, "[%s]", - info->dlpi_name); + info->dlpi_name); + vdso = 1; } } - - if (stat(resolved_path, &sostat)) { - sostat.st_size = 0; - sostat.st_mtime = -1; - } - - /* - * UST lock needs to be nested within dynamic loader - * lock. - */ - ust_lock(); - sessionsp = _lttng_get_sessions(); - cds_list_for_each_entry(session, sessionsp, node) { - if (session->owner != owner) - continue; - if (!session->statedump_pending) - continue; - tracepoint(ust_baddr_statedump, soinfo, - session, base_addr_ptr, - resolved_path, sostat.st_size, - sostat.st_mtime); + if (trace_baddr(base_addr_ptr, resolved_path, vdso, owner)) { + return 1; } - ust_unlock(); - /* * We are only interested in the base address (lowest virtual * address associated with the memory image), skip the rest @@ -113,15 +150,62 @@ int extract_soinfo_events(struct dl_phdr_info *info, size_t size, void *data) return 0; } +static +void dump_exec_baddr(struct extract_data *data) +{ + void *owner = data->owner; + Dl_info dl_info = { 0 }; + void *base_addr_ptr; + char resolved_path[PATH_MAX]; + + base_addr_ptr = data->exec_baddr; + if (!base_addr_ptr) + return; + /* + * We have to use Dl_info to determine the executable full path. + */ + if (!dladdr(base_addr_ptr, &dl_info)) + return; + if (!realpath(dl_info.dli_fname, resolved_path)) + return; + trace_baddr(base_addr_ptr, resolved_path, 0, owner); +} + int lttng_ust_baddr_statedump(void *owner) { + struct extract_data data; + if (getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP")) return 0; + + data.owner = owner; + data.exec_baddr = NULL; /* * Iterate through the list of currently loaded shared objects and * generate events for loadable segments using * extract_soinfo_events. */ - dl_iterate_phdr(extract_soinfo_events, owner); + dl_iterate_phdr(extract_soinfo_events, &data); + /* + * We cannot call dladdr() from within phdr iteration, without + * causing constructor vs dynamic loader vs multithread internal + * deadlocks, so dump the executable outside of the phdr + * iteration. + */ + dump_exec_baddr(&data); return 0; } + +void lttng_ust_baddr_statedump_init(void) +{ + __tracepoints__init(); + __tracepoints__ptrs_init(); + __lttng_events_init__ust_baddr_statedump(); +} + +void lttng_ust_baddr_statedump_destroy(void) +{ + __lttng_events_exit__ust_baddr_statedump(); + __tracepoints__ptrs_destroy(); + __tracepoints__destroy(); +}