Move to kernel style SPDX license identifiers
[lttng-ust.git] / liblttng-ust / lttng-ust-statedump.c
CommitLineData
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
8e2aed3f 19#include <lttng/ust-elf.h>
97c7c238 20#include <helper.h>
cf73e0fe
AB
21#include "lttng-tracer-core.h"
22#include "lttng-ust-statedump.h"
97c7c238 23#include "jhash.h"
6f626d28 24#include "getenv.h"
94be38e8 25#include "compat.h"
cf73e0fe
AB
26
27#define TRACEPOINT_DEFINE
97c7c238
MD
28#include "ust_lib.h" /* Only define. */
29
cf73e0fe
AB
30#define TRACEPOINT_CREATE_PROBES
31#define TP_SESSION_CHECK
97c7c238 32#include "lttng-ust-statedump-provider.h" /* Define and create probes. */
cf73e0fe
AB
33
34struct dl_iterate_data {
cf73e0fe 35 int exec_found;
97c7c238
MD
36 bool first;
37 bool cancel;
cf73e0fe
AB
38};
39
f60e49df 40struct 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
54struct 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)
63struct cds_hlist_head dl_state_table[UST_DL_STATE_TABLE_SIZE];
64
cf73e0fe
AB
65typedef void (*tracepoint_cb)(struct lttng_session *session, void *priv);
66
97c7c238
MD
67static
68struct 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
98error:
99 free(e->bin_data.build_id);
100 free(e->bin_data.dbg_file);
101 free(e);
102 return NULL;
103}
104
105static
106void 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. */
114static
115int 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
152static
153struct 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
179static
180void 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 */
189static
97c7c238 190void trace_statedump_event(tracepoint_cb tp_cb, void *owner, void *priv)
cf73e0fe
AB
191{
192 struct cds_list_head *sessionsp;
193 struct lttng_session *session;
194
cf73e0fe
AB
195 sessionsp = _lttng_get_sessions();
196 cds_list_for_each_entry(session, sessionsp, node) {
197 if (session->owner != owner)
198 continue;
199 if (!session->statedump_pending)
200 continue;
201 tp_cb(session, priv);
202 }
cf73e0fe
AB
203}
204
205static
f60e49df 206void trace_bin_info_cb(struct lttng_session *session, void *priv)
cf73e0fe 207{
f60e49df 208 struct bin_info_data *bin_data = (struct bin_info_data *) priv;
cf73e0fe 209
f60e49df
AB
210 tracepoint(lttng_ust_statedump, bin_info,
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
217static
218void trace_build_id_cb(struct lttng_session *session, void *priv)
219{
f60e49df 220 struct bin_info_data *bin_data = (struct bin_info_data *) priv;
8e2aed3f
AB
221
222 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
227static
228void trace_debug_link_cb(struct lttng_session *session, void *priv)
229{
f60e49df 230 struct bin_info_data *bin_data = (struct bin_info_data *) priv;
8e2aed3f
AB
231
232 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
JR
237static
238void procname_cb(struct lttng_session *session, void *priv)
239{
240 char *procname = (char *) priv;
241 tracepoint(lttng_ust_statedump, procname, session, procname);
242}
243
cf73e0fe
AB
244static
245void trace_start_cb(struct lttng_session *session, void *priv)
246{
247 tracepoint(lttng_ust_statedump, start, session);
248}
249
250static
251void trace_end_cb(struct lttng_session *session, void *priv)
252{
253 tracepoint(lttng_ust_statedump, end, session);
254}
255
8e2aed3f 256static
c5c4fd82
MD
257int 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
292end:
293 lttng_ust_elf_destroy(elf);
294 return ret;
295}
296
cf73e0fe 297static
97c7c238
MD
298void 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
309static
310int 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 332end:
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
340static
97c7c238 341void trace_statedump_start(void *owner)
cf73e0fe 342{
97c7c238 343 trace_statedump_event(trace_start_cb, owner, NULL);
cf73e0fe
AB
344}
345
346static
97c7c238 347void trace_statedump_end(void *owner)
cf73e0fe 348{
97c7c238 349 trace_statedump_event(trace_end_cb, owner, NULL);
cf73e0fe
AB
350}
351
352static
97c7c238 353void 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
380static
381void trace_lib_load(const struct bin_info_data *bin_data, void *ip)
382{
383 tracepoint(lttng_ust_lib, load,
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) {
389 tracepoint(lttng_ust_lib, build_id,
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) {
395 tracepoint(lttng_ust_lib, debug_link,
396 ip, bin_data->base_addr_ptr, bin_data->dbg_file,
397 bin_data->crc);
398 }
399}
400
401static
402void trace_lib_unload(const struct bin_info_data *bin_data, void *ip)
403{
404 tracepoint(lttng_ust_lib, unload, ip, bin_data->base_addr_ptr);
405}
406
407static
408void 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 441end:
97c7c238
MD
442 ust_unlock();
443}
444
445static
446int extract_bin_info_events(struct dl_phdr_info *info, size_t size, void *_data)
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 518end:
d34e6761 519 return ret;
cf73e0fe
AB
520}
521
cf73e0fe 522static
97c7c238
MD
523void 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
542end:
543 ust_unlock();
544}
545
546void lttng_ust_dl_update(void *ip)
cf73e0fe
AB
547{
548 struct dl_iterate_data data;
549
6f626d28 550 if (lttng_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 */
581static
582int do_baddr_statedump(void *owner)
583{
6f626d28 584 if (lttng_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
591static
592int do_procname_statedump(void *owner)
593{
594 if (lttng_getenv("LTTNG_UST_WITHOUT_PROCNAME_STATEDUMP"))
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 */
613int 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
629void lttng_ust_statedump_init(void)
630{
631 __tracepoints__init();
632 __tracepoints__ptrs_init();
633 __lttng_events_init__lttng_ust_statedump();
97c7c238
MD
634 lttng_ust_dl_update(LTTNG_UST_CALLER_IP());
635}
636
637static
638void 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
653void lttng_ust_statedump_destroy(void)
654{
655 __lttng_events_exit__lttng_ust_statedump();
656 __tracepoints__ptrs_destroy();
657 __tracepoints__destroy();
97c7c238 658 ust_dl_state_destroy();
cf73e0fe 659}
This page took 0.056529 seconds and 4 git commands to generate.