Add unit tests for lttng_ust_elf
[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
45struct soinfo_data {
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;
cf73e0fe
AB
55};
56
57typedef void (*tracepoint_cb)(struct lttng_session *session, void *priv);
58
59/*
60 * Trace statedump event into all sessions owned by the caller thread
61 * for which statedump is pending.
62 */
63static
64int trace_statedump_event(tracepoint_cb tp_cb, void *owner, void *priv)
65{
66 struct cds_list_head *sessionsp;
67 struct lttng_session *session;
68
69 /*
70 * UST lock nests within dynamic loader lock.
71 */
72 if (ust_lock()) {
73 ust_unlock();
74 return 1;
75 }
76
77 sessionsp = _lttng_get_sessions();
78 cds_list_for_each_entry(session, sessionsp, node) {
79 if (session->owner != owner)
80 continue;
81 if (!session->statedump_pending)
82 continue;
83 tp_cb(session, priv);
84 }
85 ust_unlock();
86 return 0;
87}
88
89static
90void trace_soinfo_cb(struct lttng_session *session, void *priv)
91{
92 struct soinfo_data *so_data = (struct soinfo_data *) priv;
93
94 tracepoint(lttng_ust_statedump, soinfo,
8e2aed3f
AB
95 session, so_data->base_addr_ptr,
96 so_data->resolved_path, so_data->memsz);
97}
98
99static
100void trace_build_id_cb(struct lttng_session *session, void *priv)
101{
102 struct soinfo_data *so_data = (struct soinfo_data *) priv;
103
104 tracepoint(lttng_ust_statedump, build_id,
105 session, so_data->base_addr_ptr,
106 so_data->build_id, so_data->build_id_len);
107}
108
109static
110void trace_debug_link_cb(struct lttng_session *session, void *priv)
111{
112 struct soinfo_data *so_data = (struct soinfo_data *) priv;
113
114 tracepoint(lttng_ust_statedump, debug_link,
115 session, so_data->base_addr_ptr,
116 so_data->dbg_file, so_data->crc);
cf73e0fe
AB
117}
118
119static
120void trace_start_cb(struct lttng_session *session, void *priv)
121{
122 tracepoint(lttng_ust_statedump, start, session);
123}
124
125static
126void trace_end_cb(struct lttng_session *session, void *priv)
127{
128 tracepoint(lttng_ust_statedump, end, session);
129}
130
8e2aed3f
AB
131static
132int get_elf_info(struct soinfo_data *so_data, int *has_build_id,
133 int *has_debug_link) {
134 struct lttng_ust_elf *elf;
135 int ret = 0;
136
137 elf = lttng_ust_elf_create(so_data->resolved_path);
138 if (!elf) {
139 ret = -1;
140 goto end;
141 }
142
143 ret = lttng_ust_elf_get_memsz(elf, &so_data->memsz);
144 if (ret) {
145 goto end;
146 }
147
148 ret = lttng_ust_elf_get_build_id(elf, &so_data->build_id,
149 &so_data->build_id_len, has_build_id);
150 if (ret) {
151 goto end;
152 }
153 ret = lttng_ust_elf_get_debug_link(elf, &so_data->dbg_file,
154 &so_data->crc, has_debug_link);
155 if (ret) {
156 goto end;
157 }
158
159end:
160 lttng_ust_elf_destroy(elf);
161 return ret;
162}
163
cf73e0fe
AB
164static
165int trace_baddr(struct soinfo_data *so_data)
166{
8e2aed3f
AB
167 int ret = 0, has_build_id = 0, has_debug_link = 0;
168
169 if (!so_data->vdso) {
170 ret = get_elf_info(so_data, &has_build_id, &has_debug_link);
171 if (ret) {
172 goto end;
173 }
174 } else {
175 so_data->memsz = 0;
176 }
177
178 ret = trace_statedump_event(trace_soinfo_cb, so_data->owner, so_data);
179 if (ret) {
180 goto end;
181 }
cf73e0fe 182
8e2aed3f
AB
183 if (has_build_id) {
184 ret = trace_statedump_event(
185 trace_build_id_cb, so_data->owner, so_data);
186 free(so_data->build_id);
187 if (ret) {
188 goto end;
189 }
cf73e0fe
AB
190 }
191
8e2aed3f
AB
192 if (has_debug_link) {
193 ret = trace_statedump_event(
194 trace_debug_link_cb, so_data->owner, so_data);
195 free(so_data->dbg_file);
196 if (ret) {
197 goto end;
198 }
199 }
cf73e0fe 200
8e2aed3f
AB
201end:
202 return ret;
cf73e0fe
AB
203}
204
205static
206int trace_statedump_start(void *owner)
207{
208 return trace_statedump_event(trace_start_cb, owner, NULL);
209}
210
211static
212int trace_statedump_end(void *owner)
213{
214 return trace_statedump_event(trace_end_cb, owner, NULL);
215}
216
217static
218int extract_soinfo_events(struct dl_phdr_info *info, size_t size, void *_data)
219{
220 int j;
221 struct dl_iterate_data *data = _data;
222
223 for (j = 0; j < info->dlpi_phnum; j++) {
224 struct soinfo_data so_data;
225 char resolved_path[PATH_MAX];
226 void *base_addr_ptr;
227
228 if (info->dlpi_phdr[j].p_type != PT_LOAD)
229 continue;
230
231 /* Calculate virtual memory address of the loadable segment */
232 base_addr_ptr = (void *) info->dlpi_addr +
233 info->dlpi_phdr[j].p_vaddr;
234
235 if ((info->dlpi_name == NULL || info->dlpi_name[0] == 0)) {
236 /*
237 * Only the first phdr without a dlpi_name
238 * encountered is considered as the program
239 * executable. The rest are vdsos.
240 */
241 if (!data->exec_found) {
242 ssize_t path_len;
243 data->exec_found = 1;
244
245 /*
246 * Use /proc/self/exe to resolve the
247 * executable's full path.
248 */
249 path_len = readlink("/proc/self/exe",
250 resolved_path,
251 PATH_MAX - 1);
252 if (path_len <= 0)
253 break;
254
255 resolved_path[path_len] = '\0';
256 so_data.vdso = 0;
257 } else {
258 snprintf(resolved_path, PATH_MAX - 1, "[vdso]");
259 so_data.vdso = 1;
260 }
261 } else {
262 /*
263 * For regular dl_phdr_info entries check if
264 * the path to the SO really exists. If not,
265 * treat as vdso and use dlpi_name as 'path'.
266 */
267 if (!realpath(info->dlpi_name, resolved_path)) {
268 snprintf(resolved_path, PATH_MAX - 1, "[%s]",
269 info->dlpi_name);
270 so_data.vdso = 1;
89be5359
AB
271 } else {
272 so_data.vdso = 0;
cf73e0fe
AB
273 }
274 }
275
276 so_data.owner = data->owner;
277 so_data.base_addr_ptr = base_addr_ptr;
278 so_data.resolved_path = resolved_path;
279 return trace_baddr(&so_data);
280 }
281
282 return 0;
283}
284
285/*
286 * Generate a statedump of base addresses of all shared objects loaded
287 * by the traced application, as well as for the application's
288 * executable itself.
289 */
290static
291int do_baddr_statedump(void *owner)
292{
293 struct dl_iterate_data data;
294
295 if (getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP"))
296 return 0;
297
298 data.owner = owner;
299 data.exec_found = 0;
300 /*
301 * Iterate through the list of currently loaded shared objects and
302 * generate events for loadable segments using
303 * extract_soinfo_events.
304 */
305 dl_iterate_phdr(extract_soinfo_events, &data);
306
307 return 0;
308}
309
310/*
311 * Generate a statedump of a given traced application. A statedump is
312 * delimited by start and end events. For a given (process, session)
313 * pair, begin/end events are serialized and will match. However, in a
314 * session, statedumps from different processes may be
315 * interleaved. The vpid context should be used to identify which
316 * events belong to which process.
317 */
318int do_lttng_ust_statedump(void *owner)
319{
320 trace_statedump_start(owner);
321 do_baddr_statedump(owner);
322 trace_statedump_end(owner);
323
324 return 0;
325}
326
327void lttng_ust_statedump_init(void)
328{
329 __tracepoints__init();
330 __tracepoints__ptrs_init();
331 __lttng_events_init__lttng_ust_statedump();
332}
333
334void lttng_ust_statedump_destroy(void)
335{
336 __lttng_events_exit__lttng_ust_statedump();
337 __tracepoints__ptrs_destroy();
338 __tracepoints__destroy();
339}
This page took 0.035233 seconds and 4 git commands to generate.