Commit | Line | Data |
---|---|---|
cf73e0fe | 1 | /* |
c0c0989a | 2 | * SPDX-License-Identifier: LGPL-2.1-or-later |
cf73e0fe | 3 | * |
c0c0989a MJ |
4 | * Copyright (C) 2013 Paul Woegerer <paul_woegerer@mentor.com> |
5 | * Copyright (C) 2015 Antoine Busque <abusque@efficios.com> | |
6 | * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
cf73e0fe AB |
7 | */ |
8 | ||
1ddceb36 | 9 | #define _LGPL_SOURCE |
8e2aed3f | 10 | #include <link.h> |
cf73e0fe | 11 | #include <limits.h> |
cf73e0fe | 12 | #include <stdio.h> |
8e2aed3f AB |
13 | #include <stdint.h> |
14 | #include <stdlib.h> | |
97c7c238 | 15 | #include <stdbool.h> |
8e2aed3f AB |
16 | #include <sys/types.h> |
17 | #include <unistd.h> | |
cf73e0fe | 18 | |
9d315d6d MJ |
19 | #include "common/elf.h" |
20 | #include "common/macros.h" | |
cf73e0fe AB |
21 | #include "lttng-tracer-core.h" |
22 | #include "lttng-ust-statedump.h" | |
e58e5ad5 | 23 | #include "common/jhash.h" |
910dcd72 | 24 | #include "common/getenv.h" |
36c52fff | 25 | #include "lib/lttng-ust/events.h" |
cf73e0fe | 26 | |
88c7c4ea | 27 | #define LTTNG_UST_TRACEPOINT_DEFINE |
97c7c238 MD |
28 | #include "ust_lib.h" /* Only define. */ |
29 | ||
660323e6 | 30 | #define LTTNG_UST_TRACEPOINT_CREATE_PROBES |
91fe3e13 | 31 | #define LTTNG_UST_TP_SESSION_CHECK |
97c7c238 | 32 | #include "lttng-ust-statedump-provider.h" /* Define and create probes. */ |
cf73e0fe AB |
33 | |
34 | struct dl_iterate_data { | |
cf73e0fe | 35 | int exec_found; |
97c7c238 MD |
36 | bool first; |
37 | bool cancel; | |
cf73e0fe AB |
38 | }; |
39 | ||
f60e49df | 40 | struct bin_info_data { |
cf73e0fe | 41 | void *base_addr_ptr; |
97c7c238 | 42 | char resolved_path[PATH_MAX]; |
8e2aed3f AB |
43 | char *dbg_file; |
44 | uint8_t *build_id; | |
45 | uint64_t memsz; | |
46 | size_t build_id_len; | |
cf73e0fe | 47 | int vdso; |
8e2aed3f | 48 | uint32_t crc; |
f5eb039d | 49 | uint8_t is_pic; |
c5c4fd82 MD |
50 | uint8_t has_build_id; |
51 | uint8_t has_debug_link; | |
cf73e0fe AB |
52 | }; |
53 | ||
97c7c238 MD |
54 | struct lttng_ust_dl_node { |
55 | struct bin_info_data bin_data; | |
56 | struct cds_hlist_node node; | |
57 | bool traced; | |
58 | bool marked; | |
59 | }; | |
60 | ||
61 | #define UST_DL_STATE_HASH_BITS 8 | |
62 | #define UST_DL_STATE_TABLE_SIZE (1 << UST_DL_STATE_HASH_BITS) | |
63 | struct cds_hlist_head dl_state_table[UST_DL_STATE_TABLE_SIZE]; | |
64 | ||
f69fe5fb | 65 | typedef void (*tracepoint_cb)(struct lttng_ust_session *session, void *priv); |
cf73e0fe | 66 | |
97c7c238 MD |
67 | static |
68 | struct lttng_ust_dl_node *alloc_dl_node(const struct bin_info_data *bin_data) | |
69 | { | |
70 | struct lttng_ust_dl_node *e; | |
71 | ||
72 | e = zmalloc(sizeof(struct lttng_ust_dl_node)); | |
73 | if (!e) | |
74 | return NULL; | |
75 | if (bin_data->dbg_file) { | |
76 | e->bin_data.dbg_file = strdup(bin_data->dbg_file); | |
77 | if (!e->bin_data.dbg_file) | |
78 | goto error; | |
79 | } | |
80 | if (bin_data->build_id) { | |
81 | e->bin_data.build_id = zmalloc(bin_data->build_id_len); | |
82 | if (!e->bin_data.build_id) | |
83 | goto error; | |
84 | memcpy(e->bin_data.build_id, bin_data->build_id, | |
85 | bin_data->build_id_len); | |
86 | } | |
87 | e->bin_data.base_addr_ptr = bin_data->base_addr_ptr; | |
88 | memcpy(e->bin_data.resolved_path, bin_data->resolved_path, PATH_MAX); | |
89 | e->bin_data.memsz = bin_data->memsz; | |
90 | e->bin_data.build_id_len = bin_data->build_id_len; | |
91 | e->bin_data.vdso = bin_data->vdso; | |
92 | e->bin_data.crc = bin_data->crc; | |
93 | e->bin_data.is_pic = bin_data->is_pic; | |
94 | e->bin_data.has_build_id = bin_data->has_build_id; | |
95 | e->bin_data.has_debug_link = bin_data->has_debug_link; | |
96 | return e; | |
97 | ||
98 | error: | |
99 | free(e->bin_data.build_id); | |
100 | free(e->bin_data.dbg_file); | |
101 | free(e); | |
102 | return NULL; | |
103 | } | |
104 | ||
105 | static | |
106 | void free_dl_node(struct lttng_ust_dl_node *e) | |
107 | { | |
108 | free(e->bin_data.build_id); | |
109 | free(e->bin_data.dbg_file); | |
110 | free(e); | |
111 | } | |
112 | ||
113 | /* Return 0 if same, nonzero if not. */ | |
114 | static | |
115 | int compare_bin_data(const struct bin_info_data *a, | |
116 | const struct bin_info_data *b) | |
117 | { | |
118 | if (a->base_addr_ptr != b->base_addr_ptr) | |
119 | return -1; | |
120 | if (strcmp(a->resolved_path, b->resolved_path) != 0) | |
121 | return -1; | |
122 | if (a->dbg_file && !b->dbg_file) | |
123 | return -1; | |
124 | if (!a->dbg_file && b->dbg_file) | |
125 | return -1; | |
126 | if (a->dbg_file && strcmp(a->dbg_file, b->dbg_file) != 0) | |
127 | return -1; | |
128 | if (a->build_id && !b->build_id) | |
129 | return -1; | |
130 | if (!a->build_id && b->build_id) | |
131 | return -1; | |
132 | if (a->build_id_len != b->build_id_len) | |
133 | return -1; | |
134 | if (a->build_id && | |
135 | memcmp(a->build_id, b->build_id, a->build_id_len) != 0) | |
136 | return -1; | |
137 | if (a->memsz != b->memsz) | |
138 | return -1; | |
139 | if (a->vdso != b->vdso) | |
140 | return -1; | |
141 | if (a->crc != b->crc) | |
142 | return -1; | |
143 | if (a->is_pic != b->is_pic) | |
144 | return -1; | |
145 | if (a->has_build_id != b->has_build_id) | |
146 | return -1; | |
147 | if (a->has_debug_link != b->has_debug_link) | |
148 | return -1; | |
149 | return 0; | |
150 | } | |
151 | ||
152 | static | |
153 | struct lttng_ust_dl_node *find_or_create_dl_node(struct bin_info_data *bin_data) | |
154 | { | |
155 | struct cds_hlist_head *head; | |
156 | struct lttng_ust_dl_node *e; | |
157 | unsigned int hash; | |
158 | bool found = false; | |
159 | ||
160 | hash = jhash(&bin_data->base_addr_ptr, | |
161 | sizeof(bin_data->base_addr_ptr), 0); | |
162 | head = &dl_state_table[hash & (UST_DL_STATE_TABLE_SIZE - 1)]; | |
163 | cds_hlist_for_each_entry_2(e, head, node) { | |
164 | if (compare_bin_data(&e->bin_data, bin_data) != 0) | |
165 | continue; | |
166 | found = true; | |
167 | break; | |
168 | } | |
169 | if (!found) { | |
170 | /* Create */ | |
171 | e = alloc_dl_node(bin_data); | |
172 | if (!e) | |
173 | return NULL; | |
174 | cds_hlist_add_head(&e->node, head); | |
175 | } | |
176 | return e; | |
177 | } | |
178 | ||
179 | static | |
180 | void remove_dl_node(struct lttng_ust_dl_node *e) | |
181 | { | |
182 | cds_hlist_del(&e->node); | |
183 | } | |
184 | ||
cf73e0fe AB |
185 | /* |
186 | * Trace statedump event into all sessions owned by the caller thread | |
187 | * for which statedump is pending. | |
188 | */ | |
189 | static | |
97c7c238 | 190 | void trace_statedump_event(tracepoint_cb tp_cb, void *owner, void *priv) |
cf73e0fe AB |
191 | { |
192 | struct cds_list_head *sessionsp; | |
bdb12629 | 193 | struct lttng_ust_session_private *session_priv; |
cf73e0fe | 194 | |
7753d283 | 195 | sessionsp = lttng_get_sessions(); |
bdb12629 MD |
196 | cds_list_for_each_entry(session_priv, sessionsp, node) { |
197 | if (session_priv->owner != owner) | |
cf73e0fe | 198 | continue; |
bdb12629 | 199 | if (!session_priv->statedump_pending) |
cf73e0fe | 200 | continue; |
bdb12629 | 201 | tp_cb(session_priv->pub, priv); |
cf73e0fe | 202 | } |
cf73e0fe AB |
203 | } |
204 | ||
205 | static | |
f69fe5fb | 206 | void trace_bin_info_cb(struct lttng_ust_session *session, void *priv) |
cf73e0fe | 207 | { |
f60e49df | 208 | struct bin_info_data *bin_data = (struct bin_info_data *) priv; |
cf73e0fe | 209 | |
cbc06a3b | 210 | lttng_ust_tracepoint(lttng_ust_statedump, bin_info, |
f60e49df | 211 | session, bin_data->base_addr_ptr, |
c5c4fd82 MD |
212 | bin_data->resolved_path, bin_data->memsz, |
213 | bin_data->is_pic, bin_data->has_build_id, | |
214 | bin_data->has_debug_link); | |
8e2aed3f AB |
215 | } |
216 | ||
217 | static | |
f69fe5fb | 218 | void trace_build_id_cb(struct lttng_ust_session *session, void *priv) |
8e2aed3f | 219 | { |
f60e49df | 220 | struct bin_info_data *bin_data = (struct bin_info_data *) priv; |
8e2aed3f | 221 | |
cbc06a3b | 222 | lttng_ust_tracepoint(lttng_ust_statedump, build_id, |
f60e49df AB |
223 | session, bin_data->base_addr_ptr, |
224 | bin_data->build_id, bin_data->build_id_len); | |
8e2aed3f AB |
225 | } |
226 | ||
227 | static | |
f69fe5fb | 228 | void trace_debug_link_cb(struct lttng_ust_session *session, void *priv) |
8e2aed3f | 229 | { |
f60e49df | 230 | struct bin_info_data *bin_data = (struct bin_info_data *) priv; |
8e2aed3f | 231 | |
cbc06a3b | 232 | lttng_ust_tracepoint(lttng_ust_statedump, debug_link, |
f60e49df AB |
233 | session, bin_data->base_addr_ptr, |
234 | bin_data->dbg_file, bin_data->crc); | |
cf73e0fe AB |
235 | } |
236 | ||
94be38e8 | 237 | static |
f69fe5fb | 238 | void procname_cb(struct lttng_ust_session *session, void *priv) |
94be38e8 JR |
239 | { |
240 | char *procname = (char *) priv; | |
cbc06a3b | 241 | lttng_ust_tracepoint(lttng_ust_statedump, procname, session, procname); |
94be38e8 JR |
242 | } |
243 | ||
cf73e0fe | 244 | static |
2208d8b5 | 245 | void trace_start_cb(struct lttng_ust_session *session, void *priv __attribute__((unused))) |
cf73e0fe | 246 | { |
cbc06a3b | 247 | lttng_ust_tracepoint(lttng_ust_statedump, start, session); |
cf73e0fe AB |
248 | } |
249 | ||
250 | static | |
2208d8b5 | 251 | void trace_end_cb(struct lttng_ust_session *session, void *priv __attribute__((unused))) |
cf73e0fe | 252 | { |
cbc06a3b | 253 | lttng_ust_tracepoint(lttng_ust_statedump, end, session); |
cf73e0fe AB |
254 | } |
255 | ||
8e2aed3f | 256 | static |
c5c4fd82 MD |
257 | int get_elf_info(struct bin_info_data *bin_data) |
258 | { | |
8e2aed3f | 259 | struct lttng_ust_elf *elf; |
c5c4fd82 | 260 | int ret = 0, found; |
8e2aed3f | 261 | |
f60e49df | 262 | elf = lttng_ust_elf_create(bin_data->resolved_path); |
8e2aed3f AB |
263 | if (!elf) { |
264 | ret = -1; | |
265 | goto end; | |
266 | } | |
267 | ||
f60e49df | 268 | ret = lttng_ust_elf_get_memsz(elf, &bin_data->memsz); |
8e2aed3f AB |
269 | if (ret) { |
270 | goto end; | |
271 | } | |
272 | ||
c5c4fd82 | 273 | found = 0; |
f60e49df | 274 | ret = lttng_ust_elf_get_build_id(elf, &bin_data->build_id, |
c5c4fd82 MD |
275 | &bin_data->build_id_len, |
276 | &found); | |
8e2aed3f AB |
277 | if (ret) { |
278 | goto end; | |
279 | } | |
c5c4fd82 MD |
280 | bin_data->has_build_id = !!found; |
281 | found = 0; | |
f60e49df | 282 | ret = lttng_ust_elf_get_debug_link(elf, &bin_data->dbg_file, |
c5c4fd82 MD |
283 | &bin_data->crc, |
284 | &found); | |
8e2aed3f AB |
285 | if (ret) { |
286 | goto end; | |
287 | } | |
c5c4fd82 | 288 | bin_data->has_debug_link = !!found; |
8e2aed3f | 289 | |
f60e49df | 290 | bin_data->is_pic = lttng_ust_elf_is_pic(elf); |
f5eb039d | 291 | |
8e2aed3f AB |
292 | end: |
293 | lttng_ust_elf_destroy(elf); | |
294 | return ret; | |
295 | } | |
296 | ||
cf73e0fe | 297 | static |
97c7c238 MD |
298 | void trace_baddr(struct bin_info_data *bin_data, void *owner) |
299 | { | |
300 | trace_statedump_event(trace_bin_info_cb, owner, bin_data); | |
301 | ||
302 | if (bin_data->has_build_id) | |
303 | trace_statedump_event(trace_build_id_cb, owner, bin_data); | |
304 | ||
305 | if (bin_data->has_debug_link) | |
306 | trace_statedump_event(trace_debug_link_cb, owner, bin_data); | |
307 | } | |
308 | ||
309 | static | |
310 | int extract_baddr(struct bin_info_data *bin_data) | |
cf73e0fe | 311 | { |
c5c4fd82 | 312 | int ret = 0; |
97c7c238 | 313 | struct lttng_ust_dl_node *e; |
8e2aed3f | 314 | |
f60e49df | 315 | if (!bin_data->vdso) { |
c5c4fd82 | 316 | ret = get_elf_info(bin_data); |
8e2aed3f AB |
317 | if (ret) { |
318 | goto end; | |
319 | } | |
320 | } else { | |
f60e49df | 321 | bin_data->memsz = 0; |
fd783031 MD |
322 | bin_data->has_build_id = 0; |
323 | bin_data->has_debug_link = 0; | |
8e2aed3f AB |
324 | } |
325 | ||
97c7c238 MD |
326 | e = find_or_create_dl_node(bin_data); |
327 | if (!e) { | |
328 | ret = -1; | |
8e2aed3f AB |
329 | goto end; |
330 | } | |
97c7c238 | 331 | e->marked = true; |
8e2aed3f | 332 | end: |
97c7c238 MD |
333 | free(bin_data->build_id); |
334 | bin_data->build_id = NULL; | |
335 | free(bin_data->dbg_file); | |
336 | bin_data->dbg_file = NULL; | |
8e2aed3f | 337 | return ret; |
cf73e0fe AB |
338 | } |
339 | ||
340 | static | |
97c7c238 | 341 | void trace_statedump_start(void *owner) |
cf73e0fe | 342 | { |
97c7c238 | 343 | trace_statedump_event(trace_start_cb, owner, NULL); |
cf73e0fe AB |
344 | } |
345 | ||
346 | static | |
97c7c238 | 347 | void trace_statedump_end(void *owner) |
cf73e0fe | 348 | { |
97c7c238 | 349 | trace_statedump_event(trace_end_cb, owner, NULL); |
cf73e0fe AB |
350 | } |
351 | ||
352 | static | |
97c7c238 | 353 | void iter_begin(struct dl_iterate_data *data) |
cf73e0fe | 354 | { |
97c7c238 | 355 | unsigned int i; |
cf73e0fe | 356 | |
d34e6761 MD |
357 | /* |
358 | * UST lock nests within dynamic loader lock. | |
359 | * | |
97c7c238 | 360 | * Hold this lock across handling of the module listing to |
d34e6761 MD |
361 | * protect memory allocation at early process start, due to |
362 | * interactions with libc-wrapper lttng malloc instrumentation. | |
363 | */ | |
364 | if (ust_lock()) { | |
97c7c238 MD |
365 | data->cancel = true; |
366 | return; | |
d34e6761 MD |
367 | } |
368 | ||
97c7c238 MD |
369 | /* Ensure all entries are unmarked. */ |
370 | for (i = 0; i < UST_DL_STATE_TABLE_SIZE; i++) { | |
371 | struct cds_hlist_head *head; | |
372 | struct lttng_ust_dl_node *e; | |
373 | ||
374 | head = &dl_state_table[i]; | |
375 | cds_hlist_for_each_entry_2(e, head, node) | |
376 | assert(!e->marked); | |
377 | } | |
378 | } | |
379 | ||
380 | static | |
381 | void trace_lib_load(const struct bin_info_data *bin_data, void *ip) | |
382 | { | |
cbc06a3b | 383 | lttng_ust_tracepoint(lttng_ust_lib, load, |
97c7c238 MD |
384 | ip, bin_data->base_addr_ptr, bin_data->resolved_path, |
385 | bin_data->memsz, bin_data->has_build_id, | |
386 | bin_data->has_debug_link); | |
387 | ||
388 | if (bin_data->has_build_id) { | |
cbc06a3b | 389 | lttng_ust_tracepoint(lttng_ust_lib, build_id, |
97c7c238 MD |
390 | ip, bin_data->base_addr_ptr, bin_data->build_id, |
391 | bin_data->build_id_len); | |
392 | } | |
393 | ||
394 | if (bin_data->has_debug_link) { | |
cbc06a3b | 395 | lttng_ust_tracepoint(lttng_ust_lib, debug_link, |
97c7c238 MD |
396 | ip, bin_data->base_addr_ptr, bin_data->dbg_file, |
397 | bin_data->crc); | |
398 | } | |
399 | } | |
400 | ||
401 | static | |
402 | void trace_lib_unload(const struct bin_info_data *bin_data, void *ip) | |
403 | { | |
cbc06a3b | 404 | lttng_ust_tracepoint(lttng_ust_lib, unload, ip, bin_data->base_addr_ptr); |
97c7c238 MD |
405 | } |
406 | ||
407 | static | |
408 | void iter_end(struct dl_iterate_data *data, void *ip) | |
409 | { | |
410 | unsigned int i; | |
411 | ||
2eb235ec MD |
412 | if (data->cancel) |
413 | goto end; | |
97c7c238 MD |
414 | /* |
415 | * Iterate on hash table. | |
416 | * For each marked, traced, do nothing. | |
417 | * For each marked, not traced, trace lib open event. traced = true. | |
418 | * For each unmarked, traced, trace lib close event. remove node. | |
419 | * For each unmarked, not traced, remove node. | |
420 | */ | |
421 | for (i = 0; i < UST_DL_STATE_TABLE_SIZE; i++) { | |
422 | struct cds_hlist_head *head; | |
423 | struct lttng_ust_dl_node *e; | |
424 | ||
425 | head = &dl_state_table[i]; | |
426 | cds_hlist_for_each_entry_2(e, head, node) { | |
427 | if (e->marked) { | |
428 | if (!e->traced) { | |
429 | trace_lib_load(&e->bin_data, ip); | |
430 | e->traced = true; | |
431 | } | |
b891574e | 432 | e->marked = false; |
97c7c238 MD |
433 | } else { |
434 | if (e->traced) | |
435 | trace_lib_unload(&e->bin_data, ip); | |
436 | remove_dl_node(e); | |
437 | free_dl_node(e); | |
438 | } | |
97c7c238 MD |
439 | } |
440 | } | |
2eb235ec | 441 | end: |
97c7c238 MD |
442 | ust_unlock(); |
443 | } | |
444 | ||
445 | static | |
2208d8b5 | 446 | int extract_bin_info_events(struct dl_phdr_info *info, size_t size __attribute__((unused)), void *_data) |
97c7c238 MD |
447 | { |
448 | int j, ret = 0; | |
449 | struct dl_iterate_data *data = _data; | |
450 | ||
451 | if (data->first) { | |
452 | iter_begin(data); | |
453 | data->first = false; | |
454 | } | |
455 | ||
456 | if (data->cancel) | |
457 | goto end; | |
458 | ||
cf73e0fe | 459 | for (j = 0; j < info->dlpi_phnum; j++) { |
f60e49df | 460 | struct bin_info_data bin_data; |
cf73e0fe AB |
461 | |
462 | if (info->dlpi_phdr[j].p_type != PT_LOAD) | |
463 | continue; | |
464 | ||
97c7c238 MD |
465 | memset(&bin_data, 0, sizeof(bin_data)); |
466 | ||
cf73e0fe | 467 | /* Calculate virtual memory address of the loadable segment */ |
97c7c238 | 468 | bin_data.base_addr_ptr = (void *) info->dlpi_addr + |
cf73e0fe AB |
469 | info->dlpi_phdr[j].p_vaddr; |
470 | ||
471 | if ((info->dlpi_name == NULL || info->dlpi_name[0] == 0)) { | |
472 | /* | |
473 | * Only the first phdr without a dlpi_name | |
474 | * encountered is considered as the program | |
475 | * executable. The rest are vdsos. | |
476 | */ | |
477 | if (!data->exec_found) { | |
478 | ssize_t path_len; | |
479 | data->exec_found = 1; | |
480 | ||
481 | /* | |
482 | * Use /proc/self/exe to resolve the | |
483 | * executable's full path. | |
484 | */ | |
485 | path_len = readlink("/proc/self/exe", | |
97c7c238 | 486 | bin_data.resolved_path, |
cf73e0fe AB |
487 | PATH_MAX - 1); |
488 | if (path_len <= 0) | |
489 | break; | |
490 | ||
97c7c238 | 491 | bin_data.resolved_path[path_len] = '\0'; |
f60e49df | 492 | bin_data.vdso = 0; |
cf73e0fe | 493 | } else { |
97c7c238 MD |
494 | snprintf(bin_data.resolved_path, |
495 | PATH_MAX - 1, "[vdso]"); | |
f60e49df | 496 | bin_data.vdso = 1; |
cf73e0fe AB |
497 | } |
498 | } else { | |
499 | /* | |
500 | * For regular dl_phdr_info entries check if | |
f60e49df | 501 | * the path to the binary really exists. If not, |
cf73e0fe AB |
502 | * treat as vdso and use dlpi_name as 'path'. |
503 | */ | |
97c7c238 MD |
504 | if (!realpath(info->dlpi_name, |
505 | bin_data.resolved_path)) { | |
506 | snprintf(bin_data.resolved_path, | |
507 | PATH_MAX - 1, "[%s]", | |
cf73e0fe | 508 | info->dlpi_name); |
f60e49df | 509 | bin_data.vdso = 1; |
89be5359 | 510 | } else { |
f60e49df | 511 | bin_data.vdso = 0; |
cf73e0fe AB |
512 | } |
513 | } | |
514 | ||
97c7c238 | 515 | ret = extract_baddr(&bin_data); |
d34e6761 | 516 | break; |
cf73e0fe | 517 | } |
d34e6761 | 518 | end: |
d34e6761 | 519 | return ret; |
cf73e0fe AB |
520 | } |
521 | ||
cf73e0fe | 522 | static |
97c7c238 MD |
523 | void ust_dl_table_statedump(void *owner) |
524 | { | |
525 | unsigned int i; | |
526 | ||
527 | if (ust_lock()) | |
528 | goto end; | |
529 | ||
530 | /* Statedump each traced table entry into session for owner. */ | |
531 | for (i = 0; i < UST_DL_STATE_TABLE_SIZE; i++) { | |
532 | struct cds_hlist_head *head; | |
533 | struct lttng_ust_dl_node *e; | |
534 | ||
535 | head = &dl_state_table[i]; | |
536 | cds_hlist_for_each_entry_2(e, head, node) { | |
537 | if (e->traced) | |
538 | trace_baddr(&e->bin_data, owner); | |
539 | } | |
540 | } | |
541 | ||
542 | end: | |
543 | ust_unlock(); | |
544 | } | |
545 | ||
546 | void lttng_ust_dl_update(void *ip) | |
cf73e0fe AB |
547 | { |
548 | struct dl_iterate_data data; | |
549 | ||
4c41b460 | 550 | if (lttng_ust_getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP")) |
97c7c238 | 551 | return; |
cf73e0fe | 552 | |
c362addf MD |
553 | /* |
554 | * Fixup lttng-ust TLS when called from dlopen/dlclose | |
555 | * instrumentation. | |
556 | */ | |
557 | lttng_ust_fixup_tls(); | |
558 | ||
cf73e0fe | 559 | data.exec_found = 0; |
97c7c238 MD |
560 | data.first = true; |
561 | data.cancel = false; | |
cf73e0fe AB |
562 | /* |
563 | * Iterate through the list of currently loaded shared objects and | |
97c7c238 | 564 | * generate tables entries for loadable segments using |
f60e49df | 565 | * extract_bin_info_events. |
97c7c238 MD |
566 | * Removed libraries are detected by mark-and-sweep: marking is |
567 | * done in the iteration over libraries, and sweeping is | |
568 | * performed by iter_end(). | |
cf73e0fe | 569 | */ |
f60e49df | 570 | dl_iterate_phdr(extract_bin_info_events, &data); |
97c7c238 MD |
571 | if (data.first) |
572 | iter_begin(&data); | |
573 | iter_end(&data, ip); | |
574 | } | |
cf73e0fe | 575 | |
97c7c238 MD |
576 | /* |
577 | * Generate a statedump of base addresses of all shared objects loaded | |
578 | * by the traced application, as well as for the application's | |
579 | * executable itself. | |
580 | */ | |
581 | static | |
582 | int do_baddr_statedump(void *owner) | |
583 | { | |
4c41b460 | 584 | if (lttng_ust_getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP")) |
97c7c238 MD |
585 | return 0; |
586 | lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); | |
587 | ust_dl_table_statedump(owner); | |
cf73e0fe AB |
588 | return 0; |
589 | } | |
590 | ||
94be38e8 JR |
591 | static |
592 | int do_procname_statedump(void *owner) | |
593 | { | |
4c41b460 | 594 | if (lttng_ust_getenv("LTTNG_UST_WITHOUT_PROCNAME_STATEDUMP")) |
94be38e8 JR |
595 | return 0; |
596 | ||
597 | trace_statedump_event(procname_cb, owner, lttng_ust_sockinfo_get_procname(owner)); | |
598 | return 0; | |
599 | } | |
600 | ||
cf73e0fe AB |
601 | /* |
602 | * Generate a statedump of a given traced application. A statedump is | |
603 | * delimited by start and end events. For a given (process, session) | |
604 | * pair, begin/end events are serialized and will match. However, in a | |
605 | * session, statedumps from different processes may be | |
606 | * interleaved. The vpid context should be used to identify which | |
607 | * events belong to which process. | |
8002ea62 MD |
608 | * |
609 | * Grab the ust_lock outside of the RCU read-side lock because we | |
610 | * perform synchronize_rcu with the ust_lock held, which can trigger | |
611 | * deadlocks otherwise. | |
cf73e0fe AB |
612 | */ |
613 | int do_lttng_ust_statedump(void *owner) | |
614 | { | |
8002ea62 | 615 | ust_lock_nocheck(); |
cf73e0fe | 616 | trace_statedump_start(owner); |
8002ea62 MD |
617 | ust_unlock(); |
618 | ||
94be38e8 | 619 | do_procname_statedump(owner); |
cf73e0fe | 620 | do_baddr_statedump(owner); |
8002ea62 MD |
621 | |
622 | ust_lock_nocheck(); | |
cf73e0fe | 623 | trace_statedump_end(owner); |
8002ea62 | 624 | ust_unlock(); |
cf73e0fe AB |
625 | |
626 | return 0; | |
627 | } | |
628 | ||
629 | void lttng_ust_statedump_init(void) | |
630 | { | |
ac9f44c2 MJ |
631 | lttng_ust__tracepoints__init(); |
632 | lttng_ust__tracepoints__ptrs_init(); | |
26a318c7 | 633 | __lttng_ust_events_init__lttng_ust_statedump(); |
97c7c238 MD |
634 | lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); |
635 | } | |
636 | ||
637 | static | |
638 | void ust_dl_state_destroy(void) | |
639 | { | |
640 | unsigned int i; | |
641 | ||
642 | for (i = 0; i < UST_DL_STATE_TABLE_SIZE; i++) { | |
643 | struct cds_hlist_head *head; | |
644 | struct lttng_ust_dl_node *e, *tmp; | |
645 | ||
646 | head = &dl_state_table[i]; | |
647 | cds_hlist_for_each_entry_safe_2(e, tmp, head, node) | |
648 | free_dl_node(e); | |
649 | CDS_INIT_HLIST_HEAD(head); | |
650 | } | |
cf73e0fe AB |
651 | } |
652 | ||
653 | void lttng_ust_statedump_destroy(void) | |
654 | { | |
26a318c7 | 655 | __lttng_ust_events_exit__lttng_ust_statedump(); |
ac9f44c2 MJ |
656 | lttng_ust__tracepoints__ptrs_destroy(); |
657 | lttng_ust__tracepoints__destroy(); | |
97c7c238 | 658 | ust_dl_state_destroy(); |
cf73e0fe | 659 | } |