lib: replace trace is_static with destruction listeners
[babeltrace.git] / plugins / lttng-utils / bin-info.c
CommitLineData
c40a57e5 1/*
d5ddf820 2 * bin-info.c
c40a57e5
AB
3 *
4 * Babeltrace - Executable and Shared Object Debug Info Reader
5 *
6 * Copyright 2015 Antoine Busque <abusque@efficios.com>
7 *
8 * Author: Antoine Busque <abusque@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
f4f9e43b
PP
29#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT-BIN-INFO"
30#include "logging.h"
31
c40a57e5
AB
32#include <fcntl.h>
33#include <math.h>
34#include <libgen.h>
35#include <stdio.h>
36#include <inttypes.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <dwarf.h>
41#include <glib.h>
545e1e92 42#include <errno.h>
4f45f9bb
JD
43#include "dwarf.h"
44#include "bin-info.h"
45#include "crc32.h"
46#include "utils.h"
c40a57e5
AB
47
48/*
49 * An address printed in hex is at most 20 bytes (16 for 64-bits +
50 * leading 0x + optional leading '+' if addr is an offset + null
51 * character).
52 */
53#define ADDR_STR_LEN 20
54
55BT_HIDDEN
d5ddf820 56int bin_info_init(void)
c40a57e5
AB
57{
58 int ret = 0;
59
60 if (elf_version(EV_CURRENT) == EV_NONE) {
f4f9e43b
PP
61 BT_LOGD("ELF library initialization failed: %s.",
62 elf_errmsg(-1));
c40a57e5
AB
63 ret = -1;
64 }
65
66 return ret;
67}
68
69BT_HIDDEN
d5ddf820 70struct bin_info *bin_info_create(const char *path, uint64_t low_addr,
9d325e17
PP
71 uint64_t memsz, bool is_pic, const char *debug_info_dir,
72 const char *target_prefix)
c40a57e5 73{
d5ddf820 74 struct bin_info *bin = NULL;
c40a57e5
AB
75
76 if (!path) {
77 goto error;
78 }
79
d5ddf820
AB
80 bin = g_new0(struct bin_info, 1);
81 if (!bin) {
c40a57e5
AB
82 goto error;
83 }
84
9d325e17
PP
85 if (target_prefix) {
86 bin->elf_path = g_build_path("/", target_prefix,
5cde0dc1
AB
87 path, NULL);
88 } else {
d5ddf820 89 bin->elf_path = strdup(path);
5cde0dc1
AB
90 }
91
d5ddf820 92 if (!bin->elf_path) {
c40a57e5
AB
93 goto error;
94 }
95
9d325e17
PP
96 if (debug_info_dir) {
97 bin->debug_info_dir = strdup(debug_info_dir);
98 if (!bin->debug_info_dir) {
99 goto error;
100 }
101 }
102
d5ddf820
AB
103 bin->is_pic = is_pic;
104 bin->memsz = memsz;
105 bin->low_addr = low_addr;
106 bin->high_addr = bin->low_addr + bin->memsz;
c40a57e5 107
d5ddf820 108 return bin;
c40a57e5
AB
109
110error:
d5ddf820 111 bin_info_destroy(bin);
c40a57e5
AB
112 return NULL;
113}
114
115BT_HIDDEN
d5ddf820 116void bin_info_destroy(struct bin_info *bin)
c40a57e5 117{
d5ddf820 118 if (!bin) {
c40a57e5
AB
119 return;
120 }
121
d5ddf820 122 dwarf_end(bin->dwarf_info);
c40a57e5 123
9d325e17 124 free(bin->debug_info_dir);
d5ddf820
AB
125 free(bin->elf_path);
126 free(bin->dwarf_path);
4f45f9bb 127 g_free(bin->build_id);
d5ddf820 128 free(bin->dbg_link_filename);
c40a57e5 129
d5ddf820 130 elf_end(bin->elf_file);
c40a57e5 131
d5ddf820
AB
132 close(bin->elf_fd);
133 close(bin->dwarf_fd);
c40a57e5 134
d5ddf820 135 g_free(bin);
c40a57e5
AB
136}
137
138BT_HIDDEN
d5ddf820 139int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id,
c40a57e5
AB
140 size_t build_id_len)
141{
d5ddf820 142 if (!bin || !build_id) {
c40a57e5
AB
143 goto error;
144 }
145
d5ddf820
AB
146 bin->build_id = malloc(build_id_len);
147 if (!bin->build_id) {
c40a57e5
AB
148 goto error;
149 }
150
d5ddf820
AB
151 memcpy(bin->build_id, build_id, build_id_len);
152 bin->build_id_len = build_id_len;
c40a57e5
AB
153
154 /*
155 * Reset the is_elf_only flag in case it had been set
156 * previously, because we might find separate debug info using
157 * the new build id information.
158 */
d5ddf820 159 bin->is_elf_only = false;
c40a57e5
AB
160
161 return 0;
162
163error:
164
165 return -1;
166}
167
168BT_HIDDEN
4f45f9bb
JD
169int bin_info_set_debug_link(struct bin_info *bin, const char *filename,
170 uint32_t crc)
c40a57e5 171{
d5ddf820 172 if (!bin || !filename) {
c40a57e5
AB
173 goto error;
174 }
175
d5ddf820
AB
176 bin->dbg_link_filename = strdup(filename);
177 if (!bin->dbg_link_filename) {
c40a57e5
AB
178 goto error;
179 }
180
d5ddf820 181 bin->dbg_link_crc = crc;
c40a57e5
AB
182
183 /*
184 * Reset the is_elf_only flag in case it had been set
185 * previously, because we might find separate debug info using
186 * the new build id information.
187 */
d5ddf820 188 bin->is_elf_only = false;
c40a57e5
AB
189
190 return 0;
191
192error:
193
194 return -1;
195}
196
197/**
198 * Tries to read DWARF info from the location given by path, and
d5ddf820 199 * attach it to the given bin_info instance if it exists.
c40a57e5 200 *
d5ddf820 201 * @param bin bin_info instance for which to set DWARF info
c40a57e5 202 * @param path Presumed location of the DWARF info
545e1e92 203 * @returns 0 on success, negative value on failure
c40a57e5
AB
204 */
205static
d5ddf820 206int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
c40a57e5
AB
207{
208 int fd = -1, ret = 0;
209 struct bt_dwarf_cu *cu = NULL;
210 Dwarf *dwarf_info = NULL;
211
d5ddf820 212 if (!bin || !path) {
c40a57e5
AB
213 goto error;
214 }
215
216 fd = open(path, O_RDONLY);
217 if (fd < 0) {
545e1e92 218 fd = -errno;
c40a57e5
AB
219 goto error;
220 }
221
222 dwarf_info = dwarf_begin(fd, DWARF_C_READ);
223 if (!dwarf_info) {
224 goto error;
225 }
226
227 /*
d5ddf820
AB
228 * Check if the dwarf info has any CU. If not, the
229 * executable's object file contains no DWARF info.
c40a57e5
AB
230 */
231 cu = bt_dwarf_cu_create(dwarf_info);
232 if (!cu) {
233 goto error;
234 }
235
236 ret = bt_dwarf_cu_next(cu);
237 if (ret) {
238 goto error;
239 }
240
d5ddf820
AB
241 bin->dwarf_fd = fd;
242 bin->dwarf_path = strdup(path);
243 if (!bin->dwarf_path) {
c40a57e5
AB
244 goto error;
245 }
d5ddf820 246 bin->dwarf_info = dwarf_info;
c40a57e5
AB
247 free(cu);
248
249 return 0;
250
251error:
545e1e92
JG
252 if (fd >= 0) {
253 close(fd);
254 fd = -1;
255 }
c40a57e5
AB
256 dwarf_end(dwarf_info);
257 g_free(dwarf_info);
258 free(cu);
259
545e1e92 260 return fd;
c40a57e5
AB
261}
262
263/**
d5ddf820 264 * Try to set the dwarf_info for a given bin_info instance via the
c40a57e5
AB
265 * build ID method.
266 *
d5ddf820 267 * @param bin bin_info instance for which to retrieve the
c40a57e5
AB
268 * DWARF info via build ID
269 * @returns 0 on success (i.e. dwarf_info set), -1 on failure
270 */
271static
d5ddf820 272int bin_info_set_dwarf_info_build_id(struct bin_info *bin)
c40a57e5 273{
f06ce5e5 274 int i = 0, ret = 0;
c40a57e5
AB
275 char *path = NULL, *build_id_file = NULL;
276 const char *dbg_dir = NULL;
f06ce5e5 277 size_t build_id_file_len;
c40a57e5 278
d5ddf820 279 if (!bin || !bin->build_id) {
c40a57e5
AB
280 goto error;
281 }
282
9d325e17 283 dbg_dir = bin->debug_info_dir ? : DEFAULT_DEBUG_DIR;
c40a57e5 284
b3599eb3 285 /* 2 characters per byte printed in hex, +1 for '/' and +1 for '\0' */
d5ddf820 286 build_id_file_len = (2 * bin->build_id_len) + 1 +
f06ce5e5 287 strlen(BUILD_ID_SUFFIX) + 1;
c40a57e5
AB
288 build_id_file = malloc(build_id_file_len);
289 if (!build_id_file) {
290 goto error;
291 }
292
d5ddf820
AB
293 snprintf(build_id_file, 4, "%02x/", bin->build_id[0]);
294 for (i = 1; i < bin->build_id_len; ++i) {
c40a57e5
AB
295 int path_idx = 3 + 2 * (i - 1);
296
d5ddf820 297 snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]);
c40a57e5 298 }
f06ce5e5 299 strcat(build_id_file, BUILD_ID_SUFFIX);
c40a57e5 300
f06ce5e5 301 path = g_build_path("/", dbg_dir, BUILD_ID_SUBDIR, build_id_file, NULL);
c40a57e5
AB
302 if (!path) {
303 goto error;
304 }
305
d5ddf820 306 ret = bin_info_set_dwarf_info_from_path(bin, path);
c40a57e5
AB
307 if (ret) {
308 goto error;
309 }
310
311 goto end;
312
313error:
314 ret = -1;
315end:
316 free(build_id_file);
317 free(path);
318
319 return ret;
320}
321
322/**
323 * Tests whether the file located at path exists and has the expected
324 * checksum.
325 *
326 * This predicate is used when looking up separate debug info via the
327 * GNU debuglink method. The expected crc can be found .gnu_debuglink
328 * section in the original ELF file, along with the filename for the
329 * file containing the debug info.
330 *
331 * @param path Full path at which to look for the debug file
332 * @param crc Expected checksum for the debug file
333 * @returns 1 if the file exists and has the correct checksum,
334 * 0 otherwise
335 */
336static
337int is_valid_debug_file(char *path, uint32_t crc)
338{
339 int ret = 0, fd = -1;
340 uint32_t _crc = 0;
341
342 if (!path) {
998f3499 343 goto end_noclose;
c40a57e5
AB
344 }
345
346 fd = open(path, O_RDONLY);
347 if (fd < 0) {
998f3499 348 goto end_noclose;
c40a57e5
AB
349 }
350
351 ret = crc32(fd, &_crc);
352 if (ret) {
353 ret = 0;
354 goto end;
355 }
356
357 ret = (crc == _crc);
358
359end:
360 close(fd);
998f3499 361end_noclose:
c40a57e5
AB
362 return ret;
363}
364
365/**
d5ddf820 366 * Try to set the dwarf_info for a given bin_info instance via the
c40a57e5
AB
367 * build ID method.
368 *
d5ddf820 369 * @param bin bin_info instance for which to retrieve the
c40a57e5
AB
370 * DWARF info via debug link
371 * @returns 0 on success (i.e. dwarf_info set), -1 on failure
372 */
373static
d5ddf820 374int bin_info_set_dwarf_info_debug_link(struct bin_info *bin)
c40a57e5
AB
375{
376 int ret = 0;
377 const char *dbg_dir = NULL;
d5ddf820 378 char *dir_name = NULL, *bin_dir = NULL, *path = NULL;
c40a57e5
AB
379 size_t max_path_len = 0;
380
d5ddf820 381 if (!bin || !bin->dbg_link_filename) {
c40a57e5
AB
382 goto error;
383 }
384
9d325e17 385 dbg_dir = bin->debug_info_dir ? : DEFAULT_DEBUG_DIR;
c40a57e5 386
d30bb635 387 dir_name = g_path_get_dirname(bin->elf_path);
c40a57e5
AB
388 if (!dir_name) {
389 goto error;
390 }
391
d5ddf820 392 /* bin_dir is just dir_name with a trailing slash */
d30bb635 393 bin_dir = g_new0(char, strlen(dir_name) + 2);
d5ddf820 394 if (!bin_dir) {
c40a57e5
AB
395 goto error;
396 }
397
d5ddf820
AB
398 strcpy(bin_dir, dir_name);
399 strcat(bin_dir, "/");
c40a57e5 400
d5ddf820
AB
401 max_path_len = strlen(dbg_dir) + strlen(bin_dir) +
402 strlen(DEBUG_SUBDIR) + strlen(bin->dbg_link_filename)
c40a57e5 403 + 1;
d30bb635 404 path = g_new0(char, max_path_len);
c40a57e5
AB
405 if (!path) {
406 goto error;
407 }
408
d5ddf820
AB
409 /* First look in the executable's dir */
410 strcpy(path, bin_dir);
411 strcat(path, bin->dbg_link_filename);
c40a57e5 412
d5ddf820 413 if (is_valid_debug_file(path, bin->dbg_link_crc)) {
c40a57e5
AB
414 goto found;
415 }
416
417 /* If not found, look in .debug subdir */
d5ddf820 418 strcpy(path, bin_dir);
c40a57e5 419 strcat(path, DEBUG_SUBDIR);
d5ddf820 420 strcat(path, bin->dbg_link_filename);
c40a57e5 421
d5ddf820 422 if (is_valid_debug_file(path, bin->dbg_link_crc)) {
c40a57e5
AB
423 goto found;
424 }
425
426 /* Lastly, look under the global debug directory */
427 strcpy(path, dbg_dir);
d5ddf820
AB
428 strcat(path, bin_dir);
429 strcat(path, bin->dbg_link_filename);
c40a57e5 430
d5ddf820 431 if (is_valid_debug_file(path, bin->dbg_link_crc)) {
c40a57e5
AB
432 goto found;
433 }
434
435error:
436 ret = -1;
437end:
d30bb635
FD
438 g_free(dir_name);
439 g_free(path);
440 g_free(bin_dir);
c40a57e5
AB
441
442 return ret;
443
444found:
d5ddf820 445 ret = bin_info_set_dwarf_info_from_path(bin, path);
c40a57e5
AB
446 if (ret) {
447 goto error;
448 }
449
450 goto end;
451}
452
453/**
454 * Initialize the DWARF info for a given executable.
455 *
d5ddf820 456 * @param bin bin_info instance
545e1e92 457 * @returns 0 on success, negative value on failure
c40a57e5
AB
458 */
459static
d5ddf820 460int bin_info_set_dwarf_info(struct bin_info *bin)
c40a57e5
AB
461{
462 int ret = 0;
463
d5ddf820 464 if (!bin) {
545e1e92
JG
465 ret = -1;
466 goto end;
c40a57e5
AB
467 }
468
469 /* First try to set the DWARF info from the ELF file */
d5ddf820 470 ret = bin_info_set_dwarf_info_from_path(bin, bin->elf_path);
c40a57e5
AB
471 if (!ret) {
472 goto end;
473 }
474
475 /*
476 * If that fails, try to find separate debug info via build ID
477 * and debug link.
478 */
d5ddf820 479 ret = bin_info_set_dwarf_info_build_id(bin);
c40a57e5
AB
480 if (!ret) {
481 goto end;
482 }
483
d5ddf820 484 ret = bin_info_set_dwarf_info_debug_link(bin);
c40a57e5
AB
485 if (!ret) {
486 goto end;
487 }
488
c40a57e5
AB
489end:
490 return ret;
491}
492
49824faa
AB
493/**
494 * Initialize the ELF file for a given executable.
495 *
d5ddf820 496 * @param bin bin_info instance
545e1e92 497 * @returns 0 on success, negative value on error.
49824faa
AB
498 */
499static
d5ddf820 500int bin_info_set_elf_file(struct bin_info *bin)
49824faa 501{
d460dc7f 502 int elf_fd = -1;
f99dc219 503 Elf *elf_file = NULL;
49824faa 504
d5ddf820 505 if (!bin) {
49824faa
AB
506 goto error;
507 }
508
d5ddf820 509 elf_fd = open(bin->elf_path, O_RDONLY);
49824faa 510 if (elf_fd < 0) {
545e1e92 511 elf_fd = -errno;
f4f9e43b 512 BT_LOGD("Failed to open ELF file: path=\"%s\"", bin->elf_path);
49824faa
AB
513 goto error;
514 }
515
516 elf_file = elf_begin(elf_fd, ELF_C_READ, NULL);
517 if (!elf_file) {
f4f9e43b 518 BT_LOGD("elf_begin() failed: %s.", elf_errmsg(-1));
49824faa
AB
519 goto error;
520 }
521
522 if (elf_kind(elf_file) != ELF_K_ELF) {
f4f9e43b
PP
523 BT_LOGD("ELF file is not an ELF object: path=\"%s\"",
524 bin->elf_path);
49824faa
AB
525 goto error;
526 }
527
d5ddf820
AB
528 bin->elf_fd = elf_fd;
529 bin->elf_file = elf_file;
49824faa
AB
530 return 0;
531
532error:
d460dc7f
JG
533 if (elf_fd >= 0) {
534 close(elf_fd);
545e1e92 535 elf_fd = -1;
d460dc7f 536 }
49824faa 537 elf_end(elf_file);
545e1e92 538 return elf_fd;
49824faa
AB
539}
540
c40a57e5
AB
541BT_HIDDEN
542void source_location_destroy(struct source_location *src_loc)
543{
544 if (!src_loc) {
545 return;
546 }
547
548 free(src_loc->filename);
549 g_free(src_loc);
550}
d6d3f4e8 551
d2ac1099
AB
552/**
553 * Append a string representation of an address offset to an existing
554 * string.
555 *
556 * On success, the out parameter `result` will contain the base string
557 * followed by the offset string of the form "+0x1234". On failure,
558 * `result` remains unchanged.
559 *
560 * @param base_str The string to which to append an offset string
561 * @param low_addr The lower virtual memory address, the base from
562 * which the offset is computed
563 * @param high_addr The higher virtual memory address
564 * @param result Out parameter, the base string followed by the
565 * offset string
566 * @returns 0 on success, -1 on failure
567 */
568static
d5ddf820 569int bin_info_append_offset_str(const char *base_str, uint64_t low_addr,
d2ac1099
AB
570 uint64_t high_addr, char **result)
571{
572 int ret;
573 uint64_t offset;
574 char *_result = NULL;
575 char offset_str[ADDR_STR_LEN];
576
577 if (!base_str || !result) {
578 goto error;
579 }
580
581 offset = high_addr - low_addr;
582
583 _result = malloc(strlen(base_str) + ADDR_STR_LEN);
584 if (!_result) {
585 goto error;
586 }
587
588 ret = snprintf(offset_str, ADDR_STR_LEN, "+%#0" PRIx64, offset);
589 if (ret < 0) {
590 goto error;
591 }
592 strcpy(_result, base_str);
593 strcat(_result, offset_str);
594 *result = _result;
595
596 return 0;
597
598error:
599 free(_result);
600 return -1;
601}
c40a57e5
AB
602
603/**
604 * Try to find the symbol closest to an address within a given ELF
605 * section.
606 *
607 * Only function symbols are taken into account. The symbol's address
608 * must precede `addr`. A symbol with a closer address might exist
609 * after `addr` but is irrelevant because it cannot encompass `addr`.
610 *
611 * On success, if found, the out parameters `sym` and `shdr` are
612 * set. On failure or if none are found, they remain unchanged.
613 *
614 * @param scn ELF section in which to look for the address
615 * @param addr Virtual memory address for which to find the
616 * nearest function symbol
617 * @param sym Out parameter, the nearest function symbol
618 * @param shdr Out parameter, the section header for scn
619 * @returns 0 on success, -1 on failure
620 */
621static
d5ddf820 622int bin_info_get_nearest_symbol_from_section(Elf_Scn *scn, uint64_t addr,
c40a57e5
AB
623 GElf_Sym **sym, GElf_Shdr **shdr)
624{
625 int i;
626 size_t symbol_count;
627 Elf_Data *data = NULL;
628 GElf_Shdr *_shdr = NULL;
629 GElf_Sym *nearest_sym = NULL;
630
631 if (!scn || !sym || !shdr) {
632 goto error;
633 }
634
635 _shdr = g_new0(GElf_Shdr, 1);
636 if (!_shdr) {
637 goto error;
638 }
639
640 _shdr = gelf_getshdr(scn, _shdr);
641 if (!_shdr) {
642 goto error;
643 }
644
645 if (_shdr->sh_type != SHT_SYMTAB) {
646 /*
647 * We are only interested in symbol table (symtab)
648 * sections, skip this one.
649 */
650 goto end;
651 }
652
653 data = elf_getdata(scn, NULL);
654 if (!data) {
655 goto error;
656 }
657
658 symbol_count = _shdr->sh_size / _shdr->sh_entsize;
659
660 for (i = 0; i < symbol_count; ++i) {
661 GElf_Sym *cur_sym = NULL;
662
663 cur_sym = g_new0(GElf_Sym, 1);
664 if (!cur_sym) {
665 goto error;
666 }
667 cur_sym = gelf_getsym(data, i, cur_sym);
668 if (!cur_sym) {
669 goto error;
670 }
671 if (GELF_ST_TYPE(cur_sym->st_info) != STT_FUNC) {
672 /* We're only interested in the functions. */
673 g_free(cur_sym);
674 continue;
675 }
676
677 if (cur_sym->st_value <= addr &&
678 (!nearest_sym ||
679 cur_sym->st_value > nearest_sym->st_value)) {
680 g_free(nearest_sym);
681 nearest_sym = cur_sym;
682 } else {
683 g_free(cur_sym);
684 }
685 }
686
687end:
688 if (nearest_sym) {
689 *sym = nearest_sym;
690 *shdr = _shdr;
691 } else {
692 g_free(_shdr);
693 }
694
695 return 0;
696
697error:
698 g_free(nearest_sym);
699 g_free(_shdr);
700 return -1;
701}
702
703/**
704 * Get the name of the function containing a given address within an
705 * executable using ELF symbols.
706 *
707 * The function name is in fact the name of the nearest ELF symbol,
708 * followed by the offset in bytes between the address and the symbol
709 * (in hex), separated by a '+' character.
710 *
711 * If found, the out parameter `func_name` is set on success. On failure,
712 * it remains unchanged.
713 *
d5ddf820 714 * @param bin bin_info instance for the executable containing
c40a57e5
AB
715 * the address
716 * @param addr Virtual memory address for which to find the
717 * function name
718 * @param func_name Out parameter, the function name
719 * @returns 0 on success, -1 on failure
720 */
721static
d5ddf820 722int bin_info_lookup_elf_function_name(struct bin_info *bin, uint64_t addr,
c40a57e5
AB
723 char **func_name)
724{
725 /*
726 * TODO (possible optimisation): if an ELF has no symtab
727 * section, it has been stripped. Therefore, it would be wise
728 * to store a flag indicating the stripped status after the
729 * first iteration to prevent subsequent ones.
730 */
731 int ret = 0;
732 Elf_Scn *scn = NULL;
733 GElf_Sym *sym = NULL;
734 GElf_Shdr *shdr = NULL;
735 char *sym_name = NULL;
c40a57e5 736
49824faa 737 /* Set ELF file if it hasn't been accessed yet. */
d5ddf820
AB
738 if (!bin->elf_file) {
739 ret = bin_info_set_elf_file(bin);
49824faa
AB
740 if (ret) {
741 /* Failed to set ELF file. */
742 goto error;
743 }
744 }
745
d5ddf820 746 scn = elf_nextscn(bin->elf_file, scn);
c40a57e5
AB
747 if (!scn) {
748 goto error;
749 }
750
751 while (scn && !sym) {
d5ddf820 752 ret = bin_info_get_nearest_symbol_from_section(
c40a57e5
AB
753 scn, addr, &sym, &shdr);
754 if (ret) {
755 goto error;
756 }
757
d5ddf820 758 scn = elf_nextscn(bin->elf_file, scn);
c40a57e5
AB
759 }
760
761 if (sym) {
d5ddf820 762 sym_name = elf_strptr(bin->elf_file, shdr->sh_link,
c40a57e5
AB
763 sym->st_name);
764 if (!sym_name) {
765 goto error;
766 }
767
d5ddf820 768 ret = bin_info_append_offset_str(sym_name, sym->st_value, addr,
d2ac1099
AB
769 func_name);
770 if (ret) {
c40a57e5
AB
771 goto error;
772 }
c40a57e5
AB
773 }
774
775 g_free(shdr);
776 g_free(sym);
777 return 0;
778
779error:
780 g_free(shdr);
781 g_free(sym);
545e1e92 782 return ret;
c40a57e5
AB
783}
784
785/**
786 * Get the name of the function containing a given address within a
787 * given compile unit (CU).
788 *
789 * If found, the out parameter `func_name` is set on success. On
790 * failure, it remains unchanged.
791 *
792 * @param cu bt_dwarf_cu instance which may contain the address
793 * @param addr Virtual memory address for which to find the
794 * function name
795 * @param func_name Out parameter, the function name
796 * @returns 0 on success, -1 on failure
797 */
798static
d5ddf820 799int bin_info_lookup_cu_function_name(struct bt_dwarf_cu *cu, uint64_t addr,
c40a57e5
AB
800 char **func_name)
801{
a54aa699
AB
802 int ret = 0;
803 bool found = false;
c40a57e5
AB
804 struct bt_dwarf_die *die = NULL;
805
806 if (!cu || !func_name) {
807 goto error;
808 }
809
810 die = bt_dwarf_die_create(cu);
811 if (!die) {
812 goto error;
813 }
814
815 while (bt_dwarf_die_next(die) == 0) {
816 int tag;
817
818 ret = bt_dwarf_die_get_tag(die, &tag);
819 if (ret) {
820 goto error;
821 }
822
823 if (tag == DW_TAG_subprogram) {
824 ret = bt_dwarf_die_contains_addr(die, addr, &found);
825 if (ret) {
826 goto error;
827 }
828
829 if (found) {
830 break;
831 }
832 }
833 }
834
835 if (found) {
d2ac1099
AB
836 uint64_t low_addr = 0;
837 char *die_name = NULL;
838
7935ee7a
AB
839 ret = bt_dwarf_die_get_name(die, &die_name);
840 if (ret) {
841 goto error;
842 }
843
844 ret = dwarf_lowpc(die->dwarf_die, &low_addr);
c40a57e5 845 if (ret) {
7d41a84b 846 free(die_name);
c40a57e5
AB
847 goto error;
848 }
849
d5ddf820 850 ret = bin_info_append_offset_str(die_name, low_addr, addr,
d2ac1099 851 func_name);
7d41a84b 852 free(die_name);
d2ac1099 853 if (ret) {
7935ee7a
AB
854 goto error;
855 }
c40a57e5
AB
856 }
857
858 bt_dwarf_die_destroy(die);
859 return 0;
860
861error:
862 bt_dwarf_die_destroy(die);
863 return -1;
864}
865
866/**
867 * Get the name of the function containing a given address within an
868 * executable using DWARF debug info.
869 *
870 * If found, the out parameter `func_name` is set on success. On
871 * failure, it remains unchanged.
872 *
d5ddf820 873 * @param bin bin_info instance for the executable containing
c40a57e5
AB
874 * the address
875 * @param addr Virtual memory address for which to find the
876 * function name
877 * @param func_name Out parameter, the function name
878 * @returns 0 on success, -1 on failure
879 */
880static
d5ddf820 881int bin_info_lookup_dwarf_function_name(struct bin_info *bin, uint64_t addr,
c40a57e5
AB
882 char **func_name)
883{
884 int ret = 0;
885 char *_func_name = NULL;
886 struct bt_dwarf_cu *cu = NULL;
887
d5ddf820 888 if (!bin || !func_name) {
c40a57e5
AB
889 goto error;
890 }
891
d5ddf820 892 cu = bt_dwarf_cu_create(bin->dwarf_info);
c40a57e5
AB
893 if (!cu) {
894 goto error;
895 }
896
897 while (bt_dwarf_cu_next(cu) == 0) {
d5ddf820 898 ret = bin_info_lookup_cu_function_name(cu, addr, &_func_name);
c40a57e5
AB
899 if (ret) {
900 goto error;
901 }
902
903 if (_func_name) {
904 break;
905 }
906 }
907
908 if (_func_name) {
909 *func_name = _func_name;
93d65223
JG
910 } else {
911 goto error;
c40a57e5
AB
912 }
913
914 bt_dwarf_cu_destroy(cu);
915 return 0;
916
917error:
918 bt_dwarf_cu_destroy(cu);
919 return -1;
920}
921
922BT_HIDDEN
9d325e17
PP
923int bin_info_lookup_function_name(struct bin_info *bin,
924 uint64_t addr, char **func_name)
c40a57e5
AB
925{
926 int ret = 0;
927 char *_func_name = NULL;
928
d5ddf820 929 if (!bin || !func_name) {
c40a57e5
AB
930 goto error;
931 }
932
933 /* Set DWARF info if it hasn't been accessed yet. */
d5ddf820
AB
934 if (!bin->dwarf_info && !bin->is_elf_only) {
935 ret = bin_info_set_dwarf_info(bin);
c40a57e5 936 if (ret) {
f4f9e43b 937 BT_LOGD_STR("Failed to set bin dwarf info, falling back to ELF lookup.");
c40a57e5 938 /* Failed to set DWARF info, fallback to ELF. */
d5ddf820 939 bin->is_elf_only = true;
c40a57e5
AB
940 }
941 }
942
d5ddf820 943 if (!bin_info_has_address(bin, addr)) {
c40a57e5
AB
944 goto error;
945 }
946
947 /*
948 * Addresses in ELF and DWARF are relative to base address for
949 * PIC, so make the address argument relative too if needed.
950 */
d5ddf820
AB
951 if (bin->is_pic) {
952 addr -= bin->low_addr;
36ae9941
AB
953 }
954
d5ddf820
AB
955 if (bin->is_elf_only) {
956 ret = bin_info_lookup_elf_function_name(bin, addr, &_func_name);
f4f9e43b 957 BT_LOGD("Failed to lookup function name (ELF): ret=%d", ret);
c40a57e5 958 } else {
d5ddf820 959 ret = bin_info_lookup_dwarf_function_name(bin, addr, &_func_name);
f4f9e43b 960 BT_LOGD("Failed to lookup function name (DWARF): ret=%d", ret);
c40a57e5
AB
961 }
962
36ae9941
AB
963 *func_name = _func_name;
964 return 0;
55cd033d 965
36ae9941
AB
966error:
967 return -1;
968}
969
970BT_HIDDEN
d5ddf820 971int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc)
36ae9941
AB
972{
973 int ret = 0;
974 char *_bin_loc = NULL;
975
d5ddf820 976 if (!bin || !bin_loc) {
36ae9941 977 goto error;
c40a57e5
AB
978 }
979
d5ddf820
AB
980 if (bin->is_pic) {
981 addr -= bin->low_addr;
36ae9941
AB
982 ret = asprintf(&_bin_loc, "+%#0" PRIx64, addr);
983 } else {
984 ret = asprintf(&_bin_loc, "@%#0" PRIx64, addr);
985 }
986
987 if (ret == -1 || !_bin_loc) {
988 goto error;
989 }
990
991 *bin_loc = _bin_loc;
c40a57e5
AB
992 return 0;
993
994error:
995 return -1;
996}
997
998/**
999 * Predicate used to determine whether the children of a given DIE
1000 * contain a specific address.
1001 *
1002 * More specifically, the parameter `die` is expected to be a
1003 * subprogram (function) DIE, and this predicate tells whether any
1004 * subroutines are inlined within this function and would contain
1005 * `addr`.
1006 *
a54aa699
AB
1007 * On success, the out parameter `contains` is set with the boolean
1008 * value indicating whether the DIE's range covers `addr`. On failure,
1009 * it remains unchanged.
1010 *
c40a57e5
AB
1011 * Do note that this function advances the position of `die`. If the
1012 * address is found within one of its children, `die` will be pointing
1013 * to that child upon returning from the function, allowing to extract
1014 * the information deemed necessary.
1015 *
a54aa699
AB
1016 * @param die The parent DIE in whose children the address will be
1017 * looked for
1018 * @param addr The address for which to look for in the DIEs
1019 * @param contains Out parameter, true if addr is contained,
1020 * false if not
1021 * @returns Returns 0 on success, -1 on failure
c40a57e5
AB
1022 */
1023static
a54aa699 1024int bin_info_child_die_has_address(struct bt_dwarf_die *die, uint64_t addr, bool *contains)
c40a57e5 1025{
a54aa699
AB
1026 int ret = 0;
1027 bool _contains = false;
c40a57e5
AB
1028
1029 if (!die) {
1030 goto error;
1031 }
1032
1033 ret = bt_dwarf_die_child(die);
1034 if (ret) {
1035 goto error;
1036 }
1037
1038 do {
1039 int tag;
1040
1041 ret = bt_dwarf_die_get_tag(die, &tag);
1042 if (ret) {
1043 goto error;
1044 }
1045
1046 if (tag == DW_TAG_inlined_subroutine) {
a54aa699 1047 ret = bt_dwarf_die_contains_addr(die, addr, &_contains);
c40a57e5
AB
1048 if (ret) {
1049 goto error;
1050 }
1051
14c2a191 1052 if (_contains) {
c40a57e5
AB
1053 goto end;
1054 }
1055 }
1056 } while (bt_dwarf_die_next(die) == 0);
1057
1058end:
a54aa699
AB
1059 *contains = _contains;
1060 return 0;
c40a57e5
AB
1061
1062error:
a54aa699 1063 return -1;
c40a57e5
AB
1064}
1065
1066/**
1067 * Lookup the source location for a given address within a CU, making
1068 * the assumption that it is contained within an inline routine in a
1069 * function.
1070 *
1071 * @param cu bt_dwarf_cu instance in which to look for the address
1072 * @param addr The address for which to look for
1073 * @param src_loc Out parameter, the source location (filename and
1074 * line number) for the address
1075 * @returns 0 on success, -1 on failure
1076 */
1077static
d5ddf820 1078int bin_info_lookup_cu_src_loc_inl(struct bt_dwarf_cu *cu, uint64_t addr,
c40a57e5
AB
1079 struct source_location **src_loc)
1080{
a54aa699
AB
1081 int ret = 0;
1082 bool found = false;
c40a57e5
AB
1083 struct bt_dwarf_die *die = NULL;
1084 struct source_location *_src_loc = NULL;
1085
1086 if (!cu || !src_loc) {
1087 goto error;
1088 }
1089
1090 die = bt_dwarf_die_create(cu);
1091 if (!die) {
1092 goto error;
1093 }
1094
1095 while (bt_dwarf_die_next(die) == 0) {
1096 int tag;
1097
1098 ret = bt_dwarf_die_get_tag(die, &tag);
1099 if (ret) {
1100 goto error;
1101 }
1102
1103 if (tag == DW_TAG_subprogram) {
a54aa699 1104 bool contains = false;
c40a57e5
AB
1105
1106 ret = bt_dwarf_die_contains_addr(die, addr, &contains);
1107 if (ret) {
1108 goto error;
1109 }
1110
1111 if (contains) {
1112 /*
1113 * Try to find an inlined subroutine
1114 * child of this DIE containing addr.
1115 */
a54aa699
AB
1116 ret = bin_info_child_die_has_address(die, addr,
1117 &found);
1118 if(ret) {
1119 goto error;
1120 }
1121
c40a57e5
AB
1122 goto end;
1123 }
1124 }
1125 }
1126
1127end:
1128 if (found) {
1129 char *filename = NULL;
1130 uint64_t line_no;
1131
1132 _src_loc = g_new0(struct source_location, 1);
1133 if (!_src_loc) {
1134 goto error;
1135 }
1136
1137 ret = bt_dwarf_die_get_call_file(die, &filename);
1138 if (ret) {
1139 goto error;
1140 }
1141 ret = bt_dwarf_die_get_call_line(die, &line_no);
1142 if (ret) {
1143 free(filename);
1144 goto error;
1145 }
1146
1147 _src_loc->filename = filename;
1148 _src_loc->line_no = line_no;
1149 *src_loc = _src_loc;
1150 }
1151
1152 bt_dwarf_die_destroy(die);
1153 return 0;
1154
1155error:
1156 source_location_destroy(_src_loc);
1157 bt_dwarf_die_destroy(die);
1158 return -1;
1159}
1160
1161/**
1162 * Lookup the source location for a given address within a CU,
1163 * assuming that it is contained within an inlined function.
1164 *
1165 * A source location can be found regardless of inlining status for
1166 * this method, but in the case of an inlined function, the returned
1167 * source location will point not to the callsite but rather to the
1168 * definition site of the inline function.
1169 *
1170 * @param cu bt_dwarf_cu instance in which to look for the address
1171 * @param addr The address for which to look for
1172 * @param src_loc Out parameter, the source location (filename and
1173 * line number) for the address
1174 * @returns 0 on success, -1 on failure
1175 */
1176static
d5ddf820 1177int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr,
c40a57e5
AB
1178 struct source_location **src_loc)
1179{
1180 struct source_location *_src_loc = NULL;
1181 struct bt_dwarf_die *die = NULL;
1182 const char *filename = NULL;
1183 Dwarf_Line *line = NULL;
1184 Dwarf_Addr line_addr;
1185 int ret, line_no;
1186
1187 if (!cu || !src_loc) {
1188 goto error;
1189 }
1190
1191 die = bt_dwarf_die_create(cu);
1192 if (!die) {
1193 goto error;
1194 }
1195
1196 line = dwarf_getsrc_die(die->dwarf_die, addr);
1197 if (!line) {
1198 goto error;
1199 }
1200
1201 ret = dwarf_lineaddr(line, &line_addr);
1202 if (ret) {
1203 goto error;
1204 }
1205
1206 filename = dwarf_linesrc(line, NULL, NULL);
1207 if (!filename) {
1208 goto error;
1209 }
1210
1211 if (addr == line_addr) {
1212 _src_loc = g_new0(struct source_location, 1);
1213 if (!_src_loc) {
1214 goto error;
1215 }
1216
1217 ret = dwarf_lineno(line, &line_no);
1218 if (ret) {
1219 goto error;
1220 }
1221
1222 _src_loc->line_no = line_no;
1223 _src_loc->filename = strdup(filename);
1224 }
1225
1226 bt_dwarf_die_destroy(die);
1227
1228 if (_src_loc) {
1229 *src_loc = _src_loc;
1230 }
1231
1232 return 0;
1233
1234error:
1235 source_location_destroy(_src_loc);
1236 bt_dwarf_die_destroy(die);
1237 return -1;
1238}
1239
1240/**
1241 * Get the source location (file name and line number) for a given
1242 * address within a compile unit (CU).
1243 *
1244 * On success, the out parameter `src_loc` is set if found. On
1245 * failure, it remains unchanged.
1246 *
d5ddf820 1247 * @param cu bt_dwarf_cu instance for the compile unit which
c40a57e5
AB
1248 * may contain the address
1249 * @param addr Virtual memory address for which to find the
1250 * source location
1251 * @param src_loc Out parameter, the source location
1252 * @returns 0 on success, -1 on failure
1253 */
1254static
d5ddf820 1255int bin_info_lookup_cu_src_loc(struct bt_dwarf_cu *cu, uint64_t addr,
c40a57e5
AB
1256 struct source_location **src_loc)
1257{
1258 int ret = 0;
1259 struct source_location *_src_loc = NULL;
1260
1261 if (!cu || !src_loc) {
1262 goto error;
1263 }
1264
d5ddf820 1265 ret = bin_info_lookup_cu_src_loc_inl(cu, addr, &_src_loc);
c40a57e5
AB
1266 if (ret) {
1267 goto error;
1268 }
1269
1270 if (_src_loc) {
1271 goto end;
1272 }
1273
d5ddf820 1274 ret = bin_info_lookup_cu_src_loc_no_inl(cu, addr, &_src_loc);
c40a57e5
AB
1275 if (ret) {
1276 goto error;
1277 }
1278
1279 if (_src_loc) {
1280 goto end;
1281 }
1282
1283end:
1284 if (_src_loc) {
1285 *src_loc = _src_loc;
1286 }
1287
1288 return 0;
1289
1290error:
1291 source_location_destroy(_src_loc);
1292 return -1;
1293}
1294
1295BT_HIDDEN
d5ddf820 1296int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr,
c40a57e5
AB
1297 struct source_location **src_loc)
1298{
1299 struct bt_dwarf_cu *cu = NULL;
1300 struct source_location *_src_loc = NULL;
1301
d5ddf820 1302 if (!bin || !src_loc) {
c40a57e5
AB
1303 goto error;
1304 }
1305
1306 /* Set DWARF info if it hasn't been accessed yet. */
d5ddf820
AB
1307 if (!bin->dwarf_info && !bin->is_elf_only) {
1308 if (bin_info_set_dwarf_info(bin)) {
c40a57e5 1309 /* Failed to set DWARF info. */
d5ddf820 1310 bin->is_elf_only = true;
c40a57e5
AB
1311 }
1312 }
1313
d5ddf820 1314 if (bin->is_elf_only) {
c40a57e5
AB
1315 /* We cannot lookup source location without DWARF info. */
1316 goto error;
1317 }
1318
d5ddf820 1319 if (!bin_info_has_address(bin, addr)) {
c40a57e5
AB
1320 goto error;
1321 }
1322
1323 /*
1324 * Addresses in ELF and DWARF are relative to base address for
1325 * PIC, so make the address argument relative too if needed.
1326 */
d5ddf820
AB
1327 if (bin->is_pic) {
1328 addr -= bin->low_addr;
c40a57e5
AB
1329 }
1330
d5ddf820 1331 cu = bt_dwarf_cu_create(bin->dwarf_info);
c40a57e5
AB
1332 if (!cu) {
1333 goto error;
1334 }
1335
1336 while (bt_dwarf_cu_next(cu) == 0) {
1337 int ret;
1338
d5ddf820 1339 ret = bin_info_lookup_cu_src_loc(cu, addr, &_src_loc);
c40a57e5
AB
1340 if (ret) {
1341 goto error;
1342 }
1343
1344 if (_src_loc) {
1345 break;
1346 }
1347 }
1348
1349 bt_dwarf_cu_destroy(cu);
1350 if (_src_loc) {
1351 *src_loc = _src_loc;
1352 }
1353
1354 return 0;
1355
1356error:
1357 source_location_destroy(_src_loc);
1358 bt_dwarf_cu_destroy(cu);
1359 return -1;
1360}
This page took 0.098031 seconds and 4 git commands to generate.