| .. | .. |
|---|
| 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 */ |
|---|