Tests: dynamically create test list based on enabled features
[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 to so info; owned by
37 * proc_debug_info_sources.
38 */
39 GHashTable *baddr_to_so_info;
40
41 /*
42 * Hash table: IP to (struct debug_info_source *); owned by
43 * proc_debug_info_sources.
44 */
45 GHashTable *ip_to_debug_info_src;
46};
47
48struct debug_info {
49 /*
50 * Hash table of VPIDs (int64_t) to (struct ctf_proc_debug_infos*);
51 * 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 NULL, NULL, NULL, (GDestroyNotify) so_info_destroy);
173 if (!proc_dbg_info_src->baddr_to_so_info) {
174 goto error;
175 }
176
177 proc_dbg_info_src->ip_to_debug_info_src = g_hash_table_new_full(
178 NULL, NULL, NULL,
179 (GDestroyNotify) debug_info_source_destroy);
180 if (!proc_dbg_info_src->ip_to_debug_info_src) {
181 goto error;
182 }
183
184end:
185 return proc_dbg_info_src;
186
187error:
188 proc_debug_info_sources_destroy(proc_dbg_info_src);
189 return NULL;
190}
191
192static
193struct proc_debug_info_sources *proc_debug_info_sources_ht_get_entry(
194 GHashTable *ht, int64_t vpid)
195{
196 gpointer key = (gpointer) vpid;
197 struct proc_debug_info_sources *proc_dbg_info_src = NULL;
198
199 /* Exists? Return it */
200 proc_dbg_info_src = g_hash_table_lookup(ht, key);
201 if (proc_dbg_info_src) {
202 goto end;
203 }
204
205 /* Otherwise, create and return it */
206 proc_dbg_info_src = proc_debug_info_sources_create();
207 if (!proc_dbg_info_src) {
208 goto end;
209 }
210
211 g_hash_table_insert(ht, key, proc_dbg_info_src);
212end:
213 return proc_dbg_info_src;
214}
215
216static
217struct debug_info_source *proc_debug_info_sources_get_entry(
218 struct proc_debug_info_sources *proc_dbg_info_src, uint64_t ip)
219{
220 struct debug_info_source *debug_info_src = NULL;
221 gint64 key = (gint64) ip;
222 GHashTableIter iter;
223 gpointer baddr, value;
224
225 /* Look in IP to debug infos hash table first. */
226 debug_info_src = g_hash_table_lookup(
227 proc_dbg_info_src->ip_to_debug_info_src,
228 (gpointer) key);
229 if (debug_info_src) {
230 goto end;
231 }
232
233 /* Check in all so_infos. */
234 g_hash_table_iter_init(&iter, proc_dbg_info_src->baddr_to_so_info);
235
236 while (g_hash_table_iter_next(&iter, &baddr, &value))
237 {
238 struct so_info *so = value;
239
240 if (!so_info_has_address(value, ip)) {
241 continue;
242 }
243
244 /* Found; add it to cache. */
245 debug_info_src = debug_info_source_create_from_so(so, ip);
246 if (debug_info_src) {
247 g_hash_table_insert(
248 proc_dbg_info_src->ip_to_debug_info_src,
249 (gpointer) key, debug_info_src);
250 }
251 break;
252 }
253
254end:
255 return debug_info_src;
256}
257
258BT_HIDDEN
259struct debug_info_source *debug_info_query(struct debug_info *debug_info,
260 int64_t vpid, uint64_t ip)
261{
262 struct debug_info_source *dbg_info_src = NULL;
263 struct proc_debug_info_sources *proc_dbg_info_src;
264
265 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
266 debug_info->vpid_to_proc_dbg_info_src, vpid);
267 if (!proc_dbg_info_src) {
268 goto end;
269 }
270
271 dbg_info_src = proc_debug_info_sources_get_entry(
272 proc_dbg_info_src, ip);
273 if (!dbg_info_src) {
274 goto end;
275 }
276
277end:
278 return dbg_info_src;
279}
280
281BT_HIDDEN
282struct debug_info *debug_info_create(void)
283{
284 int ret;
285 struct debug_info *debug_info;
286
287 debug_info = g_new0(struct debug_info, 1);
288 if (!debug_info) {
289 goto end;
290 }
291
292 debug_info->vpid_to_proc_dbg_info_src = g_hash_table_new_full(NULL,
293 NULL, NULL,
294 (GDestroyNotify) proc_debug_info_sources_destroy);
295 if (!debug_info->vpid_to_proc_dbg_info_src) {
296 goto error;
297 }
298
299 ret = debug_info_init(debug_info);
300 if (ret) {
301 goto error;
302 }
303
304end:
305 return debug_info;
306error:
307 g_free(debug_info);
308 return NULL;
309}
310
311BT_HIDDEN
312void debug_info_destroy(struct debug_info *debug_info)
313{
314 if (!debug_info) {
315 goto end;
316 }
317
318 if (debug_info->vpid_to_proc_dbg_info_src) {
319 g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src);
320 }
321
322 g_free(debug_info);
323end:
324 return;
325}
326
327static
328void handle_statedump_build_id_event(struct debug_info *debug_info,
329 struct ctf_event_definition *event_def)
330{
331 struct proc_debug_info_sources *proc_dbg_info_src;
332 struct bt_definition *event_fields_def = NULL;
333 struct bt_definition *sec_def = NULL;
334 struct bt_definition *baddr_def = NULL;
335 struct bt_definition *vpid_def = NULL;
336 struct bt_definition *build_id_def = NULL;
337 struct definition_sequence *build_id_seq;
338 struct so_info *so = NULL;
339 int i;
340 int64_t vpid;
341 uint64_t baddr;
342 uint8_t *build_id = NULL;
343 uint64_t build_id_len;
344
345 event_fields_def = (struct bt_definition *) event_def->event_fields;
346 sec_def = (struct bt_definition *)
347 event_def->stream->stream_event_context;
348
349 if (!event_fields_def || !sec_def) {
350 goto end;
351 }
352
353 baddr_def = bt_lookup_definition(event_fields_def, "_baddr");
354 if (!baddr_def) {
355 goto end;
356 }
357
358 vpid_def = bt_lookup_definition(sec_def, "_vpid");
359 if (!vpid_def) {
360 goto end;
361 }
362
363 build_id_def = bt_lookup_definition(event_fields_def, "_build_id");
364 if (!build_id_def) {
365 goto end;
366 }
367
368 if (baddr_def->declaration->id != CTF_TYPE_INTEGER) {
369 goto end;
370 }
371
372 if (vpid_def->declaration->id != CTF_TYPE_INTEGER) {
373 goto end;
374 }
375
376 if (build_id_def->declaration->id != CTF_TYPE_SEQUENCE) {
377 goto end;
378 }
379
380 baddr = bt_get_unsigned_int(baddr_def);
381 vpid = bt_get_signed_int(vpid_def);
382 build_id_seq = container_of(build_id_def,
383 struct definition_sequence, p);
384 build_id_len = build_id_seq->length->value._unsigned;
385
386 build_id = g_malloc(build_id_len);
387 if (!build_id) {
388 goto end;
389 }
390
391 for (i = 0; i < build_id_len; ++i) {
392 struct bt_definition **field;
393
394 field = (struct bt_definition **) &g_ptr_array_index(
395 build_id_seq->elems, i);
396 build_id[i] = bt_get_unsigned_int(*field);
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 so = g_hash_table_lookup(proc_dbg_info_src->baddr_to_so_info,
406 (gpointer) &baddr);
407 if (!so) {
408 /*
409 * The build_id event comes after the so has been
410 * created. If it isn't found, just ignore this event.
411 */
412 goto end;
413 }
414
415 so_info_set_build_id(so, build_id, build_id_len);
416
417end:
418 free(build_id);
419 return;
420}
421
422static
423void handle_statedump_debug_link_event(struct debug_info *debug_info,
424 struct ctf_event_definition *event_def)
425{
426 struct proc_debug_info_sources *proc_dbg_info_src;
427 struct bt_definition *event_fields_def = NULL;
428 struct bt_definition *sec_def = NULL;
429 struct bt_definition *baddr_def = NULL;
430 struct bt_definition *vpid_def = NULL;
431 struct bt_definition *filename_def = NULL;
432 struct bt_definition *crc32_def = NULL;
433 struct so_info *so = NULL;
434 int64_t vpid;
435 uint64_t baddr;
436 char *filename = NULL;
437 uint32_t crc32;
438
439 event_fields_def = (struct bt_definition *) event_def->event_fields;
440 sec_def = (struct bt_definition *)
441 event_def->stream->stream_event_context;
442
443 if (!event_fields_def || !sec_def) {
444 goto end;
445 }
446
447 baddr_def = bt_lookup_definition(event_fields_def, "_baddr");
448 if (!baddr_def) {
449 goto end;
450 }
451
452 vpid_def = bt_lookup_definition(sec_def, "_vpid");
453 if (!vpid_def) {
454 goto end;
455 }
456
457 filename_def = bt_lookup_definition(event_fields_def, "_filename");
458 if (!filename_def) {
459 goto end;
460 }
461
462 crc32_def = bt_lookup_definition(event_fields_def, "_crc32");
463 if (!crc32_def) {
464 goto end;
465 }
466
467 if (baddr_def->declaration->id != CTF_TYPE_INTEGER) {
468 goto end;
469 }
470
471 if (vpid_def->declaration->id != CTF_TYPE_INTEGER) {
472 goto end;
473 }
474
475 if (filename_def->declaration->id != CTF_TYPE_STRING) {
476 goto end;
477 }
478
479 if (crc32_def->declaration->id != CTF_TYPE_INTEGER) {
480 goto end;
481 }
482
483 baddr = bt_get_unsigned_int(baddr_def);
484 vpid = bt_get_signed_int(vpid_def);
485
486 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
487 debug_info->vpid_to_proc_dbg_info_src, vpid);
488 if (!proc_dbg_info_src) {
489 goto end;
490 }
491
492 so = g_hash_table_lookup(proc_dbg_info_src->baddr_to_so_info,
493 (gpointer) &baddr);
494 if (!so) {
495 /*
496 * The debug_link event comes after the so has been
497 * created. If it isn't found, just ignore this event.
498 */
499 goto end;
500 }
501
502 filename = bt_get_string(filename_def);
503 crc32 = bt_get_unsigned_int(crc32_def);
504
505 so_info_set_debug_link(so, filename, crc32);
506
507end:
508 return;
509}
510
511static
512void handle_statedump_soinfo_event(struct debug_info *debug_info,
513 struct ctf_event_definition *event_def)
514{
515 struct bt_definition *baddr_def = NULL;
516 struct bt_definition *memsz_def = NULL;
517 struct bt_definition *sopath_def = NULL;
518 struct bt_definition *vpid_def = NULL;
519 struct bt_definition *event_fields_def = NULL;
520 struct bt_definition *sec_def = NULL;
521 struct proc_debug_info_sources *proc_dbg_info_src;
522 struct so_info *so;
523 uint64_t baddr, memsz;
524 int64_t vpid;
525 const char *sopath;
526
527 event_fields_def = (struct bt_definition *) event_def->event_fields;
528 sec_def = (struct bt_definition *)
529 event_def->stream->stream_event_context;
530
531 if (!event_fields_def || !sec_def) {
532 goto end;
533 }
534
535 baddr_def = bt_lookup_definition(event_fields_def, "_baddr");
536 if (!baddr_def) {
537 goto end;
538 }
539
540 memsz_def = bt_lookup_definition(event_fields_def, "_memsz");
541 if (!memsz_def) {
542 goto end;
543 }
544
545 sopath_def = bt_lookup_definition(event_fields_def, "_sopath");
546 if (!sopath_def) {
547 goto end;
548 }
549
550 vpid_def = bt_lookup_definition(sec_def, "_vpid");
551 if (!vpid_def) {
552 goto end;
553 }
554
555 if (baddr_def->declaration->id != CTF_TYPE_INTEGER) {
556 goto end;
557 }
558
559 if (memsz_def->declaration->id != CTF_TYPE_INTEGER) {
560 goto end;
561 }
562
563 if (sopath_def->declaration->id != CTF_TYPE_STRING) {
564 goto end;
565 }
566
567 if (vpid_def->declaration->id != CTF_TYPE_INTEGER) {
568 goto end;
569 }
570
571 baddr = bt_get_unsigned_int(baddr_def);
572 memsz = bt_get_unsigned_int(memsz_def);
573 sopath = bt_get_string(sopath_def);
574 vpid = bt_get_signed_int(vpid_def);
575
576 if (!sopath) {
577 goto end;
578 }
579
580 if (memsz == 0) {
581 /* Ignore VDSO. */
582 goto end;
583 }
584
585 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
586 debug_info->vpid_to_proc_dbg_info_src, vpid);
587 if (!proc_dbg_info_src) {
588 goto end;
589 }
590
591 so = g_hash_table_lookup(proc_dbg_info_src->baddr_to_so_info,
592 (gpointer) baddr);
593 if (so) {
594 goto end;
595 }
596
597 so = so_info_create(sopath, baddr, memsz);
598 if (!so) {
599 goto end;
600 }
601
602 g_hash_table_insert(proc_dbg_info_src->baddr_to_so_info,
603 (gpointer) baddr, so);
604
605end:
606 return;
607}
608
609static
610void handle_statedump_start(struct debug_info *debug_info,
611 struct ctf_event_definition *event_def)
612{
613 struct bt_definition *vpid_def = NULL;
614 struct bt_definition *sec_def = NULL;
615 struct proc_debug_info_sources *proc_dbg_info_src;
616 int64_t vpid;
617
618 sec_def = (struct bt_definition *)
619 event_def->stream->stream_event_context;
620 if (!sec_def) {
621 goto end;
622 }
623
624 vpid_def = bt_lookup_definition(sec_def, "_vpid");
625 if (!vpid_def) {
626 goto end;
627 }
628
629 vpid = bt_get_signed_int(vpid_def);
630
631 proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
632 debug_info->vpid_to_proc_dbg_info_src, vpid);
633 if (!proc_dbg_info_src) {
634 goto end;
635 }
636
637 g_hash_table_remove_all(proc_dbg_info_src->baddr_to_so_info);
638 g_hash_table_remove_all(proc_dbg_info_src->ip_to_debug_info_src);
639
640end:
641 return;
642}
643
644static
645void register_event_debug_infos(struct debug_info *debug_info,
646 struct ctf_event_definition *event)
647{
648 struct bt_definition *ip_def, *vpid_def;
649 int64_t vpid;
650 uint64_t ip;
651 struct bt_definition *sec_def;
652
653 /* Get stream event context definition. */
654 sec_def = (struct bt_definition *) event->stream->stream_event_context;
655 if (!sec_def) {
656 goto end;
657 }
658
659 /* Get "ip" and "vpid" definitions. */
660 vpid_def = bt_lookup_definition((struct bt_definition *) sec_def,
661 "_vpid");
662 ip_def = bt_lookup_definition((struct bt_definition *) sec_def, "_ip");
663
664 if (!vpid_def || !ip_def) {
665 goto end;
666 }
667
668 vpid = bt_get_signed_int(vpid_def);
669 ip = bt_get_unsigned_int(ip_def);
670
671 /* Get debug info for this context. */
672 ((struct definition_integer *) ip_def)->debug_info_src =
673 debug_info_query(debug_info, vpid, ip);
674
675end:
676 return;
677}
678
679BT_HIDDEN
680void debug_info_handle_event(struct debug_info *debug_info,
681 struct ctf_event_definition *event)
682{
683 struct ctf_event_declaration *event_class;
684 struct ctf_stream_declaration *stream_class;
685
686 if (!debug_info || !event) {
687 goto end;
688 }
689
690 stream_class = event->stream->stream_class;
691 event_class = g_ptr_array_index(stream_class->events_by_id,
692 event->stream->event_id);
693
694 if (event_class->name == debug_info->q_statedump_soinfo ||
695 event_class->name == debug_info->q_dl_open) {
696 /* State dump/dlopen() */
697 handle_statedump_soinfo_event(debug_info, event);
698 } else if (event_class->name == debug_info->q_statedump_start) {
699 /* Start state dump */
700 handle_statedump_start(debug_info, event);
701 } else if (event_class->name == debug_info->q_statedump_debug_link) {
702 /* Debug link info */
703 handle_statedump_debug_link_event(debug_info, event);
704 } else if (event_class->name == debug_info->q_statedump_build_id) {
705 /* Build ID info */
706 handle_statedump_build_id_event(debug_info, event);
707 } else {
708 /* Other events: register debug infos */
709 register_event_debug_infos(debug_info, event);
710 }
711
712end:
713 return;
714}
This page took 0.026266 seconds and 4 git commands to generate.