Fix: cast of 64 bit addresses from trace to 32-bit pointer
[babeltrace.git] / lib / debuginfo.c
... / ...
CommitLineData
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 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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
24 * SOFTWARE.
25 */
26
27#include <assert.h>
28#include <glib.h>
29#include <babeltrace/types.h>
30#include <babeltrace/ctf-ir/metadata.h>
31#include <babeltrace/debuginfo.h>
32#include <babeltrace/so-info.h>
33
34struct proc_debug_info_sources {
35 /*
36 * Hash table: base address (pointer to uint64_t) to so info; owned by
37 * proc_debug_info_sources.
38 */
39 GHashTable *baddr_to_so_info;
40
41 /*
42 * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *);
43 * owned by proc_debug_info_sources.
44 */
45 GHashTable *ip_to_debug_info_src;
46};
47
48struct debug_info {
49 /*
50 * Hash table of VPIDs (pointer to int64_t) to
51 * (struct ctf_proc_debug_infos*); owned by debug_info.
52 */
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;
58 GQuark q_dl_open;
59};
60
61static
62int debug_info_init(struct debug_info *info)
63{
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");
73
74 return so_info_init();
75}
76
77static
78void debug_info_source_destroy(struct debug_info_source *debug_info_src)
79{
80 if (!debug_info_src) {
81 return;
82 }
83
84 free(debug_info_src->func);
85 free(debug_info_src->filename);
86 g_free(debug_info_src);
87}
88
89static
90struct debug_info_source *debug_info_source_create_from_so(struct so_info *so,
91 uint64_t ip)
92{
93 int ret;
94 struct debug_info_source *debug_info_src = NULL;
95 struct source_location *src_loc = NULL;
96
97 debug_info_src = g_new0(struct debug_info_source, 1);
98
99 if (!debug_info_src) {
100 goto end;
101 }
102
103 /* Lookup function name */
104 ret = so_info_lookup_function_name(so, ip, &debug_info_src->func);
105 if (ret) {
106 goto error;
107 }
108
109 /* Can't retrieve src_loc from ELF only, skip it */
110 if (so->is_elf_only) {
111 goto end;
112 }
113
114 /* Lookup source location */
115 ret = so_info_lookup_source_location(so, ip, &src_loc);
116 if (ret) {
117 goto error;
118 }
119
120 if (src_loc) {
121 debug_info_src->line_no = src_loc->line_no;
122
123 if (src_loc->filename) {
124 debug_info_src->filename = strdup(src_loc->filename);
125
126 if (!debug_info_src->filename) {
127 goto error;
128 }
129 }
130
131 source_location_destroy(src_loc);
132 }
133
134end:
135 return debug_info_src;
136
137error:
138 debug_info_source_destroy(debug_info_src);
139 return NULL;
140}
141
142static
143void proc_debug_info_sources_destroy(
144 struct proc_debug_info_sources *proc_dbg_info_src)
145{
146 if (!proc_dbg_info_src) {
147 return;
148 }
149
150 if (proc_dbg_info_src->baddr_to_so_info) {
151 g_hash_table_destroy(proc_dbg_info_src->baddr_to_so_info);
152 }
153
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);
156 }
157
158 g_free(proc_dbg_info_src);
159}
160
161static
162struct proc_debug_info_sources *proc_debug_info_sources_create(void)
163{
164 struct proc_debug_info_sources *proc_dbg_info_src = NULL;
165
166 proc_dbg_info_src = g_new0(struct proc_debug_info_sources, 1);
167 if (!proc_dbg_info_src) {
168 goto end;
169 }
170
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) {
175 goto error;
176 }
177
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) {
182 goto error;
183 }
184
185end:
186 return proc_dbg_info_src;
187
188error:
189 proc_debug_info_sources_destroy(proc_dbg_info_src);
190 return NULL;
191}
192
193static
194struct proc_debug_info_sources *proc_debug_info_sources_ht_get_entry(
195 GHashTable *ht, int64_t vpid)
196{
197 gpointer key = g_new0(int64_t, 1);
198 struct proc_debug_info_sources *proc_dbg_info_src = NULL;
199
200 if (!key) {
201 goto end;
202 }
203
204 *((int64_t *) key) = vpid;
205
206 /* Exists? Return it */
207 proc_dbg_info_src = g_hash_table_lookup(ht, key);
208 if (proc_dbg_info_src) {
209 goto end;
210 }
211
212 /* Otherwise, create and return it */
213 proc_dbg_info_src = proc_debug_info_sources_create();
214 if (!proc_dbg_info_src) {
215 goto end;
216 }
217
218 g_hash_table_insert(ht, key, proc_dbg_info_src);
219 /* Ownership passed to ht */
220 key = NULL;
221end:
222 g_free(key);
223 return proc_dbg_info_src;
224}
225
226static
227struct debug_info_source *proc_debug_info_sources_get_entry(
228 struct proc_debug_info_sources *proc_dbg_info_src, uint64_t ip)
229{
230 struct debug_info_source *debug_info_src = NULL;
231 gpointer key = g_new0(uint64_t, 1);
232 GHashTableIter iter;
233 gpointer baddr, value;
234
235 if (!key) {
236 goto end;
237 }
238
239 *((uint64_t *) key) = ip;
240
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,
244 key);
245 if (debug_info_src) {
246 goto end;
247 }
248
249 /* Check in all so_infos. */
250 g_hash_table_iter_init(&iter, proc_dbg_info_src->baddr_to_so_info);
251
252 while (g_hash_table_iter_next(&iter, &baddr, &value))
253 {
254 struct so_info *so = value;
255
256 if (!so_info_has_address(value, ip)) {
257 continue;
258 }
259
260 /*
261 * Found; add it to cache.
262 *
263 * FIXME: this should be bounded in size (and implement
264 * a caching policy), and entries should be prunned when
265 * libraries are unmapped.
266 */
267 debug_info_src = debug_info_source_create_from_so(so, ip);
268 if (debug_info_src) {
269 g_hash_table_insert(
270 proc_dbg_info_src->ip_to_debug_info_src,
271 key, debug_info_src);
272 /* Ownership passed to ht. */
273 key = NULL;
274 }
275 break;
276 }
277
278end:
279 free(key);
280 return debug_info_src;
281}
282
283BT_HIDDEN
284struct debug_info_source *debug_info_query(struct debug_info *debug_info,
285 int64_t vpid, uint64_t ip)
286{
287 struct debug_info_source *dbg_info_src = NULL;
288 struct proc_debug_info_sources *proc_dbg_info_src;
289
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) {
293 goto end;
294 }
295
296 dbg_info_src = proc_debug_info_sources_get_entry(
297 proc_dbg_info_src, ip);
298 if (!dbg_info_src) {
299 goto end;
300 }
301
302end:
303 return dbg_info_src;
304}
305
306BT_HIDDEN
307struct debug_info *debug_info_create(void)
308{
309 int ret;
310 struct debug_info *debug_info;
311
312 debug_info = g_new0(struct debug_info, 1);
313 if (!debug_info) {
314 goto end;
315 }
316
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) {
321 goto error;
322 }
323
324 ret = debug_info_init(debug_info);
325 if (ret) {
326 goto error;
327 }
328
329end:
330 return debug_info;
331error:
332 g_free(debug_info);
333 return NULL;
334}
335
336BT_HIDDEN
337void debug_info_destroy(struct debug_info *debug_info)
338{
339 if (!debug_info) {
340 goto end;
341 }
342
343 if (debug_info->vpid_to_proc_dbg_info_src) {
344 g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src);
345 }
346
347 g_free(debug_info);
348end:
349 return;
350}
351
352static
353void handle_statedump_build_id_event(struct debug_info *debug_info,
354 struct ctf_event_definition *event_def)
355{
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;
364 int i;
365 int64_t vpid;
366 uint64_t baddr;
367 uint8_t *build_id = NULL;
368 uint64_t build_id_len;
369
370 event_fields_def = (struct bt_definition *) event_def->event_fields;
371 sec_def = (struct bt_definition *)
372 event_def->stream->stream_event_context;
373
374 if (!event_fields_def || !sec_def) {
375 goto end;
376 }
377
378 baddr_def = bt_lookup_definition(event_fields_def, "_baddr");
379 if (!baddr_def) {
380 goto end;
381 }
382
383 vpid_def = bt_lookup_definition(sec_def, "_vpid");
384 if (!vpid_def) {
385 goto end;
386 }
387
388 build_id_def = bt_lookup_definition(event_fields_def, "_build_id");
389 if (!build_id_def) {
390 goto end;
391 }
392
393 if (baddr_def->declaration->id != CTF_TYPE_INTEGER) {
394 goto end;
395 }
396
397 if (vpid_def->declaration->id != CTF_TYPE_INTEGER) {
398 goto end;
399 }
400
401 if (build_id_def->declaration->id != CTF_TYPE_SEQUENCE) {
402 goto end;
403 }
404
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;
410
411 build_id = g_malloc(build_id_len);
412 if (!build_id) {
413 goto end;
414 }
415
416 for (i = 0; i < build_id_len; ++i) {
417 struct bt_definition **field;
418
419 field = (struct bt_definition **) &g_ptr_array_index(
420 build_id_seq->elems, i);
421 build_id[i] = bt_get_unsigned_int(*field);
422 }
423
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) {
427 goto end;
428 }
429
430 so = g_hash_table_lookup(proc_dbg_info_src->baddr_to_so_info,
431 (gpointer) &baddr);
432 if (!so) {
433 /*
434 * The build_id event comes after the so has been
435 * created. If it isn't found, just ignore this event.
436 */
437 goto end;
438 }
439
440 so_info_set_build_id(so, build_id, build_id_len);
441
442end:
443 free(build_id);
444 return;
445}
446
447static
448void handle_statedump_debug_link_event(struct debug_info *debug_info,
449 struct ctf_event_definition *event_def)
450{
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;
459 int64_t vpid;
460 uint64_t baddr;
461 char *filename = NULL;
462 uint32_t crc32;
463
464 event_fields_def = (struct bt_definition *) event_def->event_fields;
465 sec_def = (struct bt_definition *)
466 event_def->stream->stream_event_context;
467
468 if (!event_fields_def || !sec_def) {
469 goto end;
470 }
471
472 baddr_def = bt_lookup_definition(event_fields_def, "_baddr");
473 if (!baddr_def) {
474 goto end;
475 }
476
477 vpid_def = bt_lookup_definition(sec_def, "_vpid");
478 if (!vpid_def) {
479 goto end;
480 }
481
482 filename_def = bt_lookup_definition(event_fields_def, "_filename");
483 if (!filename_def) {
484 goto end;
485 }
486
487 crc32_def = bt_lookup_definition(event_fields_def, "_crc32");
488 if (!crc32_def) {
489 goto end;
490 }
491
492 if (baddr_def->declaration->id != CTF_TYPE_INTEGER) {
493 goto end;
494 }
495
496 if (vpid_def->declaration->id != CTF_TYPE_INTEGER) {
497 goto end;
498 }
499
500 if (filename_def->declaration->id != CTF_TYPE_STRING) {
501 goto end;
502 }
503
504 if (crc32_def->declaration->id != CTF_TYPE_INTEGER) {
505 goto end;
506 }
507
508 baddr = bt_get_unsigned_int(baddr_def);
509 vpid = bt_get_signed_int(vpid_def);
510
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) {
514 goto end;
515 }
516
517 so = g_hash_table_lookup(proc_dbg_info_src->baddr_to_so_info,
518 (gpointer) &baddr);
519 if (!so) {
520 /*
521 * The debug_link event comes after the so has been
522 * created. If it isn't found, just ignore this event.
523 */
524 goto end;
525 }
526
527 filename = bt_get_string(filename_def);
528 crc32 = bt_get_unsigned_int(crc32_def);
529
530 so_info_set_debug_link(so, filename, crc32);
531
532end:
533 return;
534}
535
536static
537void handle_statedump_soinfo_event(struct debug_info *debug_info,
538 struct ctf_event_definition *event_def)
539{
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;
547 struct so_info *so;
548 uint64_t baddr, memsz;
549 int64_t vpid;
550 const char *sopath;
551 gpointer key = NULL;
552
553 event_fields_def = (struct bt_definition *) event_def->event_fields;
554 sec_def = (struct bt_definition *)
555 event_def->stream->stream_event_context;
556
557 if (!event_fields_def || !sec_def) {
558 goto end;
559 }
560
561 baddr_def = bt_lookup_definition(event_fields_def, "_baddr");
562 if (!baddr_def) {
563 goto end;
564 }
565
566 memsz_def = bt_lookup_definition(event_fields_def, "_memsz");
567 if (!memsz_def) {
568 goto end;
569 }
570
571 sopath_def = bt_lookup_definition(event_fields_def, "_sopath");
572 if (!sopath_def) {
573 goto end;
574 }
575
576 vpid_def = bt_lookup_definition(sec_def, "_vpid");
577 if (!vpid_def) {
578 goto end;
579 }
580
581 if (baddr_def->declaration->id != CTF_TYPE_INTEGER) {
582 goto end;
583 }
584
585 if (memsz_def->declaration->id != CTF_TYPE_INTEGER) {
586 goto end;
587 }
588
589 if (sopath_def->declaration->id != CTF_TYPE_STRING) {
590 goto end;
591 }
592
593 if (vpid_def->declaration->id != CTF_TYPE_INTEGER) {
594 goto end;
595 }
596
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);
601
602 if (!sopath) {
603 goto end;
604 }
605
606 if (memsz == 0) {
607 /* Ignore VDSO. */
608 goto end;
609 }
610
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) {
614 goto end;
615 }
616
617 key = g_new0(uint64_t, 1);
618 if (!key) {
619 goto end;
620 }
621
622 *((uint64_t *) key) = baddr;
623
624 so = g_hash_table_lookup(proc_dbg_info_src->baddr_to_so_info,
625 key);
626 if (so) {
627 goto end;
628 }
629
630 so = so_info_create(sopath, baddr, memsz);
631 if (!so) {
632 goto end;
633 }
634
635 g_hash_table_insert(proc_dbg_info_src->baddr_to_so_info,
636 key, so);
637 /* Ownership passed to ht. */
638 key = NULL;
639
640end:
641 g_free(key);
642 return;
643}
644
645static
646void handle_statedump_start(struct debug_info *debug_info,
647 struct ctf_event_definition *event_def)
648{
649 struct bt_definition *vpid_def = NULL;
650 struct bt_definition *sec_def = NULL;
651 struct proc_debug_info_sources *proc_dbg_info_src;
652 int64_t vpid;
653
654 sec_def = (struct bt_definition *)
655 event_def->stream->stream_event_context;
656 if (!sec_def) {
657 goto end;
658 }
659
660 vpid_def = bt_lookup_definition(sec_def, "_vpid");
661 if (!vpid_def) {
662 goto end;
663 }
664
665 vpid = bt_get_signed_int(vpid_def);
666
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) {
670 goto end;
671 }
672
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);
675
676end:
677 return;
678}
679
680static
681void register_event_debug_infos(struct debug_info *debug_info,
682 struct ctf_event_definition *event)
683{
684 struct bt_definition *ip_def, *vpid_def;
685 int64_t vpid;
686 uint64_t ip;
687 struct bt_definition *sec_def;
688
689 /* Get stream event context definition. */
690 sec_def = (struct bt_definition *) event->stream->stream_event_context;
691 if (!sec_def) {
692 goto end;
693 }
694
695 /* Get "ip" and "vpid" definitions. */
696 vpid_def = bt_lookup_definition((struct bt_definition *) sec_def,
697 "_vpid");
698 ip_def = bt_lookup_definition((struct bt_definition *) sec_def, "_ip");
699
700 if (!vpid_def || !ip_def) {
701 goto end;
702 }
703
704 vpid = bt_get_signed_int(vpid_def);
705 ip = bt_get_unsigned_int(ip_def);
706
707 /* Get debug info for this context. */
708 ((struct definition_integer *) ip_def)->debug_info_src =
709 debug_info_query(debug_info, vpid, ip);
710
711end:
712 return;
713}
714
715BT_HIDDEN
716void debug_info_handle_event(struct debug_info *debug_info,
717 struct ctf_event_definition *event)
718{
719 struct ctf_event_declaration *event_class;
720 struct ctf_stream_declaration *stream_class;
721
722 if (!debug_info || !event) {
723 goto end;
724 }
725
726 stream_class = event->stream->stream_class;
727 event_class = g_ptr_array_index(stream_class->events_by_id,
728 event->stream->event_id);
729
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) {
741 /* Build ID info */
742 handle_statedump_build_id_event(debug_info, event);
743 } else {
744 /* Other events: register debug infos */
745 register_event_debug_infos(debug_info, event);
746 }
747
748end:
749 return;
750}
This page took 0.024106 seconds and 4 git commands to generate.