18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * probe-finder.c : C expression to kprobe event converter 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Written by Masami Hiramatsu <mhiramat@redhat.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <inttypes.h> 98c2ecf20Sopenharmony_ci#include <sys/utsname.h> 108c2ecf20Sopenharmony_ci#include <sys/types.h> 118c2ecf20Sopenharmony_ci#include <sys/stat.h> 128c2ecf20Sopenharmony_ci#include <fcntl.h> 138c2ecf20Sopenharmony_ci#include <errno.h> 148c2ecf20Sopenharmony_ci#include <stdio.h> 158c2ecf20Sopenharmony_ci#include <unistd.h> 168c2ecf20Sopenharmony_ci#include <stdlib.h> 178c2ecf20Sopenharmony_ci#include <string.h> 188c2ecf20Sopenharmony_ci#include <stdarg.h> 198c2ecf20Sopenharmony_ci#include <dwarf-regs.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/bitops.h> 228c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 238c2ecf20Sopenharmony_ci#include "event.h" 248c2ecf20Sopenharmony_ci#include "dso.h" 258c2ecf20Sopenharmony_ci#include "debug.h" 268c2ecf20Sopenharmony_ci#include "intlist.h" 278c2ecf20Sopenharmony_ci#include "strbuf.h" 288c2ecf20Sopenharmony_ci#include "strlist.h" 298c2ecf20Sopenharmony_ci#include "symbol.h" 308c2ecf20Sopenharmony_ci#include "probe-finder.h" 318c2ecf20Sopenharmony_ci#include "probe-file.h" 328c2ecf20Sopenharmony_ci#include "string2.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#ifdef HAVE_DEBUGINFOD_SUPPORT 358c2ecf20Sopenharmony_ci#include <elfutils/debuginfod.h> 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Kprobe tracer basic type is up to u64 */ 398c2ecf20Sopenharmony_ci#define MAX_BASIC_TYPE_BITS 64 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Dwarf FL wrappers */ 428c2ecf20Sopenharmony_cistatic char *debuginfo_path; /* Currently dummy */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic const Dwfl_Callbacks offline_callbacks = { 458c2ecf20Sopenharmony_ci .find_debuginfo = dwfl_standard_find_debuginfo, 468c2ecf20Sopenharmony_ci .debuginfo_path = &debuginfo_path, 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci .section_address = dwfl_offline_section_address, 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* We use this table for core files too. */ 518c2ecf20Sopenharmony_ci .find_elf = dwfl_build_id_find_elf, 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Get a Dwarf from offline image */ 558c2ecf20Sopenharmony_cistatic int debuginfo__init_offline_dwarf(struct debuginfo *dbg, 568c2ecf20Sopenharmony_ci const char *path) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci GElf_Addr dummy; 598c2ecf20Sopenharmony_ci int fd; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci fd = open(path, O_RDONLY); 628c2ecf20Sopenharmony_ci if (fd < 0) 638c2ecf20Sopenharmony_ci return fd; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci dbg->dwfl = dwfl_begin(&offline_callbacks); 668c2ecf20Sopenharmony_ci if (!dbg->dwfl) 678c2ecf20Sopenharmony_ci goto error; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci dwfl_report_begin(dbg->dwfl); 708c2ecf20Sopenharmony_ci dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); 718c2ecf20Sopenharmony_ci if (!dbg->mod) 728c2ecf20Sopenharmony_ci goto error; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); 758c2ecf20Sopenharmony_ci if (!dbg->dbg) 768c2ecf20Sopenharmony_ci goto error; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci dwfl_report_end(dbg->dwfl, NULL, NULL); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_cierror: 848c2ecf20Sopenharmony_ci if (dbg->dwfl) 858c2ecf20Sopenharmony_ci dwfl_end(dbg->dwfl); 868c2ecf20Sopenharmony_ci else 878c2ecf20Sopenharmony_ci close(fd); 888c2ecf20Sopenharmony_ci memset(dbg, 0, sizeof(*dbg)); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return -ENOENT; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic struct debuginfo *__debuginfo__new(const char *path) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct debuginfo *dbg = zalloc(sizeof(*dbg)); 968c2ecf20Sopenharmony_ci if (!dbg) 978c2ecf20Sopenharmony_ci return NULL; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (debuginfo__init_offline_dwarf(dbg, path) < 0) 1008c2ecf20Sopenharmony_ci zfree(&dbg); 1018c2ecf20Sopenharmony_ci if (dbg) 1028c2ecf20Sopenharmony_ci pr_debug("Open Debuginfo file: %s\n", path); 1038c2ecf20Sopenharmony_ci return dbg; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cienum dso_binary_type distro_dwarf_types[] = { 1078c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 1088c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 1098c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 1108c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 1118c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO, 1128c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__NOT_FOUND, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistruct debuginfo *debuginfo__new(const char *path) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci enum dso_binary_type *type; 1188c2ecf20Sopenharmony_ci char buf[PATH_MAX], nil = '\0'; 1198c2ecf20Sopenharmony_ci struct dso *dso; 1208c2ecf20Sopenharmony_ci struct debuginfo *dinfo = NULL; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* Try to open distro debuginfo files */ 1238c2ecf20Sopenharmony_ci dso = dso__new(path); 1248c2ecf20Sopenharmony_ci if (!dso) 1258c2ecf20Sopenharmony_ci goto out; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci for (type = distro_dwarf_types; 1288c2ecf20Sopenharmony_ci !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; 1298c2ecf20Sopenharmony_ci type++) { 1308c2ecf20Sopenharmony_ci if (dso__read_binary_type_filename(dso, *type, &nil, 1318c2ecf20Sopenharmony_ci buf, PATH_MAX) < 0) 1328c2ecf20Sopenharmony_ci continue; 1338c2ecf20Sopenharmony_ci dinfo = __debuginfo__new(buf); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci dso__put(dso); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciout: 1388c2ecf20Sopenharmony_ci /* if failed to open all distro debuginfo, open given binary */ 1398c2ecf20Sopenharmony_ci return dinfo ? : __debuginfo__new(path); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_civoid debuginfo__delete(struct debuginfo *dbg) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci if (dbg) { 1458c2ecf20Sopenharmony_ci if (dbg->dwfl) 1468c2ecf20Sopenharmony_ci dwfl_end(dbg->dwfl); 1478c2ecf20Sopenharmony_ci free(dbg); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* 1528c2ecf20Sopenharmony_ci * Probe finder related functions 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct probe_trace_arg_ref *ref; 1588c2ecf20Sopenharmony_ci ref = zalloc(sizeof(struct probe_trace_arg_ref)); 1598c2ecf20Sopenharmony_ci if (ref != NULL) 1608c2ecf20Sopenharmony_ci ref->offset = offs; 1618c2ecf20Sopenharmony_ci return ref; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* 1658c2ecf20Sopenharmony_ci * Convert a location into trace_arg. 1668c2ecf20Sopenharmony_ci * If tvar == NULL, this just checks variable can be converted. 1678c2ecf20Sopenharmony_ci * If fentry == true and vr_die is a parameter, do huristic search 1688c2ecf20Sopenharmony_ci * for the location fuzzed by function entry mcount. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_cistatic int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 1718c2ecf20Sopenharmony_ci Dwarf_Op *fb_ops, Dwarf_Die *sp_die, 1728c2ecf20Sopenharmony_ci unsigned int machine, 1738c2ecf20Sopenharmony_ci struct probe_trace_arg *tvar) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 1768c2ecf20Sopenharmony_ci Dwarf_Addr tmp = 0; 1778c2ecf20Sopenharmony_ci Dwarf_Op *op; 1788c2ecf20Sopenharmony_ci size_t nops; 1798c2ecf20Sopenharmony_ci unsigned int regn; 1808c2ecf20Sopenharmony_ci Dwarf_Word offs = 0; 1818c2ecf20Sopenharmony_ci bool ref = false; 1828c2ecf20Sopenharmony_ci const char *regs; 1838c2ecf20Sopenharmony_ci int ret, ret2 = 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 1868c2ecf20Sopenharmony_ci goto static_var; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Constant value */ 1898c2ecf20Sopenharmony_ci if (dwarf_attr(vr_die, DW_AT_const_value, &attr) && 1908c2ecf20Sopenharmony_ci immediate_value_is_supported()) { 1918c2ecf20Sopenharmony_ci Dwarf_Sword snum; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (!tvar) 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci dwarf_formsdata(&attr, &snum); 1978c2ecf20Sopenharmony_ci ret = asprintf(&tvar->value, "\\%ld", (long)snum); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return ret < 0 ? -ENOMEM : 0; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* TODO: handle more than 1 exprs */ 2038c2ecf20Sopenharmony_ci if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 2048c2ecf20Sopenharmony_ci return -EINVAL; /* Broken DIE ? */ 2058c2ecf20Sopenharmony_ci if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { 2068c2ecf20Sopenharmony_ci ret = dwarf_entrypc(sp_die, &tmp); 2078c2ecf20Sopenharmony_ci if (ret) 2088c2ecf20Sopenharmony_ci return -ENOENT; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (probe_conf.show_location_range && 2118c2ecf20Sopenharmony_ci (dwarf_tag(vr_die) == DW_TAG_variable)) { 2128c2ecf20Sopenharmony_ci ret2 = -ERANGE; 2138c2ecf20Sopenharmony_ci } else if (addr != tmp || 2148c2ecf20Sopenharmony_ci dwarf_tag(vr_die) != DW_TAG_formal_parameter) { 2158c2ecf20Sopenharmony_ci return -ENOENT; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ret = dwarf_highpc(sp_die, &tmp); 2198c2ecf20Sopenharmony_ci if (ret) 2208c2ecf20Sopenharmony_ci return -ENOENT; 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * This is fuzzed by fentry mcount. We try to find the 2238c2ecf20Sopenharmony_ci * parameter location at the earliest address. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci for (addr += 1; addr <= tmp; addr++) { 2268c2ecf20Sopenharmony_ci if (dwarf_getlocation_addr(&attr, addr, &op, 2278c2ecf20Sopenharmony_ci &nops, 1) > 0) 2288c2ecf20Sopenharmony_ci goto found; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci return -ENOENT; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_cifound: 2338c2ecf20Sopenharmony_ci if (nops == 0) 2348c2ecf20Sopenharmony_ci /* TODO: Support const_value */ 2358c2ecf20Sopenharmony_ci return -ENOENT; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (op->atom == DW_OP_addr) { 2388c2ecf20Sopenharmony_cistatic_var: 2398c2ecf20Sopenharmony_ci if (!tvar) 2408c2ecf20Sopenharmony_ci return ret2; 2418c2ecf20Sopenharmony_ci /* Static variables on memory (not stack), make @varname */ 2428c2ecf20Sopenharmony_ci ret = strlen(dwarf_diename(vr_die)); 2438c2ecf20Sopenharmony_ci tvar->value = zalloc(ret + 2); 2448c2ecf20Sopenharmony_ci if (tvar->value == NULL) 2458c2ecf20Sopenharmony_ci return -ENOMEM; 2468c2ecf20Sopenharmony_ci snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 2478c2ecf20Sopenharmony_ci tvar->ref = alloc_trace_arg_ref((long)offs); 2488c2ecf20Sopenharmony_ci if (tvar->ref == NULL) 2498c2ecf20Sopenharmony_ci return -ENOMEM; 2508c2ecf20Sopenharmony_ci return ret2; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* If this is based on frame buffer, set the offset */ 2548c2ecf20Sopenharmony_ci if (op->atom == DW_OP_fbreg) { 2558c2ecf20Sopenharmony_ci if (fb_ops == NULL) 2568c2ecf20Sopenharmony_ci return -ENOTSUP; 2578c2ecf20Sopenharmony_ci ref = true; 2588c2ecf20Sopenharmony_ci offs = op->number; 2598c2ecf20Sopenharmony_ci op = &fb_ops[0]; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 2638c2ecf20Sopenharmony_ci regn = op->atom - DW_OP_breg0; 2648c2ecf20Sopenharmony_ci offs += op->number; 2658c2ecf20Sopenharmony_ci ref = true; 2668c2ecf20Sopenharmony_ci } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 2678c2ecf20Sopenharmony_ci regn = op->atom - DW_OP_reg0; 2688c2ecf20Sopenharmony_ci } else if (op->atom == DW_OP_bregx) { 2698c2ecf20Sopenharmony_ci regn = op->number; 2708c2ecf20Sopenharmony_ci offs += op->number2; 2718c2ecf20Sopenharmony_ci ref = true; 2728c2ecf20Sopenharmony_ci } else if (op->atom == DW_OP_regx) { 2738c2ecf20Sopenharmony_ci regn = op->number; 2748c2ecf20Sopenharmony_ci } else { 2758c2ecf20Sopenharmony_ci pr_debug("DW_OP %x is not supported.\n", op->atom); 2768c2ecf20Sopenharmony_ci return -ENOTSUP; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (!tvar) 2808c2ecf20Sopenharmony_ci return ret2; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci regs = get_dwarf_regstr(regn, machine); 2838c2ecf20Sopenharmony_ci if (!regs) { 2848c2ecf20Sopenharmony_ci /* This should be a bug in DWARF or this tool */ 2858c2ecf20Sopenharmony_ci pr_warning("Mapping for the register number %u " 2868c2ecf20Sopenharmony_ci "missing on this architecture.\n", regn); 2878c2ecf20Sopenharmony_ci return -ENOTSUP; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci tvar->value = strdup(regs); 2918c2ecf20Sopenharmony_ci if (tvar->value == NULL) 2928c2ecf20Sopenharmony_ci return -ENOMEM; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (ref) { 2958c2ecf20Sopenharmony_ci tvar->ref = alloc_trace_arg_ref((long)offs); 2968c2ecf20Sopenharmony_ci if (tvar->ref == NULL) 2978c2ecf20Sopenharmony_ci return -ENOMEM; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci return ret2; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int convert_variable_type(Dwarf_Die *vr_die, 3058c2ecf20Sopenharmony_ci struct probe_trace_arg *tvar, 3068c2ecf20Sopenharmony_ci const char *cast, bool user_access) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 3098c2ecf20Sopenharmony_ci Dwarf_Die type; 3108c2ecf20Sopenharmony_ci char buf[16]; 3118c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 3128c2ecf20Sopenharmony_ci int bsize, boffs, total; 3138c2ecf20Sopenharmony_ci int ret; 3148c2ecf20Sopenharmony_ci char prefix; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* TODO: check all types */ 3178c2ecf20Sopenharmony_ci if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "ustring") && 3188c2ecf20Sopenharmony_ci strcmp(cast, "x") != 0 && 3198c2ecf20Sopenharmony_ci strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) { 3208c2ecf20Sopenharmony_ci /* Non string type is OK */ 3218c2ecf20Sopenharmony_ci /* and respect signedness/hexadecimal cast */ 3228c2ecf20Sopenharmony_ci tvar->type = strdup(cast); 3238c2ecf20Sopenharmony_ci return (tvar->type == NULL) ? -ENOMEM : 0; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci bsize = dwarf_bitsize(vr_die); 3278c2ecf20Sopenharmony_ci if (bsize > 0) { 3288c2ecf20Sopenharmony_ci /* This is a bitfield */ 3298c2ecf20Sopenharmony_ci boffs = dwarf_bitoffset(vr_die); 3308c2ecf20Sopenharmony_ci total = dwarf_bytesize(vr_die); 3318c2ecf20Sopenharmony_ci if (boffs < 0 || total < 0) 3328c2ecf20Sopenharmony_ci return -ENOENT; 3338c2ecf20Sopenharmony_ci ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 3348c2ecf20Sopenharmony_ci BYTES_TO_BITS(total)); 3358c2ecf20Sopenharmony_ci goto formatted; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (die_get_real_type(vr_die, &type) == NULL) { 3398c2ecf20Sopenharmony_ci pr_warning("Failed to get a type information of %s.\n", 3408c2ecf20Sopenharmony_ci dwarf_diename(vr_die)); 3418c2ecf20Sopenharmony_ci return -ENOENT; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci pr_debug("%s type is %s.\n", 3458c2ecf20Sopenharmony_ci dwarf_diename(vr_die), dwarf_diename(&type)); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (cast && (!strcmp(cast, "string") || !strcmp(cast, "ustring"))) { 3488c2ecf20Sopenharmony_ci /* String type */ 3498c2ecf20Sopenharmony_ci ret = dwarf_tag(&type); 3508c2ecf20Sopenharmony_ci if (ret != DW_TAG_pointer_type && 3518c2ecf20Sopenharmony_ci ret != DW_TAG_array_type) { 3528c2ecf20Sopenharmony_ci pr_warning("Failed to cast into string: " 3538c2ecf20Sopenharmony_ci "%s(%s) is not a pointer nor array.\n", 3548c2ecf20Sopenharmony_ci dwarf_diename(vr_die), dwarf_diename(&type)); 3558c2ecf20Sopenharmony_ci return -EINVAL; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci if (die_get_real_type(&type, &type) == NULL) { 3588c2ecf20Sopenharmony_ci pr_warning("Failed to get a type" 3598c2ecf20Sopenharmony_ci " information.\n"); 3608c2ecf20Sopenharmony_ci return -ENOENT; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci if (ret == DW_TAG_pointer_type) { 3638c2ecf20Sopenharmony_ci while (*ref_ptr) 3648c2ecf20Sopenharmony_ci ref_ptr = &(*ref_ptr)->next; 3658c2ecf20Sopenharmony_ci /* Add new reference with offset +0 */ 3668c2ecf20Sopenharmony_ci *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 3678c2ecf20Sopenharmony_ci if (*ref_ptr == NULL) { 3688c2ecf20Sopenharmony_ci pr_warning("Out of memory error\n"); 3698c2ecf20Sopenharmony_ci return -ENOMEM; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci (*ref_ptr)->user_access = user_access; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci if (!die_compare_name(&type, "char") && 3748c2ecf20Sopenharmony_ci !die_compare_name(&type, "unsigned char")) { 3758c2ecf20Sopenharmony_ci pr_warning("Failed to cast into string: " 3768c2ecf20Sopenharmony_ci "%s is not (unsigned) char *.\n", 3778c2ecf20Sopenharmony_ci dwarf_diename(vr_die)); 3788c2ecf20Sopenharmony_ci return -EINVAL; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci tvar->type = strdup(cast); 3818c2ecf20Sopenharmony_ci return (tvar->type == NULL) ? -ENOMEM : 0; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (cast && (strcmp(cast, "u") == 0)) 3858c2ecf20Sopenharmony_ci prefix = 'u'; 3868c2ecf20Sopenharmony_ci else if (cast && (strcmp(cast, "s") == 0)) 3878c2ecf20Sopenharmony_ci prefix = 's'; 3888c2ecf20Sopenharmony_ci else if (cast && (strcmp(cast, "x") == 0) && 3898c2ecf20Sopenharmony_ci probe_type_is_available(PROBE_TYPE_X)) 3908c2ecf20Sopenharmony_ci prefix = 'x'; 3918c2ecf20Sopenharmony_ci else 3928c2ecf20Sopenharmony_ci prefix = die_is_signed_type(&type) ? 's' : 3938c2ecf20Sopenharmony_ci probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u'; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci ret = dwarf_bytesize(&type); 3968c2ecf20Sopenharmony_ci if (ret <= 0) 3978c2ecf20Sopenharmony_ci /* No size ... try to use default type */ 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci ret = BYTES_TO_BITS(ret); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Check the bitwidth */ 4028c2ecf20Sopenharmony_ci if (ret > MAX_BASIC_TYPE_BITS) { 4038c2ecf20Sopenharmony_ci pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 4048c2ecf20Sopenharmony_ci dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 4058c2ecf20Sopenharmony_ci ret = MAX_BASIC_TYPE_BITS; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci ret = snprintf(buf, 16, "%c%d", prefix, ret); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ciformatted: 4108c2ecf20Sopenharmony_ci if (ret < 0 || ret >= 16) { 4118c2ecf20Sopenharmony_ci if (ret >= 16) 4128c2ecf20Sopenharmony_ci ret = -E2BIG; 4138c2ecf20Sopenharmony_ci pr_warning("Failed to convert variable type: %s\n", 4148c2ecf20Sopenharmony_ci str_error_r(-ret, sbuf, sizeof(sbuf))); 4158c2ecf20Sopenharmony_ci return ret; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci tvar->type = strdup(buf); 4188c2ecf20Sopenharmony_ci if (tvar->type == NULL) 4198c2ecf20Sopenharmony_ci return -ENOMEM; 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 4248c2ecf20Sopenharmony_ci struct perf_probe_arg_field *field, 4258c2ecf20Sopenharmony_ci struct probe_trace_arg_ref **ref_ptr, 4268c2ecf20Sopenharmony_ci Dwarf_Die *die_mem, bool user_access) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct probe_trace_arg_ref *ref = *ref_ptr; 4298c2ecf20Sopenharmony_ci Dwarf_Die type; 4308c2ecf20Sopenharmony_ci Dwarf_Word offs; 4318c2ecf20Sopenharmony_ci int ret, tag; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci pr_debug("converting %s in %s\n", field->name, varname); 4348c2ecf20Sopenharmony_ci if (die_get_real_type(vr_die, &type) == NULL) { 4358c2ecf20Sopenharmony_ci pr_warning("Failed to get the type of %s.\n", varname); 4368c2ecf20Sopenharmony_ci return -ENOENT; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci pr_debug2("Var real type: %s (%x)\n", dwarf_diename(&type), 4398c2ecf20Sopenharmony_ci (unsigned)dwarf_dieoffset(&type)); 4408c2ecf20Sopenharmony_ci tag = dwarf_tag(&type); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (field->name[0] == '[' && 4438c2ecf20Sopenharmony_ci (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 4448c2ecf20Sopenharmony_ci /* Save original type for next field or type */ 4458c2ecf20Sopenharmony_ci memcpy(die_mem, &type, sizeof(*die_mem)); 4468c2ecf20Sopenharmony_ci /* Get the type of this array */ 4478c2ecf20Sopenharmony_ci if (die_get_real_type(&type, &type) == NULL) { 4488c2ecf20Sopenharmony_ci pr_warning("Failed to get the type of %s.\n", varname); 4498c2ecf20Sopenharmony_ci return -ENOENT; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci pr_debug2("Array real type: %s (%x)\n", dwarf_diename(&type), 4528c2ecf20Sopenharmony_ci (unsigned)dwarf_dieoffset(&type)); 4538c2ecf20Sopenharmony_ci if (tag == DW_TAG_pointer_type) { 4548c2ecf20Sopenharmony_ci ref = zalloc(sizeof(struct probe_trace_arg_ref)); 4558c2ecf20Sopenharmony_ci if (ref == NULL) 4568c2ecf20Sopenharmony_ci return -ENOMEM; 4578c2ecf20Sopenharmony_ci if (*ref_ptr) 4588c2ecf20Sopenharmony_ci (*ref_ptr)->next = ref; 4598c2ecf20Sopenharmony_ci else 4608c2ecf20Sopenharmony_ci *ref_ptr = ref; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci ref->offset += dwarf_bytesize(&type) * field->index; 4638c2ecf20Sopenharmony_ci ref->user_access = user_access; 4648c2ecf20Sopenharmony_ci goto next; 4658c2ecf20Sopenharmony_ci } else if (tag == DW_TAG_pointer_type) { 4668c2ecf20Sopenharmony_ci /* Check the pointer and dereference */ 4678c2ecf20Sopenharmony_ci if (!field->ref) { 4688c2ecf20Sopenharmony_ci pr_err("Semantic error: %s must be referred by '->'\n", 4698c2ecf20Sopenharmony_ci field->name); 4708c2ecf20Sopenharmony_ci return -EINVAL; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci /* Get the type pointed by this pointer */ 4738c2ecf20Sopenharmony_ci if (die_get_real_type(&type, &type) == NULL) { 4748c2ecf20Sopenharmony_ci pr_warning("Failed to get the type of %s.\n", varname); 4758c2ecf20Sopenharmony_ci return -ENOENT; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci /* Verify it is a data structure */ 4788c2ecf20Sopenharmony_ci tag = dwarf_tag(&type); 4798c2ecf20Sopenharmony_ci if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 4808c2ecf20Sopenharmony_ci pr_warning("%s is not a data structure nor a union.\n", 4818c2ecf20Sopenharmony_ci varname); 4828c2ecf20Sopenharmony_ci return -EINVAL; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci ref = zalloc(sizeof(struct probe_trace_arg_ref)); 4868c2ecf20Sopenharmony_ci if (ref == NULL) 4878c2ecf20Sopenharmony_ci return -ENOMEM; 4888c2ecf20Sopenharmony_ci if (*ref_ptr) 4898c2ecf20Sopenharmony_ci (*ref_ptr)->next = ref; 4908c2ecf20Sopenharmony_ci else 4918c2ecf20Sopenharmony_ci *ref_ptr = ref; 4928c2ecf20Sopenharmony_ci } else { 4938c2ecf20Sopenharmony_ci /* Verify it is a data structure */ 4948c2ecf20Sopenharmony_ci if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 4958c2ecf20Sopenharmony_ci pr_warning("%s is not a data structure nor a union.\n", 4968c2ecf20Sopenharmony_ci varname); 4978c2ecf20Sopenharmony_ci return -EINVAL; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci if (field->name[0] == '[') { 5008c2ecf20Sopenharmony_ci pr_err("Semantic error: %s is not a pointer" 5018c2ecf20Sopenharmony_ci " nor array.\n", varname); 5028c2ecf20Sopenharmony_ci return -EINVAL; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci /* While prcessing unnamed field, we don't care about this */ 5058c2ecf20Sopenharmony_ci if (field->ref && dwarf_diename(vr_die)) { 5068c2ecf20Sopenharmony_ci pr_err("Semantic error: %s must be referred by '.'\n", 5078c2ecf20Sopenharmony_ci field->name); 5088c2ecf20Sopenharmony_ci return -EINVAL; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci if (!ref) { 5118c2ecf20Sopenharmony_ci pr_warning("Structure on a register is not " 5128c2ecf20Sopenharmony_ci "supported yet.\n"); 5138c2ecf20Sopenharmony_ci return -ENOTSUP; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (die_find_member(&type, field->name, die_mem) == NULL) { 5188c2ecf20Sopenharmony_ci pr_warning("%s(type:%s) has no member %s.\n", varname, 5198c2ecf20Sopenharmony_ci dwarf_diename(&type), field->name); 5208c2ecf20Sopenharmony_ci return -EINVAL; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* Get the offset of the field */ 5248c2ecf20Sopenharmony_ci if (tag == DW_TAG_union_type) { 5258c2ecf20Sopenharmony_ci offs = 0; 5268c2ecf20Sopenharmony_ci } else { 5278c2ecf20Sopenharmony_ci ret = die_get_data_member_location(die_mem, &offs); 5288c2ecf20Sopenharmony_ci if (ret < 0) { 5298c2ecf20Sopenharmony_ci pr_warning("Failed to get the offset of %s.\n", 5308c2ecf20Sopenharmony_ci field->name); 5318c2ecf20Sopenharmony_ci return ret; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci ref->offset += (long)offs; 5358c2ecf20Sopenharmony_ci ref->user_access = user_access; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* If this member is unnamed, we need to reuse this field */ 5388c2ecf20Sopenharmony_ci if (!dwarf_diename(die_mem)) 5398c2ecf20Sopenharmony_ci return convert_variable_fields(die_mem, varname, field, 5408c2ecf20Sopenharmony_ci &ref, die_mem, user_access); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cinext: 5438c2ecf20Sopenharmony_ci /* Converting next field */ 5448c2ecf20Sopenharmony_ci if (field->next) 5458c2ecf20Sopenharmony_ci return convert_variable_fields(die_mem, field->name, 5468c2ecf20Sopenharmony_ci field->next, &ref, die_mem, user_access); 5478c2ecf20Sopenharmony_ci else 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic void print_var_not_found(const char *varname) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci pr_err("Failed to find the location of the '%s' variable at this address.\n" 5548c2ecf20Sopenharmony_ci " Perhaps it has been optimized out.\n" 5558c2ecf20Sopenharmony_ci " Use -V with the --range option to show '%s' location range.\n", 5568c2ecf20Sopenharmony_ci varname, varname); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/* Show a variables in kprobe event format */ 5608c2ecf20Sopenharmony_cistatic int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci Dwarf_Die die_mem; 5638c2ecf20Sopenharmony_ci int ret; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci pr_debug("Converting variable %s into trace event.\n", 5668c2ecf20Sopenharmony_ci dwarf_diename(vr_die)); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 5698c2ecf20Sopenharmony_ci &pf->sp_die, pf->machine, pf->tvar); 5708c2ecf20Sopenharmony_ci if (ret == -ENOENT && pf->skip_empty_arg) 5718c2ecf20Sopenharmony_ci /* This can be found in other place. skip it */ 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci if (ret == -ENOENT || ret == -EINVAL) { 5748c2ecf20Sopenharmony_ci print_var_not_found(pf->pvar->var); 5758c2ecf20Sopenharmony_ci } else if (ret == -ENOTSUP) 5768c2ecf20Sopenharmony_ci pr_err("Sorry, we don't support this variable location yet.\n"); 5778c2ecf20Sopenharmony_ci else if (ret == 0 && pf->pvar->field) { 5788c2ecf20Sopenharmony_ci ret = convert_variable_fields(vr_die, pf->pvar->var, 5798c2ecf20Sopenharmony_ci pf->pvar->field, &pf->tvar->ref, 5808c2ecf20Sopenharmony_ci &die_mem, pf->pvar->user_access); 5818c2ecf20Sopenharmony_ci vr_die = &die_mem; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci if (ret == 0) 5848c2ecf20Sopenharmony_ci ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type, 5858c2ecf20Sopenharmony_ci pf->pvar->user_access); 5868c2ecf20Sopenharmony_ci /* *expr will be cached in libdw. Don't free it. */ 5878c2ecf20Sopenharmony_ci return ret; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci/* Find a variable in a scope DIE */ 5918c2ecf20Sopenharmony_cistatic int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci Dwarf_Die vr_die; 5948c2ecf20Sopenharmony_ci char *buf, *ptr; 5958c2ecf20Sopenharmony_ci int ret = 0; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* Copy raw parameters */ 5988c2ecf20Sopenharmony_ci if (!is_c_varname(pf->pvar->var)) 5998c2ecf20Sopenharmony_ci return copy_to_probe_trace_arg(pf->tvar, pf->pvar); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (pf->pvar->name) 6028c2ecf20Sopenharmony_ci pf->tvar->name = strdup(pf->pvar->name); 6038c2ecf20Sopenharmony_ci else { 6048c2ecf20Sopenharmony_ci buf = synthesize_perf_probe_arg(pf->pvar); 6058c2ecf20Sopenharmony_ci if (!buf) 6068c2ecf20Sopenharmony_ci return -ENOMEM; 6078c2ecf20Sopenharmony_ci ptr = strchr(buf, ':'); /* Change type separator to _ */ 6088c2ecf20Sopenharmony_ci if (ptr) 6098c2ecf20Sopenharmony_ci *ptr = '_'; 6108c2ecf20Sopenharmony_ci pf->tvar->name = buf; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci if (pf->tvar->name == NULL) 6138c2ecf20Sopenharmony_ci return -ENOMEM; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 6168c2ecf20Sopenharmony_ci /* Search child die for local variables and parameters. */ 6178c2ecf20Sopenharmony_ci if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 6188c2ecf20Sopenharmony_ci /* Search again in global variables */ 6198c2ecf20Sopenharmony_ci if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 6208c2ecf20Sopenharmony_ci 0, &vr_die)) { 6218c2ecf20Sopenharmony_ci if (pf->skip_empty_arg) 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci pr_warning("Failed to find '%s' in this function.\n", 6248c2ecf20Sopenharmony_ci pf->pvar->var); 6258c2ecf20Sopenharmony_ci ret = -ENOENT; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci if (ret >= 0) 6298c2ecf20Sopenharmony_ci ret = convert_variable(&vr_die, pf); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return ret; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci/* Convert subprogram DIE to trace point */ 6358c2ecf20Sopenharmony_cistatic int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, 6368c2ecf20Sopenharmony_ci Dwarf_Addr paddr, bool retprobe, 6378c2ecf20Sopenharmony_ci const char *function, 6388c2ecf20Sopenharmony_ci struct probe_trace_point *tp) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci Dwarf_Addr eaddr; 6418c2ecf20Sopenharmony_ci GElf_Sym sym; 6428c2ecf20Sopenharmony_ci const char *symbol; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Verify the address is correct */ 6458c2ecf20Sopenharmony_ci if (!dwarf_haspc(sp_die, paddr)) { 6468c2ecf20Sopenharmony_ci pr_warning("Specified offset is out of %s\n", 6478c2ecf20Sopenharmony_ci dwarf_diename(sp_die)); 6488c2ecf20Sopenharmony_ci return -EINVAL; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (dwarf_entrypc(sp_die, &eaddr) == 0) { 6528c2ecf20Sopenharmony_ci /* If the DIE has entrypc, use it. */ 6538c2ecf20Sopenharmony_ci symbol = dwarf_diename(sp_die); 6548c2ecf20Sopenharmony_ci } else { 6558c2ecf20Sopenharmony_ci /* Try to get actual symbol name and address from symtab */ 6568c2ecf20Sopenharmony_ci symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); 6578c2ecf20Sopenharmony_ci eaddr = sym.st_value; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci if (!symbol) { 6608c2ecf20Sopenharmony_ci pr_warning("Failed to find symbol at 0x%lx\n", 6618c2ecf20Sopenharmony_ci (unsigned long)paddr); 6628c2ecf20Sopenharmony_ci return -ENOENT; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci tp->offset = (unsigned long)(paddr - eaddr); 6668c2ecf20Sopenharmony_ci tp->address = (unsigned long)paddr; 6678c2ecf20Sopenharmony_ci tp->symbol = strdup(symbol); 6688c2ecf20Sopenharmony_ci if (!tp->symbol) 6698c2ecf20Sopenharmony_ci return -ENOMEM; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* Return probe must be on the head of a subprogram */ 6728c2ecf20Sopenharmony_ci if (retprobe) { 6738c2ecf20Sopenharmony_ci if (eaddr != paddr) { 6748c2ecf20Sopenharmony_ci pr_warning("Failed to find \"%s%%return\",\n" 6758c2ecf20Sopenharmony_ci " because %s is an inlined function and" 6768c2ecf20Sopenharmony_ci " has no return point.\n", function, 6778c2ecf20Sopenharmony_ci function); 6788c2ecf20Sopenharmony_ci return -EINVAL; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci tp->retprobe = true; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci/* Call probe_finder callback with scope DIE */ 6878c2ecf20Sopenharmony_cistatic int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci Dwarf_Attribute fb_attr; 6908c2ecf20Sopenharmony_ci Dwarf_Frame *frame = NULL; 6918c2ecf20Sopenharmony_ci size_t nops; 6928c2ecf20Sopenharmony_ci int ret; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (!sc_die) { 6958c2ecf20Sopenharmony_ci pr_err("Caller must pass a scope DIE. Program error.\n"); 6968c2ecf20Sopenharmony_ci return -EINVAL; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* If not a real subprogram, find a real one */ 7008c2ecf20Sopenharmony_ci if (!die_is_func_def(sc_die)) { 7018c2ecf20Sopenharmony_ci if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 7028c2ecf20Sopenharmony_ci if (die_find_tailfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 7038c2ecf20Sopenharmony_ci pr_warning("Ignoring tail call from %s\n", 7048c2ecf20Sopenharmony_ci dwarf_diename(&pf->sp_die)); 7058c2ecf20Sopenharmony_ci return 0; 7068c2ecf20Sopenharmony_ci } else { 7078c2ecf20Sopenharmony_ci pr_warning("Failed to find probe point in any " 7088c2ecf20Sopenharmony_ci "functions.\n"); 7098c2ecf20Sopenharmony_ci return -ENOENT; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci } else 7138c2ecf20Sopenharmony_ci memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* Get the frame base attribute/ops from subprogram */ 7168c2ecf20Sopenharmony_ci dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 7178c2ecf20Sopenharmony_ci ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 7188c2ecf20Sopenharmony_ci if (ret <= 0 || nops == 0) { 7198c2ecf20Sopenharmony_ci pf->fb_ops = NULL; 7208c2ecf20Sopenharmony_ci#if _ELFUTILS_PREREQ(0, 142) 7218c2ecf20Sopenharmony_ci } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 7228c2ecf20Sopenharmony_ci (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) { 7238c2ecf20Sopenharmony_ci if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 && 7248c2ecf20Sopenharmony_ci (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) || 7258c2ecf20Sopenharmony_ci dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 7268c2ecf20Sopenharmony_ci pr_warning("Failed to get call frame on 0x%jx\n", 7278c2ecf20Sopenharmony_ci (uintmax_t)pf->addr); 7288c2ecf20Sopenharmony_ci free(frame); 7298c2ecf20Sopenharmony_ci return -ENOENT; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci#endif 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* Call finder's callback handler */ 7358c2ecf20Sopenharmony_ci ret = pf->callback(sc_die, pf); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Since *pf->fb_ops can be a part of frame. we should free it here. */ 7388c2ecf20Sopenharmony_ci free(frame); 7398c2ecf20Sopenharmony_ci pf->fb_ops = NULL; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return ret; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistruct find_scope_param { 7458c2ecf20Sopenharmony_ci const char *function; 7468c2ecf20Sopenharmony_ci const char *file; 7478c2ecf20Sopenharmony_ci int line; 7488c2ecf20Sopenharmony_ci int diff; 7498c2ecf20Sopenharmony_ci Dwarf_Die *die_mem; 7508c2ecf20Sopenharmony_ci bool found; 7518c2ecf20Sopenharmony_ci}; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct find_scope_param *fsp = data; 7568c2ecf20Sopenharmony_ci const char *file; 7578c2ecf20Sopenharmony_ci int lno; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* Skip if declared file name does not match */ 7608c2ecf20Sopenharmony_ci if (fsp->file) { 7618c2ecf20Sopenharmony_ci file = dwarf_decl_file(fn_die); 7628c2ecf20Sopenharmony_ci if (!file || strcmp(fsp->file, file) != 0) 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci /* If the function name is given, that's what user expects */ 7668c2ecf20Sopenharmony_ci if (fsp->function) { 7678c2ecf20Sopenharmony_ci if (die_match_name(fn_die, fsp->function)) { 7688c2ecf20Sopenharmony_ci memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 7698c2ecf20Sopenharmony_ci fsp->found = true; 7708c2ecf20Sopenharmony_ci return 1; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci } else { 7738c2ecf20Sopenharmony_ci /* With the line number, find the nearest declared DIE */ 7748c2ecf20Sopenharmony_ci dwarf_decl_line(fn_die, &lno); 7758c2ecf20Sopenharmony_ci if (lno < fsp->line && fsp->diff > fsp->line - lno) { 7768c2ecf20Sopenharmony_ci /* Keep a candidate and continue */ 7778c2ecf20Sopenharmony_ci fsp->diff = fsp->line - lno; 7788c2ecf20Sopenharmony_ci memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 7798c2ecf20Sopenharmony_ci fsp->found = true; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci/* Return innermost DIE */ 7868c2ecf20Sopenharmony_cistatic int find_inner_scope_cb(Dwarf_Die *fn_die, void *data) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct find_scope_param *fsp = data; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 7918c2ecf20Sopenharmony_ci fsp->found = true; 7928c2ecf20Sopenharmony_ci return 1; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci/* Find an appropriate scope fits to given conditions */ 7968c2ecf20Sopenharmony_cistatic Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct find_scope_param fsp = { 7998c2ecf20Sopenharmony_ci .function = pf->pev->point.function, 8008c2ecf20Sopenharmony_ci .file = pf->fname, 8018c2ecf20Sopenharmony_ci .line = pf->lno, 8028c2ecf20Sopenharmony_ci .diff = INT_MAX, 8038c2ecf20Sopenharmony_ci .die_mem = die_mem, 8048c2ecf20Sopenharmony_ci .found = false, 8058c2ecf20Sopenharmony_ci }; 8068c2ecf20Sopenharmony_ci int ret; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci ret = cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, 8098c2ecf20Sopenharmony_ci &fsp); 8108c2ecf20Sopenharmony_ci if (!ret && !fsp.found) 8118c2ecf20Sopenharmony_ci cu_walk_functions_at(&pf->cu_die, pf->addr, 8128c2ecf20Sopenharmony_ci find_inner_scope_cb, &fsp); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return fsp.found ? die_mem : NULL; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int verify_representive_line(struct probe_finder *pf, const char *fname, 8188c2ecf20Sopenharmony_ci int lineno, Dwarf_Addr addr) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci const char *__fname, *__func = NULL; 8218c2ecf20Sopenharmony_ci Dwarf_Die die_mem; 8228c2ecf20Sopenharmony_ci int __lineno; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Verify line number and address by reverse search */ 8258c2ecf20Sopenharmony_ci if (cu_find_lineinfo(&pf->cu_die, addr, &__fname, &__lineno) < 0) 8268c2ecf20Sopenharmony_ci return 0; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci pr_debug2("Reversed line: %s:%d\n", __fname, __lineno); 8298c2ecf20Sopenharmony_ci if (strcmp(fname, __fname) || lineno == __lineno) 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci pr_warning("This line is sharing the address with other lines.\n"); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (pf->pev->point.function) { 8358c2ecf20Sopenharmony_ci /* Find best match function name and lines */ 8368c2ecf20Sopenharmony_ci pf->addr = addr; 8378c2ecf20Sopenharmony_ci if (find_best_scope(pf, &die_mem) 8388c2ecf20Sopenharmony_ci && die_match_name(&die_mem, pf->pev->point.function) 8398c2ecf20Sopenharmony_ci && dwarf_decl_line(&die_mem, &lineno) == 0) { 8408c2ecf20Sopenharmony_ci __func = dwarf_diename(&die_mem); 8418c2ecf20Sopenharmony_ci __lineno -= lineno; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci pr_warning("Please try to probe at %s:%d instead.\n", 8458c2ecf20Sopenharmony_ci __func ? : __fname, __lineno); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci return -ENOENT; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic int probe_point_line_walker(const char *fname, int lineno, 8518c2ecf20Sopenharmony_ci Dwarf_Addr addr, void *data) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci struct probe_finder *pf = data; 8548c2ecf20Sopenharmony_ci Dwarf_Die *sc_die, die_mem; 8558c2ecf20Sopenharmony_ci int ret; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (verify_representive_line(pf, fname, lineno, addr)) 8618c2ecf20Sopenharmony_ci return -ENOENT; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci pf->addr = addr; 8648c2ecf20Sopenharmony_ci sc_die = find_best_scope(pf, &die_mem); 8658c2ecf20Sopenharmony_ci if (!sc_die) { 8668c2ecf20Sopenharmony_ci pr_warning("Failed to find scope of probe point.\n"); 8678c2ecf20Sopenharmony_ci return -ENOENT; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci ret = call_probe_finder(sc_die, pf); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* Continue if no error, because the line will be in inline function */ 8738c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci/* Find probe point from its line number */ 8778c2ecf20Sopenharmony_cistatic int find_probe_point_by_line(struct probe_finder *pf) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci/* Find lines which match lazy pattern */ 8838c2ecf20Sopenharmony_cistatic int find_lazy_match_lines(struct intlist *list, 8848c2ecf20Sopenharmony_ci const char *fname, const char *pat) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci FILE *fp; 8878c2ecf20Sopenharmony_ci char *line = NULL; 8888c2ecf20Sopenharmony_ci size_t line_len; 8898c2ecf20Sopenharmony_ci ssize_t len; 8908c2ecf20Sopenharmony_ci int count = 0, linenum = 1; 8918c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci fp = fopen(fname, "r"); 8948c2ecf20Sopenharmony_ci if (!fp) { 8958c2ecf20Sopenharmony_ci pr_warning("Failed to open %s: %s\n", fname, 8968c2ecf20Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf))); 8978c2ecf20Sopenharmony_ci return -errno; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci while ((len = getline(&line, &line_len, fp)) > 0) { 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (line[len - 1] == '\n') 9038c2ecf20Sopenharmony_ci line[len - 1] = '\0'; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (strlazymatch(line, pat)) { 9068c2ecf20Sopenharmony_ci intlist__add(list, linenum); 9078c2ecf20Sopenharmony_ci count++; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci linenum++; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (ferror(fp)) 9138c2ecf20Sopenharmony_ci count = -errno; 9148c2ecf20Sopenharmony_ci free(line); 9158c2ecf20Sopenharmony_ci fclose(fp); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (count == 0) 9188c2ecf20Sopenharmony_ci pr_debug("No matched lines found in %s.\n", fname); 9198c2ecf20Sopenharmony_ci return count; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic int probe_point_lazy_walker(const char *fname, int lineno, 9238c2ecf20Sopenharmony_ci Dwarf_Addr addr, void *data) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci struct probe_finder *pf = data; 9268c2ecf20Sopenharmony_ci Dwarf_Die *sc_die, die_mem; 9278c2ecf20Sopenharmony_ci int ret; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (!intlist__has_entry(pf->lcache, lineno) || 9308c2ecf20Sopenharmony_ci strtailcmp(fname, pf->fname) != 0) 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci pr_debug("Probe line found: line:%d addr:0x%llx\n", 9348c2ecf20Sopenharmony_ci lineno, (unsigned long long)addr); 9358c2ecf20Sopenharmony_ci pf->addr = addr; 9368c2ecf20Sopenharmony_ci pf->lno = lineno; 9378c2ecf20Sopenharmony_ci sc_die = find_best_scope(pf, &die_mem); 9388c2ecf20Sopenharmony_ci if (!sc_die) { 9398c2ecf20Sopenharmony_ci pr_warning("Failed to find scope of probe point.\n"); 9408c2ecf20Sopenharmony_ci return -ENOENT; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci ret = call_probe_finder(sc_die, pf); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci /* 9468c2ecf20Sopenharmony_ci * Continue if no error, because the lazy pattern will match 9478c2ecf20Sopenharmony_ci * to other lines 9488c2ecf20Sopenharmony_ci */ 9498c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci/* Find probe points from lazy pattern */ 9538c2ecf20Sopenharmony_cistatic int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci struct build_id bid; 9568c2ecf20Sopenharmony_ci char sbuild_id[SBUILD_ID_SIZE] = ""; 9578c2ecf20Sopenharmony_ci int ret = 0; 9588c2ecf20Sopenharmony_ci char *fpath; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (intlist__empty(pf->lcache)) { 9618c2ecf20Sopenharmony_ci const char *comp_dir; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci comp_dir = cu_get_comp_dir(&pf->cu_die); 9648c2ecf20Sopenharmony_ci if (pf->dbg->build_id) { 9658c2ecf20Sopenharmony_ci build_id__init(&bid, pf->dbg->build_id, BUILD_ID_SIZE); 9668c2ecf20Sopenharmony_ci build_id__sprintf(&bid, sbuild_id); 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci ret = find_source_path(pf->fname, sbuild_id, comp_dir, &fpath); 9698c2ecf20Sopenharmony_ci if (ret < 0) { 9708c2ecf20Sopenharmony_ci pr_warning("Failed to find source file path.\n"); 9718c2ecf20Sopenharmony_ci return ret; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* Matching lazy line pattern */ 9758c2ecf20Sopenharmony_ci ret = find_lazy_match_lines(pf->lcache, fpath, 9768c2ecf20Sopenharmony_ci pf->pev->point.lazy_line); 9778c2ecf20Sopenharmony_ci free(fpath); 9788c2ecf20Sopenharmony_ci if (ret <= 0) 9798c2ecf20Sopenharmony_ci return ret; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct perf_probe_point *pp = &pf->pev->point; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci /* Not uprobe? */ 9908c2ecf20Sopenharmony_ci if (!pf->pev->uprobes) 9918c2ecf20Sopenharmony_ci return; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* Compiled with optimization? */ 9948c2ecf20Sopenharmony_ci if (die_is_optimized_target(&pf->cu_die)) 9958c2ecf20Sopenharmony_ci return; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* Don't know entrypc? */ 9988c2ecf20Sopenharmony_ci if (!pf->addr) 9998c2ecf20Sopenharmony_ci return; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Only FUNC and FUNC@SRC are eligible. */ 10028c2ecf20Sopenharmony_ci if (!pp->function || pp->line || pp->retprobe || pp->lazy_line || 10038c2ecf20Sopenharmony_ci pp->offset || pp->abs_address) 10048c2ecf20Sopenharmony_ci return; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci /* Not interested in func parameter? */ 10078c2ecf20Sopenharmony_ci if (!perf_probe_with_var(pf->pev)) 10088c2ecf20Sopenharmony_ci return; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci pr_info("Target program is compiled without optimization. Skipping prologue.\n" 10118c2ecf20Sopenharmony_ci "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n", 10128c2ecf20Sopenharmony_ci pf->addr); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci die_skip_prologue(sp_die, &pf->cu_die, &pf->addr); 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cistatic int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci struct probe_finder *pf = data; 10208c2ecf20Sopenharmony_ci struct perf_probe_point *pp = &pf->pev->point; 10218c2ecf20Sopenharmony_ci Dwarf_Addr addr; 10228c2ecf20Sopenharmony_ci int ret; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (pp->lazy_line) 10258c2ecf20Sopenharmony_ci ret = find_probe_point_lazy(in_die, pf); 10268c2ecf20Sopenharmony_ci else { 10278c2ecf20Sopenharmony_ci /* Get probe address */ 10288c2ecf20Sopenharmony_ci if (die_entrypc(in_die, &addr) != 0) { 10298c2ecf20Sopenharmony_ci pr_warning("Failed to get entry address of %s.\n", 10308c2ecf20Sopenharmony_ci dwarf_diename(in_die)); 10318c2ecf20Sopenharmony_ci return -ENOENT; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci if (addr == 0) { 10348c2ecf20Sopenharmony_ci pr_debug("%s has no valid entry address. skipped.\n", 10358c2ecf20Sopenharmony_ci dwarf_diename(in_die)); 10368c2ecf20Sopenharmony_ci return -ENOENT; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci pf->addr = addr; 10398c2ecf20Sopenharmony_ci pf->addr += pp->offset; 10408c2ecf20Sopenharmony_ci pr_debug("found inline addr: 0x%jx\n", 10418c2ecf20Sopenharmony_ci (uintmax_t)pf->addr); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci ret = call_probe_finder(in_die, pf); 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci return ret; 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci/* Callback parameter with return value for libdw */ 10508c2ecf20Sopenharmony_cistruct dwarf_callback_param { 10518c2ecf20Sopenharmony_ci void *data; 10528c2ecf20Sopenharmony_ci int retval; 10538c2ecf20Sopenharmony_ci}; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci/* Search function from function name */ 10568c2ecf20Sopenharmony_cistatic int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci struct dwarf_callback_param *param = data; 10598c2ecf20Sopenharmony_ci struct probe_finder *pf = param->data; 10608c2ecf20Sopenharmony_ci struct perf_probe_point *pp = &pf->pev->point; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* Check tag and diename */ 10638c2ecf20Sopenharmony_ci if (!die_is_func_def(sp_die) || 10648c2ecf20Sopenharmony_ci !die_match_name(sp_die, pp->function)) 10658c2ecf20Sopenharmony_ci return DWARF_CB_OK; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* Check declared file */ 10688c2ecf20Sopenharmony_ci if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 10698c2ecf20Sopenharmony_ci return DWARF_CB_OK; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci pr_debug("Matched function: %s [%lx]\n", dwarf_diename(sp_die), 10728c2ecf20Sopenharmony_ci (unsigned long)dwarf_dieoffset(sp_die)); 10738c2ecf20Sopenharmony_ci pf->fname = dwarf_decl_file(sp_die); 10748c2ecf20Sopenharmony_ci if (pp->line) { /* Function relative line */ 10758c2ecf20Sopenharmony_ci dwarf_decl_line(sp_die, &pf->lno); 10768c2ecf20Sopenharmony_ci pf->lno += pp->line; 10778c2ecf20Sopenharmony_ci param->retval = find_probe_point_by_line(pf); 10788c2ecf20Sopenharmony_ci } else if (die_is_func_instance(sp_die)) { 10798c2ecf20Sopenharmony_ci /* Instances always have the entry address */ 10808c2ecf20Sopenharmony_ci die_entrypc(sp_die, &pf->addr); 10818c2ecf20Sopenharmony_ci /* But in some case the entry address is 0 */ 10828c2ecf20Sopenharmony_ci if (pf->addr == 0) { 10838c2ecf20Sopenharmony_ci pr_debug("%s has no entry PC. Skipped\n", 10848c2ecf20Sopenharmony_ci dwarf_diename(sp_die)); 10858c2ecf20Sopenharmony_ci param->retval = 0; 10868c2ecf20Sopenharmony_ci /* Real function */ 10878c2ecf20Sopenharmony_ci } else if (pp->lazy_line) 10888c2ecf20Sopenharmony_ci param->retval = find_probe_point_lazy(sp_die, pf); 10898c2ecf20Sopenharmony_ci else { 10908c2ecf20Sopenharmony_ci skip_prologue(sp_die, pf); 10918c2ecf20Sopenharmony_ci pf->addr += pp->offset; 10928c2ecf20Sopenharmony_ci /* TODO: Check the address in this function */ 10938c2ecf20Sopenharmony_ci param->retval = call_probe_finder(sp_die, pf); 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci } else if (!probe_conf.no_inlines) { 10968c2ecf20Sopenharmony_ci /* Inlined function: search instances */ 10978c2ecf20Sopenharmony_ci param->retval = die_walk_instances(sp_die, 10988c2ecf20Sopenharmony_ci probe_point_inline_cb, (void *)pf); 10998c2ecf20Sopenharmony_ci /* This could be a non-existed inline definition */ 11008c2ecf20Sopenharmony_ci if (param->retval == -ENOENT) 11018c2ecf20Sopenharmony_ci param->retval = 0; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* We need to find other candidates */ 11058c2ecf20Sopenharmony_ci if (strisglob(pp->function) && param->retval >= 0) { 11068c2ecf20Sopenharmony_ci param->retval = 0; /* We have to clear the result */ 11078c2ecf20Sopenharmony_ci return DWARF_CB_OK; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic int find_probe_point_by_func(struct probe_finder *pf) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci struct dwarf_callback_param _param = {.data = (void *)pf, 11168c2ecf20Sopenharmony_ci .retval = 0}; 11178c2ecf20Sopenharmony_ci dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 11188c2ecf20Sopenharmony_ci return _param.retval; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistruct pubname_callback_param { 11228c2ecf20Sopenharmony_ci char *function; 11238c2ecf20Sopenharmony_ci char *file; 11248c2ecf20Sopenharmony_ci Dwarf_Die *cu_die; 11258c2ecf20Sopenharmony_ci Dwarf_Die *sp_die; 11268c2ecf20Sopenharmony_ci int found; 11278c2ecf20Sopenharmony_ci}; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct pubname_callback_param *param = data; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 11348c2ecf20Sopenharmony_ci if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 11358c2ecf20Sopenharmony_ci return DWARF_CB_OK; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (die_match_name(param->sp_die, param->function)) { 11388c2ecf20Sopenharmony_ci if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 11398c2ecf20Sopenharmony_ci return DWARF_CB_OK; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (param->file && 11428c2ecf20Sopenharmony_ci strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 11438c2ecf20Sopenharmony_ci return DWARF_CB_OK; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci param->found = 1; 11468c2ecf20Sopenharmony_ci return DWARF_CB_ABORT; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci return DWARF_CB_OK; 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic int debuginfo__find_probe_location(struct debuginfo *dbg, 11548c2ecf20Sopenharmony_ci struct probe_finder *pf) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci struct perf_probe_point *pp = &pf->pev->point; 11578c2ecf20Sopenharmony_ci Dwarf_Off off, noff; 11588c2ecf20Sopenharmony_ci size_t cuhl; 11598c2ecf20Sopenharmony_ci Dwarf_Die *diep; 11608c2ecf20Sopenharmony_ci int ret = 0; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci off = 0; 11638c2ecf20Sopenharmony_ci pf->lcache = intlist__new(NULL); 11648c2ecf20Sopenharmony_ci if (!pf->lcache) 11658c2ecf20Sopenharmony_ci return -ENOMEM; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci /* Fastpath: lookup by function name from .debug_pubnames section */ 11688c2ecf20Sopenharmony_ci if (pp->function && !strisglob(pp->function)) { 11698c2ecf20Sopenharmony_ci struct pubname_callback_param pubname_param = { 11708c2ecf20Sopenharmony_ci .function = pp->function, 11718c2ecf20Sopenharmony_ci .file = pp->file, 11728c2ecf20Sopenharmony_ci .cu_die = &pf->cu_die, 11738c2ecf20Sopenharmony_ci .sp_die = &pf->sp_die, 11748c2ecf20Sopenharmony_ci .found = 0, 11758c2ecf20Sopenharmony_ci }; 11768c2ecf20Sopenharmony_ci struct dwarf_callback_param probe_param = { 11778c2ecf20Sopenharmony_ci .data = pf, 11788c2ecf20Sopenharmony_ci }; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci dwarf_getpubnames(dbg->dbg, pubname_search_cb, 11818c2ecf20Sopenharmony_ci &pubname_param, 0); 11828c2ecf20Sopenharmony_ci if (pubname_param.found) { 11838c2ecf20Sopenharmony_ci ret = probe_point_search_cb(&pf->sp_die, &probe_param); 11848c2ecf20Sopenharmony_ci if (ret) 11858c2ecf20Sopenharmony_ci goto found; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* Loop on CUs (Compilation Unit) */ 11908c2ecf20Sopenharmony_ci while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 11918c2ecf20Sopenharmony_ci /* Get the DIE(Debugging Information Entry) of this CU */ 11928c2ecf20Sopenharmony_ci diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die); 11938c2ecf20Sopenharmony_ci if (!diep) 11948c2ecf20Sopenharmony_ci continue; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* Check if target file is included. */ 11978c2ecf20Sopenharmony_ci if (pp->file) 11988c2ecf20Sopenharmony_ci pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 11998c2ecf20Sopenharmony_ci else 12008c2ecf20Sopenharmony_ci pf->fname = NULL; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (!pp->file || pf->fname) { 12038c2ecf20Sopenharmony_ci if (pp->function) 12048c2ecf20Sopenharmony_ci ret = find_probe_point_by_func(pf); 12058c2ecf20Sopenharmony_ci else if (pp->lazy_line) 12068c2ecf20Sopenharmony_ci ret = find_probe_point_lazy(&pf->cu_die, pf); 12078c2ecf20Sopenharmony_ci else { 12088c2ecf20Sopenharmony_ci pf->lno = pp->line; 12098c2ecf20Sopenharmony_ci ret = find_probe_point_by_line(pf); 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci if (ret < 0) 12128c2ecf20Sopenharmony_ci break; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci off = noff; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cifound: 12188c2ecf20Sopenharmony_ci intlist__delete(pf->lcache); 12198c2ecf20Sopenharmony_ci pf->lcache = NULL; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci return ret; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci/* Find probe points from debuginfo */ 12258c2ecf20Sopenharmony_cistatic int debuginfo__find_probes(struct debuginfo *dbg, 12268c2ecf20Sopenharmony_ci struct probe_finder *pf) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci int ret = 0; 12298c2ecf20Sopenharmony_ci Elf *elf; 12308c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (pf->cfi_eh || pf->cfi_dbg) 12338c2ecf20Sopenharmony_ci return debuginfo__find_probe_location(dbg, pf); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* Get the call frame information from this dwarf */ 12368c2ecf20Sopenharmony_ci elf = dwarf_getelf(dbg->dbg); 12378c2ecf20Sopenharmony_ci if (elf == NULL) 12388c2ecf20Sopenharmony_ci return -EINVAL; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) 12418c2ecf20Sopenharmony_ci return -EINVAL; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci pf->machine = ehdr.e_machine; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci#if _ELFUTILS_PREREQ(0, 142) 12468c2ecf20Sopenharmony_ci do { 12478c2ecf20Sopenharmony_ci GElf_Shdr shdr; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && 12508c2ecf20Sopenharmony_ci shdr.sh_type == SHT_PROGBITS) 12518c2ecf20Sopenharmony_ci pf->cfi_eh = dwarf_getcfi_elf(elf); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci pf->cfi_dbg = dwarf_getcfi(dbg->dbg); 12548c2ecf20Sopenharmony_ci } while (0); 12558c2ecf20Sopenharmony_ci#endif 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci ret = debuginfo__find_probe_location(dbg, pf); 12588c2ecf20Sopenharmony_ci return ret; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistruct local_vars_finder { 12628c2ecf20Sopenharmony_ci struct probe_finder *pf; 12638c2ecf20Sopenharmony_ci struct perf_probe_arg *args; 12648c2ecf20Sopenharmony_ci bool vars; 12658c2ecf20Sopenharmony_ci int max_args; 12668c2ecf20Sopenharmony_ci int nargs; 12678c2ecf20Sopenharmony_ci int ret; 12688c2ecf20Sopenharmony_ci}; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci/* Collect available variables in this scope */ 12718c2ecf20Sopenharmony_cistatic int copy_variables_cb(Dwarf_Die *die_mem, void *data) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci struct local_vars_finder *vf = data; 12748c2ecf20Sopenharmony_ci struct probe_finder *pf = vf->pf; 12758c2ecf20Sopenharmony_ci int tag; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci tag = dwarf_tag(die_mem); 12788c2ecf20Sopenharmony_ci if (tag == DW_TAG_formal_parameter || 12798c2ecf20Sopenharmony_ci (tag == DW_TAG_variable && vf->vars)) { 12808c2ecf20Sopenharmony_ci if (convert_variable_location(die_mem, vf->pf->addr, 12818c2ecf20Sopenharmony_ci vf->pf->fb_ops, &pf->sp_die, 12828c2ecf20Sopenharmony_ci pf->machine, NULL) == 0) { 12838c2ecf20Sopenharmony_ci vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); 12848c2ecf20Sopenharmony_ci if (vf->args[vf->nargs].var == NULL) { 12858c2ecf20Sopenharmony_ci vf->ret = -ENOMEM; 12868c2ecf20Sopenharmony_ci return DIE_FIND_CB_END; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci pr_debug(" %s", vf->args[vf->nargs].var); 12898c2ecf20Sopenharmony_ci vf->nargs++; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (dwarf_haspc(die_mem, vf->pf->addr)) 12948c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 12958c2ecf20Sopenharmony_ci else 12968c2ecf20Sopenharmony_ci return DIE_FIND_CB_SIBLING; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, 13008c2ecf20Sopenharmony_ci struct perf_probe_arg *args) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci Dwarf_Die die_mem; 13038c2ecf20Sopenharmony_ci int i; 13048c2ecf20Sopenharmony_ci int n = 0; 13058c2ecf20Sopenharmony_ci struct local_vars_finder vf = {.pf = pf, .args = args, .vars = false, 13068c2ecf20Sopenharmony_ci .max_args = MAX_PROBE_ARGS, .ret = 0}; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci for (i = 0; i < pf->pev->nargs; i++) { 13098c2ecf20Sopenharmony_ci /* var never be NULL */ 13108c2ecf20Sopenharmony_ci if (strcmp(pf->pev->args[i].var, PROBE_ARG_VARS) == 0) 13118c2ecf20Sopenharmony_ci vf.vars = true; 13128c2ecf20Sopenharmony_ci else if (strcmp(pf->pev->args[i].var, PROBE_ARG_PARAMS) != 0) { 13138c2ecf20Sopenharmony_ci /* Copy normal argument */ 13148c2ecf20Sopenharmony_ci args[n] = pf->pev->args[i]; 13158c2ecf20Sopenharmony_ci n++; 13168c2ecf20Sopenharmony_ci continue; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci pr_debug("Expanding %s into:", pf->pev->args[i].var); 13198c2ecf20Sopenharmony_ci vf.nargs = n; 13208c2ecf20Sopenharmony_ci /* Special local variables */ 13218c2ecf20Sopenharmony_ci die_find_child(sc_die, copy_variables_cb, (void *)&vf, 13228c2ecf20Sopenharmony_ci &die_mem); 13238c2ecf20Sopenharmony_ci pr_debug(" (%d)\n", vf.nargs - n); 13248c2ecf20Sopenharmony_ci if (vf.ret < 0) 13258c2ecf20Sopenharmony_ci return vf.ret; 13268c2ecf20Sopenharmony_ci n = vf.nargs; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci return n; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic bool trace_event_finder_overlap(struct trace_event_finder *tf) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci int i; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci for (i = 0; i < tf->ntevs; i++) { 13368c2ecf20Sopenharmony_ci if (tf->pf.addr == tf->tevs[i].point.address) 13378c2ecf20Sopenharmony_ci return true; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci return false; 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci/* Add a found probe point into trace event list */ 13438c2ecf20Sopenharmony_cistatic int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct trace_event_finder *tf = 13468c2ecf20Sopenharmony_ci container_of(pf, struct trace_event_finder, pf); 13478c2ecf20Sopenharmony_ci struct perf_probe_point *pp = &pf->pev->point; 13488c2ecf20Sopenharmony_ci struct probe_trace_event *tev; 13498c2ecf20Sopenharmony_ci struct perf_probe_arg *args = NULL; 13508c2ecf20Sopenharmony_ci int ret, i; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* 13538c2ecf20Sopenharmony_ci * For some reason (e.g. different column assigned to same address) 13548c2ecf20Sopenharmony_ci * This callback can be called with the address which already passed. 13558c2ecf20Sopenharmony_ci * Ignore it first. 13568c2ecf20Sopenharmony_ci */ 13578c2ecf20Sopenharmony_ci if (trace_event_finder_overlap(tf)) 13588c2ecf20Sopenharmony_ci return 0; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci /* Check number of tevs */ 13618c2ecf20Sopenharmony_ci if (tf->ntevs == tf->max_tevs) { 13628c2ecf20Sopenharmony_ci pr_warning("Too many( > %d) probe point found.\n", 13638c2ecf20Sopenharmony_ci tf->max_tevs); 13648c2ecf20Sopenharmony_ci return -ERANGE; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci tev = &tf->tevs[tf->ntevs++]; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci /* Trace point should be converted from subprogram DIE */ 13698c2ecf20Sopenharmony_ci ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 13708c2ecf20Sopenharmony_ci pp->retprobe, pp->function, &tev->point); 13718c2ecf20Sopenharmony_ci if (ret < 0) 13728c2ecf20Sopenharmony_ci goto end; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci tev->point.realname = strdup(dwarf_diename(sc_die)); 13758c2ecf20Sopenharmony_ci if (!tev->point.realname) { 13768c2ecf20Sopenharmony_ci ret = -ENOMEM; 13778c2ecf20Sopenharmony_ci goto end; 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 13818c2ecf20Sopenharmony_ci tev->point.offset); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci /* Expand special probe argument if exist */ 13848c2ecf20Sopenharmony_ci args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); 13858c2ecf20Sopenharmony_ci if (args == NULL) { 13868c2ecf20Sopenharmony_ci ret = -ENOMEM; 13878c2ecf20Sopenharmony_ci goto end; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci ret = expand_probe_args(sc_die, pf, args); 13918c2ecf20Sopenharmony_ci if (ret < 0) 13928c2ecf20Sopenharmony_ci goto end; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci tev->nargs = ret; 13958c2ecf20Sopenharmony_ci tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 13968c2ecf20Sopenharmony_ci if (tev->args == NULL) { 13978c2ecf20Sopenharmony_ci ret = -ENOMEM; 13988c2ecf20Sopenharmony_ci goto end; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci /* Find each argument */ 14028c2ecf20Sopenharmony_ci for (i = 0; i < tev->nargs; i++) { 14038c2ecf20Sopenharmony_ci pf->pvar = &args[i]; 14048c2ecf20Sopenharmony_ci pf->tvar = &tev->args[i]; 14058c2ecf20Sopenharmony_ci /* Variable should be found from scope DIE */ 14068c2ecf20Sopenharmony_ci ret = find_variable(sc_die, pf); 14078c2ecf20Sopenharmony_ci if (ret != 0) 14088c2ecf20Sopenharmony_ci break; 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ciend: 14128c2ecf20Sopenharmony_ci if (ret) { 14138c2ecf20Sopenharmony_ci clear_probe_trace_event(tev); 14148c2ecf20Sopenharmony_ci tf->ntevs--; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci free(args); 14178c2ecf20Sopenharmony_ci return ret; 14188c2ecf20Sopenharmony_ci} 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic int fill_empty_trace_arg(struct perf_probe_event *pev, 14218c2ecf20Sopenharmony_ci struct probe_trace_event *tevs, int ntevs) 14228c2ecf20Sopenharmony_ci{ 14238c2ecf20Sopenharmony_ci char **valp; 14248c2ecf20Sopenharmony_ci char *type; 14258c2ecf20Sopenharmony_ci int i, j, ret; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (!ntevs) 14288c2ecf20Sopenharmony_ci return -ENOENT; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci for (i = 0; i < pev->nargs; i++) { 14318c2ecf20Sopenharmony_ci type = NULL; 14328c2ecf20Sopenharmony_ci for (j = 0; j < ntevs; j++) { 14338c2ecf20Sopenharmony_ci if (tevs[j].args[i].value) { 14348c2ecf20Sopenharmony_ci type = tevs[j].args[i].type; 14358c2ecf20Sopenharmony_ci break; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci if (j == ntevs) { 14398c2ecf20Sopenharmony_ci print_var_not_found(pev->args[i].var); 14408c2ecf20Sopenharmony_ci return -ENOENT; 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci for (j = 0; j < ntevs; j++) { 14438c2ecf20Sopenharmony_ci valp = &tevs[j].args[i].value; 14448c2ecf20Sopenharmony_ci if (*valp) 14458c2ecf20Sopenharmony_ci continue; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci ret = asprintf(valp, "\\%lx", probe_conf.magic_num); 14488c2ecf20Sopenharmony_ci if (ret < 0) 14498c2ecf20Sopenharmony_ci return -ENOMEM; 14508c2ecf20Sopenharmony_ci /* Note that type can be NULL */ 14518c2ecf20Sopenharmony_ci if (type) { 14528c2ecf20Sopenharmony_ci tevs[j].args[i].type = strdup(type); 14538c2ecf20Sopenharmony_ci if (!tevs[j].args[i].type) 14548c2ecf20Sopenharmony_ci return -ENOMEM; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci return 0; 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 14628c2ecf20Sopenharmony_ciint debuginfo__find_trace_events(struct debuginfo *dbg, 14638c2ecf20Sopenharmony_ci struct perf_probe_event *pev, 14648c2ecf20Sopenharmony_ci struct probe_trace_event **tevs) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci struct trace_event_finder tf = { 14678c2ecf20Sopenharmony_ci .pf = {.pev = pev, .dbg = dbg, .callback = add_probe_trace_event}, 14688c2ecf20Sopenharmony_ci .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; 14698c2ecf20Sopenharmony_ci int ret, i; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* Allocate result tevs array */ 14728c2ecf20Sopenharmony_ci *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); 14738c2ecf20Sopenharmony_ci if (*tevs == NULL) 14748c2ecf20Sopenharmony_ci return -ENOMEM; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci tf.tevs = *tevs; 14778c2ecf20Sopenharmony_ci tf.ntevs = 0; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (pev->nargs != 0 && immediate_value_is_supported()) 14808c2ecf20Sopenharmony_ci tf.pf.skip_empty_arg = true; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci ret = debuginfo__find_probes(dbg, &tf.pf); 14838c2ecf20Sopenharmony_ci if (ret >= 0 && tf.pf.skip_empty_arg) 14848c2ecf20Sopenharmony_ci ret = fill_empty_trace_arg(pev, tf.tevs, tf.ntevs); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (ret < 0 || tf.ntevs == 0) { 14878c2ecf20Sopenharmony_ci for (i = 0; i < tf.ntevs; i++) 14888c2ecf20Sopenharmony_ci clear_probe_trace_event(&tf.tevs[i]); 14898c2ecf20Sopenharmony_ci zfree(tevs); 14908c2ecf20Sopenharmony_ci return ret; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci return (ret < 0) ? ret : tf.ntevs; 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci/* Collect available variables in this scope */ 14978c2ecf20Sopenharmony_cistatic int collect_variables_cb(Dwarf_Die *die_mem, void *data) 14988c2ecf20Sopenharmony_ci{ 14998c2ecf20Sopenharmony_ci struct available_var_finder *af = data; 15008c2ecf20Sopenharmony_ci struct variable_list *vl; 15018c2ecf20Sopenharmony_ci struct strbuf buf = STRBUF_INIT; 15028c2ecf20Sopenharmony_ci int tag, ret; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci vl = &af->vls[af->nvls - 1]; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci tag = dwarf_tag(die_mem); 15078c2ecf20Sopenharmony_ci if (tag == DW_TAG_formal_parameter || 15088c2ecf20Sopenharmony_ci tag == DW_TAG_variable) { 15098c2ecf20Sopenharmony_ci ret = convert_variable_location(die_mem, af->pf.addr, 15108c2ecf20Sopenharmony_ci af->pf.fb_ops, &af->pf.sp_die, 15118c2ecf20Sopenharmony_ci af->pf.machine, NULL); 15128c2ecf20Sopenharmony_ci if (ret == 0 || ret == -ERANGE) { 15138c2ecf20Sopenharmony_ci int ret2; 15148c2ecf20Sopenharmony_ci bool externs = !af->child; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (strbuf_init(&buf, 64) < 0) 15178c2ecf20Sopenharmony_ci goto error; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (probe_conf.show_location_range) { 15208c2ecf20Sopenharmony_ci if (!externs) 15218c2ecf20Sopenharmony_ci ret2 = strbuf_add(&buf, 15228c2ecf20Sopenharmony_ci ret ? "[INV]\t" : "[VAL]\t", 6); 15238c2ecf20Sopenharmony_ci else 15248c2ecf20Sopenharmony_ci ret2 = strbuf_add(&buf, "[EXT]\t", 6); 15258c2ecf20Sopenharmony_ci if (ret2) 15268c2ecf20Sopenharmony_ci goto error; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci ret2 = die_get_varname(die_mem, &buf); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (!ret2 && probe_conf.show_location_range && 15328c2ecf20Sopenharmony_ci !externs) { 15338c2ecf20Sopenharmony_ci if (strbuf_addch(&buf, '\t') < 0) 15348c2ecf20Sopenharmony_ci goto error; 15358c2ecf20Sopenharmony_ci ret2 = die_get_var_range(&af->pf.sp_die, 15368c2ecf20Sopenharmony_ci die_mem, &buf); 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci pr_debug("Add new var: %s\n", buf.buf); 15408c2ecf20Sopenharmony_ci if (ret2 == 0) { 15418c2ecf20Sopenharmony_ci strlist__add(vl->vars, 15428c2ecf20Sopenharmony_ci strbuf_detach(&buf, NULL)); 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci strbuf_release(&buf); 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 15498c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 15508c2ecf20Sopenharmony_ci else 15518c2ecf20Sopenharmony_ci return DIE_FIND_CB_SIBLING; 15528c2ecf20Sopenharmony_cierror: 15538c2ecf20Sopenharmony_ci strbuf_release(&buf); 15548c2ecf20Sopenharmony_ci pr_debug("Error in strbuf\n"); 15558c2ecf20Sopenharmony_ci return DIE_FIND_CB_END; 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic bool available_var_finder_overlap(struct available_var_finder *af) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci int i; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci for (i = 0; i < af->nvls; i++) { 15638c2ecf20Sopenharmony_ci if (af->pf.addr == af->vls[i].point.address) 15648c2ecf20Sopenharmony_ci return true; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci return false; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci/* Add a found vars into available variables list */ 15718c2ecf20Sopenharmony_cistatic int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci struct available_var_finder *af = 15748c2ecf20Sopenharmony_ci container_of(pf, struct available_var_finder, pf); 15758c2ecf20Sopenharmony_ci struct perf_probe_point *pp = &pf->pev->point; 15768c2ecf20Sopenharmony_ci struct variable_list *vl; 15778c2ecf20Sopenharmony_ci Dwarf_Die die_mem; 15788c2ecf20Sopenharmony_ci int ret; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* 15818c2ecf20Sopenharmony_ci * For some reason (e.g. different column assigned to same address), 15828c2ecf20Sopenharmony_ci * this callback can be called with the address which already passed. 15838c2ecf20Sopenharmony_ci * Ignore it first. 15848c2ecf20Sopenharmony_ci */ 15858c2ecf20Sopenharmony_ci if (available_var_finder_overlap(af)) 15868c2ecf20Sopenharmony_ci return 0; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci /* Check number of tevs */ 15898c2ecf20Sopenharmony_ci if (af->nvls == af->max_vls) { 15908c2ecf20Sopenharmony_ci pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 15918c2ecf20Sopenharmony_ci return -ERANGE; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci vl = &af->vls[af->nvls++]; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci /* Trace point should be converted from subprogram DIE */ 15968c2ecf20Sopenharmony_ci ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, 15978c2ecf20Sopenharmony_ci pp->retprobe, pp->function, &vl->point); 15988c2ecf20Sopenharmony_ci if (ret < 0) 15998c2ecf20Sopenharmony_ci return ret; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 16028c2ecf20Sopenharmony_ci vl->point.offset); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci /* Find local variables */ 16058c2ecf20Sopenharmony_ci vl->vars = strlist__new(NULL, NULL); 16068c2ecf20Sopenharmony_ci if (vl->vars == NULL) 16078c2ecf20Sopenharmony_ci return -ENOMEM; 16088c2ecf20Sopenharmony_ci af->child = true; 16098c2ecf20Sopenharmony_ci die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci /* Find external variables */ 16128c2ecf20Sopenharmony_ci if (!probe_conf.show_ext_vars) 16138c2ecf20Sopenharmony_ci goto out; 16148c2ecf20Sopenharmony_ci /* Don't need to search child DIE for external vars. */ 16158c2ecf20Sopenharmony_ci af->child = false; 16168c2ecf20Sopenharmony_ci die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ciout: 16198c2ecf20Sopenharmony_ci if (strlist__empty(vl->vars)) { 16208c2ecf20Sopenharmony_ci strlist__delete(vl->vars); 16218c2ecf20Sopenharmony_ci vl->vars = NULL; 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci return ret; 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci/* 16288c2ecf20Sopenharmony_ci * Find available variables at given probe point 16298c2ecf20Sopenharmony_ci * Return the number of found probe points. Return 0 if there is no 16308c2ecf20Sopenharmony_ci * matched probe point. Return <0 if an error occurs. 16318c2ecf20Sopenharmony_ci */ 16328c2ecf20Sopenharmony_ciint debuginfo__find_available_vars_at(struct debuginfo *dbg, 16338c2ecf20Sopenharmony_ci struct perf_probe_event *pev, 16348c2ecf20Sopenharmony_ci struct variable_list **vls) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci struct available_var_finder af = { 16378c2ecf20Sopenharmony_ci .pf = {.pev = pev, .dbg = dbg, .callback = add_available_vars}, 16388c2ecf20Sopenharmony_ci .mod = dbg->mod, 16398c2ecf20Sopenharmony_ci .max_vls = probe_conf.max_probes}; 16408c2ecf20Sopenharmony_ci int ret; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci /* Allocate result vls array */ 16438c2ecf20Sopenharmony_ci *vls = zalloc(sizeof(struct variable_list) * af.max_vls); 16448c2ecf20Sopenharmony_ci if (*vls == NULL) 16458c2ecf20Sopenharmony_ci return -ENOMEM; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci af.vls = *vls; 16488c2ecf20Sopenharmony_ci af.nvls = 0; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci ret = debuginfo__find_probes(dbg, &af.pf); 16518c2ecf20Sopenharmony_ci if (ret < 0) { 16528c2ecf20Sopenharmony_ci /* Free vlist for error */ 16538c2ecf20Sopenharmony_ci while (af.nvls--) { 16548c2ecf20Sopenharmony_ci zfree(&af.vls[af.nvls].point.symbol); 16558c2ecf20Sopenharmony_ci strlist__delete(af.vls[af.nvls].vars); 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci zfree(vls); 16588c2ecf20Sopenharmony_ci return ret; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci return (ret < 0) ? ret : af.nvls; 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci/* For the kernel module, we need a special code to get a DIE */ 16658c2ecf20Sopenharmony_ciint debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, 16668c2ecf20Sopenharmony_ci bool adjust_offset) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci int n, i; 16698c2ecf20Sopenharmony_ci Elf32_Word shndx; 16708c2ecf20Sopenharmony_ci Elf_Scn *scn; 16718c2ecf20Sopenharmony_ci Elf *elf; 16728c2ecf20Sopenharmony_ci GElf_Shdr mem, *shdr; 16738c2ecf20Sopenharmony_ci const char *p; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci elf = dwfl_module_getelf(dbg->mod, &dbg->bias); 16768c2ecf20Sopenharmony_ci if (!elf) 16778c2ecf20Sopenharmony_ci return -EINVAL; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci /* Get the number of relocations */ 16808c2ecf20Sopenharmony_ci n = dwfl_module_relocations(dbg->mod); 16818c2ecf20Sopenharmony_ci if (n < 0) 16828c2ecf20Sopenharmony_ci return -ENOENT; 16838c2ecf20Sopenharmony_ci /* Search the relocation related .text section */ 16848c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 16858c2ecf20Sopenharmony_ci p = dwfl_module_relocation_info(dbg->mod, i, &shndx); 16868c2ecf20Sopenharmony_ci if (strcmp(p, ".text") == 0) { 16878c2ecf20Sopenharmony_ci /* OK, get the section header */ 16888c2ecf20Sopenharmony_ci scn = elf_getscn(elf, shndx); 16898c2ecf20Sopenharmony_ci if (!scn) 16908c2ecf20Sopenharmony_ci return -ENOENT; 16918c2ecf20Sopenharmony_ci shdr = gelf_getshdr(scn, &mem); 16928c2ecf20Sopenharmony_ci if (!shdr) 16938c2ecf20Sopenharmony_ci return -ENOENT; 16948c2ecf20Sopenharmony_ci *offs = shdr->sh_addr; 16958c2ecf20Sopenharmony_ci if (adjust_offset) 16968c2ecf20Sopenharmony_ci *offs -= shdr->sh_offset; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci return 0; 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci/* Reverse search */ 17038c2ecf20Sopenharmony_ciint debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, 17048c2ecf20Sopenharmony_ci struct perf_probe_point *ppt) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci Dwarf_Die cudie, spdie, indie; 17078c2ecf20Sopenharmony_ci Dwarf_Addr _addr = 0, baseaddr = 0; 17088c2ecf20Sopenharmony_ci const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; 17098c2ecf20Sopenharmony_ci int baseline = 0, lineno = 0, ret = 0; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci /* We always need to relocate the address for aranges */ 17128c2ecf20Sopenharmony_ci if (debuginfo__get_text_offset(dbg, &baseaddr, false) == 0) 17138c2ecf20Sopenharmony_ci addr += baseaddr; 17148c2ecf20Sopenharmony_ci /* Find cu die */ 17158c2ecf20Sopenharmony_ci if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { 17168c2ecf20Sopenharmony_ci pr_warning("Failed to find debug information for address %lx\n", 17178c2ecf20Sopenharmony_ci addr); 17188c2ecf20Sopenharmony_ci ret = -EINVAL; 17198c2ecf20Sopenharmony_ci goto end; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci /* Find a corresponding line (filename and lineno) */ 17238c2ecf20Sopenharmony_ci cu_find_lineinfo(&cudie, addr, &fname, &lineno); 17248c2ecf20Sopenharmony_ci /* Don't care whether it failed or not */ 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci /* Find a corresponding function (name, baseline and baseaddr) */ 17278c2ecf20Sopenharmony_ci if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 17288c2ecf20Sopenharmony_ci /* Get function entry information */ 17298c2ecf20Sopenharmony_ci func = basefunc = dwarf_diename(&spdie); 17308c2ecf20Sopenharmony_ci if (!func || 17318c2ecf20Sopenharmony_ci die_entrypc(&spdie, &baseaddr) != 0 || 17328c2ecf20Sopenharmony_ci dwarf_decl_line(&spdie, &baseline) != 0) { 17338c2ecf20Sopenharmony_ci lineno = 0; 17348c2ecf20Sopenharmony_ci goto post; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci fname = dwarf_decl_file(&spdie); 17388c2ecf20Sopenharmony_ci if (addr == (unsigned long)baseaddr) { 17398c2ecf20Sopenharmony_ci /* Function entry - Relative line number is 0 */ 17408c2ecf20Sopenharmony_ci lineno = baseline; 17418c2ecf20Sopenharmony_ci goto post; 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci /* Track down the inline functions step by step */ 17458c2ecf20Sopenharmony_ci while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, 17468c2ecf20Sopenharmony_ci &indie)) { 17478c2ecf20Sopenharmony_ci /* There is an inline function */ 17488c2ecf20Sopenharmony_ci if (die_entrypc(&indie, &_addr) == 0 && 17498c2ecf20Sopenharmony_ci _addr == addr) { 17508c2ecf20Sopenharmony_ci /* 17518c2ecf20Sopenharmony_ci * addr is at an inline function entry. 17528c2ecf20Sopenharmony_ci * In this case, lineno should be the call-site 17538c2ecf20Sopenharmony_ci * line number. (overwrite lineinfo) 17548c2ecf20Sopenharmony_ci */ 17558c2ecf20Sopenharmony_ci lineno = die_get_call_lineno(&indie); 17568c2ecf20Sopenharmony_ci fname = die_get_call_file(&indie); 17578c2ecf20Sopenharmony_ci break; 17588c2ecf20Sopenharmony_ci } else { 17598c2ecf20Sopenharmony_ci /* 17608c2ecf20Sopenharmony_ci * addr is in an inline function body. 17618c2ecf20Sopenharmony_ci * Since lineno points one of the lines 17628c2ecf20Sopenharmony_ci * of the inline function, baseline should 17638c2ecf20Sopenharmony_ci * be the entry line of the inline function. 17648c2ecf20Sopenharmony_ci */ 17658c2ecf20Sopenharmony_ci tmp = dwarf_diename(&indie); 17668c2ecf20Sopenharmony_ci if (!tmp || 17678c2ecf20Sopenharmony_ci dwarf_decl_line(&indie, &baseline) != 0) 17688c2ecf20Sopenharmony_ci break; 17698c2ecf20Sopenharmony_ci func = tmp; 17708c2ecf20Sopenharmony_ci spdie = indie; 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci /* Verify the lineno and baseline are in a same file */ 17748c2ecf20Sopenharmony_ci tmp = dwarf_decl_file(&spdie); 17758c2ecf20Sopenharmony_ci if (!tmp || strcmp(tmp, fname) != 0) 17768c2ecf20Sopenharmony_ci lineno = 0; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_cipost: 17808c2ecf20Sopenharmony_ci /* Make a relative line number or an offset */ 17818c2ecf20Sopenharmony_ci if (lineno) 17828c2ecf20Sopenharmony_ci ppt->line = lineno - baseline; 17838c2ecf20Sopenharmony_ci else if (basefunc) { 17848c2ecf20Sopenharmony_ci ppt->offset = addr - (unsigned long)baseaddr; 17858c2ecf20Sopenharmony_ci func = basefunc; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci /* Duplicate strings */ 17898c2ecf20Sopenharmony_ci if (func) { 17908c2ecf20Sopenharmony_ci ppt->function = strdup(func); 17918c2ecf20Sopenharmony_ci if (ppt->function == NULL) { 17928c2ecf20Sopenharmony_ci ret = -ENOMEM; 17938c2ecf20Sopenharmony_ci goto end; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci if (fname) { 17978c2ecf20Sopenharmony_ci ppt->file = strdup(fname); 17988c2ecf20Sopenharmony_ci if (ppt->file == NULL) { 17998c2ecf20Sopenharmony_ci zfree(&ppt->function); 18008c2ecf20Sopenharmony_ci ret = -ENOMEM; 18018c2ecf20Sopenharmony_ci goto end; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ciend: 18058c2ecf20Sopenharmony_ci if (ret == 0 && (fname || func)) 18068c2ecf20Sopenharmony_ci ret = 1; /* Found a point */ 18078c2ecf20Sopenharmony_ci return ret; 18088c2ecf20Sopenharmony_ci} 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci/* Add a line and store the src path */ 18118c2ecf20Sopenharmony_cistatic int line_range_add_line(const char *src, unsigned int lineno, 18128c2ecf20Sopenharmony_ci struct line_range *lr) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci /* Copy source path */ 18158c2ecf20Sopenharmony_ci if (!lr->path) { 18168c2ecf20Sopenharmony_ci lr->path = strdup(src); 18178c2ecf20Sopenharmony_ci if (lr->path == NULL) 18188c2ecf20Sopenharmony_ci return -ENOMEM; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci return intlist__add(lr->line_list, lineno); 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic int line_range_walk_cb(const char *fname, int lineno, 18248c2ecf20Sopenharmony_ci Dwarf_Addr addr __maybe_unused, 18258c2ecf20Sopenharmony_ci void *data) 18268c2ecf20Sopenharmony_ci{ 18278c2ecf20Sopenharmony_ci struct line_finder *lf = data; 18288c2ecf20Sopenharmony_ci const char *__fname; 18298c2ecf20Sopenharmony_ci int __lineno; 18308c2ecf20Sopenharmony_ci int err; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci if ((strtailcmp(fname, lf->fname) != 0) || 18338c2ecf20Sopenharmony_ci (lf->lno_s > lineno || lf->lno_e < lineno)) 18348c2ecf20Sopenharmony_ci return 0; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* Make sure this line can be reversable */ 18378c2ecf20Sopenharmony_ci if (cu_find_lineinfo(&lf->cu_die, addr, &__fname, &__lineno) > 0 18388c2ecf20Sopenharmony_ci && (lineno != __lineno || strcmp(fname, __fname))) 18398c2ecf20Sopenharmony_ci return 0; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci err = line_range_add_line(fname, lineno, lf->lr); 18428c2ecf20Sopenharmony_ci if (err < 0 && err != -EEXIST) 18438c2ecf20Sopenharmony_ci return err; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci return 0; 18468c2ecf20Sopenharmony_ci} 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci/* Find line range from its line number */ 18498c2ecf20Sopenharmony_cistatic int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 18508c2ecf20Sopenharmony_ci{ 18518c2ecf20Sopenharmony_ci int ret; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* Update status */ 18568c2ecf20Sopenharmony_ci if (ret >= 0) 18578c2ecf20Sopenharmony_ci if (!intlist__empty(lf->lr->line_list)) 18588c2ecf20Sopenharmony_ci ret = lf->found = 1; 18598c2ecf20Sopenharmony_ci else 18608c2ecf20Sopenharmony_ci ret = 0; /* Lines are not found */ 18618c2ecf20Sopenharmony_ci else { 18628c2ecf20Sopenharmony_ci zfree(&lf->lr->path); 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci return ret; 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic int line_range_inline_cb(Dwarf_Die *in_die, void *data) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci int ret = find_line_range_by_line(in_die, data); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci /* 18728c2ecf20Sopenharmony_ci * We have to check all instances of inlined function, because 18738c2ecf20Sopenharmony_ci * some execution paths can be optimized out depends on the 18748c2ecf20Sopenharmony_ci * function argument of instances. However, if an error occurs, 18758c2ecf20Sopenharmony_ci * it should be handled by the caller. 18768c2ecf20Sopenharmony_ci */ 18778c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 18788c2ecf20Sopenharmony_ci} 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci/* Search function definition from function name */ 18818c2ecf20Sopenharmony_cistatic int line_range_search_cb(Dwarf_Die *sp_die, void *data) 18828c2ecf20Sopenharmony_ci{ 18838c2ecf20Sopenharmony_ci struct dwarf_callback_param *param = data; 18848c2ecf20Sopenharmony_ci struct line_finder *lf = param->data; 18858c2ecf20Sopenharmony_ci struct line_range *lr = lf->lr; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci /* Check declared file */ 18888c2ecf20Sopenharmony_ci if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 18898c2ecf20Sopenharmony_ci return DWARF_CB_OK; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci if (die_match_name(sp_die, lr->function) && die_is_func_def(sp_die)) { 18928c2ecf20Sopenharmony_ci lf->fname = dwarf_decl_file(sp_die); 18938c2ecf20Sopenharmony_ci dwarf_decl_line(sp_die, &lr->offset); 18948c2ecf20Sopenharmony_ci pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 18958c2ecf20Sopenharmony_ci lf->lno_s = lr->offset + lr->start; 18968c2ecf20Sopenharmony_ci if (lf->lno_s < 0) /* Overflow */ 18978c2ecf20Sopenharmony_ci lf->lno_s = INT_MAX; 18988c2ecf20Sopenharmony_ci lf->lno_e = lr->offset + lr->end; 18998c2ecf20Sopenharmony_ci if (lf->lno_e < 0) /* Overflow */ 19008c2ecf20Sopenharmony_ci lf->lno_e = INT_MAX; 19018c2ecf20Sopenharmony_ci pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 19028c2ecf20Sopenharmony_ci lr->start = lf->lno_s; 19038c2ecf20Sopenharmony_ci lr->end = lf->lno_e; 19048c2ecf20Sopenharmony_ci if (!die_is_func_instance(sp_die)) 19058c2ecf20Sopenharmony_ci param->retval = die_walk_instances(sp_die, 19068c2ecf20Sopenharmony_ci line_range_inline_cb, lf); 19078c2ecf20Sopenharmony_ci else 19088c2ecf20Sopenharmony_ci param->retval = find_line_range_by_line(sp_die, lf); 19098c2ecf20Sopenharmony_ci return DWARF_CB_ABORT; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci return DWARF_CB_OK; 19128c2ecf20Sopenharmony_ci} 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_cistatic int find_line_range_by_func(struct line_finder *lf) 19158c2ecf20Sopenharmony_ci{ 19168c2ecf20Sopenharmony_ci struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 19178c2ecf20Sopenharmony_ci dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 19188c2ecf20Sopenharmony_ci return param.retval; 19198c2ecf20Sopenharmony_ci} 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ciint debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr) 19228c2ecf20Sopenharmony_ci{ 19238c2ecf20Sopenharmony_ci struct line_finder lf = {.lr = lr, .found = 0}; 19248c2ecf20Sopenharmony_ci int ret = 0; 19258c2ecf20Sopenharmony_ci Dwarf_Off off = 0, noff; 19268c2ecf20Sopenharmony_ci size_t cuhl; 19278c2ecf20Sopenharmony_ci Dwarf_Die *diep; 19288c2ecf20Sopenharmony_ci const char *comp_dir; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci /* Fastpath: lookup by function name from .debug_pubnames section */ 19318c2ecf20Sopenharmony_ci if (lr->function) { 19328c2ecf20Sopenharmony_ci struct pubname_callback_param pubname_param = { 19338c2ecf20Sopenharmony_ci .function = lr->function, .file = lr->file, 19348c2ecf20Sopenharmony_ci .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 19358c2ecf20Sopenharmony_ci struct dwarf_callback_param line_range_param = { 19368c2ecf20Sopenharmony_ci .data = (void *)&lf, .retval = 0}; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci dwarf_getpubnames(dbg->dbg, pubname_search_cb, 19398c2ecf20Sopenharmony_ci &pubname_param, 0); 19408c2ecf20Sopenharmony_ci if (pubname_param.found) { 19418c2ecf20Sopenharmony_ci line_range_search_cb(&lf.sp_die, &line_range_param); 19428c2ecf20Sopenharmony_ci if (lf.found) 19438c2ecf20Sopenharmony_ci goto found; 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci /* Loop on CUs (Compilation Unit) */ 19488c2ecf20Sopenharmony_ci while (!lf.found && ret >= 0) { 19498c2ecf20Sopenharmony_ci if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, 19508c2ecf20Sopenharmony_ci NULL, NULL, NULL) != 0) 19518c2ecf20Sopenharmony_ci break; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci /* Get the DIE(Debugging Information Entry) of this CU */ 19548c2ecf20Sopenharmony_ci diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die); 19558c2ecf20Sopenharmony_ci if (!diep) 19568c2ecf20Sopenharmony_ci continue; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci /* Check if target file is included. */ 19598c2ecf20Sopenharmony_ci if (lr->file) 19608c2ecf20Sopenharmony_ci lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 19618c2ecf20Sopenharmony_ci else 19628c2ecf20Sopenharmony_ci lf.fname = 0; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci if (!lr->file || lf.fname) { 19658c2ecf20Sopenharmony_ci if (lr->function) 19668c2ecf20Sopenharmony_ci ret = find_line_range_by_func(&lf); 19678c2ecf20Sopenharmony_ci else { 19688c2ecf20Sopenharmony_ci lf.lno_s = lr->start; 19698c2ecf20Sopenharmony_ci lf.lno_e = lr->end; 19708c2ecf20Sopenharmony_ci ret = find_line_range_by_line(NULL, &lf); 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci off = noff; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_cifound: 19778c2ecf20Sopenharmony_ci /* Store comp_dir */ 19788c2ecf20Sopenharmony_ci if (lf.found) { 19798c2ecf20Sopenharmony_ci comp_dir = cu_get_comp_dir(&lf.cu_die); 19808c2ecf20Sopenharmony_ci if (comp_dir) { 19818c2ecf20Sopenharmony_ci lr->comp_dir = strdup(comp_dir); 19828c2ecf20Sopenharmony_ci if (!lr->comp_dir) 19838c2ecf20Sopenharmony_ci ret = -ENOMEM; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci pr_debug("path: %s\n", lr->path); 19888c2ecf20Sopenharmony_ci return (ret < 0) ? ret : lf.found; 19898c2ecf20Sopenharmony_ci} 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci#ifdef HAVE_DEBUGINFOD_SUPPORT 19928c2ecf20Sopenharmony_ci/* debuginfod doesn't require the comp_dir but buildid is required */ 19938c2ecf20Sopenharmony_cistatic int get_source_from_debuginfod(const char *raw_path, 19948c2ecf20Sopenharmony_ci const char *sbuild_id, char **new_path) 19958c2ecf20Sopenharmony_ci{ 19968c2ecf20Sopenharmony_ci debuginfod_client *c = debuginfod_begin(); 19978c2ecf20Sopenharmony_ci const char *p = raw_path; 19988c2ecf20Sopenharmony_ci int fd; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci if (!c) 20018c2ecf20Sopenharmony_ci return -ENOMEM; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id, 20048c2ecf20Sopenharmony_ci 0, p, new_path); 20058c2ecf20Sopenharmony_ci pr_debug("Search %s from debuginfod -> %d\n", p, fd); 20068c2ecf20Sopenharmony_ci if (fd >= 0) 20078c2ecf20Sopenharmony_ci close(fd); 20088c2ecf20Sopenharmony_ci debuginfod_end(c); 20098c2ecf20Sopenharmony_ci if (fd < 0) { 20108c2ecf20Sopenharmony_ci pr_debug("Failed to find %s in debuginfod (%s)\n", 20118c2ecf20Sopenharmony_ci raw_path, sbuild_id); 20128c2ecf20Sopenharmony_ci return -ENOENT; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci pr_debug("Got a source %s\n", *new_path); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci return 0; 20178c2ecf20Sopenharmony_ci} 20188c2ecf20Sopenharmony_ci#else 20198c2ecf20Sopenharmony_cistatic inline int get_source_from_debuginfod(const char *raw_path __maybe_unused, 20208c2ecf20Sopenharmony_ci const char *sbuild_id __maybe_unused, 20218c2ecf20Sopenharmony_ci char **new_path __maybe_unused) 20228c2ecf20Sopenharmony_ci{ 20238c2ecf20Sopenharmony_ci return -ENOTSUP; 20248c2ecf20Sopenharmony_ci} 20258c2ecf20Sopenharmony_ci#endif 20268c2ecf20Sopenharmony_ci/* 20278c2ecf20Sopenharmony_ci * Find a src file from a DWARF tag path. Prepend optional source path prefix 20288c2ecf20Sopenharmony_ci * and chop off leading directories that do not exist. Result is passed back as 20298c2ecf20Sopenharmony_ci * a newly allocated path on success. 20308c2ecf20Sopenharmony_ci * Return 0 if file was found and readable, -errno otherwise. 20318c2ecf20Sopenharmony_ci */ 20328c2ecf20Sopenharmony_ciint find_source_path(const char *raw_path, const char *sbuild_id, 20338c2ecf20Sopenharmony_ci const char *comp_dir, char **new_path) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci const char *prefix = symbol_conf.source_prefix; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci if (sbuild_id && !prefix) { 20388c2ecf20Sopenharmony_ci if (!get_source_from_debuginfod(raw_path, sbuild_id, new_path)) 20398c2ecf20Sopenharmony_ci return 0; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci if (!prefix) { 20438c2ecf20Sopenharmony_ci if (raw_path[0] != '/' && comp_dir) 20448c2ecf20Sopenharmony_ci /* If not an absolute path, try to use comp_dir */ 20458c2ecf20Sopenharmony_ci prefix = comp_dir; 20468c2ecf20Sopenharmony_ci else { 20478c2ecf20Sopenharmony_ci if (access(raw_path, R_OK) == 0) { 20488c2ecf20Sopenharmony_ci *new_path = strdup(raw_path); 20498c2ecf20Sopenharmony_ci return *new_path ? 0 : -ENOMEM; 20508c2ecf20Sopenharmony_ci } else 20518c2ecf20Sopenharmony_ci return -errno; 20528c2ecf20Sopenharmony_ci } 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 20568c2ecf20Sopenharmony_ci if (!*new_path) 20578c2ecf20Sopenharmony_ci return -ENOMEM; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci for (;;) { 20608c2ecf20Sopenharmony_ci sprintf(*new_path, "%s/%s", prefix, raw_path); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci if (access(*new_path, R_OK) == 0) 20638c2ecf20Sopenharmony_ci return 0; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci if (!symbol_conf.source_prefix) { 20668c2ecf20Sopenharmony_ci /* In case of searching comp_dir, don't retry */ 20678c2ecf20Sopenharmony_ci zfree(new_path); 20688c2ecf20Sopenharmony_ci return -errno; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci switch (errno) { 20728c2ecf20Sopenharmony_ci case ENAMETOOLONG: 20738c2ecf20Sopenharmony_ci case ENOENT: 20748c2ecf20Sopenharmony_ci case EROFS: 20758c2ecf20Sopenharmony_ci case EFAULT: 20768c2ecf20Sopenharmony_ci raw_path = strchr(++raw_path, '/'); 20778c2ecf20Sopenharmony_ci if (!raw_path) { 20788c2ecf20Sopenharmony_ci zfree(new_path); 20798c2ecf20Sopenharmony_ci return -ENOENT; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci continue; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci default: 20848c2ecf20Sopenharmony_ci zfree(new_path); 20858c2ecf20Sopenharmony_ci return -errno; 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci } 20888c2ecf20Sopenharmony_ci} 2089