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>
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 #include <babeltrace/types.h>
30 #include <babeltrace/ctf-ir/metadata.h>
31 #include <babeltrace/debuginfo.h>
32 #include <babeltrace/so-info.h>
34 struct proc_debug_info_sources
{
36 * Hash table: base address (pointer to uint64_t) to so info; owned by
37 * proc_debug_info_sources.
39 GHashTable
*baddr_to_so_info
;
42 * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *);
43 * owned by proc_debug_info_sources.
45 GHashTable
*ip_to_debug_info_src
;
50 * Hash table of VPIDs (pointer to int64_t) to
51 * (struct ctf_proc_debug_infos*); owned by debug_info.
53 GHashTable
*vpid_to_proc_dbg_info_src
;
54 GQuark q_statedump_soinfo
;
55 GQuark q_statedump_debug_link
;
56 GQuark q_statedump_build_id
;
57 GQuark q_statedump_start
;
62 int debug_info_init(struct debug_info
*info
)
64 info
->q_statedump_soinfo
= g_quark_from_string(
65 "lttng_ust_statedump:soinfo");
66 info
->q_statedump_debug_link
= g_quark_from_string(
67 "lttng_ust_statedump:debug_link)");
68 info
->q_statedump_build_id
= g_quark_from_string(
69 "lttng_ust_statedump:build_id");
70 info
->q_statedump_start
= g_quark_from_string(
71 "lttng_ust_statedump:start");
72 info
->q_dl_open
= g_quark_from_string("lttng_ust_dl:dlopen");
74 return so_info_init();
78 void debug_info_source_destroy(struct debug_info_source
*debug_info_src
)
80 if (!debug_info_src
) {
84 free(debug_info_src
->func
);
85 free(debug_info_src
->filename
);
86 g_free(debug_info_src
);
90 struct debug_info_source
*debug_info_source_create_from_so(struct so_info
*so
,
94 struct debug_info_source
*debug_info_src
= NULL
;
95 struct source_location
*src_loc
= NULL
;
97 debug_info_src
= g_new0(struct debug_info_source
, 1);
99 if (!debug_info_src
) {
103 /* Lookup function name */
104 ret
= so_info_lookup_function_name(so
, ip
, &debug_info_src
->func
);
109 /* Can't retrieve src_loc from ELF only, skip it */
110 if (so
->is_elf_only
) {
114 /* Lookup source location */
115 ret
= so_info_lookup_source_location(so
, ip
, &src_loc
);
121 debug_info_src
->line_no
= src_loc
->line_no
;
123 if (src_loc
->filename
) {
124 debug_info_src
->filename
= strdup(src_loc
->filename
);
126 if (!debug_info_src
->filename
) {
131 source_location_destroy(src_loc
);
135 return debug_info_src
;
138 debug_info_source_destroy(debug_info_src
);
143 void proc_debug_info_sources_destroy(
144 struct proc_debug_info_sources
*proc_dbg_info_src
)
146 if (!proc_dbg_info_src
) {
150 if (proc_dbg_info_src
->baddr_to_so_info
) {
151 g_hash_table_destroy(proc_dbg_info_src
->baddr_to_so_info
);
154 if (proc_dbg_info_src
->ip_to_debug_info_src
) {
155 g_hash_table_destroy(proc_dbg_info_src
->ip_to_debug_info_src
);
158 g_free(proc_dbg_info_src
);
162 struct proc_debug_info_sources
*proc_debug_info_sources_create(void)
164 struct proc_debug_info_sources
*proc_dbg_info_src
= NULL
;
166 proc_dbg_info_src
= g_new0(struct proc_debug_info_sources
, 1);
167 if (!proc_dbg_info_src
) {
171 proc_dbg_info_src
->baddr_to_so_info
= g_hash_table_new_full(
172 g_int64_hash
, g_int64_equal
, (GDestroyNotify
) g_free
,
173 (GDestroyNotify
) so_info_destroy
);
174 if (!proc_dbg_info_src
->baddr_to_so_info
) {
178 proc_dbg_info_src
->ip_to_debug_info_src
= g_hash_table_new_full(
179 g_int64_hash
, g_int64_equal
, (GDestroyNotify
) g_free
,
180 (GDestroyNotify
) debug_info_source_destroy
);
181 if (!proc_dbg_info_src
->ip_to_debug_info_src
) {
186 return proc_dbg_info_src
;
189 proc_debug_info_sources_destroy(proc_dbg_info_src
);
194 struct proc_debug_info_sources
*proc_debug_info_sources_ht_get_entry(
195 GHashTable
*ht
, int64_t vpid
)
197 gpointer key
= g_new0(int64_t, 1);
198 struct proc_debug_info_sources
*proc_dbg_info_src
= NULL
;
204 *((int64_t *) key
) = vpid
;
206 /* Exists? Return it */
207 proc_dbg_info_src
= g_hash_table_lookup(ht
, key
);
208 if (proc_dbg_info_src
) {
212 /* Otherwise, create and return it */
213 proc_dbg_info_src
= proc_debug_info_sources_create();
214 if (!proc_dbg_info_src
) {
218 g_hash_table_insert(ht
, key
, proc_dbg_info_src
);
219 /* Ownership passed to ht */
223 return proc_dbg_info_src
;
227 struct debug_info_source
*proc_debug_info_sources_get_entry(
228 struct proc_debug_info_sources
*proc_dbg_info_src
, uint64_t ip
)
230 struct debug_info_source
*debug_info_src
= NULL
;
231 gpointer key
= g_new0(uint64_t, 1);
233 gpointer baddr
, value
;
239 *((uint64_t *) key
) = ip
;
241 /* Look in IP to debug infos hash table first. */
242 debug_info_src
= g_hash_table_lookup(
243 proc_dbg_info_src
->ip_to_debug_info_src
,
245 if (debug_info_src
) {
249 /* Check in all so_infos. */
250 g_hash_table_iter_init(&iter
, proc_dbg_info_src
->baddr_to_so_info
);
252 while (g_hash_table_iter_next(&iter
, &baddr
, &value
))
254 struct so_info
*so
= value
;
256 if (!so_info_has_address(value
, ip
)) {
261 * Found; add it to cache.
263 * FIXME: this should be bounded in size (and implement
264 * a caching policy), and entries should be prunned when
265 * libraries are unmapped.
267 debug_info_src
= debug_info_source_create_from_so(so
, ip
);
268 if (debug_info_src
) {
270 proc_dbg_info_src
->ip_to_debug_info_src
,
271 key
, debug_info_src
);
272 /* Ownership passed to ht. */
280 return debug_info_src
;
284 struct debug_info_source
*debug_info_query(struct debug_info
*debug_info
,
285 int64_t vpid
, uint64_t ip
)
287 struct debug_info_source
*dbg_info_src
= NULL
;
288 struct proc_debug_info_sources
*proc_dbg_info_src
;
290 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
291 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
292 if (!proc_dbg_info_src
) {
296 dbg_info_src
= proc_debug_info_sources_get_entry(
297 proc_dbg_info_src
, ip
);
307 struct debug_info
*debug_info_create(void)
310 struct debug_info
*debug_info
;
312 debug_info
= g_new0(struct debug_info
, 1);
317 debug_info
->vpid_to_proc_dbg_info_src
= g_hash_table_new_full(
318 g_int64_hash
, g_int64_equal
, (GDestroyNotify
) g_free
,
319 (GDestroyNotify
) proc_debug_info_sources_destroy
);
320 if (!debug_info
->vpid_to_proc_dbg_info_src
) {
324 ret
= debug_info_init(debug_info
);
337 void debug_info_destroy(struct debug_info
*debug_info
)
343 if (debug_info
->vpid_to_proc_dbg_info_src
) {
344 g_hash_table_destroy(debug_info
->vpid_to_proc_dbg_info_src
);
353 void handle_statedump_build_id_event(struct debug_info
*debug_info
,
354 struct ctf_event_definition
*event_def
)
356 struct proc_debug_info_sources
*proc_dbg_info_src
;
357 struct bt_definition
*event_fields_def
= NULL
;
358 struct bt_definition
*sec_def
= NULL
;
359 struct bt_definition
*baddr_def
= NULL
;
360 struct bt_definition
*vpid_def
= NULL
;
361 struct bt_definition
*build_id_def
= NULL
;
362 struct definition_sequence
*build_id_seq
;
363 struct so_info
*so
= NULL
;
367 uint8_t *build_id
= NULL
;
368 uint64_t build_id_len
;
370 event_fields_def
= (struct bt_definition
*) event_def
->event_fields
;
371 sec_def
= (struct bt_definition
*)
372 event_def
->stream
->stream_event_context
;
374 if (!event_fields_def
|| !sec_def
) {
378 baddr_def
= bt_lookup_definition(event_fields_def
, "_baddr");
383 vpid_def
= bt_lookup_definition(sec_def
, "_vpid");
388 build_id_def
= bt_lookup_definition(event_fields_def
, "_build_id");
393 if (baddr_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
397 if (vpid_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
401 if (build_id_def
->declaration
->id
!= CTF_TYPE_SEQUENCE
) {
405 baddr
= bt_get_unsigned_int(baddr_def
);
406 vpid
= bt_get_signed_int(vpid_def
);
407 build_id_seq
= container_of(build_id_def
,
408 struct definition_sequence
, p
);
409 build_id_len
= build_id_seq
->length
->value
._unsigned
;
411 build_id
= g_malloc(build_id_len
);
416 for (i
= 0; i
< build_id_len
; ++i
) {
417 struct bt_definition
**field
;
419 field
= (struct bt_definition
**) &g_ptr_array_index(
420 build_id_seq
->elems
, i
);
421 build_id
[i
] = bt_get_unsigned_int(*field
);
424 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
425 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
426 if (!proc_dbg_info_src
) {
430 so
= g_hash_table_lookup(proc_dbg_info_src
->baddr_to_so_info
,
434 * The build_id event comes after the so has been
435 * created. If it isn't found, just ignore this event.
440 so_info_set_build_id(so
, build_id
, build_id_len
);
448 void handle_statedump_debug_link_event(struct debug_info
*debug_info
,
449 struct ctf_event_definition
*event_def
)
451 struct proc_debug_info_sources
*proc_dbg_info_src
;
452 struct bt_definition
*event_fields_def
= NULL
;
453 struct bt_definition
*sec_def
= NULL
;
454 struct bt_definition
*baddr_def
= NULL
;
455 struct bt_definition
*vpid_def
= NULL
;
456 struct bt_definition
*filename_def
= NULL
;
457 struct bt_definition
*crc32_def
= NULL
;
458 struct so_info
*so
= NULL
;
461 char *filename
= NULL
;
464 event_fields_def
= (struct bt_definition
*) event_def
->event_fields
;
465 sec_def
= (struct bt_definition
*)
466 event_def
->stream
->stream_event_context
;
468 if (!event_fields_def
|| !sec_def
) {
472 baddr_def
= bt_lookup_definition(event_fields_def
, "_baddr");
477 vpid_def
= bt_lookup_definition(sec_def
, "_vpid");
482 filename_def
= bt_lookup_definition(event_fields_def
, "_filename");
487 crc32_def
= bt_lookup_definition(event_fields_def
, "_crc32");
492 if (baddr_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
496 if (vpid_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
500 if (filename_def
->declaration
->id
!= CTF_TYPE_STRING
) {
504 if (crc32_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
508 baddr
= bt_get_unsigned_int(baddr_def
);
509 vpid
= bt_get_signed_int(vpid_def
);
511 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
512 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
513 if (!proc_dbg_info_src
) {
517 so
= g_hash_table_lookup(proc_dbg_info_src
->baddr_to_so_info
,
521 * The debug_link event comes after the so has been
522 * created. If it isn't found, just ignore this event.
527 filename
= bt_get_string(filename_def
);
528 crc32
= bt_get_unsigned_int(crc32_def
);
530 so_info_set_debug_link(so
, filename
, crc32
);
537 void handle_statedump_soinfo_event(struct debug_info
*debug_info
,
538 struct ctf_event_definition
*event_def
)
540 struct bt_definition
*baddr_def
= NULL
;
541 struct bt_definition
*memsz_def
= NULL
;
542 struct bt_definition
*sopath_def
= NULL
;
543 struct bt_definition
*vpid_def
= NULL
;
544 struct bt_definition
*event_fields_def
= NULL
;
545 struct bt_definition
*sec_def
= NULL
;
546 struct proc_debug_info_sources
*proc_dbg_info_src
;
548 uint64_t baddr
, memsz
;
553 event_fields_def
= (struct bt_definition
*) event_def
->event_fields
;
554 sec_def
= (struct bt_definition
*)
555 event_def
->stream
->stream_event_context
;
557 if (!event_fields_def
|| !sec_def
) {
561 baddr_def
= bt_lookup_definition(event_fields_def
, "_baddr");
566 memsz_def
= bt_lookup_definition(event_fields_def
, "_memsz");
571 sopath_def
= bt_lookup_definition(event_fields_def
, "_sopath");
576 vpid_def
= bt_lookup_definition(sec_def
, "_vpid");
581 if (baddr_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
585 if (memsz_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
589 if (sopath_def
->declaration
->id
!= CTF_TYPE_STRING
) {
593 if (vpid_def
->declaration
->id
!= CTF_TYPE_INTEGER
) {
597 baddr
= bt_get_unsigned_int(baddr_def
);
598 memsz
= bt_get_unsigned_int(memsz_def
);
599 sopath
= bt_get_string(sopath_def
);
600 vpid
= bt_get_signed_int(vpid_def
);
611 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
612 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
613 if (!proc_dbg_info_src
) {
617 key
= g_new0(uint64_t, 1);
622 *((uint64_t *) key
) = baddr
;
624 so
= g_hash_table_lookup(proc_dbg_info_src
->baddr_to_so_info
,
630 so
= so_info_create(sopath
, baddr
, memsz
);
635 g_hash_table_insert(proc_dbg_info_src
->baddr_to_so_info
,
637 /* Ownership passed to ht. */
646 void handle_statedump_start(struct debug_info
*debug_info
,
647 struct ctf_event_definition
*event_def
)
649 struct bt_definition
*vpid_def
= NULL
;
650 struct bt_definition
*sec_def
= NULL
;
651 struct proc_debug_info_sources
*proc_dbg_info_src
;
654 sec_def
= (struct bt_definition
*)
655 event_def
->stream
->stream_event_context
;
660 vpid_def
= bt_lookup_definition(sec_def
, "_vpid");
665 vpid
= bt_get_signed_int(vpid_def
);
667 proc_dbg_info_src
= proc_debug_info_sources_ht_get_entry(
668 debug_info
->vpid_to_proc_dbg_info_src
, vpid
);
669 if (!proc_dbg_info_src
) {
673 g_hash_table_remove_all(proc_dbg_info_src
->baddr_to_so_info
);
674 g_hash_table_remove_all(proc_dbg_info_src
->ip_to_debug_info_src
);
681 void register_event_debug_infos(struct debug_info
*debug_info
,
682 struct ctf_event_definition
*event
)
684 struct bt_definition
*ip_def
, *vpid_def
;
687 struct bt_definition
*sec_def
;
689 /* Get stream event context definition. */
690 sec_def
= (struct bt_definition
*) event
->stream
->stream_event_context
;
695 /* Get "ip" and "vpid" definitions. */
696 vpid_def
= bt_lookup_definition((struct bt_definition
*) sec_def
,
698 ip_def
= bt_lookup_definition((struct bt_definition
*) sec_def
, "_ip");
700 if (!vpid_def
|| !ip_def
) {
704 vpid
= bt_get_signed_int(vpid_def
);
705 ip
= bt_get_unsigned_int(ip_def
);
707 /* Get debug info for this context. */
708 ((struct definition_integer
*) ip_def
)->debug_info_src
=
709 debug_info_query(debug_info
, vpid
, ip
);
716 void debug_info_handle_event(struct debug_info
*debug_info
,
717 struct ctf_event_definition
*event
)
719 struct ctf_event_declaration
*event_class
;
720 struct ctf_stream_declaration
*stream_class
;
722 if (!debug_info
|| !event
) {
726 stream_class
= event
->stream
->stream_class
;
727 event_class
= g_ptr_array_index(stream_class
->events_by_id
,
728 event
->stream
->event_id
);
730 if (event_class
->name
== debug_info
->q_statedump_soinfo
||
731 event_class
->name
== debug_info
->q_dl_open
) {
732 /* State dump/dlopen() */
733 handle_statedump_soinfo_event(debug_info
, event
);
734 } else if (event_class
->name
== debug_info
->q_statedump_start
) {
735 /* Start state dump */
736 handle_statedump_start(debug_info
, event
);
737 } else if (event_class
->name
== debug_info
->q_statedump_debug_link
) {
738 /* Debug link info */
739 handle_statedump_debug_link_event(debug_info
, event
);
740 } else if (event_class
->name
== debug_info
->q_statedump_build_id
) {
742 handle_statedump_build_id_event(debug_info
, event
);
744 /* Other events: register debug infos */
745 register_event_debug_infos(debug_info
, event
);