2 * Babeltrace - Debug Information State Tracker
4 * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
6 * Copyright (c) 2015 Antoine Busque <abusque@efficios.com>
7 * Copyright (c) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 #include <babeltrace/types.h>
31 #include <babeltrace/ctf-ir/metadata.h>
32 #include <babeltrace/debuginfo.h>
33 #include <babeltrace/so-info.h>
34 #include <babeltrace/babeltrace-internal.h>
36 struct proc_debug_info_sources
{
38 * Hash table: base address (pointer to uint64_t) to so info; owned by
39 * proc_debug_info_sources.
41 GHashTable
*baddr_to_so_info
;
44 * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *);
45 * owned by proc_debug_info_sources.
47 GHashTable
*ip_to_debug_info_src
;
52 * Hash table of VPIDs (pointer to int64_t) to
53 * (struct ctf_proc_debug_infos*); owned by debug_info.
55 GHashTable
*vpid_to_proc_dbg_info_src
;
56 GQuark q_statedump_soinfo
;
57 GQuark q_statedump_debug_link
;
58 GQuark q_statedump_build_id
;
59 GQuark q_statedump_start
;
64 int debug_info_init(struct debug_info
*info
)
66 info
->q_statedump_soinfo
= g_quark_from_string(
67 "lttng_ust_statedump:soinfo");
68 info
->q_statedump_debug_link
= g_quark_from_string(
69 "lttng_ust_statedump:debug_link)");
70 info
->q_statedump_build_id
= g_quark_from_string(
71 "lttng_ust_statedump:build_id");
72 info
->q_statedump_start
= g_quark_from_string(
73 "lttng_ust_statedump:start");
74 info
->q_dl_open
= g_quark_from_string("lttng_ust_dl:dlopen");
76 return so_info_init();
80 void debug_info_source_destroy(struct debug_info_source
*debug_info_src
)
82 if (!debug_info_src
) {
86 free(debug_info_src
->func
);
87 free(debug_info_src
->src_path
);
88 free(debug_info_src
->bin_path
);
89 g_free(debug_info_src
);
93 * Returns the location of a path's file (the last element of the path).
94 * Returns the original path on error.
97 const char *get_filename_from_path(const char *path
)
99 size_t i
= strlen(path
);
105 if (path
[i
- 1] == '/') {
107 * Path ends with a trailing slash, no filename to return.
108 * Return the original path.
114 if (path
[i
] == '/') {
124 struct debug_info_source
*debug_info_source_create_from_so(struct so_info
*so
,
128 struct debug_info_source
*debug_info_src
= NULL
;
129 struct source_location
*src_loc
= NULL
;
131 debug_info_src
= g_new0(struct debug_info_source
, 1);
133 if (!debug_info_src
) {
137 /* Lookup function name */
138 ret
= so_info_lookup_function_name(so
, ip
, &debug_info_src
->func
);
143 /* Can't retrieve src_loc from ELF only, skip it */
144 if (!so
->is_elf_only
) {
145 /* Lookup source location */
146 ret
= so_info_lookup_source_location(so
, ip
, &src_loc
);
153 debug_info_src
->line_no
= src_loc
->line_no
;
155 if (src_loc
->filename
) {
156 debug_info_src
->src_path
= strdup(src_loc
->filename
);
157 if (!debug_info_src
->src_path
) {
161 debug_info_src
->short_src_path
= get_filename_from_path(
166 source_location_destroy(src_loc
);
170 debug_info_src
->bin_path
= strdup(so
->elf_path
);
171 if (!debug_info_src
->bin_path
) {
175 debug_info_src
->short_bin_path
= get_filename_from_path(
176 debug_info_src
->bin_path
);
180 return debug_info_src
;
183 debug_info_source_destroy(debug_info_src
);
188 void proc_debug_info_sources_destroy(
189 struct proc_debug_info_sources
*proc_dbg_info_src
)
191 if (!proc_dbg_info_src
) {
195 if (proc_dbg_info_src
->baddr_to_so_info
) {
196 g_hash_table_destroy(proc_dbg_info_src
->baddr_to_so_info
);
199 if (proc_dbg_info_src
->ip_to_debug_info_src
) {
200 g_hash_table_destroy(proc_dbg_info_src
->ip_to_debug_info_src
);
203 g_free(proc_dbg_info_src
);
207 struct proc_debug_info_sources
*proc_debug_info_sources_create(void)
209 struct proc_debug_info_sources
*proc_dbg_info_src
= NULL
;
211 proc_dbg_info_src
= g_new0(struct proc_debug_info_sources
, 1);
212 if (!proc_dbg_info_src
) {
216 proc_dbg_info_src
->baddr_to_so_info
= g_hash_table_new_full(
217 g_int64_hash
, g_int64_equal
, (GDestroyNotify
) g_free
,
218 (GDestroyNotify
) so_info_destroy
);
219 if (!proc_dbg_info_src
->baddr_to_so_info
) {
223 proc_dbg_info_src
->ip_to_debug_info_src
= g_hash_table_new_full(
224 g_int64_hash
, g_int64_equal
, (GDestroyNotify
) g_free
,
225 (GDestroyNotify
) debug_info_source_destroy
);
226 if (!proc_dbg_info_src
->ip_to_debug_info_src
) {
231 return proc_dbg_info_src
;
234 proc_debug_info_sources_destroy(proc_dbg_info_src
);
239 struct proc_debug_info_sources
*proc_debug_info_sources_ht_get_entry(
240 GHashTable
*ht
, int64_t vpid
)
242 gpointer key
= g_new0(int64_t, 1);
243 struct proc_debug_info_sources
*proc_dbg_info_src
= NULL
;
249 *((int64_t *) key
) = vpid
;
251 /* Exists? Return it */
252 proc_dbg_info_src
= g_hash_table_lookup(ht
, key
);
253 if (proc_dbg_info_src
) {
257 /* Otherwise, create and return it */
258 proc_dbg_info_src
= proc_debug_info_sources_create();
259 if (!proc_dbg_info_src
) {
263 g_hash_table_insert(ht
, key
, proc_dbg_info_src
);
264 /* Ownership passed to ht */
268 return proc_dbg_info_src
;
272 struct debug_info_source
*proc_debug_info_sources_get_entry(
273 struct proc_debug_info_sources
*proc_dbg_info_src
, uint64_t ip
)
275 struct debug_info_source
*debug_info_src
= NULL
;
276 gpointer key
= g_new0(uint64_t, 1);
278 gpointer baddr
, value
;
284 *((uint64_t *) key
) = ip
;
286 /* Look in IP to debug infos hash table first. */
287 debug_info_src
= g_hash_table_lookup(
288 proc_dbg_info_src
->ip_to_debug_info_src
,
290 if (debug_info_src
) {
294 /* Check in all so_infos. */
295 g_hash_table_iter_init(&iter
, proc_dbg_info_src
->baddr_to_so_info
);
297 while (g_hash_table_iter_next(&iter
, &baddr
, &value
))
299 struct so_info
*so
= value
;
301 if (!so_info_has_address(value
, ip
)) {
306 * Found; add it to cache.
308 * FIXME: this should be bounded in size (and implement
309 * a caching policy), and entries should be prunned when
310 * libraries are unmapped.
312 debug_info_src
= debug_info_source_create_from_so(so
, ip
);
313 if (debug_info_src
) {
315 proc_dbg_info_src
->ip_to_debug_info_src
,
316 key
, debug_info_src
);
317 /* Ownership passed to ht. */
325 return debug_info_src
;
329 struct debug_info_source
*debug_info_query(struct debug_info
*debug_info
,
330 int64_t vpid
, uint64_t ip
)
332 struct debug_info_source
*dbg_info_src
= NULL
;
333 struct proc_debug_info_sources
*proc_dbg_info_src
;
335 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
336 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
337 if (!proc_dbg_info_src
) {
341 dbg_info_src
= proc_debug_info_sources_get_entry(
342 proc_dbg_info_src
, ip
);
352 struct debug_info
*debug_info_create(void)
355 struct debug_info
*debug_info
;
357 debug_info
= g_new0(struct debug_info
, 1);
362 debug_info
->vpid_to_proc_dbg_info_src
= g_hash_table_new_full(
363 g_int64_hash
, g_int64_equal
, (GDestroyNotify
) g_free
,
364 (GDestroyNotify
) proc_debug_info_sources_destroy
);
365 if (!debug_info
->vpid_to_proc_dbg_info_src
) {
369 ret
= debug_info_init(debug_info
);
382 void debug_info_destroy(struct debug_info
*debug_info
)
388 if (debug_info
->vpid_to_proc_dbg_info_src
) {
389 g_hash_table_destroy(debug_info
->vpid_to_proc_dbg_info_src
);
398 void handle_statedump_build_id_event(struct debug_info
*debug_info
,
399 struct ctf_event_definition
*event_def
)
401 struct proc_debug_info_sources
*proc_dbg_info_src
;
402 struct bt_definition
*event_fields_def
= NULL
;
403 struct bt_definition
*sec_def
= NULL
;
404 struct bt_definition
*baddr_def
= NULL
;
405 struct bt_definition
*vpid_def
= NULL
;
406 struct bt_definition
*build_id_def
= NULL
;
407 struct definition_sequence
*build_id_seq
;
408 struct so_info
*so
= NULL
;
412 uint8_t *build_id
= NULL
;
413 uint64_t build_id_len
;
415 event_fields_def
= (struct bt_definition
*) event_def
->event_fields
;
416 sec_def
= (struct bt_definition
*)
417 event_def
->stream
->stream_event_context
;
419 if (!event_fields_def
|| !sec_def
) {
423 baddr_def
= bt_lookup_definition(event_fields_def
, "_baddr");
428 vpid_def
= bt_lookup_definition(sec_def
, "_vpid");
433 build_id_def
= bt_lookup_definition(event_fields_def
, "_build_id");
438 if (baddr_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
442 if (vpid_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
446 if (build_id_def
->declaration
->id
!= CTF_TYPE_SEQUENCE
) {
450 baddr
= bt_get_unsigned_int(baddr_def
);
451 vpid
= bt_get_signed_int(vpid_def
);
452 build_id_seq
= container_of(build_id_def
,
453 struct definition_sequence
, p
);
454 build_id_len
= build_id_seq
->length
->value
._unsigned
;
456 build_id
= g_malloc(build_id_len
);
461 for (i
= 0; i
< build_id_len
; ++i
) {
462 struct bt_definition
**field
;
464 field
= (struct bt_definition
**) &g_ptr_array_index(
465 build_id_seq
->elems
, i
);
466 build_id
[i
] = bt_get_unsigned_int(*field
);
469 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
470 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
471 if (!proc_dbg_info_src
) {
475 so
= g_hash_table_lookup(proc_dbg_info_src
->baddr_to_so_info
,
479 * The build_id event comes after the so has been
480 * created. If it isn't found, just ignore this event.
485 so_info_set_build_id(so
, build_id
, build_id_len
);
493 void handle_statedump_debug_link_event(struct debug_info
*debug_info
,
494 struct ctf_event_definition
*event_def
)
496 struct proc_debug_info_sources
*proc_dbg_info_src
;
497 struct bt_definition
*event_fields_def
= NULL
;
498 struct bt_definition
*sec_def
= NULL
;
499 struct bt_definition
*baddr_def
= NULL
;
500 struct bt_definition
*vpid_def
= NULL
;
501 struct bt_definition
*filename_def
= NULL
;
502 struct bt_definition
*crc32_def
= NULL
;
503 struct so_info
*so
= NULL
;
506 char *filename
= NULL
;
509 event_fields_def
= (struct bt_definition
*) event_def
->event_fields
;
510 sec_def
= (struct bt_definition
*)
511 event_def
->stream
->stream_event_context
;
513 if (!event_fields_def
|| !sec_def
) {
517 baddr_def
= bt_lookup_definition(event_fields_def
, "_baddr");
522 vpid_def
= bt_lookup_definition(sec_def
, "_vpid");
527 filename_def
= bt_lookup_definition(event_fields_def
, "_filename");
532 crc32_def
= bt_lookup_definition(event_fields_def
, "_crc32");
537 if (baddr_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
541 if (vpid_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
545 if (filename_def
->declaration
->id
!= CTF_TYPE_STRING
) {
549 if (crc32_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
553 baddr
= bt_get_unsigned_int(baddr_def
);
554 vpid
= bt_get_signed_int(vpid_def
);
556 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
557 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
558 if (!proc_dbg_info_src
) {
562 so
= g_hash_table_lookup(proc_dbg_info_src
->baddr_to_so_info
,
566 * The debug_link event comes after the so has been
567 * created. If it isn't found, just ignore this event.
572 filename
= bt_get_string(filename_def
);
573 crc32
= bt_get_unsigned_int(crc32_def
);
575 so_info_set_debug_link(so
, filename
, crc32
);
582 void handle_statedump_soinfo_event(struct debug_info
*debug_info
,
583 struct ctf_event_definition
*event_def
)
585 struct bt_definition
*baddr_def
= NULL
;
586 struct bt_definition
*memsz_def
= NULL
;
587 struct bt_definition
*sopath_def
= NULL
;
588 struct bt_definition
*vpid_def
= NULL
;
589 struct bt_definition
*event_fields_def
= NULL
;
590 struct bt_definition
*sec_def
= NULL
;
591 struct proc_debug_info_sources
*proc_dbg_info_src
;
593 uint64_t baddr
, memsz
;
598 event_fields_def
= (struct bt_definition
*) event_def
->event_fields
;
599 sec_def
= (struct bt_definition
*)
600 event_def
->stream
->stream_event_context
;
602 if (!event_fields_def
|| !sec_def
) {
606 baddr_def
= bt_lookup_definition(event_fields_def
, "_baddr");
611 memsz_def
= bt_lookup_definition(event_fields_def
, "_memsz");
616 sopath_def
= bt_lookup_definition(event_fields_def
, "_sopath");
621 vpid_def
= bt_lookup_definition(sec_def
, "_vpid");
626 if (baddr_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
630 if (memsz_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
634 if (sopath_def
->declaration
->id
!= CTF_TYPE_STRING
) {
638 if (vpid_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
642 baddr
= bt_get_unsigned_int(baddr_def
);
643 memsz
= bt_get_unsigned_int(memsz_def
);
644 sopath
= bt_get_string(sopath_def
);
645 vpid
= bt_get_signed_int(vpid_def
);
656 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
657 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
658 if (!proc_dbg_info_src
) {
662 key
= g_new0(uint64_t, 1);
667 *((uint64_t *) key
) = baddr
;
669 so
= g_hash_table_lookup(proc_dbg_info_src
->baddr_to_so_info
,
675 so
= so_info_create(sopath
, baddr
, memsz
);
680 g_hash_table_insert(proc_dbg_info_src
->baddr_to_so_info
,
682 /* Ownership passed to ht. */
691 void handle_statedump_start(struct debug_info
*debug_info
,
692 struct ctf_event_definition
*event_def
)
694 struct bt_definition
*vpid_def
= NULL
;
695 struct bt_definition
*sec_def
= NULL
;
696 struct proc_debug_info_sources
*proc_dbg_info_src
;
699 sec_def
= (struct bt_definition
*)
700 event_def
->stream
->stream_event_context
;
705 vpid_def
= bt_lookup_definition(sec_def
, "_vpid");
710 vpid
= bt_get_signed_int(vpid_def
);
712 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
713 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
714 if (!proc_dbg_info_src
) {
718 g_hash_table_remove_all(proc_dbg_info_src
->baddr_to_so_info
);
719 g_hash_table_remove_all(proc_dbg_info_src
->ip_to_debug_info_src
);
726 void register_event_debug_infos(struct debug_info
*debug_info
,
727 struct ctf_event_definition
*event
)
729 struct bt_definition
*ip_def
, *vpid_def
;
732 struct bt_definition
*sec_def
;
734 /* Get stream event context definition. */
735 sec_def
= (struct bt_definition
*) event
->stream
->stream_event_context
;
740 /* Get "ip" and "vpid" definitions. */
741 vpid_def
= bt_lookup_definition((struct bt_definition
*) sec_def
,
743 ip_def
= bt_lookup_definition((struct bt_definition
*) sec_def
, "_ip");
745 if (!vpid_def
|| !ip_def
) {
749 vpid
= bt_get_signed_int(vpid_def
);
750 ip
= bt_get_unsigned_int(ip_def
);
752 /* Get debug info for this context. */
753 ((struct definition_integer
*) ip_def
)->debug_info_src
=
754 debug_info_query(debug_info
, vpid
, ip
);
761 void debug_info_handle_event(struct debug_info
*debug_info
,
762 struct ctf_event_definition
*event
)
764 struct ctf_event_declaration
*event_class
;
765 struct ctf_stream_declaration
*stream_class
;
767 if (!debug_info
|| !event
) {
771 stream_class
= event
->stream
->stream_class
;
772 event_class
= g_ptr_array_index(stream_class
->events_by_id
,
773 event
->stream
->event_id
);
775 if (event_class
->name
== debug_info
->q_statedump_soinfo
||
776 event_class
->name
== debug_info
->q_dl_open
) {
777 /* State dump/dlopen() */
778 handle_statedump_soinfo_event(debug_info
, event
);
779 } else if (event_class
->name
== debug_info
->q_statedump_start
) {
780 /* Start state dump */
781 handle_statedump_start(debug_info
, event
);
782 } else if (event_class
->name
== debug_info
->q_statedump_debug_link
) {
783 /* Debug link info */
784 handle_statedump_debug_link_event(debug_info
, event
);
785 } else if (event_class
->name
== debug_info
->q_statedump_build_id
) {
787 handle_statedump_build_id_event(debug_info
, event
);
789 /* Other events: register debug infos */
790 register_event_debug_infos(debug_info
, event
);