.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * probe-finder.c : C expression to kprobe event converter |
---|
3 | 4 | * |
---|
4 | 5 | * Written by Masami Hiramatsu <mhiramat@redhat.com> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
9 | | - * (at your option) any later version. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | | - * GNU General Public License for more details. |
---|
15 | | - * |
---|
16 | | - * You should have received a copy of the GNU General Public License |
---|
17 | | - * along with this program; if not, write to the Free Software |
---|
18 | | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
19 | | - * |
---|
20 | 6 | */ |
---|
21 | 7 | |
---|
22 | 8 | #include <inttypes.h> |
---|
.. | .. |
---|
33 | 19 | #include <dwarf-regs.h> |
---|
34 | 20 | |
---|
35 | 21 | #include <linux/bitops.h> |
---|
| 22 | +#include <linux/zalloc.h> |
---|
36 | 23 | #include "event.h" |
---|
37 | 24 | #include "dso.h" |
---|
38 | 25 | #include "debug.h" |
---|
39 | 26 | #include "intlist.h" |
---|
40 | | -#include "util.h" |
---|
| 27 | +#include "strbuf.h" |
---|
41 | 28 | #include "strlist.h" |
---|
42 | 29 | #include "symbol.h" |
---|
43 | 30 | #include "probe-finder.h" |
---|
44 | 31 | #include "probe-file.h" |
---|
45 | 32 | #include "string2.h" |
---|
| 33 | + |
---|
| 34 | +#ifdef HAVE_DEBUGINFOD_SUPPORT |
---|
| 35 | +#include <elfutils/debuginfod.h> |
---|
| 36 | +#endif |
---|
46 | 37 | |
---|
47 | 38 | /* Kprobe tracer basic type is up to u64 */ |
---|
48 | 39 | #define MAX_BASIC_TYPE_BITS 64 |
---|
.. | .. |
---|
64 | 55 | static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, |
---|
65 | 56 | const char *path) |
---|
66 | 57 | { |
---|
| 58 | + GElf_Addr dummy; |
---|
67 | 59 | int fd; |
---|
68 | 60 | |
---|
69 | 61 | fd = open(path, O_RDONLY); |
---|
.. | .. |
---|
82 | 74 | dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); |
---|
83 | 75 | if (!dbg->dbg) |
---|
84 | 76 | goto error; |
---|
| 77 | + |
---|
| 78 | + dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy); |
---|
85 | 79 | |
---|
86 | 80 | dwfl_report_end(dbg->dwfl, NULL, NULL); |
---|
87 | 81 | |
---|
.. | .. |
---|
191 | 185 | if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) |
---|
192 | 186 | goto static_var; |
---|
193 | 187 | |
---|
| 188 | + /* Constant value */ |
---|
| 189 | + if (dwarf_attr(vr_die, DW_AT_const_value, &attr) && |
---|
| 190 | + immediate_value_is_supported()) { |
---|
| 191 | + Dwarf_Sword snum; |
---|
| 192 | + |
---|
| 193 | + if (!tvar) |
---|
| 194 | + return 0; |
---|
| 195 | + |
---|
| 196 | + dwarf_formsdata(&attr, &snum); |
---|
| 197 | + ret = asprintf(&tvar->value, "\\%ld", (long)snum); |
---|
| 198 | + |
---|
| 199 | + return ret < 0 ? -ENOMEM : 0; |
---|
| 200 | + } |
---|
| 201 | + |
---|
194 | 202 | /* TODO: handle more than 1 exprs */ |
---|
195 | 203 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) |
---|
196 | 204 | return -EINVAL; /* Broken DIE ? */ |
---|
.. | .. |
---|
295 | 303 | |
---|
296 | 304 | static int convert_variable_type(Dwarf_Die *vr_die, |
---|
297 | 305 | struct probe_trace_arg *tvar, |
---|
298 | | - const char *cast) |
---|
| 306 | + const char *cast, bool user_access) |
---|
299 | 307 | { |
---|
300 | 308 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; |
---|
301 | 309 | Dwarf_Die type; |
---|
.. | .. |
---|
306 | 314 | char prefix; |
---|
307 | 315 | |
---|
308 | 316 | /* TODO: check all types */ |
---|
309 | | - if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 && |
---|
| 317 | + if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "ustring") && |
---|
| 318 | + strcmp(cast, "x") != 0 && |
---|
310 | 319 | strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) { |
---|
311 | 320 | /* Non string type is OK */ |
---|
312 | 321 | /* and respect signedness/hexadecimal cast */ |
---|
.. | .. |
---|
335 | 344 | pr_debug("%s type is %s.\n", |
---|
336 | 345 | dwarf_diename(vr_die), dwarf_diename(&type)); |
---|
337 | 346 | |
---|
338 | | - if (cast && strcmp(cast, "string") == 0) { /* String type */ |
---|
| 347 | + if (cast && (!strcmp(cast, "string") || !strcmp(cast, "ustring"))) { |
---|
| 348 | + /* String type */ |
---|
339 | 349 | ret = dwarf_tag(&type); |
---|
340 | 350 | if (ret != DW_TAG_pointer_type && |
---|
341 | 351 | ret != DW_TAG_array_type) { |
---|
.. | .. |
---|
358 | 368 | pr_warning("Out of memory error\n"); |
---|
359 | 369 | return -ENOMEM; |
---|
360 | 370 | } |
---|
| 371 | + (*ref_ptr)->user_access = user_access; |
---|
361 | 372 | } |
---|
362 | 373 | if (!die_compare_name(&type, "char") && |
---|
363 | 374 | !die_compare_name(&type, "unsigned char")) { |
---|
.. | .. |
---|
412 | 423 | static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, |
---|
413 | 424 | struct perf_probe_arg_field *field, |
---|
414 | 425 | struct probe_trace_arg_ref **ref_ptr, |
---|
415 | | - Dwarf_Die *die_mem) |
---|
| 426 | + Dwarf_Die *die_mem, bool user_access) |
---|
416 | 427 | { |
---|
417 | 428 | struct probe_trace_arg_ref *ref = *ref_ptr; |
---|
418 | 429 | Dwarf_Die type; |
---|
.. | .. |
---|
449 | 460 | *ref_ptr = ref; |
---|
450 | 461 | } |
---|
451 | 462 | ref->offset += dwarf_bytesize(&type) * field->index; |
---|
| 463 | + ref->user_access = user_access; |
---|
452 | 464 | goto next; |
---|
453 | 465 | } else if (tag == DW_TAG_pointer_type) { |
---|
454 | 466 | /* Check the pointer and dereference */ |
---|
.. | .. |
---|
520 | 532 | } |
---|
521 | 533 | } |
---|
522 | 534 | ref->offset += (long)offs; |
---|
| 535 | + ref->user_access = user_access; |
---|
523 | 536 | |
---|
524 | 537 | /* If this member is unnamed, we need to reuse this field */ |
---|
525 | 538 | if (!dwarf_diename(die_mem)) |
---|
526 | 539 | return convert_variable_fields(die_mem, varname, field, |
---|
527 | | - &ref, die_mem); |
---|
| 540 | + &ref, die_mem, user_access); |
---|
528 | 541 | |
---|
529 | 542 | next: |
---|
530 | 543 | /* Converting next field */ |
---|
531 | 544 | if (field->next) |
---|
532 | 545 | return convert_variable_fields(die_mem, field->name, |
---|
533 | | - field->next, &ref, die_mem); |
---|
| 546 | + field->next, &ref, die_mem, user_access); |
---|
534 | 547 | else |
---|
535 | 548 | return 0; |
---|
| 549 | +} |
---|
| 550 | + |
---|
| 551 | +static void print_var_not_found(const char *varname) |
---|
| 552 | +{ |
---|
| 553 | + pr_err("Failed to find the location of the '%s' variable at this address.\n" |
---|
| 554 | + " Perhaps it has been optimized out.\n" |
---|
| 555 | + " Use -V with the --range option to show '%s' location range.\n", |
---|
| 556 | + varname, varname); |
---|
536 | 557 | } |
---|
537 | 558 | |
---|
538 | 559 | /* Show a variables in kprobe event format */ |
---|
.. | .. |
---|
546 | 567 | |
---|
547 | 568 | ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, |
---|
548 | 569 | &pf->sp_die, pf->machine, pf->tvar); |
---|
| 570 | + if (ret == -ENOENT && pf->skip_empty_arg) |
---|
| 571 | + /* This can be found in other place. skip it */ |
---|
| 572 | + return 0; |
---|
549 | 573 | if (ret == -ENOENT || ret == -EINVAL) { |
---|
550 | | - pr_err("Failed to find the location of the '%s' variable at this address.\n" |
---|
551 | | - " Perhaps it has been optimized out.\n" |
---|
552 | | - " Use -V with the --range option to show '%s' location range.\n", |
---|
553 | | - pf->pvar->var, pf->pvar->var); |
---|
| 574 | + print_var_not_found(pf->pvar->var); |
---|
554 | 575 | } else if (ret == -ENOTSUP) |
---|
555 | 576 | pr_err("Sorry, we don't support this variable location yet.\n"); |
---|
556 | 577 | else if (ret == 0 && pf->pvar->field) { |
---|
557 | 578 | ret = convert_variable_fields(vr_die, pf->pvar->var, |
---|
558 | 579 | pf->pvar->field, &pf->tvar->ref, |
---|
559 | | - &die_mem); |
---|
| 580 | + &die_mem, pf->pvar->user_access); |
---|
560 | 581 | vr_die = &die_mem; |
---|
561 | 582 | } |
---|
562 | 583 | if (ret == 0) |
---|
563 | | - ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); |
---|
| 584 | + ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type, |
---|
| 585 | + pf->pvar->user_access); |
---|
564 | 586 | /* *expr will be cached in libdw. Don't free it. */ |
---|
565 | 587 | return ret; |
---|
566 | 588 | } |
---|
.. | .. |
---|
596 | 618 | /* Search again in global variables */ |
---|
597 | 619 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, |
---|
598 | 620 | 0, &vr_die)) { |
---|
| 621 | + if (pf->skip_empty_arg) |
---|
| 622 | + return 0; |
---|
599 | 623 | pr_warning("Failed to find '%s' in this function.\n", |
---|
600 | 624 | pf->pvar->var); |
---|
601 | 625 | ret = -ENOENT; |
---|
.. | .. |
---|
790 | 814 | return fsp.found ? die_mem : NULL; |
---|
791 | 815 | } |
---|
792 | 816 | |
---|
| 817 | +static int verify_representive_line(struct probe_finder *pf, const char *fname, |
---|
| 818 | + int lineno, Dwarf_Addr addr) |
---|
| 819 | +{ |
---|
| 820 | + const char *__fname, *__func = NULL; |
---|
| 821 | + Dwarf_Die die_mem; |
---|
| 822 | + int __lineno; |
---|
| 823 | + |
---|
| 824 | + /* Verify line number and address by reverse search */ |
---|
| 825 | + if (cu_find_lineinfo(&pf->cu_die, addr, &__fname, &__lineno) < 0) |
---|
| 826 | + return 0; |
---|
| 827 | + |
---|
| 828 | + pr_debug2("Reversed line: %s:%d\n", __fname, __lineno); |
---|
| 829 | + if (strcmp(fname, __fname) || lineno == __lineno) |
---|
| 830 | + return 0; |
---|
| 831 | + |
---|
| 832 | + pr_warning("This line is sharing the address with other lines.\n"); |
---|
| 833 | + |
---|
| 834 | + if (pf->pev->point.function) { |
---|
| 835 | + /* Find best match function name and lines */ |
---|
| 836 | + pf->addr = addr; |
---|
| 837 | + if (find_best_scope(pf, &die_mem) |
---|
| 838 | + && die_match_name(&die_mem, pf->pev->point.function) |
---|
| 839 | + && dwarf_decl_line(&die_mem, &lineno) == 0) { |
---|
| 840 | + __func = dwarf_diename(&die_mem); |
---|
| 841 | + __lineno -= lineno; |
---|
| 842 | + } |
---|
| 843 | + } |
---|
| 844 | + pr_warning("Please try to probe at %s:%d instead.\n", |
---|
| 845 | + __func ? : __fname, __lineno); |
---|
| 846 | + |
---|
| 847 | + return -ENOENT; |
---|
| 848 | +} |
---|
| 849 | + |
---|
793 | 850 | static int probe_point_line_walker(const char *fname, int lineno, |
---|
794 | 851 | Dwarf_Addr addr, void *data) |
---|
795 | 852 | { |
---|
.. | .. |
---|
799 | 856 | |
---|
800 | 857 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
---|
801 | 858 | return 0; |
---|
| 859 | + |
---|
| 860 | + if (verify_representive_line(pf, fname, lineno, addr)) |
---|
| 861 | + return -ENOENT; |
---|
802 | 862 | |
---|
803 | 863 | pf->addr = addr; |
---|
804 | 864 | sc_die = find_best_scope(pf, &die_mem); |
---|
.. | .. |
---|
892 | 952 | /* Find probe points from lazy pattern */ |
---|
893 | 953 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
---|
894 | 954 | { |
---|
| 955 | + struct build_id bid; |
---|
| 956 | + char sbuild_id[SBUILD_ID_SIZE] = ""; |
---|
895 | 957 | int ret = 0; |
---|
896 | 958 | char *fpath; |
---|
897 | 959 | |
---|
.. | .. |
---|
899 | 961 | const char *comp_dir; |
---|
900 | 962 | |
---|
901 | 963 | comp_dir = cu_get_comp_dir(&pf->cu_die); |
---|
902 | | - ret = get_real_path(pf->fname, comp_dir, &fpath); |
---|
| 964 | + if (pf->dbg->build_id) { |
---|
| 965 | + build_id__init(&bid, pf->dbg->build_id, BUILD_ID_SIZE); |
---|
| 966 | + build_id__sprintf(&bid, sbuild_id); |
---|
| 967 | + } |
---|
| 968 | + ret = find_source_path(pf->fname, sbuild_id, comp_dir, &fpath); |
---|
903 | 969 | if (ret < 0) { |
---|
904 | 970 | pr_warning("Failed to find source file path.\n"); |
---|
905 | 971 | return ret; |
---|
.. | .. |
---|
1262 | 1328 | return n; |
---|
1263 | 1329 | } |
---|
1264 | 1330 | |
---|
| 1331 | +static bool trace_event_finder_overlap(struct trace_event_finder *tf) |
---|
| 1332 | +{ |
---|
| 1333 | + int i; |
---|
| 1334 | + |
---|
| 1335 | + for (i = 0; i < tf->ntevs; i++) { |
---|
| 1336 | + if (tf->pf.addr == tf->tevs[i].point.address) |
---|
| 1337 | + return true; |
---|
| 1338 | + } |
---|
| 1339 | + return false; |
---|
| 1340 | +} |
---|
| 1341 | + |
---|
1265 | 1342 | /* Add a found probe point into trace event list */ |
---|
1266 | 1343 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
---|
1267 | 1344 | { |
---|
.. | .. |
---|
1271 | 1348 | struct probe_trace_event *tev; |
---|
1272 | 1349 | struct perf_probe_arg *args = NULL; |
---|
1273 | 1350 | int ret, i; |
---|
| 1351 | + |
---|
| 1352 | + /* |
---|
| 1353 | + * For some reason (e.g. different column assigned to same address) |
---|
| 1354 | + * This callback can be called with the address which already passed. |
---|
| 1355 | + * Ignore it first. |
---|
| 1356 | + */ |
---|
| 1357 | + if (trace_event_finder_overlap(tf)) |
---|
| 1358 | + return 0; |
---|
1274 | 1359 | |
---|
1275 | 1360 | /* Check number of tevs */ |
---|
1276 | 1361 | if (tf->ntevs == tf->max_tevs) { |
---|
.. | .. |
---|
1332 | 1417 | return ret; |
---|
1333 | 1418 | } |
---|
1334 | 1419 | |
---|
| 1420 | +static int fill_empty_trace_arg(struct perf_probe_event *pev, |
---|
| 1421 | + struct probe_trace_event *tevs, int ntevs) |
---|
| 1422 | +{ |
---|
| 1423 | + char **valp; |
---|
| 1424 | + char *type; |
---|
| 1425 | + int i, j, ret; |
---|
| 1426 | + |
---|
| 1427 | + if (!ntevs) |
---|
| 1428 | + return -ENOENT; |
---|
| 1429 | + |
---|
| 1430 | + for (i = 0; i < pev->nargs; i++) { |
---|
| 1431 | + type = NULL; |
---|
| 1432 | + for (j = 0; j < ntevs; j++) { |
---|
| 1433 | + if (tevs[j].args[i].value) { |
---|
| 1434 | + type = tevs[j].args[i].type; |
---|
| 1435 | + break; |
---|
| 1436 | + } |
---|
| 1437 | + } |
---|
| 1438 | + if (j == ntevs) { |
---|
| 1439 | + print_var_not_found(pev->args[i].var); |
---|
| 1440 | + return -ENOENT; |
---|
| 1441 | + } |
---|
| 1442 | + for (j = 0; j < ntevs; j++) { |
---|
| 1443 | + valp = &tevs[j].args[i].value; |
---|
| 1444 | + if (*valp) |
---|
| 1445 | + continue; |
---|
| 1446 | + |
---|
| 1447 | + ret = asprintf(valp, "\\%lx", probe_conf.magic_num); |
---|
| 1448 | + if (ret < 0) |
---|
| 1449 | + return -ENOMEM; |
---|
| 1450 | + /* Note that type can be NULL */ |
---|
| 1451 | + if (type) { |
---|
| 1452 | + tevs[j].args[i].type = strdup(type); |
---|
| 1453 | + if (!tevs[j].args[i].type) |
---|
| 1454 | + return -ENOMEM; |
---|
| 1455 | + } |
---|
| 1456 | + } |
---|
| 1457 | + } |
---|
| 1458 | + return 0; |
---|
| 1459 | +} |
---|
| 1460 | + |
---|
1335 | 1461 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
---|
1336 | 1462 | int debuginfo__find_trace_events(struct debuginfo *dbg, |
---|
1337 | 1463 | struct perf_probe_event *pev, |
---|
1338 | 1464 | struct probe_trace_event **tevs) |
---|
1339 | 1465 | { |
---|
1340 | 1466 | struct trace_event_finder tf = { |
---|
1341 | | - .pf = {.pev = pev, .callback = add_probe_trace_event}, |
---|
| 1467 | + .pf = {.pev = pev, .dbg = dbg, .callback = add_probe_trace_event}, |
---|
1342 | 1468 | .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; |
---|
1343 | 1469 | int ret, i; |
---|
1344 | 1470 | |
---|
.. | .. |
---|
1350 | 1476 | tf.tevs = *tevs; |
---|
1351 | 1477 | tf.ntevs = 0; |
---|
1352 | 1478 | |
---|
| 1479 | + if (pev->nargs != 0 && immediate_value_is_supported()) |
---|
| 1480 | + tf.pf.skip_empty_arg = true; |
---|
| 1481 | + |
---|
1353 | 1482 | ret = debuginfo__find_probes(dbg, &tf.pf); |
---|
| 1483 | + if (ret >= 0 && tf.pf.skip_empty_arg) |
---|
| 1484 | + ret = fill_empty_trace_arg(pev, tf.tevs, tf.ntevs); |
---|
| 1485 | + |
---|
1354 | 1486 | if (ret < 0 || tf.ntevs == 0) { |
---|
1355 | 1487 | for (i = 0; i < tf.ntevs; i++) |
---|
1356 | 1488 | clear_probe_trace_event(&tf.tevs[i]); |
---|
.. | .. |
---|
1502 | 1634 | struct variable_list **vls) |
---|
1503 | 1635 | { |
---|
1504 | 1636 | struct available_var_finder af = { |
---|
1505 | | - .pf = {.pev = pev, .callback = add_available_vars}, |
---|
| 1637 | + .pf = {.pev = pev, .dbg = dbg, .callback = add_available_vars}, |
---|
1506 | 1638 | .mod = dbg->mod, |
---|
1507 | 1639 | .max_vls = probe_conf.max_probes}; |
---|
1508 | 1640 | int ret; |
---|
.. | .. |
---|
1693 | 1825 | void *data) |
---|
1694 | 1826 | { |
---|
1695 | 1827 | struct line_finder *lf = data; |
---|
| 1828 | + const char *__fname; |
---|
| 1829 | + int __lineno; |
---|
1696 | 1830 | int err; |
---|
1697 | 1831 | |
---|
1698 | 1832 | if ((strtailcmp(fname, lf->fname) != 0) || |
---|
1699 | 1833 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
---|
| 1834 | + return 0; |
---|
| 1835 | + |
---|
| 1836 | + /* Make sure this line can be reversable */ |
---|
| 1837 | + if (cu_find_lineinfo(&lf->cu_die, addr, &__fname, &__lineno) > 0 |
---|
| 1838 | + && (lineno != __lineno || strcmp(fname, __fname))) |
---|
1700 | 1839 | return 0; |
---|
1701 | 1840 | |
---|
1702 | 1841 | err = line_range_add_line(fname, lineno, lf->lr); |
---|
.. | .. |
---|
1749 | 1888 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) |
---|
1750 | 1889 | return DWARF_CB_OK; |
---|
1751 | 1890 | |
---|
1752 | | - if (die_is_func_def(sp_die) && |
---|
1753 | | - die_match_name(sp_die, lr->function)) { |
---|
| 1891 | + if (die_match_name(sp_die, lr->function) && die_is_func_def(sp_die)) { |
---|
1754 | 1892 | lf->fname = dwarf_decl_file(sp_die); |
---|
1755 | 1893 | dwarf_decl_line(sp_die, &lr->offset); |
---|
1756 | 1894 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); |
---|
.. | .. |
---|
1850 | 1988 | return (ret < 0) ? ret : lf.found; |
---|
1851 | 1989 | } |
---|
1852 | 1990 | |
---|
| 1991 | +#ifdef HAVE_DEBUGINFOD_SUPPORT |
---|
| 1992 | +/* debuginfod doesn't require the comp_dir but buildid is required */ |
---|
| 1993 | +static int get_source_from_debuginfod(const char *raw_path, |
---|
| 1994 | + const char *sbuild_id, char **new_path) |
---|
| 1995 | +{ |
---|
| 1996 | + debuginfod_client *c = debuginfod_begin(); |
---|
| 1997 | + const char *p = raw_path; |
---|
| 1998 | + int fd; |
---|
| 1999 | + |
---|
| 2000 | + if (!c) |
---|
| 2001 | + return -ENOMEM; |
---|
| 2002 | + |
---|
| 2003 | + fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id, |
---|
| 2004 | + 0, p, new_path); |
---|
| 2005 | + pr_debug("Search %s from debuginfod -> %d\n", p, fd); |
---|
| 2006 | + if (fd >= 0) |
---|
| 2007 | + close(fd); |
---|
| 2008 | + debuginfod_end(c); |
---|
| 2009 | + if (fd < 0) { |
---|
| 2010 | + pr_debug("Failed to find %s in debuginfod (%s)\n", |
---|
| 2011 | + raw_path, sbuild_id); |
---|
| 2012 | + return -ENOENT; |
---|
| 2013 | + } |
---|
| 2014 | + pr_debug("Got a source %s\n", *new_path); |
---|
| 2015 | + |
---|
| 2016 | + return 0; |
---|
| 2017 | +} |
---|
| 2018 | +#else |
---|
| 2019 | +static inline int get_source_from_debuginfod(const char *raw_path __maybe_unused, |
---|
| 2020 | + const char *sbuild_id __maybe_unused, |
---|
| 2021 | + char **new_path __maybe_unused) |
---|
| 2022 | +{ |
---|
| 2023 | + return -ENOTSUP; |
---|
| 2024 | +} |
---|
| 2025 | +#endif |
---|
1853 | 2026 | /* |
---|
1854 | 2027 | * Find a src file from a DWARF tag path. Prepend optional source path prefix |
---|
1855 | 2028 | * and chop off leading directories that do not exist. Result is passed back as |
---|
1856 | 2029 | * a newly allocated path on success. |
---|
1857 | 2030 | * Return 0 if file was found and readable, -errno otherwise. |
---|
1858 | 2031 | */ |
---|
1859 | | -int get_real_path(const char *raw_path, const char *comp_dir, |
---|
1860 | | - char **new_path) |
---|
| 2032 | +int find_source_path(const char *raw_path, const char *sbuild_id, |
---|
| 2033 | + const char *comp_dir, char **new_path) |
---|
1861 | 2034 | { |
---|
1862 | 2035 | const char *prefix = symbol_conf.source_prefix; |
---|
1863 | 2036 | |
---|
| 2037 | + if (sbuild_id && !prefix) { |
---|
| 2038 | + if (!get_source_from_debuginfod(raw_path, sbuild_id, new_path)) |
---|
| 2039 | + return 0; |
---|
| 2040 | + } |
---|
| 2041 | + |
---|
1864 | 2042 | if (!prefix) { |
---|
1865 | 2043 | if (raw_path[0] != '/' && comp_dir) |
---|
1866 | 2044 | /* If not an absolute path, try to use comp_dir */ |
---|