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