Commit | Line | Data |
---|---|---|
c40a57e5 AB |
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> | |
ff9ce920 | 7 | * Copyright (c) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com> |
c40a57e5 AB |
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 | #include <assert.h> | |
29 | #include <glib.h> | |
30 | #include <babeltrace/types.h> | |
31 | #include <babeltrace/ctf-ir/metadata.h> | |
32 | #include <babeltrace/debuginfo.h> | |
d5ddf820 | 33 | #include <babeltrace/bin-info.h> |
ff9ce920 | 34 | #include <babeltrace/babeltrace-internal.h> |
55cd033d | 35 | #include <babeltrace/utils.h> |
c40a57e5 AB |
36 | |
37 | struct proc_debug_info_sources { | |
38 | /* | |
d5ddf820 | 39 | * Hash table: base address (pointer to uint64_t) to bin info; owned by |
c40a57e5 AB |
40 | * proc_debug_info_sources. |
41 | */ | |
d5ddf820 | 42 | GHashTable *baddr_to_bin_info; |
c40a57e5 AB |
43 | |
44 | /* | |
47857613 JG |
45 | * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *); |
46 | * owned by proc_debug_info_sources. | |
c40a57e5 AB |
47 | */ |
48 | GHashTable *ip_to_debug_info_src; | |
49 | }; | |
50 | ||
51 | struct debug_info { | |
52 | /* | |
47857613 JG |
53 | * Hash table of VPIDs (pointer to int64_t) to |
54 | * (struct ctf_proc_debug_infos*); owned by debug_info. | |
c40a57e5 AB |
55 | */ |
56 | GHashTable *vpid_to_proc_dbg_info_src; | |
9c713367 | 57 | GQuark q_statedump_bin_info; |
c40a57e5 AB |
58 | GQuark q_statedump_debug_link; |
59 | GQuark q_statedump_build_id; | |
60 | GQuark q_statedump_start; | |
61 | GQuark q_dl_open; | |
62 | }; | |
63 | ||
64 | static | |
65 | int debug_info_init(struct debug_info *info) | |
66 | { | |
9c713367 AB |
67 | info->q_statedump_bin_info = g_quark_from_string( |
68 | "lttng_ust_statedump:bin_info"); | |
c40a57e5 AB |
69 | info->q_statedump_debug_link = g_quark_from_string( |
70 | "lttng_ust_statedump:debug_link)"); | |
71 | info->q_statedump_build_id = g_quark_from_string( | |
72 | "lttng_ust_statedump:build_id"); | |
73 | info->q_statedump_start = g_quark_from_string( | |
74 | "lttng_ust_statedump:start"); | |
75 | info->q_dl_open = g_quark_from_string("lttng_ust_dl:dlopen"); | |
76 | ||
d5ddf820 | 77 | return bin_info_init(); |
c40a57e5 AB |
78 | } |
79 | ||
80 | static | |
81 | void debug_info_source_destroy(struct debug_info_source *debug_info_src) | |
82 | { | |
83 | if (!debug_info_src) { | |
84 | return; | |
85 | } | |
86 | ||
87 | free(debug_info_src->func); | |
a7a607cf JG |
88 | free(debug_info_src->src_path); |
89 | free(debug_info_src->bin_path); | |
36ae9941 | 90 | free(debug_info_src->bin_loc); |
c40a57e5 AB |
91 | g_free(debug_info_src); |
92 | } | |
93 | ||
94 | static | |
d5ddf820 | 95 | struct debug_info_source *debug_info_source_create_from_bin(struct bin_info *bin, |
c40a57e5 AB |
96 | uint64_t ip) |
97 | { | |
98 | int ret; | |
99 | struct debug_info_source *debug_info_src = NULL; | |
100 | struct source_location *src_loc = NULL; | |
101 | ||
102 | debug_info_src = g_new0(struct debug_info_source, 1); | |
103 | ||
104 | if (!debug_info_src) { | |
105 | goto end; | |
106 | } | |
107 | ||
108 | /* Lookup function name */ | |
d5ddf820 | 109 | ret = bin_info_lookup_function_name(bin, ip, &debug_info_src->func); |
c40a57e5 AB |
110 | if (ret) { |
111 | goto error; | |
112 | } | |
113 | ||
114 | /* Can't retrieve src_loc from ELF only, skip it */ | |
d5ddf820 | 115 | if (!bin->is_elf_only) { |
44148130 | 116 | /* Lookup source location */ |
d5ddf820 | 117 | ret = bin_info_lookup_source_location(bin, ip, &src_loc); |
44148130 JG |
118 | if (ret) { |
119 | goto error; | |
120 | } | |
c40a57e5 AB |
121 | } |
122 | ||
123 | if (src_loc) { | |
124 | debug_info_src->line_no = src_loc->line_no; | |
125 | ||
126 | if (src_loc->filename) { | |
a7a607cf JG |
127 | debug_info_src->src_path = strdup(src_loc->filename); |
128 | if (!debug_info_src->src_path) { | |
c40a57e5 AB |
129 | goto error; |
130 | } | |
ff9ce920 | 131 | |
a7a607cf | 132 | debug_info_src->short_src_path = get_filename_from_path( |
51a9f65d | 133 | debug_info_src->src_path); |
c40a57e5 AB |
134 | } |
135 | ||
136 | source_location_destroy(src_loc); | |
137 | } | |
138 | ||
d5ddf820 AB |
139 | if (bin->elf_path) { |
140 | debug_info_src->bin_path = strdup(bin->elf_path); | |
a7a607cf JG |
141 | if (!debug_info_src->bin_path) { |
142 | goto error; | |
143 | } | |
144 | ||
145 | debug_info_src->short_bin_path = get_filename_from_path( | |
146 | debug_info_src->bin_path); | |
36ae9941 | 147 | |
d5ddf820 | 148 | ret = bin_info_get_bin_loc(bin, ip, &(debug_info_src->bin_loc)); |
36ae9941 AB |
149 | if (ret) { |
150 | goto error; | |
151 | } | |
a7a607cf JG |
152 | } |
153 | ||
c40a57e5 AB |
154 | end: |
155 | return debug_info_src; | |
156 | ||
157 | error: | |
158 | debug_info_source_destroy(debug_info_src); | |
159 | return NULL; | |
160 | } | |
161 | ||
162 | static | |
163 | void proc_debug_info_sources_destroy( | |
164 | struct proc_debug_info_sources *proc_dbg_info_src) | |
165 | { | |
166 | if (!proc_dbg_info_src) { | |
167 | return; | |
168 | } | |
169 | ||
d5ddf820 AB |
170 | if (proc_dbg_info_src->baddr_to_bin_info) { |
171 | g_hash_table_destroy(proc_dbg_info_src->baddr_to_bin_info); | |
c40a57e5 AB |
172 | } |
173 | ||
174 | if (proc_dbg_info_src->ip_to_debug_info_src) { | |
175 | g_hash_table_destroy(proc_dbg_info_src->ip_to_debug_info_src); | |
176 | } | |
177 | ||
178 | g_free(proc_dbg_info_src); | |
179 | } | |
180 | ||
181 | static | |
182 | struct proc_debug_info_sources *proc_debug_info_sources_create(void) | |
183 | { | |
184 | struct proc_debug_info_sources *proc_dbg_info_src = NULL; | |
185 | ||
186 | proc_dbg_info_src = g_new0(struct proc_debug_info_sources, 1); | |
187 | if (!proc_dbg_info_src) { | |
188 | goto end; | |
189 | } | |
190 | ||
d5ddf820 | 191 | proc_dbg_info_src->baddr_to_bin_info = g_hash_table_new_full( |
47857613 | 192 | g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, |
d5ddf820 AB |
193 | (GDestroyNotify) bin_info_destroy); |
194 | if (!proc_dbg_info_src->baddr_to_bin_info) { | |
c40a57e5 AB |
195 | goto error; |
196 | } | |
197 | ||
198 | proc_dbg_info_src->ip_to_debug_info_src = g_hash_table_new_full( | |
47857613 | 199 | g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, |
c40a57e5 AB |
200 | (GDestroyNotify) debug_info_source_destroy); |
201 | if (!proc_dbg_info_src->ip_to_debug_info_src) { | |
202 | goto error; | |
203 | } | |
204 | ||
205 | end: | |
206 | return proc_dbg_info_src; | |
207 | ||
208 | error: | |
209 | proc_debug_info_sources_destroy(proc_dbg_info_src); | |
210 | return NULL; | |
211 | } | |
212 | ||
213 | static | |
214 | struct proc_debug_info_sources *proc_debug_info_sources_ht_get_entry( | |
215 | GHashTable *ht, int64_t vpid) | |
216 | { | |
47857613 | 217 | gpointer key = g_new0(int64_t, 1); |
c40a57e5 AB |
218 | struct proc_debug_info_sources *proc_dbg_info_src = NULL; |
219 | ||
47857613 JG |
220 | if (!key) { |
221 | goto end; | |
222 | } | |
223 | ||
224 | *((int64_t *) key) = vpid; | |
225 | ||
c40a57e5 AB |
226 | /* Exists? Return it */ |
227 | proc_dbg_info_src = g_hash_table_lookup(ht, key); | |
228 | if (proc_dbg_info_src) { | |
229 | goto end; | |
230 | } | |
231 | ||
232 | /* Otherwise, create and return it */ | |
233 | proc_dbg_info_src = proc_debug_info_sources_create(); | |
234 | if (!proc_dbg_info_src) { | |
235 | goto end; | |
236 | } | |
237 | ||
238 | g_hash_table_insert(ht, key, proc_dbg_info_src); | |
47857613 JG |
239 | /* Ownership passed to ht */ |
240 | key = NULL; | |
c40a57e5 | 241 | end: |
47857613 | 242 | g_free(key); |
c40a57e5 AB |
243 | return proc_dbg_info_src; |
244 | } | |
245 | ||
246 | static | |
247 | struct debug_info_source *proc_debug_info_sources_get_entry( | |
248 | struct proc_debug_info_sources *proc_dbg_info_src, uint64_t ip) | |
249 | { | |
250 | struct debug_info_source *debug_info_src = NULL; | |
47857613 | 251 | gpointer key = g_new0(uint64_t, 1); |
c40a57e5 AB |
252 | GHashTableIter iter; |
253 | gpointer baddr, value; | |
254 | ||
47857613 JG |
255 | if (!key) { |
256 | goto end; | |
257 | } | |
258 | ||
259 | *((uint64_t *) key) = ip; | |
260 | ||
c40a57e5 AB |
261 | /* Look in IP to debug infos hash table first. */ |
262 | debug_info_src = g_hash_table_lookup( | |
263 | proc_dbg_info_src->ip_to_debug_info_src, | |
47857613 | 264 | key); |
c40a57e5 AB |
265 | if (debug_info_src) { |
266 | goto end; | |
267 | } | |
268 | ||
d5ddf820 AB |
269 | /* Check in all bin_infos. */ |
270 | g_hash_table_iter_init(&iter, proc_dbg_info_src->baddr_to_bin_info); | |
c40a57e5 AB |
271 | |
272 | while (g_hash_table_iter_next(&iter, &baddr, &value)) | |
273 | { | |
d5ddf820 | 274 | struct bin_info *bin = value; |
c40a57e5 | 275 | |
d5ddf820 | 276 | if (!bin_info_has_address(value, ip)) { |
c40a57e5 AB |
277 | continue; |
278 | } | |
279 | ||
47857613 JG |
280 | /* |
281 | * Found; add it to cache. | |
282 | * | |
283 | * FIXME: this should be bounded in size (and implement | |
284 | * a caching policy), and entries should be prunned when | |
285 | * libraries are unmapped. | |
286 | */ | |
d5ddf820 | 287 | debug_info_src = debug_info_source_create_from_bin(bin, ip); |
c40a57e5 AB |
288 | if (debug_info_src) { |
289 | g_hash_table_insert( | |
290 | proc_dbg_info_src->ip_to_debug_info_src, | |
47857613 JG |
291 | key, debug_info_src); |
292 | /* Ownership passed to ht. */ | |
293 | key = NULL; | |
c40a57e5 AB |
294 | } |
295 | break; | |
296 | } | |
297 | ||
298 | end: | |
47857613 | 299 | free(key); |
c40a57e5 AB |
300 | return debug_info_src; |
301 | } | |
302 | ||
303 | BT_HIDDEN | |
304 | struct debug_info_source *debug_info_query(struct debug_info *debug_info, | |
305 | int64_t vpid, uint64_t ip) | |
306 | { | |
307 | struct debug_info_source *dbg_info_src = NULL; | |
308 | struct proc_debug_info_sources *proc_dbg_info_src; | |
309 | ||
310 | proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( | |
311 | debug_info->vpid_to_proc_dbg_info_src, vpid); | |
312 | if (!proc_dbg_info_src) { | |
313 | goto end; | |
314 | } | |
315 | ||
316 | dbg_info_src = proc_debug_info_sources_get_entry( | |
317 | proc_dbg_info_src, ip); | |
318 | if (!dbg_info_src) { | |
319 | goto end; | |
320 | } | |
321 | ||
322 | end: | |
323 | return dbg_info_src; | |
324 | } | |
325 | ||
326 | BT_HIDDEN | |
327 | struct debug_info *debug_info_create(void) | |
328 | { | |
329 | int ret; | |
330 | struct debug_info *debug_info; | |
331 | ||
332 | debug_info = g_new0(struct debug_info, 1); | |
333 | if (!debug_info) { | |
334 | goto end; | |
335 | } | |
336 | ||
47857613 JG |
337 | debug_info->vpid_to_proc_dbg_info_src = g_hash_table_new_full( |
338 | g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, | |
c40a57e5 AB |
339 | (GDestroyNotify) proc_debug_info_sources_destroy); |
340 | if (!debug_info->vpid_to_proc_dbg_info_src) { | |
341 | goto error; | |
342 | } | |
343 | ||
344 | ret = debug_info_init(debug_info); | |
345 | if (ret) { | |
346 | goto error; | |
347 | } | |
348 | ||
349 | end: | |
350 | return debug_info; | |
351 | error: | |
352 | g_free(debug_info); | |
353 | return NULL; | |
354 | } | |
355 | ||
356 | BT_HIDDEN | |
357 | void debug_info_destroy(struct debug_info *debug_info) | |
358 | { | |
359 | if (!debug_info) { | |
360 | goto end; | |
361 | } | |
362 | ||
363 | if (debug_info->vpid_to_proc_dbg_info_src) { | |
364 | g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src); | |
365 | } | |
366 | ||
367 | g_free(debug_info); | |
368 | end: | |
369 | return; | |
370 | } | |
371 | ||
372 | static | |
373 | void handle_statedump_build_id_event(struct debug_info *debug_info, | |
374 | struct ctf_event_definition *event_def) | |
375 | { | |
376 | struct proc_debug_info_sources *proc_dbg_info_src; | |
377 | struct bt_definition *event_fields_def = NULL; | |
378 | struct bt_definition *sec_def = NULL; | |
379 | struct bt_definition *baddr_def = NULL; | |
380 | struct bt_definition *vpid_def = NULL; | |
381 | struct bt_definition *build_id_def = NULL; | |
382 | struct definition_sequence *build_id_seq; | |
d5ddf820 | 383 | struct bin_info *bin = NULL; |
c40a57e5 AB |
384 | int i; |
385 | int64_t vpid; | |
386 | uint64_t baddr; | |
387 | uint8_t *build_id = NULL; | |
388 | uint64_t build_id_len; | |
389 | ||
390 | event_fields_def = (struct bt_definition *) event_def->event_fields; | |
391 | sec_def = (struct bt_definition *) | |
392 | event_def->stream->stream_event_context; | |
393 | ||
394 | if (!event_fields_def || !sec_def) { | |
395 | goto end; | |
396 | } | |
397 | ||
398 | baddr_def = bt_lookup_definition(event_fields_def, "_baddr"); | |
399 | if (!baddr_def) { | |
400 | goto end; | |
401 | } | |
402 | ||
403 | vpid_def = bt_lookup_definition(sec_def, "_vpid"); | |
404 | if (!vpid_def) { | |
405 | goto end; | |
406 | } | |
407 | ||
408 | build_id_def = bt_lookup_definition(event_fields_def, "_build_id"); | |
409 | if (!build_id_def) { | |
410 | goto end; | |
411 | } | |
412 | ||
413 | if (baddr_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
414 | goto end; | |
415 | } | |
416 | ||
417 | if (vpid_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
418 | goto end; | |
419 | } | |
420 | ||
421 | if (build_id_def->declaration->id != BT_CTF_TYPE_ID_SEQUENCE) { | |
422 | goto end; | |
423 | } | |
424 | ||
425 | baddr = bt_get_unsigned_int(baddr_def); | |
426 | vpid = bt_get_signed_int(vpid_def); | |
427 | build_id_seq = container_of(build_id_def, | |
428 | struct definition_sequence, p); | |
429 | build_id_len = build_id_seq->length->value._unsigned; | |
430 | ||
431 | build_id = g_malloc(build_id_len); | |
432 | if (!build_id) { | |
433 | goto end; | |
434 | } | |
435 | ||
436 | for (i = 0; i < build_id_len; ++i) { | |
437 | struct bt_definition **field; | |
438 | ||
439 | field = (struct bt_definition **) &g_ptr_array_index( | |
440 | build_id_seq->elems, i); | |
441 | build_id[i] = bt_get_unsigned_int(*field); | |
442 | } | |
443 | ||
444 | proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( | |
445 | debug_info->vpid_to_proc_dbg_info_src, vpid); | |
446 | if (!proc_dbg_info_src) { | |
447 | goto end; | |
448 | } | |
449 | ||
d5ddf820 | 450 | bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, |
c40a57e5 | 451 | (gpointer) &baddr); |
d5ddf820 | 452 | if (!bin) { |
c40a57e5 | 453 | /* |
d5ddf820 | 454 | * The build_id event comes after the bin has been |
c40a57e5 AB |
455 | * created. If it isn't found, just ignore this event. |
456 | */ | |
457 | goto end; | |
458 | } | |
459 | ||
d5ddf820 | 460 | bin_info_set_build_id(bin, build_id, build_id_len); |
c40a57e5 AB |
461 | |
462 | end: | |
463 | free(build_id); | |
464 | return; | |
465 | } | |
466 | ||
467 | static | |
468 | void handle_statedump_debug_link_event(struct debug_info *debug_info, | |
469 | struct ctf_event_definition *event_def) | |
470 | { | |
471 | struct proc_debug_info_sources *proc_dbg_info_src; | |
472 | struct bt_definition *event_fields_def = NULL; | |
473 | struct bt_definition *sec_def = NULL; | |
474 | struct bt_definition *baddr_def = NULL; | |
475 | struct bt_definition *vpid_def = NULL; | |
476 | struct bt_definition *filename_def = NULL; | |
477 | struct bt_definition *crc32_def = NULL; | |
d5ddf820 | 478 | struct bin_info *bin = NULL; |
c40a57e5 AB |
479 | int64_t vpid; |
480 | uint64_t baddr; | |
481 | char *filename = NULL; | |
482 | uint32_t crc32; | |
483 | ||
484 | event_fields_def = (struct bt_definition *) event_def->event_fields; | |
485 | sec_def = (struct bt_definition *) | |
486 | event_def->stream->stream_event_context; | |
487 | ||
488 | if (!event_fields_def || !sec_def) { | |
489 | goto end; | |
490 | } | |
491 | ||
492 | baddr_def = bt_lookup_definition(event_fields_def, "_baddr"); | |
493 | if (!baddr_def) { | |
494 | goto end; | |
495 | } | |
496 | ||
497 | vpid_def = bt_lookup_definition(sec_def, "_vpid"); | |
498 | if (!vpid_def) { | |
499 | goto end; | |
500 | } | |
501 | ||
502 | filename_def = bt_lookup_definition(event_fields_def, "_filename"); | |
503 | if (!filename_def) { | |
504 | goto end; | |
505 | } | |
506 | ||
507 | crc32_def = bt_lookup_definition(event_fields_def, "_crc32"); | |
508 | if (!crc32_def) { | |
509 | goto end; | |
510 | } | |
511 | ||
512 | if (baddr_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
513 | goto end; | |
514 | } | |
515 | ||
516 | if (vpid_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
517 | goto end; | |
518 | } | |
519 | ||
520 | if (filename_def->declaration->id != BT_CTF_TYPE_ID_STRING) { | |
521 | goto end; | |
522 | } | |
523 | ||
524 | if (crc32_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
525 | goto end; | |
526 | } | |
527 | ||
528 | baddr = bt_get_unsigned_int(baddr_def); | |
529 | vpid = bt_get_signed_int(vpid_def); | |
530 | ||
531 | proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( | |
532 | debug_info->vpid_to_proc_dbg_info_src, vpid); | |
533 | if (!proc_dbg_info_src) { | |
534 | goto end; | |
535 | } | |
536 | ||
d5ddf820 | 537 | bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, |
c40a57e5 | 538 | (gpointer) &baddr); |
d5ddf820 | 539 | if (!bin) { |
c40a57e5 | 540 | /* |
d5ddf820 | 541 | * The debug_link event comes after the bin has been |
c40a57e5 AB |
542 | * created. If it isn't found, just ignore this event. |
543 | */ | |
544 | goto end; | |
545 | } | |
546 | ||
547 | filename = bt_get_string(filename_def); | |
548 | crc32 = bt_get_unsigned_int(crc32_def); | |
549 | ||
d5ddf820 | 550 | bin_info_set_debug_link(bin, filename, crc32); |
c40a57e5 AB |
551 | |
552 | end: | |
553 | return; | |
554 | } | |
555 | ||
556 | static | |
9f2b13ca AB |
557 | void handle_bin_info_event(struct debug_info *debug_info, |
558 | struct ctf_event_definition *event_def, bool has_pic_field) | |
c40a57e5 AB |
559 | { |
560 | struct bt_definition *baddr_def = NULL; | |
561 | struct bt_definition *memsz_def = NULL; | |
9c713367 | 562 | struct bt_definition *path_def = NULL; |
9f2b13ca | 563 | struct bt_definition *is_pic_def = NULL; |
c40a57e5 AB |
564 | struct bt_definition *vpid_def = NULL; |
565 | struct bt_definition *event_fields_def = NULL; | |
566 | struct bt_definition *sec_def = NULL; | |
567 | struct proc_debug_info_sources *proc_dbg_info_src; | |
d5ddf820 | 568 | struct bin_info *bin; |
c40a57e5 AB |
569 | uint64_t baddr, memsz; |
570 | int64_t vpid; | |
9c713367 | 571 | const char *path; |
47857613 | 572 | gpointer key = NULL; |
9f2b13ca | 573 | bool is_pic; |
c40a57e5 AB |
574 | |
575 | event_fields_def = (struct bt_definition *) event_def->event_fields; | |
576 | sec_def = (struct bt_definition *) | |
577 | event_def->stream->stream_event_context; | |
578 | ||
579 | if (!event_fields_def || !sec_def) { | |
580 | goto end; | |
581 | } | |
582 | ||
583 | baddr_def = bt_lookup_definition(event_fields_def, "_baddr"); | |
584 | if (!baddr_def) { | |
585 | goto end; | |
586 | } | |
587 | ||
588 | memsz_def = bt_lookup_definition(event_fields_def, "_memsz"); | |
589 | if (!memsz_def) { | |
590 | goto end; | |
591 | } | |
592 | ||
9c713367 AB |
593 | path_def = bt_lookup_definition(event_fields_def, "_path"); |
594 | if (!path_def) { | |
c40a57e5 AB |
595 | goto end; |
596 | } | |
597 | ||
9f2b13ca AB |
598 | if (has_pic_field) { |
599 | is_pic_def = bt_lookup_definition(event_fields_def, "_is_pic"); | |
600 | if (!is_pic_def) { | |
601 | goto end; | |
602 | } | |
603 | ||
604 | if (is_pic_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
605 | goto end; | |
606 | } | |
607 | ||
608 | is_pic = (bt_get_unsigned_int(is_pic_def) == 1); | |
609 | } else { | |
610 | /* | |
611 | * dlopen has no is_pic field, because the shared | |
612 | * object is always PIC. | |
613 | */ | |
614 | is_pic = true; | |
615 | } | |
616 | ||
c40a57e5 AB |
617 | vpid_def = bt_lookup_definition(sec_def, "_vpid"); |
618 | if (!vpid_def) { | |
619 | goto end; | |
620 | } | |
621 | ||
622 | if (baddr_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
623 | goto end; | |
624 | } | |
625 | ||
626 | if (memsz_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
627 | goto end; | |
628 | } | |
629 | ||
9c713367 | 630 | if (path_def->declaration->id != BT_CTF_TYPE_ID_STRING) { |
c40a57e5 AB |
631 | goto end; |
632 | } | |
633 | ||
634 | if (vpid_def->declaration->id != BT_CTF_TYPE_ID_INTEGER) { | |
635 | goto end; | |
636 | } | |
637 | ||
638 | baddr = bt_get_unsigned_int(baddr_def); | |
639 | memsz = bt_get_unsigned_int(memsz_def); | |
9c713367 | 640 | path = bt_get_string(path_def); |
c40a57e5 AB |
641 | vpid = bt_get_signed_int(vpid_def); |
642 | ||
9c713367 | 643 | if (!path) { |
c40a57e5 AB |
644 | goto end; |
645 | } | |
646 | ||
647 | if (memsz == 0) { | |
648 | /* Ignore VDSO. */ | |
649 | goto end; | |
650 | } | |
651 | ||
652 | proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( | |
653 | debug_info->vpid_to_proc_dbg_info_src, vpid); | |
654 | if (!proc_dbg_info_src) { | |
655 | goto end; | |
656 | } | |
657 | ||
47857613 JG |
658 | key = g_new0(uint64_t, 1); |
659 | if (!key) { | |
660 | goto end; | |
661 | } | |
662 | ||
663 | *((uint64_t *) key) = baddr; | |
664 | ||
d5ddf820 | 665 | bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, |
47857613 | 666 | key); |
d5ddf820 | 667 | if (bin) { |
c40a57e5 AB |
668 | goto end; |
669 | } | |
670 | ||
d5ddf820 AB |
671 | bin = bin_info_create(path, baddr, memsz, is_pic); |
672 | if (!bin) { | |
c40a57e5 AB |
673 | goto end; |
674 | } | |
675 | ||
d5ddf820 AB |
676 | g_hash_table_insert(proc_dbg_info_src->baddr_to_bin_info, |
677 | key, bin); | |
47857613 JG |
678 | /* Ownership passed to ht. */ |
679 | key = NULL; | |
c40a57e5 AB |
680 | |
681 | end: | |
47857613 | 682 | g_free(key); |
c40a57e5 AB |
683 | return; |
684 | } | |
685 | ||
9f2b13ca | 686 | static inline |
9c713367 | 687 | void handle_statedump_bin_info_event(struct debug_info *debug_info, |
9f2b13ca AB |
688 | struct ctf_event_definition *event_def) |
689 | { | |
690 | handle_bin_info_event(debug_info, event_def, true); | |
691 | } | |
692 | ||
693 | static inline | |
694 | void handle_dlopen_event(struct debug_info *debug_info, | |
695 | struct ctf_event_definition *event_def) | |
696 | { | |
697 | handle_bin_info_event(debug_info, event_def, false); | |
698 | } | |
699 | ||
700 | ||
c40a57e5 AB |
701 | static |
702 | void handle_statedump_start(struct debug_info *debug_info, | |
703 | struct ctf_event_definition *event_def) | |
704 | { | |
705 | struct bt_definition *vpid_def = NULL; | |
706 | struct bt_definition *sec_def = NULL; | |
707 | struct proc_debug_info_sources *proc_dbg_info_src; | |
708 | int64_t vpid; | |
709 | ||
710 | sec_def = (struct bt_definition *) | |
711 | event_def->stream->stream_event_context; | |
712 | if (!sec_def) { | |
713 | goto end; | |
714 | } | |
715 | ||
716 | vpid_def = bt_lookup_definition(sec_def, "_vpid"); | |
717 | if (!vpid_def) { | |
718 | goto end; | |
719 | } | |
720 | ||
721 | vpid = bt_get_signed_int(vpid_def); | |
722 | ||
723 | proc_dbg_info_src = proc_debug_info_sources_ht_get_entry( | |
724 | debug_info->vpid_to_proc_dbg_info_src, vpid); | |
725 | if (!proc_dbg_info_src) { | |
726 | goto end; | |
727 | } | |
728 | ||
d5ddf820 | 729 | g_hash_table_remove_all(proc_dbg_info_src->baddr_to_bin_info); |
c40a57e5 AB |
730 | g_hash_table_remove_all(proc_dbg_info_src->ip_to_debug_info_src); |
731 | ||
732 | end: | |
733 | return; | |
734 | } | |
735 | ||
736 | static | |
737 | void register_event_debug_infos(struct debug_info *debug_info, | |
738 | struct ctf_event_definition *event) | |
739 | { | |
740 | struct bt_definition *ip_def, *vpid_def; | |
741 | int64_t vpid; | |
742 | uint64_t ip; | |
743 | struct bt_definition *sec_def; | |
744 | ||
745 | /* Get stream event context definition. */ | |
746 | sec_def = (struct bt_definition *) event->stream->stream_event_context; | |
747 | if (!sec_def) { | |
748 | goto end; | |
749 | } | |
750 | ||
751 | /* Get "ip" and "vpid" definitions. */ | |
752 | vpid_def = bt_lookup_definition((struct bt_definition *) sec_def, | |
753 | "_vpid"); | |
754 | ip_def = bt_lookup_definition((struct bt_definition *) sec_def, "_ip"); | |
755 | ||
756 | if (!vpid_def || !ip_def) { | |
757 | goto end; | |
758 | } | |
759 | ||
760 | vpid = bt_get_signed_int(vpid_def); | |
761 | ip = bt_get_unsigned_int(ip_def); | |
762 | ||
763 | /* Get debug info for this context. */ | |
764 | ((struct definition_integer *) ip_def)->debug_info_src = | |
765 | debug_info_query(debug_info, vpid, ip); | |
766 | ||
767 | end: | |
768 | return; | |
769 | } | |
770 | ||
771 | BT_HIDDEN | |
772 | void debug_info_handle_event(struct debug_info *debug_info, | |
773 | struct ctf_event_definition *event) | |
774 | { | |
775 | struct ctf_event_declaration *event_class; | |
776 | struct ctf_stream_declaration *stream_class; | |
777 | ||
778 | if (!debug_info || !event) { | |
779 | goto end; | |
780 | } | |
781 | ||
782 | stream_class = event->stream->stream_class; | |
783 | event_class = g_ptr_array_index(stream_class->events_by_id, | |
784 | event->stream->event_id); | |
785 | ||
9c713367 | 786 | if (event_class->name == debug_info->q_statedump_bin_info) { |
9f2b13ca | 787 | /* State dump */ |
9c713367 | 788 | handle_statedump_bin_info_event(debug_info, event); |
9f2b13ca AB |
789 | } else if (event_class->name == debug_info->q_dl_open) { |
790 | handle_dlopen_event(debug_info, event); | |
c40a57e5 AB |
791 | } else if (event_class->name == debug_info->q_statedump_start) { |
792 | /* Start state dump */ | |
793 | handle_statedump_start(debug_info, event); | |
794 | } else if (event_class->name == debug_info->q_statedump_debug_link) { | |
795 | /* Debug link info */ | |
796 | handle_statedump_debug_link_event(debug_info, event); | |
797 | } else if (event_class->name == debug_info->q_statedump_build_id) { | |
798 | /* Build ID info */ | |
799 | handle_statedump_build_id_event(debug_info, event); | |
800 | } else { | |
801 | /* Other events: register debug infos */ | |
802 | register_event_debug_infos(debug_info, event); | |
803 | } | |
804 | ||
805 | end: | |
806 | return; | |
807 | } |