Tests: Add tap-driver.sh for automake < 1.12
[lttng-ust.git] / liblttng-ust / lttng-ust-statedump.c
CommitLineData
cf73e0fe
AB
1/*
2 * Copyright (C) 2013 Paul Woegerer <paul_woegerer@mentor.com>
3 * Copyright (C) 2015 Antoine Busque <abusque@efficios.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#define _LGPL_SOURCE
21#define _GNU_SOURCE
cf73e0fe 22
8e2aed3f 23#include <link.h>
cf73e0fe 24#include <limits.h>
cf73e0fe 25#include <stdio.h>
8e2aed3f
AB
26#include <stdint.h>
27#include <stdlib.h>
28#include <sys/types.h>
29#include <unistd.h>
cf73e0fe 30
8e2aed3f 31#include <lttng/ust-elf.h>
cf73e0fe
AB
32#include "lttng-tracer-core.h"
33#include "lttng-ust-statedump.h"
34
35#define TRACEPOINT_DEFINE
36#define TRACEPOINT_CREATE_PROBES
37#define TP_SESSION_CHECK
38#include "lttng-ust-statedump-provider.h"
39
40struct dl_iterate_data {
41 void *owner;
42 int exec_found;
43};
44
f60e49df 45struct bin_info_data {
cf73e0fe
AB
46 void *owner;
47 void *base_addr_ptr;
48 const char *resolved_path;
8e2aed3f
AB
49 char *dbg_file;
50 uint8_t *build_id;
51 uint64_t memsz;
52 size_t build_id_len;
cf73e0fe 53 int vdso;
8e2aed3f 54 uint32_t crc;
f5eb039d 55 uint8_t is_pic;
c5c4fd82
MD
56 uint8_t has_build_id;
57 uint8_t has_debug_link;
cf73e0fe
AB
58};
59
60typedef void (*tracepoint_cb)(struct lttng_session *session, void *priv);
61
62/*
63 * Trace statedump event into all sessions owned by the caller thread
64 * for which statedump is pending.
65 */
66static
67int trace_statedump_event(tracepoint_cb tp_cb, void *owner, void *priv)
68{
69 struct cds_list_head *sessionsp;
70 struct lttng_session *session;
71
cf73e0fe
AB
72 sessionsp = _lttng_get_sessions();
73 cds_list_for_each_entry(session, sessionsp, node) {
74 if (session->owner != owner)
75 continue;
76 if (!session->statedump_pending)
77 continue;
78 tp_cb(session, priv);
79 }
cf73e0fe
AB
80 return 0;
81}
82
83static
f60e49df 84void trace_bin_info_cb(struct lttng_session *session, void *priv)
cf73e0fe 85{
f60e49df 86 struct bin_info_data *bin_data = (struct bin_info_data *) priv;
cf73e0fe 87
f60e49df
AB
88 tracepoint(lttng_ust_statedump, bin_info,
89 session, bin_data->base_addr_ptr,
c5c4fd82
MD
90 bin_data->resolved_path, bin_data->memsz,
91 bin_data->is_pic, bin_data->has_build_id,
92 bin_data->has_debug_link);
8e2aed3f
AB
93}
94
95static
96void trace_build_id_cb(struct lttng_session *session, void *priv)
97{
f60e49df 98 struct bin_info_data *bin_data = (struct bin_info_data *) priv;
8e2aed3f
AB
99
100 tracepoint(lttng_ust_statedump, build_id,
f60e49df
AB
101 session, bin_data->base_addr_ptr,
102 bin_data->build_id, bin_data->build_id_len);
8e2aed3f
AB
103}
104
105static
106void trace_debug_link_cb(struct lttng_session *session, void *priv)
107{
f60e49df 108 struct bin_info_data *bin_data = (struct bin_info_data *) priv;
8e2aed3f
AB
109
110 tracepoint(lttng_ust_statedump, debug_link,
f60e49df
AB
111 session, bin_data->base_addr_ptr,
112 bin_data->dbg_file, bin_data->crc);
cf73e0fe
AB
113}
114
115static
116void trace_start_cb(struct lttng_session *session, void *priv)
117{
118 tracepoint(lttng_ust_statedump, start, session);
119}
120
121static
122void trace_end_cb(struct lttng_session *session, void *priv)
123{
124 tracepoint(lttng_ust_statedump, end, session);
125}
126
8e2aed3f 127static
c5c4fd82
MD
128int get_elf_info(struct bin_info_data *bin_data)
129{
8e2aed3f 130 struct lttng_ust_elf *elf;
c5c4fd82 131 int ret = 0, found;
8e2aed3f 132
f60e49df 133 elf = lttng_ust_elf_create(bin_data->resolved_path);
8e2aed3f
AB
134 if (!elf) {
135 ret = -1;
136 goto end;
137 }
138
f60e49df 139 ret = lttng_ust_elf_get_memsz(elf, &bin_data->memsz);
8e2aed3f
AB
140 if (ret) {
141 goto end;
142 }
143
c5c4fd82 144 found = 0;
f60e49df 145 ret = lttng_ust_elf_get_build_id(elf, &bin_data->build_id,
c5c4fd82
MD
146 &bin_data->build_id_len,
147 &found);
8e2aed3f
AB
148 if (ret) {
149 goto end;
150 }
c5c4fd82
MD
151 bin_data->has_build_id = !!found;
152 found = 0;
f60e49df 153 ret = lttng_ust_elf_get_debug_link(elf, &bin_data->dbg_file,
c5c4fd82
MD
154 &bin_data->crc,
155 &found);
8e2aed3f
AB
156 if (ret) {
157 goto end;
158 }
c5c4fd82 159 bin_data->has_debug_link = !!found;
8e2aed3f 160
f60e49df 161 bin_data->is_pic = lttng_ust_elf_is_pic(elf);
f5eb039d 162
8e2aed3f
AB
163end:
164 lttng_ust_elf_destroy(elf);
165 return ret;
166}
167
cf73e0fe 168static
f60e49df 169int trace_baddr(struct bin_info_data *bin_data)
cf73e0fe 170{
c5c4fd82 171 int ret = 0;
8e2aed3f 172
f60e49df 173 if (!bin_data->vdso) {
c5c4fd82 174 ret = get_elf_info(bin_data);
8e2aed3f
AB
175 if (ret) {
176 goto end;
177 }
178 } else {
f60e49df 179 bin_data->memsz = 0;
8e2aed3f
AB
180 }
181
f60e49df
AB
182 ret = trace_statedump_event(trace_bin_info_cb, bin_data->owner,
183 bin_data);
8e2aed3f
AB
184 if (ret) {
185 goto end;
186 }
cf73e0fe 187
c5c4fd82 188 if (bin_data->has_build_id) {
8e2aed3f 189 ret = trace_statedump_event(
f60e49df
AB
190 trace_build_id_cb, bin_data->owner, bin_data);
191 free(bin_data->build_id);
8e2aed3f
AB
192 if (ret) {
193 goto end;
194 }
cf73e0fe
AB
195 }
196
c5c4fd82 197 if (bin_data->has_debug_link) {
8e2aed3f 198 ret = trace_statedump_event(
f60e49df
AB
199 trace_debug_link_cb, bin_data->owner, bin_data);
200 free(bin_data->dbg_file);
8e2aed3f
AB
201 if (ret) {
202 goto end;
203 }
204 }
cf73e0fe 205
8e2aed3f
AB
206end:
207 return ret;
cf73e0fe
AB
208}
209
210static
211int trace_statedump_start(void *owner)
212{
213 return trace_statedump_event(trace_start_cb, owner, NULL);
214}
215
216static
217int trace_statedump_end(void *owner)
218{
219 return trace_statedump_event(trace_end_cb, owner, NULL);
220}
221
222static
f60e49df 223int extract_bin_info_events(struct dl_phdr_info *info, size_t size, void *_data)
cf73e0fe 224{
d34e6761 225 int j, ret = 0;
cf73e0fe
AB
226 struct dl_iterate_data *data = _data;
227
d34e6761
MD
228 /*
229 * UST lock nests within dynamic loader lock.
230 *
231 * Hold this lock across handling of the entire module to
232 * protect memory allocation at early process start, due to
233 * interactions with libc-wrapper lttng malloc instrumentation.
234 */
235 if (ust_lock()) {
236 goto end;
237 }
238
cf73e0fe 239 for (j = 0; j < info->dlpi_phnum; j++) {
f60e49df 240 struct bin_info_data bin_data;
cf73e0fe
AB
241 char resolved_path[PATH_MAX];
242 void *base_addr_ptr;
243
244 if (info->dlpi_phdr[j].p_type != PT_LOAD)
245 continue;
246
247 /* Calculate virtual memory address of the loadable segment */
248 base_addr_ptr = (void *) info->dlpi_addr +
249 info->dlpi_phdr[j].p_vaddr;
250
251 if ((info->dlpi_name == NULL || info->dlpi_name[0] == 0)) {
252 /*
253 * Only the first phdr without a dlpi_name
254 * encountered is considered as the program
255 * executable. The rest are vdsos.
256 */
257 if (!data->exec_found) {
258 ssize_t path_len;
259 data->exec_found = 1;
260
261 /*
262 * Use /proc/self/exe to resolve the
263 * executable's full path.
264 */
265 path_len = readlink("/proc/self/exe",
266 resolved_path,
267 PATH_MAX - 1);
268 if (path_len <= 0)
269 break;
270
271 resolved_path[path_len] = '\0';
f60e49df 272 bin_data.vdso = 0;
cf73e0fe
AB
273 } else {
274 snprintf(resolved_path, PATH_MAX - 1, "[vdso]");
f60e49df 275 bin_data.vdso = 1;
cf73e0fe
AB
276 }
277 } else {
278 /*
279 * For regular dl_phdr_info entries check if
f60e49df 280 * the path to the binary really exists. If not,
cf73e0fe
AB
281 * treat as vdso and use dlpi_name as 'path'.
282 */
283 if (!realpath(info->dlpi_name, resolved_path)) {
284 snprintf(resolved_path, PATH_MAX - 1, "[%s]",
285 info->dlpi_name);
f60e49df 286 bin_data.vdso = 1;
89be5359 287 } else {
f60e49df 288 bin_data.vdso = 0;
cf73e0fe
AB
289 }
290 }
291
f60e49df
AB
292 bin_data.owner = data->owner;
293 bin_data.base_addr_ptr = base_addr_ptr;
294 bin_data.resolved_path = resolved_path;
295 ret = trace_baddr(&bin_data);
d34e6761 296 break;
cf73e0fe 297 }
d34e6761
MD
298end:
299 ust_unlock();
300 return ret;
cf73e0fe
AB
301}
302
303/*
304 * Generate a statedump of base addresses of all shared objects loaded
305 * by the traced application, as well as for the application's
306 * executable itself.
307 */
308static
309int do_baddr_statedump(void *owner)
310{
311 struct dl_iterate_data data;
312
313 if (getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP"))
314 return 0;
315
316 data.owner = owner;
317 data.exec_found = 0;
318 /*
319 * Iterate through the list of currently loaded shared objects and
320 * generate events for loadable segments using
f60e49df 321 * extract_bin_info_events.
cf73e0fe 322 */
f60e49df 323 dl_iterate_phdr(extract_bin_info_events, &data);
cf73e0fe
AB
324
325 return 0;
326}
327
328/*
329 * Generate a statedump of a given traced application. A statedump is
330 * delimited by start and end events. For a given (process, session)
331 * pair, begin/end events are serialized and will match. However, in a
332 * session, statedumps from different processes may be
333 * interleaved. The vpid context should be used to identify which
334 * events belong to which process.
335 */
336int do_lttng_ust_statedump(void *owner)
337{
338 trace_statedump_start(owner);
339 do_baddr_statedump(owner);
340 trace_statedump_end(owner);
341
342 return 0;
343}
344
345void lttng_ust_statedump_init(void)
346{
347 __tracepoints__init();
348 __tracepoints__ptrs_init();
349 __lttng_events_init__lttng_ust_statedump();
350}
351
352void lttng_ust_statedump_destroy(void)
353{
354 __lttng_events_exit__lttng_ust_statedump();
355 __tracepoints__ptrs_destroy();
356 __tracepoints__destroy();
357}
This page took 0.037783 seconds and 4 git commands to generate.