lib: make trace IR API const-correct
[babeltrace.git] / plugins / lttng-utils / debug-info.c
1 /*
2 * Babeltrace - Debug Information State Tracker
3 *
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>
8 *
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:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
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
25 * SOFTWARE.
26 */
27
28 #define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT"
29 #include "logging.h"
30
31 #include <babeltrace/assert-internal.h>
32 #include <glib.h>
33 #include "debug-info.h"
34 #include "bin-info.h"
35 #include "utils.h"
36 #include "copy.h"
37
38 struct proc_debug_info_sources {
39 /*
40 * Hash table: base address (pointer to uint64_t) to bin info; owned by
41 * proc_debug_info_sources.
42 */
43 GHashTable *baddr_to_bin_info;
44
45 /*
46 * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *);
47 * owned by proc_debug_info_sources.
48 */
49 GHashTable *ip_to_debug_info_src;
50 };
51
52 struct debug_info {
53 struct debug_info_component *comp;
54
55 /*
56 * Hash table of VPIDs (pointer to int64_t) to
57 * (struct ctf_proc_debug_infos*); owned by debug_info.
58 */
59 GHashTable *vpid_to_proc_dbg_info_src;
60 GQuark q_statedump_bin_info;
61 GQuark q_statedump_debug_link;
62 GQuark q_statedump_build_id;
63 GQuark q_statedump_start;
64 GQuark q_dl_open;
65 GQuark q_lib_load;
66 GQuark q_lib_unload;
67 };
68
69 static
70 int debug_info_init(struct debug_info *info)
71 {
72 info->q_statedump_bin_info = g_quark_from_string(
73 "lttng_ust_statedump:bin_info");
74 info->q_statedump_debug_link = g_quark_from_string(
75 "lttng_ust_statedump:debug_link)");
76 info->q_statedump_build_id = g_quark_from_string(
77 "lttng_ust_statedump:build_id");
78 info->q_statedump_start = g_quark_from_string(
79 "lttng_ust_statedump:start");
80 info->q_dl_open = g_quark_from_string("lttng_ust_dl:dlopen");
81 info->q_lib_load = g_quark_from_string("lttng_ust_lib:load");
82 info->q_lib_unload = g_quark_from_string("lttng_ust_lib:unload");
83
84 return bin_info_init();
85 }
86
87 static
88 void debug_info_source_destroy(struct debug_info_source *debug_info_src)
89 {
90 if (!debug_info_src) {
91 return;
92 }
93
94 free(debug_info_src->func);
95 free(debug_info_src->src_path);
96 free(debug_info_src->bin_path);
97 free(debug_info_src->bin_loc);
98 g_free(debug_info_src);
99 }
100
101 static
102 struct debug_info_source *debug_info_source_create_from_bin(struct bin_info *bin,
103 uint64_t ip)
104 {
105 int ret;
106 struct debug_info_source *debug_info_src = NULL;
107 struct source_location *src_loc = NULL;
108
109 debug_info_src = g_new0(struct debug_info_source, 1);
110
111 if (!debug_info_src) {
112 goto end;
113 }
114
115 /* Lookup function name */
116 ret = bin_info_lookup_function_name(bin, ip, &debug_info_src->func);
117 if (ret) {
118 goto error;
119 }
120
121 /* Can't retrieve src_loc from ELF, or could not find binary, skip. */
122 if (!bin->is_elf_only || !debug_info_src->func) {
123 /* Lookup source location */
124 ret = bin_info_lookup_source_location(bin, ip, &src_loc);
125 BT_LOGD("Failed to lookup source location: ret=%d", ret);
126 }
127
128 if (src_loc) {
129 debug_info_src->line_no = src_loc->line_no;
130
131 if (src_loc->filename) {
132 debug_info_src->src_path = strdup(src_loc->filename);
133 if (!debug_info_src->src_path) {
134 goto error;
135 }
136
137 debug_info_src->short_src_path = get_filename_from_path(
138 debug_info_src->src_path);
139 }
140
141 source_location_destroy(src_loc);
142 }
143
144 if (bin->elf_path) {
145 debug_info_src->bin_path = strdup(bin->elf_path);
146 if (!debug_info_src->bin_path) {
147 goto error;
148 }
149
150 debug_info_src->short_bin_path = get_filename_from_path(
151 debug_info_src->bin_path);
152
153 ret = bin_info_get_bin_loc(bin, ip, &(debug_info_src->bin_loc));
154 if (ret) {
155 goto error;
156 }
157 }
158
159 end:
160 return debug_info_src;
161
162 error:
163 debug_info_source_destroy(debug_info_src);
164 return NULL;
165 }
166
167 static
168 void proc_debug_info_sources_destroy(
169 struct proc_debug_info_sources *proc_dbg_info_src)
170 {
171 if (!proc_dbg_info_src) {
172 return;
173 }
174
175 if (proc_dbg_info_src->baddr_to_bin_info) {
176 g_hash_table_destroy(proc_dbg_info_src->baddr_to_bin_info);
177 }
178
179 if (proc_dbg_info_src->ip_to_debug_info_src) {
180 g_hash_table_destroy(proc_dbg_info_src->ip_to_debug_info_src);
181 }
182
183 g_free(proc_dbg_info_src);
184 }
185
186 static
187 struct proc_debug_info_sources *proc_debug_info_sources_create(void)
188 {
189 struct proc_debug_info_sources *proc_dbg_info_src = NULL;
190
191 proc_dbg_info_src = g_new0(struct proc_debug_info_sources, 1);
192 if (!proc_dbg_info_src) {
193 goto end;
194 }
195
196 proc_dbg_info_src->baddr_to_bin_info = g_hash_table_new_full(
197 g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
198 (GDestroyNotify) bin_info_destroy);
199 if (!proc_dbg_info_src->baddr_to_bin_info) {
200 goto error;
201 }
202
203 proc_dbg_info_src->ip_to_debug_info_src = g_hash_table_new_full(
204 g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
205 (GDestroyNotify) debug_info_source_destroy);
206 if (!proc_dbg_info_src->ip_to_debug_info_src) {
207 goto error;
208 }
209
210 end:
211 return proc_dbg_info_src;
212
213 error:
214 proc_debug_info_sources_destroy(proc_dbg_info_src);
215 return NULL;
216 }
217
218 static
219 struct proc_debug_info_sources *proc_debug_info_sources_ht_get_entry(
220 GHashTable *ht, int64_t vpid)
221 {
222 gpointer key = g_new0(int64_t, 1);
223 struct proc_debug_info_sources *proc_dbg_info_src = NULL;
224
225 if (!key) {
226 goto end;
227 }
228
229 *((int64_t *) key) = vpid;
230
231 /* Exists? Return it */
232 proc_dbg_info_src = g_hash_table_lookup(ht, key);
233 if (proc_dbg_info_src) {
234 goto end;
235 }
236
237 /* Otherwise, create and return it */
238 proc_dbg_info_src = proc_debug_info_sources_create();
239 if (!proc_dbg_info_src) {
240 goto end;
241 }
242
243 g_hash_table_insert(ht, key, proc_dbg_info_src);
244 /* Ownership passed to ht */
245 key = NULL;
246 end:
247 g_free(key);
248 return proc_dbg_info_src;
249 }
250
251 static
252 struct debug_info_source *proc_debug_info_sources_get_entry(
253 struct proc_debug_info_sources *proc_dbg_info_src, uint64_t ip)
254 {
255 struct debug_info_source *debug_info_src = NULL;
256 gpointer key = g_new0(uint64_t, 1);
257 GHashTableIter iter;
258 gpointer baddr, value;
259
260 if (!key) {
261 goto end;
262 }
263
264 *((uint64_t *) key) = ip;
265
266 /* Look in IP to debug infos hash table first. */
267 debug_info_src = g_hash_table_lookup(
268 proc_dbg_info_src->ip_to_debug_info_src,
269 key);
270 if (debug_info_src) {
271 goto end;
272 }
273
274 /* Check in all bin_infos. */
275 g_hash_table_iter_init(&iter, proc_dbg_info_src->baddr_to_bin_info);
276
277 while (g_hash_table_iter_next(&iter, &baddr, &value))
278 {
279 struct bin_info *bin = value;
280
281 if (!bin_info_has_address(value, ip)) {
282 continue;
283 }
284
285 /*
286 * Found; add it to cache.
287 *
288 * FIXME: this should be bounded in size (and implement
289 * a caching policy), and entries should be prunned when
290 * libraries are unmapped.
291 */
292 debug_info_src = debug_info_source_create_from_bin(bin, ip);
293 if (debug_info_src) {
294 g_hash_table_insert(
295 proc_dbg_info_src->ip_to_debug_info_src,
296 key, debug_info_src);
297 /* Ownership passed to ht. */
298 key = NULL;
299 }
300 break;
301 }
302
303 end:
304 free(key);
305 return debug_info_src;
306 }
307
308 BT_HIDDEN
309 struct debug_info_source *debug_info_query(struct debug_info *debug_info,
310 int64_t vpid, uint64_t ip)
311 {
312 struct debug_info_source *dbg_info_src = NULL;
313 struct proc_debug_info_sources *proc_dbg_info_src;
314
315 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
316 debug_info->vpid_to_proc_dbg_info_src, vpid);
317 if (!proc_dbg_info_src) {
318 goto end;
319 }
320
321 dbg_info_src = proc_debug_info_sources_get_entry(proc_dbg_info_src, ip);
322
323 end:
324 return dbg_info_src;
325 }
326
327 BT_HIDDEN
328 struct debug_info *debug_info_create(struct debug_info_component *comp)
329 {
330 int ret;
331 struct debug_info *debug_info;
332
333 debug_info = g_new0(struct debug_info, 1);
334 if (!debug_info) {
335 goto end;
336 }
337
338 debug_info->vpid_to_proc_dbg_info_src = g_hash_table_new_full(
339 g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
340 (GDestroyNotify) proc_debug_info_sources_destroy);
341 if (!debug_info->vpid_to_proc_dbg_info_src) {
342 goto error;
343 }
344
345 debug_info->comp = comp;
346 ret = debug_info_init(debug_info);
347 if (ret) {
348 goto error;
349 }
350
351 end:
352 return debug_info;
353 error:
354 g_free(debug_info);
355 return NULL;
356 }
357
358 BT_HIDDEN
359 void debug_info_destroy(struct debug_info *debug_info)
360 {
361 if (!debug_info) {
362 goto end;
363 }
364
365 if (debug_info->vpid_to_proc_dbg_info_src) {
366 g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src);
367 }
368
369 g_free(debug_info);
370 end:
371 return;
372 }
373
374 static
375 void handle_statedump_build_id_event(FILE *err, struct debug_info *debug_info,
376 const struct bt_event *event)
377 {
378 struct proc_debug_info_sources *proc_dbg_info_src;
379 struct bin_info *bin = NULL;
380 int ret;
381 int64_t vpid;
382 uint64_t baddr;
383 uint64_t build_id_len;
384
385 ret = get_stream_event_context_int_field_value(err,
386 event, VPID_FIELD_NAME, &vpid);
387 if (ret) {
388 goto end;
389 }
390
391 ret = get_payload_unsigned_int_field_value(err,
392 event, BADDR_FIELD_NAME, &baddr);
393 if (ret) {
394 BT_LOGE_STR("Failed to get unsigned int value for "
395 VPID_FIELD_NAME " field.");
396 goto end;
397 }
398
399 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
400 debug_info->vpid_to_proc_dbg_info_src, vpid);
401 if (!proc_dbg_info_src) {
402 goto end;
403 }
404
405 bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info,
406 (gpointer) &baddr);
407 if (!bin) {
408 /*
409 * The build_id event comes after the bin has been
410 * created. If it isn't found, just ignore this event.
411 */
412 goto end;
413 }
414
415 ret = get_payload_build_id_field_value(err, event, BUILD_ID_FIELD_NAME,
416 &bin->build_id, &build_id_len);
417 if (ret) {
418 BT_LOGE_STR("Failed to get " BUILD_ID_FIELD_NAME
419 " field value.");
420 goto end;
421 }
422 if (build_id_len > SIZE_MAX) {
423 bin->build_id_len = (size_t) build_id_len;
424 }
425
426 /*
427 * Reset the is_elf_only flag in case it had been set
428 * previously, because we might find separate debug info using
429 * the new build id information.
430 */
431 bin->is_elf_only = false;
432
433 // TODO
434 // bin_info_set_build_id(bin, build_id, build_id_len);
435
436 end:
437 return;
438 }
439
440 static
441 void handle_statedump_debug_link_event(FILE *err, struct debug_info *debug_info,
442 const struct bt_event *event)
443 {
444 struct proc_debug_info_sources *proc_dbg_info_src;
445 struct bin_info *bin = NULL;
446 int64_t vpid;
447 uint64_t baddr;
448 const char *filename = NULL;
449 uint32_t crc32;
450 uint64_t tmp;
451 int ret;
452
453 ret = get_stream_event_context_int_field_value(err, event,
454 VPID_FIELD_NAME, &vpid);
455 if (ret) {
456 goto end;
457 }
458
459 ret = get_payload_unsigned_int_field_value(err,
460 event, BADDR_FIELD_NAME, &baddr);
461 if (ret) {
462 BT_LOGE_STR("Failed to get unsigned int value for "
463 BADDR_FIELD_NAME " field.");
464 ret = -1;
465 goto end;
466 }
467
468 ret = get_payload_unsigned_int_field_value(err, event, CRC32_FIELD_NAME,
469 &tmp);
470 if (ret) {
471 BT_LOGE_STR("Failed to get unsigned int value for "
472 CRC32_FIELD_NAME " field.");
473 ret = -1;
474 goto end;
475 }
476 crc32 = (uint32_t) tmp;
477
478 ret = get_payload_string_field_value(err,
479 event, FILENAME_FIELD_NAME, &filename);
480 if (ret) {
481 BT_LOGE_STR("Failed to get string value for "
482 FILENAME_FIELD_NAME " field.");
483 ret = -1;
484 goto end;
485 }
486
487 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
488 debug_info->vpid_to_proc_dbg_info_src, vpid);
489 if (!proc_dbg_info_src) {
490 goto end;
491 }
492
493 bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info,
494 (gpointer) &baddr);
495 if (!bin) {
496 /*
497 * The debug_link event comes after the bin has been
498 * created. If it isn't found, just ignore this event.
499 */
500 goto end;
501 }
502
503 bin_info_set_debug_link(bin, filename, crc32);
504
505 end:
506 return;
507 }
508
509 static
510 void handle_bin_info_event(FILE *err, struct debug_info *debug_info,
511 const struct bt_event *event, bool has_pic_field)
512 {
513 struct proc_debug_info_sources *proc_dbg_info_src;
514 struct bin_info *bin;
515 uint64_t baddr, memsz;
516 int64_t vpid;
517 const char *path;
518 gpointer key = NULL;
519 bool is_pic;
520 int ret;
521
522 ret = get_payload_unsigned_int_field_value(err,
523 event, BADDR_FIELD_NAME, &baddr);
524 if (ret) {
525 BT_LOGE_STR("Failed to get unsigned int value for "
526 BADDR_FIELD_NAME " field.");
527 goto end;
528 }
529
530 ret = get_payload_unsigned_int_field_value(err,
531 event, MEMSZ_FIELD_NAME, &memsz);
532 if (ret) {
533 BT_LOGE_STR("Failed to get unsigned int value for "
534 MEMSZ_FIELD_NAME " field.");
535 goto end;
536 }
537
538 /*
539 * This field is not produced by the dlopen event emitted before
540 * lttng-ust 2.9.
541 */
542 ret = get_payload_string_field_value(err,
543 event, PATH_FIELD_NAME, &path);
544 if (ret || !path) {
545 goto end;
546 }
547
548 if (has_pic_field) {
549 uint64_t tmp;
550
551 ret = get_payload_unsigned_int_field_value(err,
552 event, IS_PIC_FIELD_NAME, &tmp);
553 if (ret) {
554 BT_LOGE_STR("Failed to get unsigned int value for "
555 IS_PIC_FIELD_NAME " field.");
556 ret = -1;
557 goto end;
558 }
559 is_pic = (tmp == 1);
560 } else {
561 /*
562 * dlopen has no is_pic field, because the shared
563 * object is always PIC.
564 */
565 is_pic = true;
566 }
567
568 ret = get_stream_event_context_int_field_value(err, event,
569 VPID_FIELD_NAME, &vpid);
570 if (ret) {
571 goto end;
572 }
573
574 if (memsz == 0) {
575 /* Ignore VDSO. */
576 goto end;
577 }
578
579 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
580 debug_info->vpid_to_proc_dbg_info_src, vpid);
581 if (!proc_dbg_info_src) {
582 goto end;
583 }
584
585 key = g_new0(uint64_t, 1);
586 if (!key) {
587 goto end;
588 }
589
590 *((uint64_t *) key) = baddr;
591
592 bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info,
593 key);
594 if (bin) {
595 goto end;
596 }
597
598 bin = bin_info_create(path, baddr, memsz, is_pic,
599 debug_info->comp->arg_debug_dir,
600 debug_info->comp->arg_target_prefix);
601 if (!bin) {
602 goto end;
603 }
604
605 g_hash_table_insert(proc_dbg_info_src->baddr_to_bin_info,
606 key, bin);
607 /* Ownership passed to ht. */
608 key = NULL;
609
610 end:
611 g_free(key);
612 return;
613 }
614
615 static inline
616 void handle_statedump_bin_info_event(FILE *err, struct debug_info *debug_info,
617 const struct bt_event *event)
618 {
619 handle_bin_info_event(err, debug_info, event, true);
620 }
621
622 static inline
623 void handle_lib_load_event(FILE *err, struct debug_info *debug_info,
624 const struct bt_event *event)
625 {
626 handle_bin_info_event(err, debug_info, event, false);
627 }
628
629 static inline
630 void handle_lib_unload_event(FILE *err, struct debug_info *debug_info,
631 const struct bt_event *event)
632 {
633 struct proc_debug_info_sources *proc_dbg_info_src;
634 uint64_t baddr;
635 int64_t vpid;
636 gpointer key_ptr = NULL;
637 int ret;
638
639 ret = get_payload_unsigned_int_field_value(err,
640 event, BADDR_FIELD_NAME, &baddr);
641 if (ret) {
642 BT_LOGE_STR("Failed to get unsigned int value for "
643 BADDR_FIELD_NAME " field.");
644 ret = -1;
645 goto end;
646 }
647
648 ret = get_stream_event_context_int_field_value(err, event,
649 VPID_FIELD_NAME, &vpid);
650 if (ret) {
651 goto end;
652 }
653
654 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
655 debug_info->vpid_to_proc_dbg_info_src, vpid);
656 if (!proc_dbg_info_src) {
657 goto end;
658 }
659
660 key_ptr = (gpointer) &baddr;
661 (void) g_hash_table_remove(proc_dbg_info_src->baddr_to_bin_info,
662 key_ptr);
663 end:
664 return;
665 }
666
667 static
668 void handle_statedump_start(FILE *err, struct debug_info *debug_info,
669 const struct bt_event *event)
670 {
671 struct proc_debug_info_sources *proc_dbg_info_src;
672 int64_t vpid;
673 int ret;
674
675 ret = get_stream_event_context_int_field_value(err, event,
676 VPID_FIELD_NAME, &vpid);
677 if (ret) {
678 goto end;
679 }
680
681 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
682 debug_info->vpid_to_proc_dbg_info_src, vpid);
683 if (!proc_dbg_info_src) {
684 goto end;
685 }
686
687 g_hash_table_remove_all(proc_dbg_info_src->baddr_to_bin_info);
688 g_hash_table_remove_all(proc_dbg_info_src->ip_to_debug_info_src);
689
690 end:
691 return;
692 }
693
694 BT_HIDDEN
695 void debug_info_handle_event(FILE *err, const struct bt_event *event,
696 struct debug_info *debug_info)
697 {
698 const struct bt_event_class *event_class;
699 const char *event_name;
700 GQuark q_event_name;
701
702 if (!debug_info || !event) {
703 goto end;
704 }
705 event_class = bt_event_get_class(event);
706 if (!event_class) {
707 goto end;
708 }
709 event_name = bt_event_class_get_name(event_class);
710 if (!event_name) {
711 goto end_put_class;
712 }
713 q_event_name = g_quark_try_string(event_name);
714
715 if (q_event_name == debug_info->q_statedump_bin_info) {
716 /* State dump */
717 handle_statedump_bin_info_event(err, debug_info, event);
718 } else if (q_event_name == debug_info->q_dl_open ||
719 q_event_name == debug_info->q_lib_load) {
720 /*
721 * dl_open and lib_load events are both checked for since
722 * only dl_open was produced as of lttng-ust 2.8.
723 *
724 * lib_load, which is produced from lttng-ust 2.9+, is a lot
725 * more reliable since it will be emitted when other functions
726 * of the dlopen family are called (e.g. dlmopen) and when
727 * library are transitively loaded.
728 */
729 handle_lib_load_event(err, debug_info, event);
730 } else if (q_event_name == debug_info->q_statedump_start) {
731 /* Start state dump */
732 handle_statedump_start(err, debug_info, event);
733 } else if (q_event_name == debug_info->q_statedump_debug_link) {
734 /* Debug link info */
735 handle_statedump_debug_link_event(err, debug_info, event);
736 } else if (q_event_name == debug_info->q_statedump_build_id) {
737 /* Build ID info */
738 handle_statedump_build_id_event(err, debug_info, event);
739 } else if (q_event_name == debug_info-> q_lib_unload) {
740 handle_lib_unload_event(err, debug_info, event);
741 }
742
743 end_put_class:
744 bt_object_put_ref(event_class);
745 end:
746 return;
747 }
This page took 0.047387 seconds and 4 git commands to generate.