debug-info: have `copy_*_content()` function return _STATUS
[babeltrace.git] / src / plugins / lttng-utils / debug-info / 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
91bc8451 29#define BT_COMP_LOG_SELF_COMP (bin->self_comp)
3a3d15f3 30#define BT_LOG_OUTPUT_LEVEL (bin->log_level)
350ad6c1 31#define BT_LOG_TAG "PLUGIN/FLT.LTTNG-UTILS.DEBUG-INFO/BIN-INFO"
d9c39b0a 32#include "logging/comp-logging.h"
b4565e8b 33
3a3d15f3 34#include <babeltrace2/logging.h>
1e638f98
FD
35#include <dwarf.h>
36#include <errno.h>
c40a57e5 37#include <fcntl.h>
1e638f98 38#include <inttypes.h>
c40a57e5 39#include <libgen.h>
1e638f98 40#include <math.h>
c40a57e5 41#include <stdio.h>
c40a57e5
AB
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
1e638f98 45
c40a57e5 46#include <glib.h>
1e638f98 47
578e048b 48#include "common/common.h"
af54bd18 49
4f45f9bb
JD
50#include "bin-info.h"
51#include "crc32.h"
1e638f98 52#include "dwarf.h"
4f45f9bb 53#include "utils.h"
c40a57e5
AB
54
55/*
56 * An address printed in hex is at most 20 bytes (16 for 64-bits +
57 * leading 0x + optional leading '+' if addr is an offset + null
58 * character).
59 */
60#define ADDR_STR_LEN 20
ca9f27f3 61#define BUILD_ID_NOTE_NAME "GNU"
c40a57e5
AB
62
63BT_HIDDEN
91bc8451 64int bin_info_init(bt_logging_level log_level, bt_self_component *self_comp)
c40a57e5
AB
65{
66 int ret = 0;
67
68 if (elf_version(EV_CURRENT) == EV_NONE) {
91bc8451 69 BT_COMP_LOG_CUR_LVL(BT_LOG_INFO, log_level, self_comp,
3a3d15f3 70 "ELF library initialization failed: %s.",
b4565e8b 71 elf_errmsg(-1));
c40a57e5
AB
72 ret = -1;
73 }
74
75 return ret;
76}
77
78BT_HIDDEN
1e638f98
FD
79struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path,
80 uint64_t low_addr, uint64_t memsz, bool is_pic,
3a3d15f3 81 const char *debug_info_dir, const char *target_prefix,
91bc8451 82 bt_logging_level log_level, bt_self_component *self_comp)
c40a57e5 83{
d5ddf820 84 struct bin_info *bin = NULL;
c40a57e5 85
1e638f98
FD
86 BT_ASSERT(fdc);
87
c40a57e5
AB
88 if (!path) {
89 goto error;
90 }
91
d5ddf820
AB
92 bin = g_new0(struct bin_info, 1);
93 if (!bin) {
c40a57e5
AB
94 goto error;
95 }
96
3a3d15f3 97 bin->log_level = log_level;
91bc8451 98 bin->self_comp = self_comp;
9d325e17 99 if (target_prefix) {
0cf9d412 100 bin->elf_path = g_build_filename(target_prefix, path, NULL);
5cde0dc1 101 } else {
ca9f27f3 102 bin->elf_path = g_strdup(path);
5cde0dc1
AB
103 }
104
d5ddf820 105 if (!bin->elf_path) {
c40a57e5
AB
106 goto error;
107 }
108
9d325e17 109 if (debug_info_dir) {
06d1cf5d 110 bin->debug_info_dir = g_strdup(debug_info_dir);
9d325e17
PP
111 if (!bin->debug_info_dir) {
112 goto error;
113 }
114 }
115
d5ddf820
AB
116 bin->is_pic = is_pic;
117 bin->memsz = memsz;
118 bin->low_addr = low_addr;
119 bin->high_addr = bin->low_addr + bin->memsz;
ca9f27f3
FD
120 bin->build_id = NULL;
121 bin->build_id_len = 0;
122 bin->file_build_id_matches = false;
1e638f98 123 bin->fd_cache = fdc;
c40a57e5 124
d5ddf820 125 return bin;
c40a57e5
AB
126
127error:
d5ddf820 128 bin_info_destroy(bin);
c40a57e5
AB
129 return NULL;
130}
131
132BT_HIDDEN
d5ddf820 133void bin_info_destroy(struct bin_info *bin)
c40a57e5 134{
d5ddf820 135 if (!bin) {
c40a57e5
AB
136 return;
137 }
138
d5ddf820 139 dwarf_end(bin->dwarf_info);
c40a57e5 140
06d1cf5d
FD
141 g_free(bin->debug_info_dir);
142 g_free(bin->elf_path);
143 g_free(bin->dwarf_path);
4f45f9bb 144 g_free(bin->build_id);
06d1cf5d 145 g_free(bin->dbg_link_filename);
c40a57e5 146
d5ddf820 147 elf_end(bin->elf_file);
c40a57e5 148
1e638f98
FD
149 bt_fd_cache_put_handle(bin->fd_cache, bin->elf_handle);
150 bt_fd_cache_put_handle(bin->fd_cache, bin->dwarf_handle);
c40a57e5 151
d5ddf820 152 g_free(bin);
c40a57e5
AB
153}
154
ca9f27f3
FD
155/**
156 * Initialize the ELF file for a given executable.
157 *
158 * @param bin bin_info instance
159 * @returns 0 on success, negative value on error.
160 */
161static
162int bin_info_set_elf_file(struct bin_info *bin)
163{
1e638f98 164 struct bt_fd_cache_handle *elf_handle = NULL;
ca9f27f3 165 Elf *elf_file = NULL;
9d3a71fc 166 int ret;
ca9f27f3 167
9d3a71fc 168 BT_ASSERT(bin);
ca9f27f3 169
1e638f98
FD
170 elf_handle = bt_fd_cache_get_handle(bin->fd_cache, bin->elf_path);
171 if (!elf_handle) {
91bc8451 172 BT_COMP_LOGI("Failed to open %s", bin->elf_path);
ca9f27f3
FD
173 goto error;
174 }
af54bd18
FD
175 bin->elf_handle = elf_handle;
176
af54bd18 177 elf_file = elf_begin(bt_fd_cache_handle_get_fd(bin->elf_handle),
1e638f98 178 ELF_C_READ, NULL);
ca9f27f3 179 if (!elf_file) {
3b34b490
FD
180 BT_COMP_LOGE_APPEND_CAUSE(bin->self_comp,
181 "elf_begin failed: %s", elf_errmsg(-1));
ca9f27f3
FD
182 goto error;
183 }
184
af54bd18
FD
185 bin->elf_file = elf_file;
186
ca9f27f3 187 if (elf_kind(elf_file) != ELF_K_ELF) {
3b34b490
FD
188 BT_COMP_LOGE_APPEND_CAUSE(bin->self_comp,
189 "Error: %s is not an ELF object", bin->elf_path);
ca9f27f3
FD
190 goto error;
191 }
192
9d3a71fc
FD
193
194 ret = 0;
195 goto end;
ca9f27f3
FD
196
197error:
1e638f98 198 bt_fd_cache_put_handle(bin->fd_cache, elf_handle);
ca9f27f3 199 elf_end(elf_file);
9d3a71fc
FD
200 ret = -1;
201
202end:
203 return ret;
ca9f27f3
FD
204}
205
206/**
9b1d6816 207 * From a note section data struct, check if it is a build id note.
ca9f27f3 208 *
9b1d6816 209 * @param note_data Pointer to a note section
ca9f27f3
FD
210 *
211 * @returns 1 on match, 0 if `buf` does not contain a
212 * valid build id note
213 */
214static
9b1d6816 215int is_build_id_note_section(Elf_Data *note_data)
ca9f27f3 216{
9b1d6816
FD
217 size_t name_offset, desc_offset;
218 GElf_Nhdr note_header;
ca9f27f3 219 int ret = 0;
ca9f27f3 220
9b1d6816
FD
221 /*
222 * Discard the return value as it contains the size of the note section
223 * and we don't need it.
ca9f27f3 224 */
9b1d6816
FD
225 (void) gelf_getnote(note_data, 0, &note_header, &name_offset,
226 &desc_offset);
233b228c
FD
227
228 /*
229 * Check the note name length. The name_sz field includes the
230 * terminating null byte.
231 */
9b1d6816 232 if (note_header.n_namesz != sizeof(BUILD_ID_NOTE_NAME)) {
233b228c
FD
233 goto invalid;
234 }
235
ca9f27f3 236 /* Check the note type. */
9b1d6816 237 if (note_header.n_type != NT_GNU_BUILD_ID) {
ca9f27f3
FD
238 goto invalid;
239 }
240
241 /* Check the note name. */
9b1d6816
FD
242 if (memcmp(note_data->d_buf + name_offset, BUILD_ID_NOTE_NAME,
243 note_header.n_namesz) != 0) {
ca9f27f3
FD
244 goto invalid;
245 }
246
247 ret = 1;
248
249invalid:
250 return ret;
251}
252
253/**
9b1d6816 254 * From a build id note section data struct, check if the build id it contains
ca9f27f3
FD
255 * is identical to the build id passed as parameter.
256 *
9b1d6816 257 * @param note_data Pointer to the file build id note section.
ca9f27f3
FD
258 * @param build_id Pointer to a build id to compare to.
259 * @param build_id_len length of the build id.
260 *
261 * @returns 1 on match, 0 otherwise.
262 */
263static
9b1d6816 264int is_build_id_note_section_matching(Elf_Data *note_data,
ca9f27f3
FD
265 uint8_t *build_id, size_t build_id_len)
266{
9b1d6816
FD
267 size_t name_offset, desc_offset;
268 GElf_Nhdr note_header;
ca9f27f3
FD
269
270 if (build_id_len <= 0) {
271 goto end;
272 }
273
ca9f27f3 274 /*
9b1d6816
FD
275 * Discard the return value as it contains the size of the note section
276 * and we don't need it.
ca9f27f3 277 */
9b1d6816
FD
278 (void) gelf_getnote(note_data, 0, &note_header, &name_offset,
279 &desc_offset);
ca9f27f3
FD
280
281 /*
282 * Compare the binary build id with the supplied build id.
283 */
9b1d6816
FD
284 if (memcmp(build_id, note_data->d_buf + desc_offset,
285 build_id_len) == 0) {
ca9f27f3
FD
286 return 1;
287 }
288end:
289 return 0;
290}
291
292/**
293 * Checks if the build id stored in `bin` (bin->build_id) is matching the build
294 * id of the ondisk file (bin->elf_file).
295 *
296 * @param bin bin_info instance
297 * @param build_id build id to compare ot the on disk file
298 * @param build_id_len length of the build id
299 *
300 * @returns 1 on if the build id of stored in `bin` matches
301 * the build id of the ondisk file.
302 * 0 on if they are different or an error occured.
303 */
304static
305int is_build_id_matching(struct bin_info *bin)
306{
307 int ret, is_build_id, is_matching = 0;
308 Elf_Scn *curr_section = NULL, *next_section = NULL;
bfe42dac 309 GElf_Shdr curr_section_hdr;
ca9f27f3
FD
310
311 if (!bin->build_id) {
312 goto error;
313 }
314
315 /* Set ELF file if it hasn't been accessed yet. */
316 if (!bin->elf_file) {
317 ret = bin_info_set_elf_file(bin);
318 if (ret) {
319 /* Failed to set ELF file. */
320 goto error;
321 }
322 }
323
ca9f27f3
FD
324 next_section = elf_nextscn(bin->elf_file, curr_section);
325 if (!next_section) {
326 goto error;
327 }
328
329 while (next_section) {
9b1d6816 330 Elf_Data *note_data = NULL;
af54bd18 331
ca9f27f3
FD
332 curr_section = next_section;
333 next_section = elf_nextscn(bin->elf_file, curr_section);
334
bfe42dac 335 if (!gelf_getshdr(curr_section, &curr_section_hdr)) {
ca9f27f3
FD
336 goto error;
337 }
338
bfe42dac 339 if (curr_section_hdr.sh_type != SHT_NOTE) {
ca9f27f3
FD
340 continue;
341 }
342
af54bd18 343 /*
9b1d6816 344 * elf_getdata() translates the data to native byte order.
af54bd18 345 */
9b1d6816
FD
346 note_data = elf_getdata(curr_section, NULL);
347 if (!note_data) {
348 goto error;
349 }
af54bd18 350
ca9f27f3 351 /* Check if the note is of the build-id type. */
9b1d6816 352 is_build_id = is_build_id_note_section(note_data);
ca9f27f3
FD
353 if (!is_build_id) {
354 continue;
355 }
356
357 /*
358 * Compare the build id of the on-disk file and
359 * the build id recorded in the trace.
360 */
af54bd18 361 is_matching = is_build_id_note_section_matching(
9b1d6816 362 note_data, bin->build_id, bin->build_id_len);
ca9f27f3
FD
363 if (!is_matching) {
364 break;
365 }
366 }
367error:
ca9f27f3
FD
368 return is_matching;
369}
370
c40a57e5 371BT_HIDDEN
d5ddf820 372int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id,
c40a57e5
AB
373 size_t build_id_len)
374{
d5ddf820 375 if (!bin || !build_id) {
c40a57e5
AB
376 goto error;
377 }
378
ca9f27f3
FD
379 /* Set the build id. */
380 bin->build_id = g_new0(uint8_t, build_id_len);
d5ddf820 381 if (!bin->build_id) {
c40a57e5
AB
382 goto error;
383 }
384
d5ddf820
AB
385 memcpy(bin->build_id, build_id, build_id_len);
386 bin->build_id_len = build_id_len;
c40a57e5 387
ca9f27f3
FD
388 /*
389 * Check if the file found on the file system has the same build id
390 * that what was recorded in the trace.
391 */
392 bin->file_build_id_matches = is_build_id_matching(bin);
393 if (!bin->file_build_id_matches) {
91bc8451 394 BT_COMP_LOGI_STR("Supplied Build ID does not match Build ID of the "
ca9f27f3
FD
395 "binary or library found on the file system.");
396 goto error;
397 }
398
c40a57e5
AB
399 /*
400 * Reset the is_elf_only flag in case it had been set
401 * previously, because we might find separate debug info using
402 * the new build id information.
403 */
d5ddf820 404 bin->is_elf_only = false;
c40a57e5
AB
405
406 return 0;
407
408error:
c40a57e5
AB
409 return -1;
410}
411
412BT_HIDDEN
4f45f9bb
JD
413int bin_info_set_debug_link(struct bin_info *bin, const char *filename,
414 uint32_t crc)
c40a57e5 415{
d5ddf820 416 if (!bin || !filename) {
c40a57e5
AB
417 goto error;
418 }
419
06d1cf5d 420 bin->dbg_link_filename = g_strdup(filename);
d5ddf820 421 if (!bin->dbg_link_filename) {
c40a57e5
AB
422 goto error;
423 }
424
d5ddf820 425 bin->dbg_link_crc = crc;
c40a57e5
AB
426
427 /*
428 * Reset the is_elf_only flag in case it had been set
429 * previously, because we might find separate debug info using
430 * the new build id information.
431 */
d5ddf820 432 bin->is_elf_only = false;
c40a57e5
AB
433
434 return 0;
435
436error:
437
438 return -1;
439}
440
441/**
442 * Tries to read DWARF info from the location given by path, and
d5ddf820 443 * attach it to the given bin_info instance if it exists.
c40a57e5 444 *
d5ddf820 445 * @param bin bin_info instance for which to set DWARF info
c40a57e5 446 * @param path Presumed location of the DWARF info
545e1e92 447 * @returns 0 on success, negative value on failure
c40a57e5
AB
448 */
449static
d5ddf820 450int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
c40a57e5 451{
1e638f98
FD
452 int ret = 0;
453 struct bt_fd_cache_handle *dwarf_handle = NULL;
c40a57e5
AB
454 struct bt_dwarf_cu *cu = NULL;
455 Dwarf *dwarf_info = NULL;
456
d5ddf820 457 if (!bin || !path) {
c40a57e5
AB
458 goto error;
459 }
460
1e638f98
FD
461 dwarf_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
462 if (!dwarf_handle) {
c40a57e5
AB
463 goto error;
464 }
465
1e638f98
FD
466 dwarf_info = dwarf_begin(bt_fd_cache_handle_get_fd(dwarf_handle),
467 DWARF_C_READ);
c40a57e5
AB
468 if (!dwarf_info) {
469 goto error;
470 }
471
472 /*
d5ddf820
AB
473 * Check if the dwarf info has any CU. If not, the
474 * executable's object file contains no DWARF info.
c40a57e5
AB
475 */
476 cu = bt_dwarf_cu_create(dwarf_info);
477 if (!cu) {
478 goto error;
479 }
480
481 ret = bt_dwarf_cu_next(cu);
482 if (ret) {
483 goto error;
484 }
485
1e638f98 486 bin->dwarf_handle = dwarf_handle;
06d1cf5d 487 bin->dwarf_path = g_strdup(path);
d5ddf820 488 if (!bin->dwarf_path) {
c40a57e5
AB
489 goto error;
490 }
d5ddf820 491 bin->dwarf_info = dwarf_info;
c40a57e5
AB
492 free(cu);
493
494 return 0;
495
496error:
c449a5c3
FD
497 if (bin) {
498 bt_fd_cache_put_handle(bin->fd_cache, dwarf_handle);
499 }
c40a57e5
AB
500 dwarf_end(dwarf_info);
501 g_free(dwarf_info);
502 free(cu);
503
1e638f98 504 return -1;
c40a57e5
AB
505}
506
507/**
d5ddf820 508 * Try to set the dwarf_info for a given bin_info instance via the
c40a57e5
AB
509 * build ID method.
510 *
d5ddf820 511 * @param bin bin_info instance for which to retrieve the
c40a57e5
AB
512 * DWARF info via build ID
513 * @returns 0 on success (i.e. dwarf_info set), -1 on failure
514 */
515static
d5ddf820 516int bin_info_set_dwarf_info_build_id(struct bin_info *bin)
c40a57e5 517{
f06ce5e5 518 int i = 0, ret = 0;
73485cf9 519 char *path = NULL, *build_id_prefix_dir = NULL, *build_id_file = NULL;
c40a57e5 520 const char *dbg_dir = NULL;
8486e87a 521 size_t build_id_char_len, build_id_suffix_char_len, build_id_file_len;
c40a57e5 522
d5ddf820 523 if (!bin || !bin->build_id) {
c40a57e5
AB
524 goto error;
525 }
526
06d1cf5d 527 dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR;
c40a57e5 528
73485cf9
MJ
529 /*
530 * The prefix dir is the first byte of the build id, represented in
531 * lowercase hex as two characters per byte, +1 for '\0'.
532 */
533 build_id_prefix_dir = g_new0(gchar, BUILD_ID_PREFIX_DIR_LEN + 1);
534 if (!build_id_prefix_dir) {
535 goto error;
536 }
537 g_snprintf(build_id_prefix_dir, BUILD_ID_PREFIX_DIR_LEN + 1, "%02x", bin->build_id[0]);
538
539 /*
540 * The build id file is the remaining bytes of the build id,
541 * represented in lowercase hex, as two characters per byte.
542 */
543 build_id_char_len = (2 * (bin->build_id_len - 1));
544
545 /* To which the build id suffix is added, +1 for '\0'. */
8486e87a 546 build_id_suffix_char_len = strlen(BUILD_ID_SUFFIX) + 1;
73485cf9
MJ
547
548 /*
549 * The resulting filename string is the concatenation of the
550 * hex build id and the suffix.
551 */
8486e87a 552 build_id_file_len = build_id_char_len + build_id_suffix_char_len;
06d1cf5d 553 build_id_file = g_new0(gchar, build_id_file_len);
c40a57e5
AB
554 if (!build_id_file) {
555 goto error;
556 }
557
73485cf9
MJ
558 /*
559 * For each byte, starting at offset 1, append two characters
560 * in lowercase hex.
561 */
d5ddf820 562 for (i = 1; i < bin->build_id_len; ++i) {
73485cf9 563 int path_idx = 2 * (i - 1);
c40a57e5 564
06d1cf5d 565 g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]);
c40a57e5 566 }
73485cf9 567 /* Append the suffix to the generated string, including the '\0'. */
8486e87a
FD
568 g_snprintf(&build_id_file[build_id_char_len], build_id_suffix_char_len,
569 BUILD_ID_SUFFIX);
c40a57e5 570
73485cf9 571 path = g_build_filename(dbg_dir, BUILD_ID_SUBDIR, build_id_prefix_dir, build_id_file, NULL);
c40a57e5
AB
572 if (!path) {
573 goto error;
574 }
575
d5ddf820 576 ret = bin_info_set_dwarf_info_from_path(bin, path);
c40a57e5
AB
577 if (ret) {
578 goto error;
579 }
580
581 goto end;
582
583error:
584 ret = -1;
585end:
73485cf9
MJ
586 g_free(build_id_prefix_dir);
587 g_free(build_id_file);
588 g_free(path);
c40a57e5
AB
589
590 return ret;
591}
592
593/**
594 * Tests whether the file located at path exists and has the expected
595 * checksum.
596 *
597 * This predicate is used when looking up separate debug info via the
598 * GNU debuglink method. The expected crc can be found .gnu_debuglink
599 * section in the original ELF file, along with the filename for the
600 * file containing the debug info.
601 *
602 * @param path Full path at which to look for the debug file
603 * @param crc Expected checksum for the debug file
604 * @returns 1 if the file exists and has the correct checksum,
605 * 0 otherwise
606 */
607static
1e638f98 608int is_valid_debug_file(struct bin_info *bin, char *path, uint32_t crc)
c40a57e5 609{
1e638f98
FD
610 int ret = 0;
611 struct bt_fd_cache_handle *debug_handle = NULL;
c40a57e5
AB
612 uint32_t _crc = 0;
613
614 if (!path) {
1e638f98 615 goto end;
c40a57e5
AB
616 }
617
1e638f98
FD
618 debug_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
619 if (!debug_handle) {
620 goto end;
c40a57e5
AB
621 }
622
1e638f98 623 ret = crc32(bt_fd_cache_handle_get_fd(debug_handle), &_crc);
c40a57e5
AB
624 if (ret) {
625 ret = 0;
626 goto end;
627 }
628
629 ret = (crc == _crc);
630
631end:
1e638f98 632 bt_fd_cache_put_handle(bin->fd_cache, debug_handle);
c40a57e5
AB
633 return ret;
634}
635
636/**
d5ddf820 637 * Try to set the dwarf_info for a given bin_info instance via the
ca9f27f3 638 * debug-link method.
c40a57e5 639 *
d5ddf820 640 * @param bin bin_info instance for which to retrieve the
c40a57e5
AB
641 * DWARF info via debug link
642 * @returns 0 on success (i.e. dwarf_info set), -1 on failure
643 */
644static
d5ddf820 645int bin_info_set_dwarf_info_debug_link(struct bin_info *bin)
c40a57e5
AB
646{
647 int ret = 0;
06d1cf5d 648 const gchar *dbg_dir = NULL;
73485cf9 649 gchar *bin_dir = NULL, *path = NULL;
c40a57e5 650
d5ddf820 651 if (!bin || !bin->dbg_link_filename) {
c40a57e5
AB
652 goto error;
653 }
654
06d1cf5d 655 dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR;
73485cf9 656 bin_dir = g_path_get_dirname(bin->elf_path);
c40a57e5 657
d5ddf820 658 /* First look in the executable's dir */
73485cf9 659 path = g_build_filename(bin_dir, bin->dbg_link_filename, NULL);
c40a57e5 660
1e638f98 661 if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
c40a57e5
AB
662 goto found;
663 }
664
665 /* If not found, look in .debug subdir */
06d1cf5d 666 g_free(path);
73485cf9 667 path = g_build_filename(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL);
c40a57e5 668
1e638f98 669 if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
c40a57e5
AB
670 goto found;
671 }
672
673 /* Lastly, look under the global debug directory */
06d1cf5d 674 g_free(path);
c40a57e5 675
73485cf9 676 path = g_build_filename(dbg_dir, bin_dir, bin->dbg_link_filename, NULL);
1e638f98 677 if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
c40a57e5
AB
678 goto found;
679 }
680
681error:
682 ret = -1;
683end:
39588a20 684 g_free(bin_dir);
85cf9985 685 g_free(path);
c40a57e5
AB
686
687 return ret;
688
689found:
d5ddf820 690 ret = bin_info_set_dwarf_info_from_path(bin, path);
c40a57e5
AB
691 if (ret) {
692 goto error;
693 }
694
695 goto end;
696}
697
698/**
699 * Initialize the DWARF info for a given executable.
700 *
d5ddf820 701 * @param bin bin_info instance
545e1e92 702 * @returns 0 on success, negative value on failure
c40a57e5
AB
703 */
704static
d5ddf820 705int bin_info_set_dwarf_info(struct bin_info *bin)
c40a57e5
AB
706{
707 int ret = 0;
708
d5ddf820 709 if (!bin) {
545e1e92
JG
710 ret = -1;
711 goto end;
c40a57e5
AB
712 }
713
714 /* First try to set the DWARF info from the ELF file */
d5ddf820 715 ret = bin_info_set_dwarf_info_from_path(bin, bin->elf_path);
c40a57e5
AB
716 if (!ret) {
717 goto end;
718 }
719
720 /*
721 * If that fails, try to find separate debug info via build ID
722 * and debug link.
723 */
d5ddf820 724 ret = bin_info_set_dwarf_info_build_id(bin);
c40a57e5
AB
725 if (!ret) {
726 goto end;
727 }
728
d5ddf820 729 ret = bin_info_set_dwarf_info_debug_link(bin);
c40a57e5
AB
730 if (!ret) {
731 goto end;
732 }
733
c40a57e5
AB
734end:
735 return ret;
736}
737
738BT_HIDDEN
739void source_location_destroy(struct source_location *src_loc)
740{
741 if (!src_loc) {
742 return;
743 }
744
745 free(src_loc->filename);
746 g_free(src_loc);
747}
d6d3f4e8 748
d2ac1099
AB
749/**
750 * Append a string representation of an address offset to an existing
751 * string.
752 *
753 * On success, the out parameter `result` will contain the base string
754 * followed by the offset string of the form "+0x1234". On failure,
755 * `result` remains unchanged.
756 *
757 * @param base_str The string to which to append an offset string
758 * @param low_addr The lower virtual memory address, the base from
759 * which the offset is computed
760 * @param high_addr The higher virtual memory address
761 * @param result Out parameter, the base string followed by the
762 * offset string
763 * @returns 0 on success, -1 on failure
764 */
765static
d5ddf820 766int bin_info_append_offset_str(const char *base_str, uint64_t low_addr,
d2ac1099
AB
767 uint64_t high_addr, char **result)
768{
d2ac1099
AB
769 uint64_t offset;
770 char *_result = NULL;
06d1cf5d 771
d2ac1099
AB
772 if (!base_str || !result) {
773 goto error;
774 }
775
776 offset = high_addr - low_addr;
777
06d1cf5d 778 _result = g_strdup_printf("%s+%#0" PRIx64, base_str, offset);
d2ac1099
AB
779 if (!_result) {
780 goto error;
781 }
d2ac1099
AB
782 *result = _result;
783
784 return 0;
785
786error:
787 free(_result);
788 return -1;
789}
c40a57e5
AB
790
791/**
792 * Try to find the symbol closest to an address within a given ELF
793 * section.
794 *
795 * Only function symbols are taken into account. The symbol's address
796 * must precede `addr`. A symbol with a closer address might exist
797 * after `addr` but is irrelevant because it cannot encompass `addr`.
798 *
799 * On success, if found, the out parameters `sym` and `shdr` are
800 * set. On failure or if none are found, they remain unchanged.
801 *
802 * @param scn ELF section in which to look for the address
803 * @param addr Virtual memory address for which to find the
804 * nearest function symbol
805 * @param sym Out parameter, the nearest function symbol
806 * @param shdr Out parameter, the section header for scn
807 * @returns 0 on success, -1 on failure
808 */
809static
d5ddf820 810int bin_info_get_nearest_symbol_from_section(Elf_Scn *scn, uint64_t addr,
c40a57e5
AB
811 GElf_Sym **sym, GElf_Shdr **shdr)
812{
813 int i;
814 size_t symbol_count;
815 Elf_Data *data = NULL;
816 GElf_Shdr *_shdr = NULL;
817 GElf_Sym *nearest_sym = NULL;
818
819 if (!scn || !sym || !shdr) {
820 goto error;
821 }
822
823 _shdr = g_new0(GElf_Shdr, 1);
824 if (!_shdr) {
825 goto error;
826 }
827
828 _shdr = gelf_getshdr(scn, _shdr);
829 if (!_shdr) {
830 goto error;
831 }
832
833 if (_shdr->sh_type != SHT_SYMTAB) {
834 /*
835 * We are only interested in symbol table (symtab)
836 * sections, skip this one.
837 */
838 goto end;
839 }
840
841 data = elf_getdata(scn, NULL);
842 if (!data) {
843 goto error;
844 }
845
846 symbol_count = _shdr->sh_size / _shdr->sh_entsize;
847
848 for (i = 0; i < symbol_count; ++i) {
849 GElf_Sym *cur_sym = NULL;
850
851 cur_sym = g_new0(GElf_Sym, 1);
852 if (!cur_sym) {
853 goto error;
854 }
855 cur_sym = gelf_getsym(data, i, cur_sym);
856 if (!cur_sym) {
857 goto error;
858 }
859 if (GELF_ST_TYPE(cur_sym->st_info) != STT_FUNC) {
860 /* We're only interested in the functions. */
861 g_free(cur_sym);
862 continue;
863 }
864
865 if (cur_sym->st_value <= addr &&
866 (!nearest_sym ||
867 cur_sym->st_value > nearest_sym->st_value)) {
868 g_free(nearest_sym);
869 nearest_sym = cur_sym;
870 } else {
871 g_free(cur_sym);
872 }
873 }
874
875end:
876 if (nearest_sym) {
877 *sym = nearest_sym;
878 *shdr = _shdr;
879 } else {
880 g_free(_shdr);
881 }
882
883 return 0;
884
885error:
886 g_free(nearest_sym);
887 g_free(_shdr);
888 return -1;
889}
890
891/**
892 * Get the name of the function containing a given address within an
893 * executable using ELF symbols.
894 *
895 * The function name is in fact the name of the nearest ELF symbol,
896 * followed by the offset in bytes between the address and the symbol
897 * (in hex), separated by a '+' character.
898 *
899 * If found, the out parameter `func_name` is set on success. On failure,
900 * it remains unchanged.
901 *
d5ddf820 902 * @param bin bin_info instance for the executable containing
c40a57e5
AB
903 * the address
904 * @param addr Virtual memory address for which to find the
905 * function name
906 * @param func_name Out parameter, the function name
907 * @returns 0 on success, -1 on failure
908 */
909static
d5ddf820 910int bin_info_lookup_elf_function_name(struct bin_info *bin, uint64_t addr,
c40a57e5
AB
911 char **func_name)
912{
913 /*
914 * TODO (possible optimisation): if an ELF has no symtab
915 * section, it has been stripped. Therefore, it would be wise
916 * to store a flag indicating the stripped status after the
917 * first iteration to prevent subsequent ones.
918 */
919 int ret = 0;
920 Elf_Scn *scn = NULL;
921 GElf_Sym *sym = NULL;
922 GElf_Shdr *shdr = NULL;
923 char *sym_name = NULL;
c40a57e5 924
49824faa 925 /* Set ELF file if it hasn't been accessed yet. */
d5ddf820
AB
926 if (!bin->elf_file) {
927 ret = bin_info_set_elf_file(bin);
49824faa
AB
928 if (ret) {
929 /* Failed to set ELF file. */
930 goto error;
931 }
932 }
933
d5ddf820 934 scn = elf_nextscn(bin->elf_file, scn);
c40a57e5
AB
935 if (!scn) {
936 goto error;
937 }
938
939 while (scn && !sym) {
d5ddf820 940 ret = bin_info_get_nearest_symbol_from_section(
c40a57e5
AB
941 scn, addr, &sym, &shdr);
942 if (ret) {
943 goto error;
944 }
945
d5ddf820 946 scn = elf_nextscn(bin->elf_file, scn);
c40a57e5
AB
947 }
948
949 if (sym) {
d5ddf820 950 sym_name = elf_strptr(bin->elf_file, shdr->sh_link,
c40a57e5
AB
951 sym->st_name);
952 if (!sym_name) {
953 goto error;
954 }
955
d5ddf820 956 ret = bin_info_append_offset_str(sym_name, sym->st_value, addr,
d2ac1099
AB
957 func_name);
958 if (ret) {
c40a57e5
AB
959 goto error;
960 }
c40a57e5
AB
961 }
962
963 g_free(shdr);
964 g_free(sym);
965 return 0;
966
967error:
968 g_free(shdr);
969 g_free(sym);
545e1e92 970 return ret;
c40a57e5
AB
971}
972
973/**
974 * Get the name of the function containing a given address within a
975 * given compile unit (CU).
976 *
977 * If found, the out parameter `func_name` is set on success. On
978 * failure, it remains unchanged.
979 *
980 * @param cu bt_dwarf_cu instance which may contain the address
981 * @param addr Virtual memory address for which to find the
982 * function name
983 * @param func_name Out parameter, the function name
984 * @returns 0 on success, -1 on failure
985 */
986static
d5ddf820 987int bin_info_lookup_cu_function_name(struct bt_dwarf_cu *cu, uint64_t addr,
c40a57e5
AB
988 char **func_name)
989{
a54aa699
AB
990 int ret = 0;
991 bool found = false;
c40a57e5
AB
992 struct bt_dwarf_die *die = NULL;
993
994 if (!cu || !func_name) {
995 goto error;
996 }
997
998 die = bt_dwarf_die_create(cu);
999 if (!die) {
1000 goto error;
1001 }
1002
1003 while (bt_dwarf_die_next(die) == 0) {
1004 int tag;
1005
1006 ret = bt_dwarf_die_get_tag(die, &tag);
1007 if (ret) {
1008 goto error;
1009 }
1010
1011 if (tag == DW_TAG_subprogram) {
1012 ret = bt_dwarf_die_contains_addr(die, addr, &found);
1013 if (ret) {
1014 goto error;
1015 }
1016
1017 if (found) {
1018 break;
1019 }
1020 }
1021 }
1022
1023 if (found) {
d2ac1099
AB
1024 uint64_t low_addr = 0;
1025 char *die_name = NULL;
1026
7935ee7a
AB
1027 ret = bt_dwarf_die_get_name(die, &die_name);
1028 if (ret) {
1029 goto error;
1030 }
1031
1032 ret = dwarf_lowpc(die->dwarf_die, &low_addr);
c40a57e5 1033 if (ret) {
7d41a84b 1034 free(die_name);
c40a57e5
AB
1035 goto error;
1036 }
1037
d5ddf820 1038 ret = bin_info_append_offset_str(die_name, low_addr, addr,
d2ac1099 1039 func_name);
7d41a84b 1040 free(die_name);
d2ac1099 1041 if (ret) {
7935ee7a
AB
1042 goto error;
1043 }
c40a57e5
AB
1044 }
1045
1046 bt_dwarf_die_destroy(die);
1047 return 0;
1048
1049error:
1050 bt_dwarf_die_destroy(die);
1051 return -1;
1052}
1053
1054/**
1055 * Get the name of the function containing a given address within an
1056 * executable using DWARF debug info.
1057 *
1058 * If found, the out parameter `func_name` is set on success. On
1059 * failure, it remains unchanged.
1060 *
d5ddf820 1061 * @param bin bin_info instance for the executable containing
c40a57e5
AB
1062 * the address
1063 * @param addr Virtual memory address for which to find the
1064 * function name
1065 * @param func_name Out parameter, the function name
1066 * @returns 0 on success, -1 on failure
1067 */
1068static
d5ddf820 1069int bin_info_lookup_dwarf_function_name(struct bin_info *bin, uint64_t addr,
c40a57e5
AB
1070 char **func_name)
1071{
1072 int ret = 0;
1073 char *_func_name = NULL;
1074 struct bt_dwarf_cu *cu = NULL;
1075
d5ddf820 1076 if (!bin || !func_name) {
c40a57e5
AB
1077 goto error;
1078 }
1079
d5ddf820 1080 cu = bt_dwarf_cu_create(bin->dwarf_info);
c40a57e5
AB
1081 if (!cu) {
1082 goto error;
1083 }
1084
1085 while (bt_dwarf_cu_next(cu) == 0) {
d5ddf820 1086 ret = bin_info_lookup_cu_function_name(cu, addr, &_func_name);
c40a57e5
AB
1087 if (ret) {
1088 goto error;
1089 }
1090
1091 if (_func_name) {
1092 break;
1093 }
1094 }
1095
1096 if (_func_name) {
1097 *func_name = _func_name;
93d65223
JG
1098 } else {
1099 goto error;
c40a57e5
AB
1100 }
1101
1102 bt_dwarf_cu_destroy(cu);
1103 return 0;
1104
1105error:
1106 bt_dwarf_cu_destroy(cu);
1107 return -1;
1108}
1109
1110BT_HIDDEN
9d325e17
PP
1111int bin_info_lookup_function_name(struct bin_info *bin,
1112 uint64_t addr, char **func_name)
c40a57e5
AB
1113{
1114 int ret = 0;
1115 char *_func_name = NULL;
1116
d5ddf820 1117 if (!bin || !func_name) {
c40a57e5
AB
1118 goto error;
1119 }
1120
ca9f27f3
FD
1121 /*
1122 * If the bin_info has a build id but it does not match the build id
1123 * that was found on the file system, return an error.
1124 */
1125 if (bin->build_id && !bin->file_build_id_matches) {
1126 goto error;
1127 }
1128
c40a57e5 1129 /* Set DWARF info if it hasn't been accessed yet. */
d5ddf820
AB
1130 if (!bin->dwarf_info && !bin->is_elf_only) {
1131 ret = bin_info_set_dwarf_info(bin);
c40a57e5 1132 if (ret) {
91bc8451 1133 BT_COMP_LOGI_STR("Failed to set bin dwarf info, falling "
1e638f98 1134 "back to ELF lookup.");
c40a57e5 1135 /* Failed to set DWARF info, fallback to ELF. */
d5ddf820 1136 bin->is_elf_only = true;
c40a57e5
AB
1137 }
1138 }
1139
d5ddf820 1140 if (!bin_info_has_address(bin, addr)) {
c40a57e5
AB
1141 goto error;
1142 }
1143
1144 /*
1145 * Addresses in ELF and DWARF are relative to base address for
1146 * PIC, so make the address argument relative too if needed.
1147 */
d5ddf820
AB
1148 if (bin->is_pic) {
1149 addr -= bin->low_addr;
36ae9941
AB
1150 }
1151
d5ddf820 1152 if (bin->is_elf_only) {
b223415b
FD
1153 ret = bin_info_lookup_elf_function_name(bin, addr,
1154 &_func_name);
1155 if (ret) {
91bc8451 1156 BT_COMP_LOGI("Failed to lookup function name (ELF): "
b223415b
FD
1157 "ret=%d", ret);
1158 }
c40a57e5 1159 } else {
b223415b
FD
1160 ret = bin_info_lookup_dwarf_function_name(bin, addr,
1161 &_func_name);
1162 if (ret) {
91bc8451 1163 BT_COMP_LOGI("Failed to lookup function name (DWARF): "
b223415b
FD
1164 "ret=%d", ret);
1165 }
c40a57e5
AB
1166 }
1167
36ae9941
AB
1168 *func_name = _func_name;
1169 return 0;
55cd033d 1170
36ae9941
AB
1171error:
1172 return -1;
1173}
1174
1175BT_HIDDEN
d5ddf820 1176int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc)
36ae9941 1177{
06d1cf5d 1178 gchar *_bin_loc = NULL;
36ae9941 1179
d5ddf820 1180 if (!bin || !bin_loc) {
36ae9941 1181 goto error;
c40a57e5
AB
1182 }
1183
ca9f27f3
FD
1184 /*
1185 * If the bin_info has a build id but it does not match the build id
1186 * that was found on the file system, return an error.
1187 */
1188 if (bin->build_id && !bin->file_build_id_matches) {
1189 goto error;
1190 }
1191
d5ddf820
AB
1192 if (bin->is_pic) {
1193 addr -= bin->low_addr;
06d1cf5d 1194 _bin_loc = g_strdup_printf("+%#0" PRIx64, addr);
36ae9941 1195 } else {
06d1cf5d 1196 _bin_loc = g_strdup_printf("@%#0" PRIx64, addr);
36ae9941
AB
1197 }
1198
06d1cf5d 1199 if (!_bin_loc) {
36ae9941
AB
1200 goto error;
1201 }
1202
1203 *bin_loc = _bin_loc;
c40a57e5
AB
1204 return 0;
1205
1206error:
1207 return -1;
1208}
1209
1210/**
1211 * Predicate used to determine whether the children of a given DIE
1212 * contain a specific address.
1213 *
1214 * More specifically, the parameter `die` is expected to be a
1215 * subprogram (function) DIE, and this predicate tells whether any
1216 * subroutines are inlined within this function and would contain
1217 * `addr`.
1218 *
a54aa699
AB
1219 * On success, the out parameter `contains` is set with the boolean
1220 * value indicating whether the DIE's range covers `addr`. On failure,
1221 * it remains unchanged.
1222 *
c40a57e5
AB
1223 * Do note that this function advances the position of `die`. If the
1224 * address is found within one of its children, `die` will be pointing
1225 * to that child upon returning from the function, allowing to extract
1226 * the information deemed necessary.
1227 *
a54aa699
AB
1228 * @param die The parent DIE in whose children the address will be
1229 * looked for
1230 * @param addr The address for which to look for in the DIEs
1231 * @param contains Out parameter, true if addr is contained,
1232 * false if not
1233 * @returns Returns 0 on success, -1 on failure
c40a57e5
AB
1234 */
1235static
a54aa699 1236int bin_info_child_die_has_address(struct bt_dwarf_die *die, uint64_t addr, bool *contains)
c40a57e5 1237{
a54aa699
AB
1238 int ret = 0;
1239 bool _contains = false;
c40a57e5
AB
1240
1241 if (!die) {
1242 goto error;
1243 }
1244
1245 ret = bt_dwarf_die_child(die);
1246 if (ret) {
1247 goto error;
1248 }
1249
1250 do {
e6365242 1251 ret = bt_dwarf_die_contains_addr(die, addr, &_contains);
c40a57e5
AB
1252 if (ret) {
1253 goto error;
1254 }
1255
e6365242
FD
1256 if (_contains) {
1257 /*
1258 * The address is within the range of the current DIE
1259 * or its children.
1260 */
1261 int tag;
1262
1263 ret = bt_dwarf_die_get_tag(die, &tag);
c40a57e5
AB
1264 if (ret) {
1265 goto error;
1266 }
1267
e6365242
FD
1268 if (tag == DW_TAG_inlined_subroutine) {
1269 /* Found the tracepoint. */
c40a57e5
AB
1270 goto end;
1271 }
e6365242
FD
1272
1273 if (bt_dwarf_die_has_children(die)) {
1274 /*
1275 * Look for the address in the children DIEs.
1276 */
1277 ret = bt_dwarf_die_child(die);
1278 if (ret) {
1279 goto error;
1280 }
1281 }
c40a57e5
AB
1282 }
1283 } while (bt_dwarf_die_next(die) == 0);
1284
1285end:
a54aa699
AB
1286 *contains = _contains;
1287 return 0;
c40a57e5
AB
1288
1289error:
a54aa699 1290 return -1;
c40a57e5
AB
1291}
1292
1293/**
1294 * Lookup the source location for a given address within a CU, making
1295 * the assumption that it is contained within an inline routine in a
1296 * function.
1297 *
1298 * @param cu bt_dwarf_cu instance in which to look for the address
1299 * @param addr The address for which to look for
1300 * @param src_loc Out parameter, the source location (filename and
1301 * line number) for the address
1302 * @returns 0 on success, -1 on failure
1303 */
1304static
d5ddf820 1305int bin_info_lookup_cu_src_loc_inl(struct bt_dwarf_cu *cu, uint64_t addr,
c40a57e5
AB
1306 struct source_location **src_loc)
1307{
a54aa699
AB
1308 int ret = 0;
1309 bool found = false;
c40a57e5
AB
1310 struct bt_dwarf_die *die = NULL;
1311 struct source_location *_src_loc = NULL;
1312
1313 if (!cu || !src_loc) {
1314 goto error;
1315 }
1316
1317 die = bt_dwarf_die_create(cu);
1318 if (!die) {
1319 goto error;
1320 }
1321
1322 while (bt_dwarf_die_next(die) == 0) {
1323 int tag;
1324
1325 ret = bt_dwarf_die_get_tag(die, &tag);
1326 if (ret) {
1327 goto error;
1328 }
1329
1330 if (tag == DW_TAG_subprogram) {
a54aa699 1331 bool contains = false;
c40a57e5
AB
1332
1333 ret = bt_dwarf_die_contains_addr(die, addr, &contains);
1334 if (ret) {
1335 goto error;
1336 }
1337
1338 if (contains) {
1339 /*
1340 * Try to find an inlined subroutine
1341 * child of this DIE containing addr.
1342 */
a54aa699
AB
1343 ret = bin_info_child_die_has_address(die, addr,
1344 &found);
1345 if(ret) {
1346 goto error;
1347 }
1348
c40a57e5
AB
1349 goto end;
1350 }
1351 }
1352 }
1353
1354end:
1355 if (found) {
1356 char *filename = NULL;
1357 uint64_t line_no;
1358
1359 _src_loc = g_new0(struct source_location, 1);
1360 if (!_src_loc) {
1361 goto error;
1362 }
1363
1364 ret = bt_dwarf_die_get_call_file(die, &filename);
1365 if (ret) {
1366 goto error;
1367 }
1368 ret = bt_dwarf_die_get_call_line(die, &line_no);
1369 if (ret) {
1370 free(filename);
1371 goto error;
1372 }
1373
1374 _src_loc->filename = filename;
1375 _src_loc->line_no = line_no;
1376 *src_loc = _src_loc;
1377 }
1378
1379 bt_dwarf_die_destroy(die);
1380 return 0;
1381
1382error:
1383 source_location_destroy(_src_loc);
1384 bt_dwarf_die_destroy(die);
1385 return -1;
1386}
1387
1388/**
1389 * Lookup the source location for a given address within a CU,
1390 * assuming that it is contained within an inlined function.
1391 *
1392 * A source location can be found regardless of inlining status for
1393 * this method, but in the case of an inlined function, the returned
1394 * source location will point not to the callsite but rather to the
1395 * definition site of the inline function.
1396 *
1397 * @param cu bt_dwarf_cu instance in which to look for the address
1398 * @param addr The address for which to look for
1399 * @param src_loc Out parameter, the source location (filename and
1ed6d0cc
FD
1400 * line number) for the address. Set only if the address
1401 * is found and resolved successfully
1402 *
c40a57e5
AB
1403 * @returns 0 on success, -1 on failure
1404 */
1405static
d5ddf820 1406int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr,
c40a57e5
AB
1407 struct source_location **src_loc)
1408{
1409 struct source_location *_src_loc = NULL;
1410 struct bt_dwarf_die *die = NULL;
1411 const char *filename = NULL;
1412 Dwarf_Line *line = NULL;
1413 Dwarf_Addr line_addr;
f06a3e47 1414 int ret = 0, line_no;
c40a57e5
AB
1415
1416 if (!cu || !src_loc) {
1417 goto error;
1418 }
1419
1420 die = bt_dwarf_die_create(cu);
1421 if (!die) {
1422 goto error;
1423 }
1424
1425 line = dwarf_getsrc_die(die->dwarf_die, addr);
1426 if (!line) {
1ed6d0cc
FD
1427 /* This is not an error. The caller needs to keep looking. */
1428 goto end;
c40a57e5
AB
1429 }
1430
1431 ret = dwarf_lineaddr(line, &line_addr);
1432 if (ret) {
1433 goto error;
1434 }
1435
1436 filename = dwarf_linesrc(line, NULL, NULL);
1437 if (!filename) {
1438 goto error;
1439 }
1440
1441 if (addr == line_addr) {
1442 _src_loc = g_new0(struct source_location, 1);
1443 if (!_src_loc) {
1444 goto error;
1445 }
1446
1447 ret = dwarf_lineno(line, &line_no);
1448 if (ret) {
1449 goto error;
1450 }
1451
1452 _src_loc->line_no = line_no;
06d1cf5d 1453 _src_loc->filename = g_strdup(filename);
c40a57e5
AB
1454 }
1455
c40a57e5
AB
1456 if (_src_loc) {
1457 *src_loc = _src_loc;
1458 }
1459
f06a3e47 1460 goto end;
c40a57e5
AB
1461
1462error:
1463 source_location_destroy(_src_loc);
f06a3e47
FD
1464 ret = -1;
1465end:
c40a57e5 1466 bt_dwarf_die_destroy(die);
f06a3e47 1467 return ret;
c40a57e5
AB
1468}
1469
1470/**
1471 * Get the source location (file name and line number) for a given
1472 * address within a compile unit (CU).
1473 *
1474 * On success, the out parameter `src_loc` is set if found. On
1475 * failure, it remains unchanged.
1476 *
d5ddf820 1477 * @param cu bt_dwarf_cu instance for the compile unit which
c40a57e5
AB
1478 * may contain the address
1479 * @param addr Virtual memory address for which to find the
1480 * source location
1481 * @param src_loc Out parameter, the source location
1482 * @returns 0 on success, -1 on failure
1483 */
1484static
d5ddf820 1485int bin_info_lookup_cu_src_loc(struct bt_dwarf_cu *cu, uint64_t addr,
c40a57e5
AB
1486 struct source_location **src_loc)
1487{
1488 int ret = 0;
1489 struct source_location *_src_loc = NULL;
1490
1491 if (!cu || !src_loc) {
1492 goto error;
1493 }
1494
d5ddf820 1495 ret = bin_info_lookup_cu_src_loc_inl(cu, addr, &_src_loc);
c40a57e5
AB
1496 if (ret) {
1497 goto error;
1498 }
1499
1500 if (_src_loc) {
1501 goto end;
1502 }
1503
d5ddf820 1504 ret = bin_info_lookup_cu_src_loc_no_inl(cu, addr, &_src_loc);
c40a57e5
AB
1505 if (ret) {
1506 goto error;
1507 }
1508
1509 if (_src_loc) {
1510 goto end;
1511 }
1512
1513end:
1514 if (_src_loc) {
1515 *src_loc = _src_loc;
1516 }
1517
1518 return 0;
1519
1520error:
1521 source_location_destroy(_src_loc);
1522 return -1;
1523}
1524
1525BT_HIDDEN
d5ddf820 1526int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr,
c40a57e5
AB
1527 struct source_location **src_loc)
1528{
1529 struct bt_dwarf_cu *cu = NULL;
1530 struct source_location *_src_loc = NULL;
1531
d5ddf820 1532 if (!bin || !src_loc) {
c40a57e5
AB
1533 goto error;
1534 }
1535
ca9f27f3
FD
1536 /*
1537 * If the bin_info has a build id but it does not match the build id
1538 * that was found on the file system, return an error.
1539 */
1540 if (bin->build_id && !bin->file_build_id_matches) {
1541 goto error;
1542 }
1543
c40a57e5 1544 /* Set DWARF info if it hasn't been accessed yet. */
d5ddf820
AB
1545 if (!bin->dwarf_info && !bin->is_elf_only) {
1546 if (bin_info_set_dwarf_info(bin)) {
c40a57e5 1547 /* Failed to set DWARF info. */
d5ddf820 1548 bin->is_elf_only = true;
c40a57e5
AB
1549 }
1550 }
1551
d5ddf820 1552 if (bin->is_elf_only) {
c40a57e5
AB
1553 /* We cannot lookup source location without DWARF info. */
1554 goto error;
1555 }
1556
d5ddf820 1557 if (!bin_info_has_address(bin, addr)) {
c40a57e5
AB
1558 goto error;
1559 }
1560
1561 /*
1562 * Addresses in ELF and DWARF are relative to base address for
1563 * PIC, so make the address argument relative too if needed.
1564 */
d5ddf820
AB
1565 if (bin->is_pic) {
1566 addr -= bin->low_addr;
c40a57e5
AB
1567 }
1568
d5ddf820 1569 cu = bt_dwarf_cu_create(bin->dwarf_info);
c40a57e5
AB
1570 if (!cu) {
1571 goto error;
1572 }
1573
1574 while (bt_dwarf_cu_next(cu) == 0) {
1575 int ret;
1576
d5ddf820 1577 ret = bin_info_lookup_cu_src_loc(cu, addr, &_src_loc);
c40a57e5
AB
1578 if (ret) {
1579 goto error;
1580 }
1581
1582 if (_src_loc) {
1583 break;
1584 }
1585 }
1586
1587 bt_dwarf_cu_destroy(cu);
1588 if (_src_loc) {
1589 *src_loc = _src_loc;
1590 }
1591
1592 return 0;
1593
1594error:
1595 source_location_destroy(_src_loc);
1596 bt_dwarf_cu_destroy(cu);
1597 return -1;
1598}
This page took 0.133414 seconds and 4 git commands to generate.