14ea42b18SMasami Hiramatsu /* 24ea42b18SMasami Hiramatsu * probe-finder.c : C expression to kprobe event converter 34ea42b18SMasami Hiramatsu * 44ea42b18SMasami Hiramatsu * Written by Masami Hiramatsu <mhiramat@redhat.com> 54ea42b18SMasami Hiramatsu * 64ea42b18SMasami Hiramatsu * This program is free software; you can redistribute it and/or modify 74ea42b18SMasami Hiramatsu * it under the terms of the GNU General Public License as published by 84ea42b18SMasami Hiramatsu * the Free Software Foundation; either version 2 of the License, or 94ea42b18SMasami Hiramatsu * (at your option) any later version. 104ea42b18SMasami Hiramatsu * 114ea42b18SMasami Hiramatsu * This program is distributed in the hope that it will be useful, 124ea42b18SMasami Hiramatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 134ea42b18SMasami Hiramatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 144ea42b18SMasami Hiramatsu * GNU General Public License for more details. 154ea42b18SMasami Hiramatsu * 164ea42b18SMasami Hiramatsu * You should have received a copy of the GNU General Public License 174ea42b18SMasami Hiramatsu * along with this program; if not, write to the Free Software 184ea42b18SMasami Hiramatsu * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 194ea42b18SMasami Hiramatsu * 204ea42b18SMasami Hiramatsu */ 214ea42b18SMasami Hiramatsu 224ea42b18SMasami Hiramatsu #include <sys/utsname.h> 234ea42b18SMasami Hiramatsu #include <sys/types.h> 244ea42b18SMasami Hiramatsu #include <sys/stat.h> 254ea42b18SMasami Hiramatsu #include <fcntl.h> 264ea42b18SMasami Hiramatsu #include <errno.h> 274ea42b18SMasami Hiramatsu #include <stdio.h> 284ea42b18SMasami Hiramatsu #include <unistd.h> 294ea42b18SMasami Hiramatsu #include <stdlib.h> 304ea42b18SMasami Hiramatsu #include <string.h> 314ea42b18SMasami Hiramatsu #include <stdarg.h> 32cd932c59SIan Munsie #include <dwarf-regs.h> 33074fc0e4SMasami Hiramatsu 34124bb83cSMasami Hiramatsu #include <linux/bitops.h> 3589c69c0eSMasami Hiramatsu #include "event.h" 36a15ad2f5SMasami Hiramatsu #include "dso.h" 3789c69c0eSMasami Hiramatsu #include "debug.h" 385a62257aSMasami Hiramatsu #include "intlist.h" 39074fc0e4SMasami Hiramatsu #include "util.h" 409ed7e1b8SChase Douglas #include "symbol.h" 414ea42b18SMasami Hiramatsu #include "probe-finder.h" 424ea42b18SMasami Hiramatsu 434984912eSMasami Hiramatsu /* Kprobe tracer basic type is up to u64 */ 444984912eSMasami Hiramatsu #define MAX_BASIC_TYPE_BITS 64 454984912eSMasami Hiramatsu 46469b9b88SMasami Hiramatsu /* Dwarf FL wrappers */ 47469b9b88SMasami Hiramatsu static char *debuginfo_path; /* Currently dummy */ 48469b9b88SMasami Hiramatsu 49469b9b88SMasami Hiramatsu static const Dwfl_Callbacks offline_callbacks = { 50469b9b88SMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 51469b9b88SMasami Hiramatsu .debuginfo_path = &debuginfo_path, 52469b9b88SMasami Hiramatsu 53469b9b88SMasami Hiramatsu .section_address = dwfl_offline_section_address, 54469b9b88SMasami Hiramatsu 55469b9b88SMasami Hiramatsu /* We use this table for core files too. */ 56469b9b88SMasami Hiramatsu .find_elf = dwfl_build_id_find_elf, 57469b9b88SMasami Hiramatsu }; 58469b9b88SMasami Hiramatsu 59469b9b88SMasami Hiramatsu /* Get a Dwarf from offline image */ 60316c7136SArnaldo Carvalho de Melo static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, 61ff741783SMasami Hiramatsu const char *path) 62469b9b88SMasami Hiramatsu { 63ff741783SMasami Hiramatsu int fd; 64469b9b88SMasami Hiramatsu 65ff741783SMasami Hiramatsu fd = open(path, O_RDONLY); 66ff741783SMasami Hiramatsu if (fd < 0) 67ff741783SMasami Hiramatsu return fd; 68469b9b88SMasami Hiramatsu 69316c7136SArnaldo Carvalho de Melo dbg->dwfl = dwfl_begin(&offline_callbacks); 70316c7136SArnaldo Carvalho de Melo if (!dbg->dwfl) 71ff741783SMasami Hiramatsu goto error; 72469b9b88SMasami Hiramatsu 73316c7136SArnaldo Carvalho de Melo dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); 74316c7136SArnaldo Carvalho de Melo if (!dbg->mod) 75469b9b88SMasami Hiramatsu goto error; 76469b9b88SMasami Hiramatsu 77316c7136SArnaldo Carvalho de Melo dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); 78316c7136SArnaldo Carvalho de Melo if (!dbg->dbg) 79ff741783SMasami Hiramatsu goto error; 80ff741783SMasami Hiramatsu 81ff741783SMasami Hiramatsu return 0; 82469b9b88SMasami Hiramatsu error: 83316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 84316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 85ff741783SMasami Hiramatsu else 86ff741783SMasami Hiramatsu close(fd); 87316c7136SArnaldo Carvalho de Melo memset(dbg, 0, sizeof(*dbg)); 88ff741783SMasami Hiramatsu 89ff741783SMasami Hiramatsu return -ENOENT; 90469b9b88SMasami Hiramatsu } 91469b9b88SMasami Hiramatsu 92a15ad2f5SMasami Hiramatsu static struct debuginfo *__debuginfo__new(const char *path) 93ff741783SMasami Hiramatsu { 94316c7136SArnaldo Carvalho de Melo struct debuginfo *dbg = zalloc(sizeof(*dbg)); 95316c7136SArnaldo Carvalho de Melo if (!dbg) 96ff741783SMasami Hiramatsu return NULL; 97ff741783SMasami Hiramatsu 9804662523SArnaldo Carvalho de Melo if (debuginfo__init_offline_dwarf(dbg, path) < 0) 9904662523SArnaldo Carvalho de Melo zfree(&dbg); 100a15ad2f5SMasami Hiramatsu if (dbg) 101a15ad2f5SMasami Hiramatsu pr_debug("Open Debuginfo file: %s\n", path); 102316c7136SArnaldo Carvalho de Melo return dbg; 103ff741783SMasami Hiramatsu } 104ff741783SMasami Hiramatsu 105a15ad2f5SMasami Hiramatsu enum dso_binary_type distro_dwarf_types[] = { 106a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 107a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 108a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 109a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 110a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__NOT_FOUND, 111a15ad2f5SMasami Hiramatsu }; 112a15ad2f5SMasami Hiramatsu 113a15ad2f5SMasami Hiramatsu struct debuginfo *debuginfo__new(const char *path) 114a15ad2f5SMasami Hiramatsu { 115a15ad2f5SMasami Hiramatsu enum dso_binary_type *type; 116a15ad2f5SMasami Hiramatsu char buf[PATH_MAX], nil = '\0'; 117a15ad2f5SMasami Hiramatsu struct dso *dso; 118a15ad2f5SMasami Hiramatsu struct debuginfo *dinfo = NULL; 119a15ad2f5SMasami Hiramatsu 120a15ad2f5SMasami Hiramatsu /* Try to open distro debuginfo files */ 121a15ad2f5SMasami Hiramatsu dso = dso__new(path); 122a15ad2f5SMasami Hiramatsu if (!dso) 123a15ad2f5SMasami Hiramatsu goto out; 124a15ad2f5SMasami Hiramatsu 125a15ad2f5SMasami Hiramatsu for (type = distro_dwarf_types; 126a15ad2f5SMasami Hiramatsu !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; 127a15ad2f5SMasami Hiramatsu type++) { 128a15ad2f5SMasami Hiramatsu if (dso__read_binary_type_filename(dso, *type, &nil, 129a15ad2f5SMasami Hiramatsu buf, PATH_MAX) < 0) 130a15ad2f5SMasami Hiramatsu continue; 131a15ad2f5SMasami Hiramatsu dinfo = __debuginfo__new(buf); 132a15ad2f5SMasami Hiramatsu } 133*d3a7c489SArnaldo Carvalho de Melo dso__put(dso); 134a15ad2f5SMasami Hiramatsu 135a15ad2f5SMasami Hiramatsu out: 136a15ad2f5SMasami Hiramatsu /* if failed to open all distro debuginfo, open given binary */ 137a15ad2f5SMasami Hiramatsu return dinfo ? : __debuginfo__new(path); 138a15ad2f5SMasami Hiramatsu } 139a15ad2f5SMasami Hiramatsu 140316c7136SArnaldo Carvalho de Melo void debuginfo__delete(struct debuginfo *dbg) 141ff741783SMasami Hiramatsu { 142316c7136SArnaldo Carvalho de Melo if (dbg) { 143316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 144316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 145316c7136SArnaldo Carvalho de Melo free(dbg); 146ff741783SMasami Hiramatsu } 147ff741783SMasami Hiramatsu } 148ff741783SMasami Hiramatsu 1494ea42b18SMasami Hiramatsu /* 1504ea42b18SMasami Hiramatsu * Probe finder related functions 1514ea42b18SMasami Hiramatsu */ 1524ea42b18SMasami Hiramatsu 1530e60836bSSrikar Dronamraju static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 1544ea42b18SMasami Hiramatsu { 1550e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref; 1560e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 157b7dcb857SMasami Hiramatsu if (ref != NULL) 158b7dcb857SMasami Hiramatsu ref->offset = offs; 159b7dcb857SMasami Hiramatsu return ref; 160b7dcb857SMasami Hiramatsu } 161b7dcb857SMasami Hiramatsu 162cf6eb489SMasami Hiramatsu /* 163cf6eb489SMasami Hiramatsu * Convert a location into trace_arg. 164cf6eb489SMasami Hiramatsu * If tvar == NULL, this just checks variable can be converted. 1653d918a12SMasami Hiramatsu * If fentry == true and vr_die is a parameter, do huristic search 1663d918a12SMasami Hiramatsu * for the location fuzzed by function entry mcount. 167cf6eb489SMasami Hiramatsu */ 168cf6eb489SMasami Hiramatsu static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 1693d918a12SMasami Hiramatsu Dwarf_Op *fb_ops, Dwarf_Die *sp_die, 170cf6eb489SMasami Hiramatsu struct probe_trace_arg *tvar) 171b7dcb857SMasami Hiramatsu { 172b7dcb857SMasami Hiramatsu Dwarf_Attribute attr; 1733d918a12SMasami Hiramatsu Dwarf_Addr tmp = 0; 174b7dcb857SMasami Hiramatsu Dwarf_Op *op; 175b7dcb857SMasami Hiramatsu size_t nops; 176804b3606SMasami Hiramatsu unsigned int regn; 177804b3606SMasami Hiramatsu Dwarf_Word offs = 0; 1784235b045SMasami Hiramatsu bool ref = false; 1794ea42b18SMasami Hiramatsu const char *regs; 180349e8d26SHe Kuang int ret, ret2 = 0; 181b7dcb857SMasami Hiramatsu 182632941c4SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 183632941c4SMasami Hiramatsu goto static_var; 184632941c4SMasami Hiramatsu 185b7dcb857SMasami Hiramatsu /* TODO: handle more than 1 exprs */ 1863d918a12SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 1873d918a12SMasami Hiramatsu return -EINVAL; /* Broken DIE ? */ 1883d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { 1893d918a12SMasami Hiramatsu ret = dwarf_entrypc(sp_die, &tmp); 190349e8d26SHe Kuang if (ret) 191349e8d26SHe Kuang return -ENOENT; 192349e8d26SHe Kuang 193349e8d26SHe Kuang if (probe_conf.show_location_range && 194349e8d26SHe Kuang (dwarf_tag(vr_die) == DW_TAG_variable)) { 195349e8d26SHe Kuang ret2 = -ERANGE; 196349e8d26SHe Kuang } else if (addr != tmp || 197349e8d26SHe Kuang dwarf_tag(vr_die) != DW_TAG_formal_parameter) { 198349e8d26SHe Kuang return -ENOENT; 199349e8d26SHe Kuang } 200349e8d26SHe Kuang 201349e8d26SHe Kuang ret = dwarf_highpc(sp_die, &tmp); 202349e8d26SHe Kuang if (ret) 2033d918a12SMasami Hiramatsu return -ENOENT; 2043d918a12SMasami Hiramatsu /* 2053d918a12SMasami Hiramatsu * This is fuzzed by fentry mcount. We try to find the 2063d918a12SMasami Hiramatsu * parameter location at the earliest address. 2073d918a12SMasami Hiramatsu */ 2083d918a12SMasami Hiramatsu for (addr += 1; addr <= tmp; addr++) { 2093d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, 2103d918a12SMasami Hiramatsu &nops, 1) > 0) 2113d918a12SMasami Hiramatsu goto found; 2123d918a12SMasami Hiramatsu } 213b7dcb857SMasami Hiramatsu return -ENOENT; 214b7dcb857SMasami Hiramatsu } 2153d918a12SMasami Hiramatsu found: 2163d918a12SMasami Hiramatsu if (nops == 0) 2173d918a12SMasami Hiramatsu /* TODO: Support const_value */ 2183d918a12SMasami Hiramatsu return -ENOENT; 219b7dcb857SMasami Hiramatsu 220b7dcb857SMasami Hiramatsu if (op->atom == DW_OP_addr) { 221632941c4SMasami Hiramatsu static_var: 222cf6eb489SMasami Hiramatsu if (!tvar) 223349e8d26SHe Kuang return ret2; 224b7dcb857SMasami Hiramatsu /* Static variables on memory (not stack), make @varname */ 225b7dcb857SMasami Hiramatsu ret = strlen(dwarf_diename(vr_die)); 226b7dcb857SMasami Hiramatsu tvar->value = zalloc(ret + 2); 227b7dcb857SMasami Hiramatsu if (tvar->value == NULL) 228b7dcb857SMasami Hiramatsu return -ENOMEM; 229b7dcb857SMasami Hiramatsu snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 230b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 231b7dcb857SMasami Hiramatsu if (tvar->ref == NULL) 232b7dcb857SMasami Hiramatsu return -ENOMEM; 233349e8d26SHe Kuang return ret2; 234b7dcb857SMasami Hiramatsu } 2354ea42b18SMasami Hiramatsu 2364ea42b18SMasami Hiramatsu /* If this is based on frame buffer, set the offset */ 237804b3606SMasami Hiramatsu if (op->atom == DW_OP_fbreg) { 238cf6eb489SMasami Hiramatsu if (fb_ops == NULL) 239b55a87adSMasami Hiramatsu return -ENOTSUP; 2404235b045SMasami Hiramatsu ref = true; 241804b3606SMasami Hiramatsu offs = op->number; 242cf6eb489SMasami Hiramatsu op = &fb_ops[0]; 243804b3606SMasami Hiramatsu } 2444ea42b18SMasami Hiramatsu 245804b3606SMasami Hiramatsu if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 246804b3606SMasami Hiramatsu regn = op->atom - DW_OP_breg0; 247804b3606SMasami Hiramatsu offs += op->number; 2484235b045SMasami Hiramatsu ref = true; 249804b3606SMasami Hiramatsu } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 250804b3606SMasami Hiramatsu regn = op->atom - DW_OP_reg0; 251804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_bregx) { 252804b3606SMasami Hiramatsu regn = op->number; 253804b3606SMasami Hiramatsu offs += op->number2; 2544235b045SMasami Hiramatsu ref = true; 255804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_regx) { 256804b3606SMasami Hiramatsu regn = op->number; 257b55a87adSMasami Hiramatsu } else { 258cf6eb489SMasami Hiramatsu pr_debug("DW_OP %x is not supported.\n", op->atom); 259b55a87adSMasami Hiramatsu return -ENOTSUP; 260b55a87adSMasami Hiramatsu } 2614ea42b18SMasami Hiramatsu 262cf6eb489SMasami Hiramatsu if (!tvar) 263349e8d26SHe Kuang return ret2; 264cf6eb489SMasami Hiramatsu 2654ea42b18SMasami Hiramatsu regs = get_arch_regstr(regn); 266b55a87adSMasami Hiramatsu if (!regs) { 267cf6eb489SMasami Hiramatsu /* This should be a bug in DWARF or this tool */ 2680e43e5d2SMasami Hiramatsu pr_warning("Mapping for the register number %u " 2690e43e5d2SMasami Hiramatsu "missing on this architecture.\n", regn); 270349e8d26SHe Kuang return -ENOTSUP; 271b55a87adSMasami Hiramatsu } 2724ea42b18SMasami Hiramatsu 27302b95dadSMasami Hiramatsu tvar->value = strdup(regs); 27402b95dadSMasami Hiramatsu if (tvar->value == NULL) 27502b95dadSMasami Hiramatsu return -ENOMEM; 27602b95dadSMasami Hiramatsu 2774235b045SMasami Hiramatsu if (ref) { 278b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 279e334016fSMasami Hiramatsu if (tvar->ref == NULL) 280e334016fSMasami Hiramatsu return -ENOMEM; 2814235b045SMasami Hiramatsu } 282349e8d26SHe Kuang return ret2; 2834ea42b18SMasami Hiramatsu } 2844ea42b18SMasami Hiramatsu 285124bb83cSMasami Hiramatsu #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 286124bb83cSMasami Hiramatsu 287b55a87adSMasami Hiramatsu static int convert_variable_type(Dwarf_Die *vr_die, 2880e60836bSSrikar Dronamraju struct probe_trace_arg *tvar, 28973317b95SMasami Hiramatsu const char *cast) 2904984912eSMasami Hiramatsu { 2910e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 2924984912eSMasami Hiramatsu Dwarf_Die type; 2934984912eSMasami Hiramatsu char buf[16]; 2945f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 295bcfc0821SMasami Hiramatsu int bsize, boffs, total; 2964984912eSMasami Hiramatsu int ret; 2974984912eSMasami Hiramatsu 29873317b95SMasami Hiramatsu /* TODO: check all types */ 29973317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") != 0) { 30073317b95SMasami Hiramatsu /* Non string type is OK */ 30173317b95SMasami Hiramatsu tvar->type = strdup(cast); 30273317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 30373317b95SMasami Hiramatsu } 30473317b95SMasami Hiramatsu 305bcfc0821SMasami Hiramatsu bsize = dwarf_bitsize(vr_die); 306bcfc0821SMasami Hiramatsu if (bsize > 0) { 307124bb83cSMasami Hiramatsu /* This is a bitfield */ 308bcfc0821SMasami Hiramatsu boffs = dwarf_bitoffset(vr_die); 309bcfc0821SMasami Hiramatsu total = dwarf_bytesize(vr_die); 310bcfc0821SMasami Hiramatsu if (boffs < 0 || total < 0) 311bcfc0821SMasami Hiramatsu return -ENOENT; 312bcfc0821SMasami Hiramatsu ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 313bcfc0821SMasami Hiramatsu BYTES_TO_BITS(total)); 314124bb83cSMasami Hiramatsu goto formatted; 315124bb83cSMasami Hiramatsu } 316124bb83cSMasami Hiramatsu 317b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 318b55a87adSMasami Hiramatsu pr_warning("Failed to get a type information of %s.\n", 3194984912eSMasami Hiramatsu dwarf_diename(vr_die)); 320b55a87adSMasami Hiramatsu return -ENOENT; 321b55a87adSMasami Hiramatsu } 3224984912eSMasami Hiramatsu 323b2a3c12bSMasami Hiramatsu pr_debug("%s type is %s.\n", 324b2a3c12bSMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 325b2a3c12bSMasami Hiramatsu 32673317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") == 0) { /* String type */ 32773317b95SMasami Hiramatsu ret = dwarf_tag(&type); 32873317b95SMasami Hiramatsu if (ret != DW_TAG_pointer_type && 32973317b95SMasami Hiramatsu ret != DW_TAG_array_type) { 33073317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3310e43e5d2SMasami Hiramatsu "%s(%s) is not a pointer nor array.\n", 33273317b95SMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 33373317b95SMasami Hiramatsu return -EINVAL; 33473317b95SMasami Hiramatsu } 33573317b95SMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 3360e43e5d2SMasami Hiramatsu pr_warning("Failed to get a type" 3370e43e5d2SMasami Hiramatsu " information.\n"); 33873317b95SMasami Hiramatsu return -ENOENT; 33973317b95SMasami Hiramatsu } 3407ce28b5bSHyeoncheol Lee if (ret == DW_TAG_pointer_type) { 34173317b95SMasami Hiramatsu while (*ref_ptr) 34273317b95SMasami Hiramatsu ref_ptr = &(*ref_ptr)->next; 34373317b95SMasami Hiramatsu /* Add new reference with offset +0 */ 3440e60836bSSrikar Dronamraju *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 34573317b95SMasami Hiramatsu if (*ref_ptr == NULL) { 34673317b95SMasami Hiramatsu pr_warning("Out of memory error\n"); 34773317b95SMasami Hiramatsu return -ENOMEM; 34873317b95SMasami Hiramatsu } 34973317b95SMasami Hiramatsu } 35082175633SMasami Hiramatsu if (!die_compare_name(&type, "char") && 35182175633SMasami Hiramatsu !die_compare_name(&type, "unsigned char")) { 35273317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3530e43e5d2SMasami Hiramatsu "%s is not (unsigned) char *.\n", 35473317b95SMasami Hiramatsu dwarf_diename(vr_die)); 35573317b95SMasami Hiramatsu return -EINVAL; 35673317b95SMasami Hiramatsu } 35773317b95SMasami Hiramatsu tvar->type = strdup(cast); 35873317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 35973317b95SMasami Hiramatsu } 36073317b95SMasami Hiramatsu 361bcfc0821SMasami Hiramatsu ret = dwarf_bytesize(&type); 362bcfc0821SMasami Hiramatsu if (ret <= 0) 363124bb83cSMasami Hiramatsu /* No size ... try to use default type */ 364124bb83cSMasami Hiramatsu return 0; 365bcfc0821SMasami Hiramatsu ret = BYTES_TO_BITS(ret); 366124bb83cSMasami Hiramatsu 3674984912eSMasami Hiramatsu /* Check the bitwidth */ 3684984912eSMasami Hiramatsu if (ret > MAX_BASIC_TYPE_BITS) { 369124bb83cSMasami Hiramatsu pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 3704984912eSMasami Hiramatsu dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 3714984912eSMasami Hiramatsu ret = MAX_BASIC_TYPE_BITS; 3724984912eSMasami Hiramatsu } 3734984912eSMasami Hiramatsu ret = snprintf(buf, 16, "%c%d", 3744984912eSMasami Hiramatsu die_is_signed_type(&type) ? 's' : 'u', ret); 375124bb83cSMasami Hiramatsu 376124bb83cSMasami Hiramatsu formatted: 377b55a87adSMasami Hiramatsu if (ret < 0 || ret >= 16) { 378b55a87adSMasami Hiramatsu if (ret >= 16) 379b55a87adSMasami Hiramatsu ret = -E2BIG; 380b55a87adSMasami Hiramatsu pr_warning("Failed to convert variable type: %s\n", 3815f03cba4SMasami Hiramatsu strerror_r(-ret, sbuf, sizeof(sbuf))); 382b55a87adSMasami Hiramatsu return ret; 383b55a87adSMasami Hiramatsu } 38473317b95SMasami Hiramatsu tvar->type = strdup(buf); 38573317b95SMasami Hiramatsu if (tvar->type == NULL) 38602b95dadSMasami Hiramatsu return -ENOMEM; 387b55a87adSMasami Hiramatsu return 0; 3884984912eSMasami Hiramatsu } 3894984912eSMasami Hiramatsu 390b55a87adSMasami Hiramatsu static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 3917df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, 3920e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr, 3934984912eSMasami Hiramatsu Dwarf_Die *die_mem) 3947df2f329SMasami Hiramatsu { 3950e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = *ref_ptr; 3967df2f329SMasami Hiramatsu Dwarf_Die type; 3977df2f329SMasami Hiramatsu Dwarf_Word offs; 398b2a3c12bSMasami Hiramatsu int ret, tag; 3997df2f329SMasami Hiramatsu 4007df2f329SMasami Hiramatsu pr_debug("converting %s in %s\n", field->name, varname); 401b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 402b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 403b55a87adSMasami Hiramatsu return -ENOENT; 404b55a87adSMasami Hiramatsu } 405b2a3c12bSMasami Hiramatsu pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); 406b2a3c12bSMasami Hiramatsu tag = dwarf_tag(&type); 4077df2f329SMasami Hiramatsu 408b2a3c12bSMasami Hiramatsu if (field->name[0] == '[' && 409b2a3c12bSMasami Hiramatsu (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 410b2a3c12bSMasami Hiramatsu if (field->next) 411b2a3c12bSMasami Hiramatsu /* Save original type for next field */ 412b2a3c12bSMasami Hiramatsu memcpy(die_mem, &type, sizeof(*die_mem)); 413b2a3c12bSMasami Hiramatsu /* Get the type of this array */ 414b2a3c12bSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 415b2a3c12bSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 416b2a3c12bSMasami Hiramatsu return -ENOENT; 417b2a3c12bSMasami Hiramatsu } 418b2a3c12bSMasami Hiramatsu pr_debug2("Array real type: (%x)\n", 419b2a3c12bSMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 420b2a3c12bSMasami Hiramatsu if (tag == DW_TAG_pointer_type) { 4210e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 422b2a3c12bSMasami Hiramatsu if (ref == NULL) 423b2a3c12bSMasami Hiramatsu return -ENOMEM; 424b2a3c12bSMasami Hiramatsu if (*ref_ptr) 425b2a3c12bSMasami Hiramatsu (*ref_ptr)->next = ref; 426b2a3c12bSMasami Hiramatsu else 427b2a3c12bSMasami Hiramatsu *ref_ptr = ref; 428b2a3c12bSMasami Hiramatsu } 429bcfc0821SMasami Hiramatsu ref->offset += dwarf_bytesize(&type) * field->index; 430b2a3c12bSMasami Hiramatsu if (!field->next) 431b2a3c12bSMasami Hiramatsu /* Save vr_die for converting types */ 432b2a3c12bSMasami Hiramatsu memcpy(die_mem, vr_die, sizeof(*die_mem)); 433b2a3c12bSMasami Hiramatsu goto next; 434b2a3c12bSMasami Hiramatsu } else if (tag == DW_TAG_pointer_type) { 4357df2f329SMasami Hiramatsu /* Check the pointer and dereference */ 436b55a87adSMasami Hiramatsu if (!field->ref) { 437b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '->'\n", 4387df2f329SMasami Hiramatsu field->name); 439b55a87adSMasami Hiramatsu return -EINVAL; 440b55a87adSMasami Hiramatsu } 4417df2f329SMasami Hiramatsu /* Get the type pointed by this pointer */ 442b55a87adSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 443b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 444b55a87adSMasami Hiramatsu return -ENOENT; 445b55a87adSMasami Hiramatsu } 44612e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4477b0295b3SHyeoncheol Lee tag = dwarf_tag(&type); 4487b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 4497b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 4507b0295b3SHyeoncheol Lee varname); 451b55a87adSMasami Hiramatsu return -EINVAL; 452b55a87adSMasami Hiramatsu } 45312e5a7aeSMasami Hiramatsu 4540e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 455e334016fSMasami Hiramatsu if (ref == NULL) 456e334016fSMasami Hiramatsu return -ENOMEM; 4577df2f329SMasami Hiramatsu if (*ref_ptr) 4587df2f329SMasami Hiramatsu (*ref_ptr)->next = ref; 4597df2f329SMasami Hiramatsu else 4607df2f329SMasami Hiramatsu *ref_ptr = ref; 4617df2f329SMasami Hiramatsu } else { 46212e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4637b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 4647b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 4657b0295b3SHyeoncheol Lee varname); 466b55a87adSMasami Hiramatsu return -EINVAL; 467b55a87adSMasami Hiramatsu } 468b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') { 469d939be3aSMasanari Iida pr_err("Semantic error: %s is not a pointer" 4700e43e5d2SMasami Hiramatsu " nor array.\n", varname); 471b2a3c12bSMasami Hiramatsu return -EINVAL; 472b2a3c12bSMasami Hiramatsu } 473c7273835SMasami Hiramatsu /* While prcessing unnamed field, we don't care about this */ 474c7273835SMasami Hiramatsu if (field->ref && dwarf_diename(vr_die)) { 475b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '.'\n", 4767df2f329SMasami Hiramatsu field->name); 477b55a87adSMasami Hiramatsu return -EINVAL; 478b55a87adSMasami Hiramatsu } 479b55a87adSMasami Hiramatsu if (!ref) { 480b55a87adSMasami Hiramatsu pr_warning("Structure on a register is not " 481b55a87adSMasami Hiramatsu "supported yet.\n"); 482b55a87adSMasami Hiramatsu return -ENOTSUP; 483b55a87adSMasami Hiramatsu } 4847df2f329SMasami Hiramatsu } 4857df2f329SMasami Hiramatsu 486b55a87adSMasami Hiramatsu if (die_find_member(&type, field->name, die_mem) == NULL) { 4879ef0438aSArnaldo Carvalho de Melo pr_warning("%s(type:%s) has no member %s.\n", varname, 4887df2f329SMasami Hiramatsu dwarf_diename(&type), field->name); 489b55a87adSMasami Hiramatsu return -EINVAL; 490b55a87adSMasami Hiramatsu } 4917df2f329SMasami Hiramatsu 4927df2f329SMasami Hiramatsu /* Get the offset of the field */ 4937b0295b3SHyeoncheol Lee if (tag == DW_TAG_union_type) { 4947b0295b3SHyeoncheol Lee offs = 0; 4957b0295b3SHyeoncheol Lee } else { 496de1439d8SMasami Hiramatsu ret = die_get_data_member_location(die_mem, &offs); 497de1439d8SMasami Hiramatsu if (ret < 0) { 4987b0295b3SHyeoncheol Lee pr_warning("Failed to get the offset of %s.\n", 4997b0295b3SHyeoncheol Lee field->name); 500de1439d8SMasami Hiramatsu return ret; 501b55a87adSMasami Hiramatsu } 5027b0295b3SHyeoncheol Lee } 5037df2f329SMasami Hiramatsu ref->offset += (long)offs; 5047df2f329SMasami Hiramatsu 505c7273835SMasami Hiramatsu /* If this member is unnamed, we need to reuse this field */ 506c7273835SMasami Hiramatsu if (!dwarf_diename(die_mem)) 507c7273835SMasami Hiramatsu return convert_variable_fields(die_mem, varname, field, 508c7273835SMasami Hiramatsu &ref, die_mem); 509c7273835SMasami Hiramatsu 510b2a3c12bSMasami Hiramatsu next: 5117df2f329SMasami Hiramatsu /* Converting next field */ 5127df2f329SMasami Hiramatsu if (field->next) 513b55a87adSMasami Hiramatsu return convert_variable_fields(die_mem, field->name, 514b55a87adSMasami Hiramatsu field->next, &ref, die_mem); 515b55a87adSMasami Hiramatsu else 516b55a87adSMasami Hiramatsu return 0; 5177df2f329SMasami Hiramatsu } 5187df2f329SMasami Hiramatsu 5194ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */ 520b55a87adSMasami Hiramatsu static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 5214ea42b18SMasami Hiramatsu { 5224984912eSMasami Hiramatsu Dwarf_Die die_mem; 5234ea42b18SMasami Hiramatsu int ret; 5244ea42b18SMasami Hiramatsu 525b7dcb857SMasami Hiramatsu pr_debug("Converting variable %s into trace event.\n", 526b7dcb857SMasami Hiramatsu dwarf_diename(vr_die)); 527804b3606SMasami Hiramatsu 528cf6eb489SMasami Hiramatsu ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 5293d918a12SMasami Hiramatsu &pf->sp_die, pf->tvar); 5307d5eaba9SHe Kuang if (ret == -ENOENT || ret == -EINVAL) { 5317d5eaba9SHe Kuang pr_err("Failed to find the location of the '%s' variable at this address.\n" 5327d5eaba9SHe Kuang " Perhaps it has been optimized out.\n" 5337d5eaba9SHe Kuang " Use -V with the --range option to show '%s' location range.\n", 5347d5eaba9SHe Kuang pf->pvar->var, pf->pvar->var); 5357d5eaba9SHe Kuang } else if (ret == -ENOTSUP) 536cf6eb489SMasami Hiramatsu pr_err("Sorry, we don't support this variable location yet.\n"); 5370c188a07SMasami Hiramatsu else if (ret == 0 && pf->pvar->field) { 538b55a87adSMasami Hiramatsu ret = convert_variable_fields(vr_die, pf->pvar->var, 5394984912eSMasami Hiramatsu pf->pvar->field, &pf->tvar->ref, 5404984912eSMasami Hiramatsu &die_mem); 5414984912eSMasami Hiramatsu vr_die = &die_mem; 5424984912eSMasami Hiramatsu } 54373317b95SMasami Hiramatsu if (ret == 0) 54473317b95SMasami Hiramatsu ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); 545804b3606SMasami Hiramatsu /* *expr will be cached in libdw. Don't free it. */ 546b55a87adSMasami Hiramatsu return ret; 5474ea42b18SMasami Hiramatsu } 5484ea42b18SMasami Hiramatsu 549221d0611SMasami Hiramatsu /* Find a variable in a scope DIE */ 550221d0611SMasami Hiramatsu static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 5514ea42b18SMasami Hiramatsu { 552f182e3e1SMasami Hiramatsu Dwarf_Die vr_die; 55311a1ca35SMasami Hiramatsu char buf[32], *ptr; 554f182e3e1SMasami Hiramatsu int ret = 0; 5554ea42b18SMasami Hiramatsu 556367e94c1SMasami Hiramatsu if (!is_c_varname(pf->pvar->var)) { 557367e94c1SMasami Hiramatsu /* Copy raw parameters */ 558367e94c1SMasami Hiramatsu pf->tvar->value = strdup(pf->pvar->var); 559367e94c1SMasami Hiramatsu if (pf->tvar->value == NULL) 560367e94c1SMasami Hiramatsu return -ENOMEM; 561367e94c1SMasami Hiramatsu if (pf->pvar->type) { 562367e94c1SMasami Hiramatsu pf->tvar->type = strdup(pf->pvar->type); 563367e94c1SMasami Hiramatsu if (pf->tvar->type == NULL) 564367e94c1SMasami Hiramatsu return -ENOMEM; 565367e94c1SMasami Hiramatsu } 566367e94c1SMasami Hiramatsu if (pf->pvar->name) { 567367e94c1SMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 568367e94c1SMasami Hiramatsu if (pf->tvar->name == NULL) 569367e94c1SMasami Hiramatsu return -ENOMEM; 570367e94c1SMasami Hiramatsu } else 571367e94c1SMasami Hiramatsu pf->tvar->name = NULL; 572367e94c1SMasami Hiramatsu return 0; 573367e94c1SMasami Hiramatsu } 574367e94c1SMasami Hiramatsu 57548481938SMasami Hiramatsu if (pf->pvar->name) 57602b95dadSMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 57748481938SMasami Hiramatsu else { 57802b95dadSMasami Hiramatsu ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); 57902b95dadSMasami Hiramatsu if (ret < 0) 58002b95dadSMasami Hiramatsu return ret; 58111a1ca35SMasami Hiramatsu ptr = strchr(buf, ':'); /* Change type separator to _ */ 58211a1ca35SMasami Hiramatsu if (ptr) 58311a1ca35SMasami Hiramatsu *ptr = '_'; 58402b95dadSMasami Hiramatsu pf->tvar->name = strdup(buf); 58548481938SMasami Hiramatsu } 58602b95dadSMasami Hiramatsu if (pf->tvar->name == NULL) 58702b95dadSMasami Hiramatsu return -ENOMEM; 58848481938SMasami Hiramatsu 589f182e3e1SMasami Hiramatsu pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 5904ea42b18SMasami Hiramatsu /* Search child die for local variables and parameters. */ 591f182e3e1SMasami Hiramatsu if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 592f182e3e1SMasami Hiramatsu /* Search again in global variables */ 593d13855efSHe Kuang if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 594d13855efSHe Kuang 0, &vr_die)) { 59536d789a4SMasami Hiramatsu pr_warning("Failed to find '%s' in this function.\n", 59636d789a4SMasami Hiramatsu pf->pvar->var); 5978afa2a70SMasami Hiramatsu ret = -ENOENT; 598f182e3e1SMasami Hiramatsu } 599d13855efSHe Kuang } 600f66fedcbSMasami Hiramatsu if (ret >= 0) 601b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 602f182e3e1SMasami Hiramatsu 603b7dcb857SMasami Hiramatsu return ret; 6044ea42b18SMasami Hiramatsu } 6054ea42b18SMasami Hiramatsu 606cf6eb489SMasami Hiramatsu /* Convert subprogram DIE to trace point */ 607576b5237SMasami Hiramatsu static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, 608576b5237SMasami Hiramatsu Dwarf_Addr paddr, bool retprobe, 609576b5237SMasami Hiramatsu struct probe_trace_point *tp) 6104ea42b18SMasami Hiramatsu { 61126b79524SPrashanth Nageshappa Dwarf_Addr eaddr, highaddr; 612576b5237SMasami Hiramatsu GElf_Sym sym; 613576b5237SMasami Hiramatsu const char *symbol; 614cf6eb489SMasami Hiramatsu 615576b5237SMasami Hiramatsu /* Verify the address is correct */ 616cf6eb489SMasami Hiramatsu if (dwarf_entrypc(sp_die, &eaddr) != 0) { 6170e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s\n", 618cf6eb489SMasami Hiramatsu dwarf_diename(sp_die)); 619cf6eb489SMasami Hiramatsu return -ENOENT; 620cf6eb489SMasami Hiramatsu } 62126b79524SPrashanth Nageshappa if (dwarf_highpc(sp_die, &highaddr) != 0) { 62226b79524SPrashanth Nageshappa pr_warning("Failed to get end address of %s\n", 62326b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 62426b79524SPrashanth Nageshappa return -ENOENT; 62526b79524SPrashanth Nageshappa } 62626b79524SPrashanth Nageshappa if (paddr > highaddr) { 62726b79524SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 62826b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 62926b79524SPrashanth Nageshappa return -EINVAL; 63026b79524SPrashanth Nageshappa } 631576b5237SMasami Hiramatsu 632664fee3dSMasami Hiramatsu symbol = dwarf_diename(sp_die); 633664fee3dSMasami Hiramatsu if (!symbol) { 634664fee3dSMasami Hiramatsu /* Try to get the symbol name from symtab */ 635576b5237SMasami Hiramatsu symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); 636576b5237SMasami Hiramatsu if (!symbol) { 637576b5237SMasami Hiramatsu pr_warning("Failed to find symbol at 0x%lx\n", 638576b5237SMasami Hiramatsu (unsigned long)paddr); 639576b5237SMasami Hiramatsu return -ENOENT; 640576b5237SMasami Hiramatsu } 641664fee3dSMasami Hiramatsu eaddr = sym.st_value; 642664fee3dSMasami Hiramatsu } 643664fee3dSMasami Hiramatsu tp->offset = (unsigned long)(paddr - eaddr); 644fb7345bbSMasami Hiramatsu tp->address = (unsigned long)paddr; 645576b5237SMasami Hiramatsu tp->symbol = strdup(symbol); 646576b5237SMasami Hiramatsu if (!tp->symbol) 647cf6eb489SMasami Hiramatsu return -ENOMEM; 648cf6eb489SMasami Hiramatsu 649cf6eb489SMasami Hiramatsu /* Return probe must be on the head of a subprogram */ 650cf6eb489SMasami Hiramatsu if (retprobe) { 651cf6eb489SMasami Hiramatsu if (eaddr != paddr) { 652cf6eb489SMasami Hiramatsu pr_warning("Return probe must be on the head of" 6530e43e5d2SMasami Hiramatsu " a real function.\n"); 654cf6eb489SMasami Hiramatsu return -EINVAL; 655cf6eb489SMasami Hiramatsu } 656cf6eb489SMasami Hiramatsu tp->retprobe = true; 657cf6eb489SMasami Hiramatsu } 658cf6eb489SMasami Hiramatsu 659cf6eb489SMasami Hiramatsu return 0; 660cf6eb489SMasami Hiramatsu } 661cf6eb489SMasami Hiramatsu 662221d0611SMasami Hiramatsu /* Call probe_finder callback with scope DIE */ 663221d0611SMasami Hiramatsu static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 664cf6eb489SMasami Hiramatsu { 665804b3606SMasami Hiramatsu Dwarf_Attribute fb_attr; 666804b3606SMasami Hiramatsu size_t nops; 667cf6eb489SMasami Hiramatsu int ret; 6684235b045SMasami Hiramatsu 669221d0611SMasami Hiramatsu if (!sc_die) { 670221d0611SMasami Hiramatsu pr_err("Caller must pass a scope DIE. Program error.\n"); 671221d0611SMasami Hiramatsu return -EINVAL; 672221d0611SMasami Hiramatsu } 673221d0611SMasami Hiramatsu 674221d0611SMasami Hiramatsu /* If not a real subprogram, find a real one */ 6750dbb1cacSMasami Hiramatsu if (!die_is_func_def(sc_die)) { 676221d0611SMasami Hiramatsu if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 677d4c537e6SNaveen N. Rao if (die_find_tailfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 678d4c537e6SNaveen N. Rao pr_warning("Ignoring tail call from %s\n", 679d4c537e6SNaveen N. Rao dwarf_diename(&pf->sp_die)); 680d4c537e6SNaveen N. Rao return 0; 681d4c537e6SNaveen N. Rao } else { 682b55a87adSMasami Hiramatsu pr_warning("Failed to find probe point in any " 683b55a87adSMasami Hiramatsu "functions.\n"); 684b55a87adSMasami Hiramatsu return -ENOENT; 685b55a87adSMasami Hiramatsu } 686d4c537e6SNaveen N. Rao } 687221d0611SMasami Hiramatsu } else 688221d0611SMasami Hiramatsu memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 689e92b85e1SMasami Hiramatsu 690221d0611SMasami Hiramatsu /* Get the frame base attribute/ops from subprogram */ 691221d0611SMasami Hiramatsu dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 692d0cb4260SMasami Hiramatsu ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 693a34a9854SMasami Hiramatsu if (ret <= 0 || nops == 0) { 694804b3606SMasami Hiramatsu pf->fb_ops = NULL; 6957752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 696a34a9854SMasami Hiramatsu } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 697a34a9854SMasami Hiramatsu pf->cfi != NULL) { 698a34a9854SMasami Hiramatsu Dwarf_Frame *frame; 699b55a87adSMasami Hiramatsu if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 700b55a87adSMasami Hiramatsu dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 7010e43e5d2SMasami Hiramatsu pr_warning("Failed to get call frame on 0x%jx\n", 702b55a87adSMasami Hiramatsu (uintmax_t)pf->addr); 703b55a87adSMasami Hiramatsu return -ENOENT; 704b55a87adSMasami Hiramatsu } 7057752f1b0SMasami Hiramatsu #endif 706a34a9854SMasami Hiramatsu } 707804b3606SMasami Hiramatsu 708cf6eb489SMasami Hiramatsu /* Call finder's callback handler */ 709221d0611SMasami Hiramatsu ret = pf->callback(sc_die, pf); 710804b3606SMasami Hiramatsu 711804b3606SMasami Hiramatsu /* *pf->fb_ops will be cached in libdw. Don't free it. */ 712804b3606SMasami Hiramatsu pf->fb_ops = NULL; 713cf6eb489SMasami Hiramatsu 714cf6eb489SMasami Hiramatsu return ret; 7154ea42b18SMasami Hiramatsu } 7164ea42b18SMasami Hiramatsu 717221d0611SMasami Hiramatsu struct find_scope_param { 718221d0611SMasami Hiramatsu const char *function; 719221d0611SMasami Hiramatsu const char *file; 720221d0611SMasami Hiramatsu int line; 721221d0611SMasami Hiramatsu int diff; 722221d0611SMasami Hiramatsu Dwarf_Die *die_mem; 723221d0611SMasami Hiramatsu bool found; 724221d0611SMasami Hiramatsu }; 725221d0611SMasami Hiramatsu 726221d0611SMasami Hiramatsu static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 727221d0611SMasami Hiramatsu { 728221d0611SMasami Hiramatsu struct find_scope_param *fsp = data; 729221d0611SMasami Hiramatsu const char *file; 730221d0611SMasami Hiramatsu int lno; 731221d0611SMasami Hiramatsu 732221d0611SMasami Hiramatsu /* Skip if declared file name does not match */ 733221d0611SMasami Hiramatsu if (fsp->file) { 734221d0611SMasami Hiramatsu file = dwarf_decl_file(fn_die); 735221d0611SMasami Hiramatsu if (!file || strcmp(fsp->file, file) != 0) 736221d0611SMasami Hiramatsu return 0; 737221d0611SMasami Hiramatsu } 738221d0611SMasami Hiramatsu /* If the function name is given, that's what user expects */ 739221d0611SMasami Hiramatsu if (fsp->function) { 7404c859351SMasami Hiramatsu if (die_match_name(fn_die, fsp->function)) { 741221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 742221d0611SMasami Hiramatsu fsp->found = true; 743221d0611SMasami Hiramatsu return 1; 744221d0611SMasami Hiramatsu } 745221d0611SMasami Hiramatsu } else { 746221d0611SMasami Hiramatsu /* With the line number, find the nearest declared DIE */ 747221d0611SMasami Hiramatsu dwarf_decl_line(fn_die, &lno); 748221d0611SMasami Hiramatsu if (lno < fsp->line && fsp->diff > fsp->line - lno) { 749221d0611SMasami Hiramatsu /* Keep a candidate and continue */ 750221d0611SMasami Hiramatsu fsp->diff = fsp->line - lno; 751221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 752221d0611SMasami Hiramatsu fsp->found = true; 753221d0611SMasami Hiramatsu } 754221d0611SMasami Hiramatsu } 755221d0611SMasami Hiramatsu return 0; 756221d0611SMasami Hiramatsu } 757221d0611SMasami Hiramatsu 758221d0611SMasami Hiramatsu /* Find an appropriate scope fits to given conditions */ 759221d0611SMasami Hiramatsu static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 760221d0611SMasami Hiramatsu { 761221d0611SMasami Hiramatsu struct find_scope_param fsp = { 762221d0611SMasami Hiramatsu .function = pf->pev->point.function, 763221d0611SMasami Hiramatsu .file = pf->fname, 764221d0611SMasami Hiramatsu .line = pf->lno, 765221d0611SMasami Hiramatsu .diff = INT_MAX, 766221d0611SMasami Hiramatsu .die_mem = die_mem, 767221d0611SMasami Hiramatsu .found = false, 768221d0611SMasami Hiramatsu }; 769221d0611SMasami Hiramatsu 770221d0611SMasami Hiramatsu cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 771221d0611SMasami Hiramatsu 772221d0611SMasami Hiramatsu return fsp.found ? die_mem : NULL; 773221d0611SMasami Hiramatsu } 774221d0611SMasami Hiramatsu 7754cc9cec6SMasami Hiramatsu static int probe_point_line_walker(const char *fname, int lineno, 7764cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 7774cc9cec6SMasami Hiramatsu { 7784cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 779221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 7804cc9cec6SMasami Hiramatsu int ret; 7814cc9cec6SMasami Hiramatsu 7824cc9cec6SMasami Hiramatsu if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 7834cc9cec6SMasami Hiramatsu return 0; 7844cc9cec6SMasami Hiramatsu 7854cc9cec6SMasami Hiramatsu pf->addr = addr; 786221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 787221d0611SMasami Hiramatsu if (!sc_die) { 788221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 789221d0611SMasami Hiramatsu return -ENOENT; 790221d0611SMasami Hiramatsu } 791221d0611SMasami Hiramatsu 792221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 7934cc9cec6SMasami Hiramatsu 7944cc9cec6SMasami Hiramatsu /* Continue if no error, because the line will be in inline function */ 795fbee632dSArnaldo Carvalho de Melo return ret < 0 ? ret : 0; 7964cc9cec6SMasami Hiramatsu } 7974cc9cec6SMasami Hiramatsu 7984ea42b18SMasami Hiramatsu /* Find probe point from its line number */ 799b55a87adSMasami Hiramatsu static int find_probe_point_by_line(struct probe_finder *pf) 8004ea42b18SMasami Hiramatsu { 8014cc9cec6SMasami Hiramatsu return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 8024ea42b18SMasami Hiramatsu } 8034ea42b18SMasami Hiramatsu 8042a9c8c36SMasami Hiramatsu /* Find lines which match lazy pattern */ 8055a62257aSMasami Hiramatsu static int find_lazy_match_lines(struct intlist *list, 8062a9c8c36SMasami Hiramatsu const char *fname, const char *pat) 8072a9c8c36SMasami Hiramatsu { 808f50c2169SFranck Bui-Huu FILE *fp; 809f50c2169SFranck Bui-Huu char *line = NULL; 810f50c2169SFranck Bui-Huu size_t line_len; 811f50c2169SFranck Bui-Huu ssize_t len; 812f50c2169SFranck Bui-Huu int count = 0, linenum = 1; 8135f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 8142a9c8c36SMasami Hiramatsu 815f50c2169SFranck Bui-Huu fp = fopen(fname, "r"); 816f50c2169SFranck Bui-Huu if (!fp) { 8175f03cba4SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", fname, 8185f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 819b448c4b6SArnaldo Carvalho de Melo return -errno; 820b55a87adSMasami Hiramatsu } 821b55a87adSMasami Hiramatsu 822f50c2169SFranck Bui-Huu while ((len = getline(&line, &line_len, fp)) > 0) { 823f50c2169SFranck Bui-Huu 824f50c2169SFranck Bui-Huu if (line[len - 1] == '\n') 825f50c2169SFranck Bui-Huu line[len - 1] = '\0'; 826f50c2169SFranck Bui-Huu 827f50c2169SFranck Bui-Huu if (strlazymatch(line, pat)) { 8285a62257aSMasami Hiramatsu intlist__add(list, linenum); 829f50c2169SFranck Bui-Huu count++; 830f50c2169SFranck Bui-Huu } 831f50c2169SFranck Bui-Huu linenum++; 832b55a87adSMasami Hiramatsu } 833b448c4b6SArnaldo Carvalho de Melo 834f50c2169SFranck Bui-Huu if (ferror(fp)) 835f50c2169SFranck Bui-Huu count = -errno; 836f50c2169SFranck Bui-Huu free(line); 837f50c2169SFranck Bui-Huu fclose(fp); 838f50c2169SFranck Bui-Huu 839f50c2169SFranck Bui-Huu if (count == 0) 840f50c2169SFranck Bui-Huu pr_debug("No matched lines found in %s.\n", fname); 841f50c2169SFranck Bui-Huu return count; 8422a9c8c36SMasami Hiramatsu } 8432a9c8c36SMasami Hiramatsu 8444cc9cec6SMasami Hiramatsu static int probe_point_lazy_walker(const char *fname, int lineno, 8454cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 8464cc9cec6SMasami Hiramatsu { 8474cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 848221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 8494cc9cec6SMasami Hiramatsu int ret; 8504cc9cec6SMasami Hiramatsu 8515a62257aSMasami Hiramatsu if (!intlist__has_entry(pf->lcache, lineno) || 8524cc9cec6SMasami Hiramatsu strtailcmp(fname, pf->fname) != 0) 8534cc9cec6SMasami Hiramatsu return 0; 8544cc9cec6SMasami Hiramatsu 8554cc9cec6SMasami Hiramatsu pr_debug("Probe line found: line:%d addr:0x%llx\n", 8564cc9cec6SMasami Hiramatsu lineno, (unsigned long long)addr); 8574cc9cec6SMasami Hiramatsu pf->addr = addr; 858221d0611SMasami Hiramatsu pf->lno = lineno; 859221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 860221d0611SMasami Hiramatsu if (!sc_die) { 861221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 862221d0611SMasami Hiramatsu return -ENOENT; 863221d0611SMasami Hiramatsu } 864221d0611SMasami Hiramatsu 865221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8664cc9cec6SMasami Hiramatsu 8674cc9cec6SMasami Hiramatsu /* 8684cc9cec6SMasami Hiramatsu * Continue if no error, because the lazy pattern will match 8694cc9cec6SMasami Hiramatsu * to other lines 8704cc9cec6SMasami Hiramatsu */ 8715e814dd5SIngo Molnar return ret < 0 ? ret : 0; 8724cc9cec6SMasami Hiramatsu } 8734cc9cec6SMasami Hiramatsu 8742a9c8c36SMasami Hiramatsu /* Find probe points from lazy pattern */ 875b55a87adSMasami Hiramatsu static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 8762a9c8c36SMasami Hiramatsu { 877b55a87adSMasami Hiramatsu int ret = 0; 87809ed8975SNaohiro Aota char *fpath; 8792a9c8c36SMasami Hiramatsu 8805a62257aSMasami Hiramatsu if (intlist__empty(pf->lcache)) { 88109ed8975SNaohiro Aota const char *comp_dir; 88209ed8975SNaohiro Aota 88309ed8975SNaohiro Aota comp_dir = cu_get_comp_dir(&pf->cu_die); 88409ed8975SNaohiro Aota ret = get_real_path(pf->fname, comp_dir, &fpath); 88509ed8975SNaohiro Aota if (ret < 0) { 88609ed8975SNaohiro Aota pr_warning("Failed to find source file path.\n"); 88709ed8975SNaohiro Aota return ret; 88809ed8975SNaohiro Aota } 88909ed8975SNaohiro Aota 8902a9c8c36SMasami Hiramatsu /* Matching lazy line pattern */ 89109ed8975SNaohiro Aota ret = find_lazy_match_lines(pf->lcache, fpath, 8924235b045SMasami Hiramatsu pf->pev->point.lazy_line); 89309ed8975SNaohiro Aota free(fpath); 894f50c2169SFranck Bui-Huu if (ret <= 0) 895b55a87adSMasami Hiramatsu return ret; 8962a9c8c36SMasami Hiramatsu } 8972a9c8c36SMasami Hiramatsu 8984cc9cec6SMasami Hiramatsu return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 8992a9c8c36SMasami Hiramatsu } 9002a9c8c36SMasami Hiramatsu 901e92b85e1SMasami Hiramatsu static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 9024ea42b18SMasami Hiramatsu { 903db0d2c64SMasami Hiramatsu struct probe_finder *pf = data; 9044235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 905b55a87adSMasami Hiramatsu Dwarf_Addr addr; 906db0d2c64SMasami Hiramatsu int ret; 9074ea42b18SMasami Hiramatsu 9082a9c8c36SMasami Hiramatsu if (pp->lazy_line) 909db0d2c64SMasami Hiramatsu ret = find_probe_point_lazy(in_die, pf); 9102a9c8c36SMasami Hiramatsu else { 911e92b85e1SMasami Hiramatsu /* Get probe address */ 912b55a87adSMasami Hiramatsu if (dwarf_entrypc(in_die, &addr) != 0) { 9130e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s.\n", 914b55a87adSMasami Hiramatsu dwarf_diename(in_die)); 915db0d2c64SMasami Hiramatsu return -ENOENT; 916b55a87adSMasami Hiramatsu } 917b55a87adSMasami Hiramatsu pf->addr = addr; 918e92b85e1SMasami Hiramatsu pf->addr += pp->offset; 9192a9c8c36SMasami Hiramatsu pr_debug("found inline addr: 0x%jx\n", 9202a9c8c36SMasami Hiramatsu (uintmax_t)pf->addr); 921e92b85e1SMasami Hiramatsu 922db0d2c64SMasami Hiramatsu ret = call_probe_finder(in_die, pf); 9232a9c8c36SMasami Hiramatsu } 9242a9c8c36SMasami Hiramatsu 925db0d2c64SMasami Hiramatsu return ret; 926e92b85e1SMasami Hiramatsu } 927e92b85e1SMasami Hiramatsu 928db0d2c64SMasami Hiramatsu /* Callback parameter with return value for libdw */ 929db0d2c64SMasami Hiramatsu struct dwarf_callback_param { 930db0d2c64SMasami Hiramatsu void *data; 931db0d2c64SMasami Hiramatsu int retval; 932db0d2c64SMasami Hiramatsu }; 933db0d2c64SMasami Hiramatsu 934e92b85e1SMasami Hiramatsu /* Search function from function name */ 935e92b85e1SMasami Hiramatsu static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 936e92b85e1SMasami Hiramatsu { 937b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 938b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 9394235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 940e92b85e1SMasami Hiramatsu 941e92b85e1SMasami Hiramatsu /* Check tag and diename */ 9420dbb1cacSMasami Hiramatsu if (!die_is_func_def(sp_die) || 9434c859351SMasami Hiramatsu !die_match_name(sp_die, pp->function)) 944b55a87adSMasami Hiramatsu return DWARF_CB_OK; 945e92b85e1SMasami Hiramatsu 9467d21635aSMasami Hiramatsu /* Check declared file */ 9477d21635aSMasami Hiramatsu if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 9487d21635aSMasami Hiramatsu return DWARF_CB_OK; 9497d21635aSMasami Hiramatsu 9504c859351SMasami Hiramatsu pr_debug("Matched function: %s\n", dwarf_diename(sp_die)); 951e92b85e1SMasami Hiramatsu pf->fname = dwarf_decl_file(sp_die); 9522a9c8c36SMasami Hiramatsu if (pp->line) { /* Function relative line */ 953e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &pf->lno); 954804b3606SMasami Hiramatsu pf->lno += pp->line; 955b55a87adSMasami Hiramatsu param->retval = find_probe_point_by_line(pf); 956e1ecbbc3SMasami Hiramatsu } else if (die_is_func_instance(sp_die)) { 957e1ecbbc3SMasami Hiramatsu /* Instances always have the entry address */ 958e1ecbbc3SMasami Hiramatsu dwarf_entrypc(sp_die, &pf->addr); 959e92b85e1SMasami Hiramatsu /* Real function */ 9602a9c8c36SMasami Hiramatsu if (pp->lazy_line) 961b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(sp_die, pf); 9622a9c8c36SMasami Hiramatsu else { 9634ea42b18SMasami Hiramatsu pf->addr += pp->offset; 9644ea42b18SMasami Hiramatsu /* TODO: Check the address in this function */ 965cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(sp_die, pf); 9662a9c8c36SMasami Hiramatsu } 9674c859351SMasami Hiramatsu } else if (!probe_conf.no_inlines) { 968e92b85e1SMasami Hiramatsu /* Inlined function: search instances */ 969db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 970db0d2c64SMasami Hiramatsu probe_point_inline_cb, (void *)pf); 9714c859351SMasami Hiramatsu /* This could be a non-existed inline definition */ 9724c859351SMasami Hiramatsu if (param->retval == -ENOENT && strisglob(pp->function)) 9734c859351SMasami Hiramatsu param->retval = 0; 9744c859351SMasami Hiramatsu } 9754c859351SMasami Hiramatsu 9764c859351SMasami Hiramatsu /* We need to find other candidates */ 9774c859351SMasami Hiramatsu if (strisglob(pp->function) && param->retval >= 0) { 9784c859351SMasami Hiramatsu param->retval = 0; /* We have to clear the result */ 9794c859351SMasami Hiramatsu return DWARF_CB_OK; 9804c859351SMasami Hiramatsu } 9814ea42b18SMasami Hiramatsu 982b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 983b55a87adSMasami Hiramatsu } 984b55a87adSMasami Hiramatsu 985b55a87adSMasami Hiramatsu static int find_probe_point_by_func(struct probe_finder *pf) 9864ea42b18SMasami Hiramatsu { 987b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 988b55a87adSMasami Hiramatsu .retval = 0}; 989b55a87adSMasami Hiramatsu dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 990b55a87adSMasami Hiramatsu return _param.retval; 9914ea42b18SMasami Hiramatsu } 9924ea42b18SMasami Hiramatsu 993cd25f8bcSLin Ming struct pubname_callback_param { 994cd25f8bcSLin Ming char *function; 995cd25f8bcSLin Ming char *file; 996cd25f8bcSLin Ming Dwarf_Die *cu_die; 997cd25f8bcSLin Ming Dwarf_Die *sp_die; 998cd25f8bcSLin Ming int found; 999cd25f8bcSLin Ming }; 1000cd25f8bcSLin Ming 1001cd25f8bcSLin Ming static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 1002cd25f8bcSLin Ming { 1003cd25f8bcSLin Ming struct pubname_callback_param *param = data; 1004cd25f8bcSLin Ming 1005cd25f8bcSLin Ming if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1006cd25f8bcSLin Ming if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1007cd25f8bcSLin Ming return DWARF_CB_OK; 1008cd25f8bcSLin Ming 10094c859351SMasami Hiramatsu if (die_match_name(param->sp_die, param->function)) { 1010cd25f8bcSLin Ming if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1011cd25f8bcSLin Ming return DWARF_CB_OK; 1012cd25f8bcSLin Ming 1013cd25f8bcSLin Ming if (param->file && 1014cd25f8bcSLin Ming strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1015cd25f8bcSLin Ming return DWARF_CB_OK; 1016cd25f8bcSLin Ming 1017cd25f8bcSLin Ming param->found = 1; 1018cd25f8bcSLin Ming return DWARF_CB_ABORT; 1019cd25f8bcSLin Ming } 1020cd25f8bcSLin Ming } 1021cd25f8bcSLin Ming 1022cd25f8bcSLin Ming return DWARF_CB_OK; 1023cd25f8bcSLin Ming } 1024cd25f8bcSLin Ming 1025cf6eb489SMasami Hiramatsu /* Find probe points from debuginfo */ 1026316c7136SArnaldo Carvalho de Melo static int debuginfo__find_probes(struct debuginfo *dbg, 1027ff741783SMasami Hiramatsu struct probe_finder *pf) 10284ea42b18SMasami Hiramatsu { 1029cf6eb489SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1030804b3606SMasami Hiramatsu Dwarf_Off off, noff; 1031804b3606SMasami Hiramatsu size_t cuhl; 1032804b3606SMasami Hiramatsu Dwarf_Die *diep; 1033b55a87adSMasami Hiramatsu int ret = 0; 10344ea42b18SMasami Hiramatsu 10357752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 10364093325fSNamhyung Kim Elf *elf; 10374093325fSNamhyung Kim GElf_Ehdr ehdr; 10384093325fSNamhyung Kim GElf_Shdr shdr; 10394093325fSNamhyung Kim 1040a34a9854SMasami Hiramatsu /* Get the call frame information from this dwarf */ 10414093325fSNamhyung Kim elf = dwarf_getelf(dbg->dbg); 10424093325fSNamhyung Kim if (elf == NULL) 10434093325fSNamhyung Kim return -EINVAL; 10444093325fSNamhyung Kim 10454093325fSNamhyung Kim if (gelf_getehdr(elf, &ehdr) == NULL) 10464093325fSNamhyung Kim return -EINVAL; 10474093325fSNamhyung Kim 10484093325fSNamhyung Kim if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && 10494093325fSNamhyung Kim shdr.sh_type == SHT_PROGBITS) { 10504093325fSNamhyung Kim pf->cfi = dwarf_getcfi_elf(elf); 10514093325fSNamhyung Kim } else { 10524093325fSNamhyung Kim pf->cfi = dwarf_getcfi(dbg->dbg); 10534093325fSNamhyung Kim } 10547752f1b0SMasami Hiramatsu #endif 1055a34a9854SMasami Hiramatsu 1056804b3606SMasami Hiramatsu off = 0; 10575a62257aSMasami Hiramatsu pf->lcache = intlist__new(NULL); 10585a62257aSMasami Hiramatsu if (!pf->lcache) 10595a62257aSMasami Hiramatsu return -ENOMEM; 1060cd25f8bcSLin Ming 1061cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 10624c859351SMasami Hiramatsu if (pp->function && !strisglob(pp->function)) { 1063cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1064cd25f8bcSLin Ming .function = pp->function, 1065cd25f8bcSLin Ming .file = pp->file, 1066cd25f8bcSLin Ming .cu_die = &pf->cu_die, 1067cd25f8bcSLin Ming .sp_die = &pf->sp_die, 10682b348a77SLin Ming .found = 0, 1069cd25f8bcSLin Ming }; 1070cd25f8bcSLin Ming struct dwarf_callback_param probe_param = { 1071cd25f8bcSLin Ming .data = pf, 1072cd25f8bcSLin Ming }; 1073cd25f8bcSLin Ming 1074316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1075ff741783SMasami Hiramatsu &pubname_param, 0); 1076cd25f8bcSLin Ming if (pubname_param.found) { 1077cd25f8bcSLin Ming ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1078cd25f8bcSLin Ming if (ret) 1079cd25f8bcSLin Ming goto found; 1080cd25f8bcSLin Ming } 1081cd25f8bcSLin Ming } 1082cd25f8bcSLin Ming 1083804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1084316c7136SArnaldo Carvalho de Melo while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 10854ea42b18SMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1086316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die); 1087804b3606SMasami Hiramatsu if (!diep) 1088804b3606SMasami Hiramatsu continue; 10894ea42b18SMasami Hiramatsu 10904ea42b18SMasami Hiramatsu /* Check if target file is included. */ 10914ea42b18SMasami Hiramatsu if (pp->file) 1092cf6eb489SMasami Hiramatsu pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1093804b3606SMasami Hiramatsu else 1094cf6eb489SMasami Hiramatsu pf->fname = NULL; 10954ea42b18SMasami Hiramatsu 1096cf6eb489SMasami Hiramatsu if (!pp->file || pf->fname) { 10974ea42b18SMasami Hiramatsu if (pp->function) 1098cf6eb489SMasami Hiramatsu ret = find_probe_point_by_func(pf); 10992a9c8c36SMasami Hiramatsu else if (pp->lazy_line) 1100f19e80c6SHe Kuang ret = find_probe_point_lazy(&pf->cu_die, pf); 1101b0ef0732SMasami Hiramatsu else { 1102cf6eb489SMasami Hiramatsu pf->lno = pp->line; 1103cf6eb489SMasami Hiramatsu ret = find_probe_point_by_line(pf); 11044ea42b18SMasami Hiramatsu } 11058635bf6eSArnaldo Carvalho de Melo if (ret < 0) 1106fbee632dSArnaldo Carvalho de Melo break; 1107b0ef0732SMasami Hiramatsu } 1108804b3606SMasami Hiramatsu off = noff; 11094ea42b18SMasami Hiramatsu } 1110cd25f8bcSLin Ming 1111cd25f8bcSLin Ming found: 11125a62257aSMasami Hiramatsu intlist__delete(pf->lcache); 11135a62257aSMasami Hiramatsu pf->lcache = NULL; 11144ea42b18SMasami Hiramatsu 1115cf6eb489SMasami Hiramatsu return ret; 1116cf6eb489SMasami Hiramatsu } 1117cf6eb489SMasami Hiramatsu 11187969ec77SMasami Hiramatsu struct local_vars_finder { 11197969ec77SMasami Hiramatsu struct probe_finder *pf; 11207969ec77SMasami Hiramatsu struct perf_probe_arg *args; 1121f8bffbf1SMasami Hiramatsu bool vars; 11227969ec77SMasami Hiramatsu int max_args; 11237969ec77SMasami Hiramatsu int nargs; 11247969ec77SMasami Hiramatsu int ret; 11257969ec77SMasami Hiramatsu }; 11267969ec77SMasami Hiramatsu 11277969ec77SMasami Hiramatsu /* Collect available variables in this scope */ 11287969ec77SMasami Hiramatsu static int copy_variables_cb(Dwarf_Die *die_mem, void *data) 11297969ec77SMasami Hiramatsu { 11307969ec77SMasami Hiramatsu struct local_vars_finder *vf = data; 11313d918a12SMasami Hiramatsu struct probe_finder *pf = vf->pf; 11327969ec77SMasami Hiramatsu int tag; 11337969ec77SMasami Hiramatsu 11347969ec77SMasami Hiramatsu tag = dwarf_tag(die_mem); 11357969ec77SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1136f8bffbf1SMasami Hiramatsu (tag == DW_TAG_variable && vf->vars)) { 11377969ec77SMasami Hiramatsu if (convert_variable_location(die_mem, vf->pf->addr, 11383d918a12SMasami Hiramatsu vf->pf->fb_ops, &pf->sp_die, 11393d918a12SMasami Hiramatsu NULL) == 0) { 11407969ec77SMasami Hiramatsu vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); 11417969ec77SMasami Hiramatsu if (vf->args[vf->nargs].var == NULL) { 11427969ec77SMasami Hiramatsu vf->ret = -ENOMEM; 11437969ec77SMasami Hiramatsu return DIE_FIND_CB_END; 11447969ec77SMasami Hiramatsu } 11457969ec77SMasami Hiramatsu pr_debug(" %s", vf->args[vf->nargs].var); 11467969ec77SMasami Hiramatsu vf->nargs++; 11477969ec77SMasami Hiramatsu } 11487969ec77SMasami Hiramatsu } 11497969ec77SMasami Hiramatsu 11507969ec77SMasami Hiramatsu if (dwarf_haspc(die_mem, vf->pf->addr)) 11517969ec77SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 11527969ec77SMasami Hiramatsu else 11537969ec77SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 11547969ec77SMasami Hiramatsu } 11557969ec77SMasami Hiramatsu 11567969ec77SMasami Hiramatsu static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, 11577969ec77SMasami Hiramatsu struct perf_probe_arg *args) 11587969ec77SMasami Hiramatsu { 11597969ec77SMasami Hiramatsu Dwarf_Die die_mem; 11607969ec77SMasami Hiramatsu int i; 11617969ec77SMasami Hiramatsu int n = 0; 1162f8bffbf1SMasami Hiramatsu struct local_vars_finder vf = {.pf = pf, .args = args, .vars = false, 11637969ec77SMasami Hiramatsu .max_args = MAX_PROBE_ARGS, .ret = 0}; 11647969ec77SMasami Hiramatsu 11657969ec77SMasami Hiramatsu for (i = 0; i < pf->pev->nargs; i++) { 11667969ec77SMasami Hiramatsu /* var never be NULL */ 1167f8bffbf1SMasami Hiramatsu if (strcmp(pf->pev->args[i].var, PROBE_ARG_VARS) == 0) 1168f8bffbf1SMasami Hiramatsu vf.vars = true; 1169f8bffbf1SMasami Hiramatsu else if (strcmp(pf->pev->args[i].var, PROBE_ARG_PARAMS) != 0) { 1170f8bffbf1SMasami Hiramatsu /* Copy normal argument */ 1171f8bffbf1SMasami Hiramatsu args[n] = pf->pev->args[i]; 1172f8bffbf1SMasami Hiramatsu n++; 1173f8bffbf1SMasami Hiramatsu continue; 1174f8bffbf1SMasami Hiramatsu } 1175f8bffbf1SMasami Hiramatsu pr_debug("Expanding %s into:", pf->pev->args[i].var); 11767969ec77SMasami Hiramatsu vf.nargs = n; 11777969ec77SMasami Hiramatsu /* Special local variables */ 11787969ec77SMasami Hiramatsu die_find_child(sc_die, copy_variables_cb, (void *)&vf, 11797969ec77SMasami Hiramatsu &die_mem); 11807969ec77SMasami Hiramatsu pr_debug(" (%d)\n", vf.nargs - n); 11817969ec77SMasami Hiramatsu if (vf.ret < 0) 11827969ec77SMasami Hiramatsu return vf.ret; 11837969ec77SMasami Hiramatsu n = vf.nargs; 11847969ec77SMasami Hiramatsu } 11857969ec77SMasami Hiramatsu return n; 11867969ec77SMasami Hiramatsu } 11877969ec77SMasami Hiramatsu 1188cf6eb489SMasami Hiramatsu /* Add a found probe point into trace event list */ 1189221d0611SMasami Hiramatsu static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1190cf6eb489SMasami Hiramatsu { 1191cf6eb489SMasami Hiramatsu struct trace_event_finder *tf = 1192cf6eb489SMasami Hiramatsu container_of(pf, struct trace_event_finder, pf); 1193cf6eb489SMasami Hiramatsu struct probe_trace_event *tev; 11947969ec77SMasami Hiramatsu struct perf_probe_arg *args; 1195cf6eb489SMasami Hiramatsu int ret, i; 1196cf6eb489SMasami Hiramatsu 1197cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1198cf6eb489SMasami Hiramatsu if (tf->ntevs == tf->max_tevs) { 1199cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", 1200cf6eb489SMasami Hiramatsu tf->max_tevs); 1201cf6eb489SMasami Hiramatsu return -ERANGE; 1202cf6eb489SMasami Hiramatsu } 1203cf6eb489SMasami Hiramatsu tev = &tf->tevs[tf->ntevs++]; 1204cf6eb489SMasami Hiramatsu 1205221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1206576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 1207221d0611SMasami Hiramatsu pf->pev->point.retprobe, &tev->point); 1208cf6eb489SMasami Hiramatsu if (ret < 0) 1209cf6eb489SMasami Hiramatsu return ret; 1210cf6eb489SMasami Hiramatsu 12114c859351SMasami Hiramatsu tev->point.realname = strdup(dwarf_diename(sc_die)); 12124c859351SMasami Hiramatsu if (!tev->point.realname) 12134c859351SMasami Hiramatsu return -ENOMEM; 12144c859351SMasami Hiramatsu 1215cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1216cf6eb489SMasami Hiramatsu tev->point.offset); 1217cf6eb489SMasami Hiramatsu 12187969ec77SMasami Hiramatsu /* Expand special probe argument if exist */ 12197969ec77SMasami Hiramatsu args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); 12207969ec77SMasami Hiramatsu if (args == NULL) 1221cf6eb489SMasami Hiramatsu return -ENOMEM; 12227969ec77SMasami Hiramatsu 12237969ec77SMasami Hiramatsu ret = expand_probe_args(sc_die, pf, args); 12247969ec77SMasami Hiramatsu if (ret < 0) 12257969ec77SMasami Hiramatsu goto end; 12267969ec77SMasami Hiramatsu 12277969ec77SMasami Hiramatsu tev->nargs = ret; 12287969ec77SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 12297969ec77SMasami Hiramatsu if (tev->args == NULL) { 12307969ec77SMasami Hiramatsu ret = -ENOMEM; 12317969ec77SMasami Hiramatsu goto end; 12327969ec77SMasami Hiramatsu } 12337969ec77SMasami Hiramatsu 12347969ec77SMasami Hiramatsu /* Find each argument */ 12357969ec77SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 12367969ec77SMasami Hiramatsu pf->pvar = &args[i]; 1237cf6eb489SMasami Hiramatsu pf->tvar = &tev->args[i]; 1238221d0611SMasami Hiramatsu /* Variable should be found from scope DIE */ 1239221d0611SMasami Hiramatsu ret = find_variable(sc_die, pf); 1240cf6eb489SMasami Hiramatsu if (ret != 0) 12417969ec77SMasami Hiramatsu break; 1242cf6eb489SMasami Hiramatsu } 1243cf6eb489SMasami Hiramatsu 12447969ec77SMasami Hiramatsu end: 12457969ec77SMasami Hiramatsu free(args); 12467969ec77SMasami Hiramatsu return ret; 1247cf6eb489SMasami Hiramatsu } 1248cf6eb489SMasami Hiramatsu 1249cf6eb489SMasami Hiramatsu /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1250316c7136SArnaldo Carvalho de Melo int debuginfo__find_trace_events(struct debuginfo *dbg, 1251ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1252ddb2f58fSMasami Hiramatsu struct probe_trace_event **tevs) 1253cf6eb489SMasami Hiramatsu { 1254cf6eb489SMasami Hiramatsu struct trace_event_finder tf = { 1255cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_probe_trace_event}, 1256ddb2f58fSMasami Hiramatsu .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; 1257cf6eb489SMasami Hiramatsu int ret; 1258cf6eb489SMasami Hiramatsu 1259cf6eb489SMasami Hiramatsu /* Allocate result tevs array */ 1260ddb2f58fSMasami Hiramatsu *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); 1261cf6eb489SMasami Hiramatsu if (*tevs == NULL) 1262cf6eb489SMasami Hiramatsu return -ENOMEM; 1263cf6eb489SMasami Hiramatsu 1264cf6eb489SMasami Hiramatsu tf.tevs = *tevs; 1265cf6eb489SMasami Hiramatsu tf.ntevs = 0; 1266cf6eb489SMasami Hiramatsu 1267316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &tf.pf); 1268cf6eb489SMasami Hiramatsu if (ret < 0) { 126904662523SArnaldo Carvalho de Melo zfree(tevs); 1270cf6eb489SMasami Hiramatsu return ret; 1271cf6eb489SMasami Hiramatsu } 1272cf6eb489SMasami Hiramatsu 1273cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : tf.ntevs; 1274cf6eb489SMasami Hiramatsu } 1275cf6eb489SMasami Hiramatsu 1276cf6eb489SMasami Hiramatsu /* Collect available variables in this scope */ 1277cf6eb489SMasami Hiramatsu static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1278cf6eb489SMasami Hiramatsu { 1279cf6eb489SMasami Hiramatsu struct available_var_finder *af = data; 1280cf6eb489SMasami Hiramatsu struct variable_list *vl; 1281cf6eb489SMasami Hiramatsu int tag, ret; 1282cf6eb489SMasami Hiramatsu 1283cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls - 1]; 1284cf6eb489SMasami Hiramatsu 1285cf6eb489SMasami Hiramatsu tag = dwarf_tag(die_mem); 1286cf6eb489SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1287cf6eb489SMasami Hiramatsu tag == DW_TAG_variable) { 1288cf6eb489SMasami Hiramatsu ret = convert_variable_location(die_mem, af->pf.addr, 12893d918a12SMasami Hiramatsu af->pf.fb_ops, &af->pf.sp_die, 12903d918a12SMasami Hiramatsu NULL); 1291349e8d26SHe Kuang if (ret == 0 || ret == -ERANGE) { 1292349e8d26SHe Kuang int ret2; 1293349e8d26SHe Kuang bool externs = !af->child; 1294fb9596d1SHe Kuang struct strbuf buf; 1295fb9596d1SHe Kuang 1296fb9596d1SHe Kuang strbuf_init(&buf, 64); 1297349e8d26SHe Kuang 1298349e8d26SHe Kuang if (probe_conf.show_location_range) { 1299349e8d26SHe Kuang if (!externs) { 1300349e8d26SHe Kuang if (ret) 1301349e8d26SHe Kuang strbuf_addf(&buf, "[INV]\t"); 1302349e8d26SHe Kuang else 1303349e8d26SHe Kuang strbuf_addf(&buf, "[VAL]\t"); 1304349e8d26SHe Kuang } else 1305349e8d26SHe Kuang strbuf_addf(&buf, "[EXT]\t"); 1306349e8d26SHe Kuang } 1307349e8d26SHe Kuang 1308349e8d26SHe Kuang ret2 = die_get_varname(die_mem, &buf); 1309349e8d26SHe Kuang 1310349e8d26SHe Kuang if (!ret2 && probe_conf.show_location_range && 1311349e8d26SHe Kuang !externs) { 1312349e8d26SHe Kuang strbuf_addf(&buf, "\t"); 1313349e8d26SHe Kuang ret2 = die_get_var_range(&af->pf.sp_die, 1314349e8d26SHe Kuang die_mem, &buf); 1315349e8d26SHe Kuang } 1316349e8d26SHe Kuang 1317349e8d26SHe Kuang pr_debug("Add new var: %s\n", buf.buf); 1318349e8d26SHe Kuang if (ret2 == 0) { 1319fb9596d1SHe Kuang strlist__add(vl->vars, 1320fb9596d1SHe Kuang strbuf_detach(&buf, NULL)); 1321fb9596d1SHe Kuang } 1322fb9596d1SHe Kuang strbuf_release(&buf); 1323cf6eb489SMasami Hiramatsu } 1324cf6eb489SMasami Hiramatsu } 1325cf6eb489SMasami Hiramatsu 1326fb8c5a56SMasami Hiramatsu if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1327cf6eb489SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 1328cf6eb489SMasami Hiramatsu else 1329cf6eb489SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 1330cf6eb489SMasami Hiramatsu } 1331cf6eb489SMasami Hiramatsu 1332cf6eb489SMasami Hiramatsu /* Add a found vars into available variables list */ 1333221d0611SMasami Hiramatsu static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1334cf6eb489SMasami Hiramatsu { 1335cf6eb489SMasami Hiramatsu struct available_var_finder *af = 1336cf6eb489SMasami Hiramatsu container_of(pf, struct available_var_finder, pf); 1337cf6eb489SMasami Hiramatsu struct variable_list *vl; 1338f182e3e1SMasami Hiramatsu Dwarf_Die die_mem; 1339f182e3e1SMasami Hiramatsu int ret; 1340cf6eb489SMasami Hiramatsu 1341cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1342cf6eb489SMasami Hiramatsu if (af->nvls == af->max_vls) { 1343cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1344cf6eb489SMasami Hiramatsu return -ERANGE; 1345cf6eb489SMasami Hiramatsu } 1346cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls++]; 1347cf6eb489SMasami Hiramatsu 1348221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1349576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, 1350221d0611SMasami Hiramatsu pf->pev->point.retprobe, &vl->point); 1351cf6eb489SMasami Hiramatsu if (ret < 0) 1352cf6eb489SMasami Hiramatsu return ret; 1353cf6eb489SMasami Hiramatsu 1354cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1355cf6eb489SMasami Hiramatsu vl->point.offset); 1356cf6eb489SMasami Hiramatsu 1357cf6eb489SMasami Hiramatsu /* Find local variables */ 1358cf6eb489SMasami Hiramatsu vl->vars = strlist__new(true, NULL); 1359cf6eb489SMasami Hiramatsu if (vl->vars == NULL) 1360cf6eb489SMasami Hiramatsu return -ENOMEM; 1361fb8c5a56SMasami Hiramatsu af->child = true; 1362221d0611SMasami Hiramatsu die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1363cf6eb489SMasami Hiramatsu 1364fb8c5a56SMasami Hiramatsu /* Find external variables */ 1365ddb2f58fSMasami Hiramatsu if (!probe_conf.show_ext_vars) 1366fb8c5a56SMasami Hiramatsu goto out; 1367ddb2f58fSMasami Hiramatsu /* Don't need to search child DIE for external vars. */ 1368fb8c5a56SMasami Hiramatsu af->child = false; 1369f182e3e1SMasami Hiramatsu die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1370fb8c5a56SMasami Hiramatsu 1371fb8c5a56SMasami Hiramatsu out: 1372cf6eb489SMasami Hiramatsu if (strlist__empty(vl->vars)) { 1373cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 1374cf6eb489SMasami Hiramatsu vl->vars = NULL; 1375cf6eb489SMasami Hiramatsu } 1376cf6eb489SMasami Hiramatsu 1377cf6eb489SMasami Hiramatsu return ret; 1378cf6eb489SMasami Hiramatsu } 1379cf6eb489SMasami Hiramatsu 138069e96eaaSMasami Hiramatsu /* 138169e96eaaSMasami Hiramatsu * Find available variables at given probe point 138269e96eaaSMasami Hiramatsu * Return the number of found probe points. Return 0 if there is no 138369e96eaaSMasami Hiramatsu * matched probe point. Return <0 if an error occurs. 138469e96eaaSMasami Hiramatsu */ 1385316c7136SArnaldo Carvalho de Melo int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1386ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1387ddb2f58fSMasami Hiramatsu struct variable_list **vls) 1388cf6eb489SMasami Hiramatsu { 1389cf6eb489SMasami Hiramatsu struct available_var_finder af = { 1390cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_available_vars}, 1391316c7136SArnaldo Carvalho de Melo .mod = dbg->mod, 1392ddb2f58fSMasami Hiramatsu .max_vls = probe_conf.max_probes}; 1393cf6eb489SMasami Hiramatsu int ret; 1394cf6eb489SMasami Hiramatsu 1395cf6eb489SMasami Hiramatsu /* Allocate result vls array */ 1396ddb2f58fSMasami Hiramatsu *vls = zalloc(sizeof(struct variable_list) * af.max_vls); 1397cf6eb489SMasami Hiramatsu if (*vls == NULL) 1398cf6eb489SMasami Hiramatsu return -ENOMEM; 1399cf6eb489SMasami Hiramatsu 1400cf6eb489SMasami Hiramatsu af.vls = *vls; 1401cf6eb489SMasami Hiramatsu af.nvls = 0; 1402cf6eb489SMasami Hiramatsu 1403316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &af.pf); 1404cf6eb489SMasami Hiramatsu if (ret < 0) { 1405cf6eb489SMasami Hiramatsu /* Free vlist for error */ 1406cf6eb489SMasami Hiramatsu while (af.nvls--) { 140774cf249dSArnaldo Carvalho de Melo zfree(&af.vls[af.nvls].point.symbol); 1408cf6eb489SMasami Hiramatsu strlist__delete(af.vls[af.nvls].vars); 1409cf6eb489SMasami Hiramatsu } 141004662523SArnaldo Carvalho de Melo zfree(vls); 1411cf6eb489SMasami Hiramatsu return ret; 1412cf6eb489SMasami Hiramatsu } 1413cf6eb489SMasami Hiramatsu 1414cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : af.nvls; 14154ea42b18SMasami Hiramatsu } 14164ea42b18SMasami Hiramatsu 1417fb1587d8SMasami Hiramatsu /* Reverse search */ 1418316c7136SArnaldo Carvalho de Melo int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, 1419ff741783SMasami Hiramatsu struct perf_probe_point *ppt) 1420fb1587d8SMasami Hiramatsu { 1421fb1587d8SMasami Hiramatsu Dwarf_Die cudie, spdie, indie; 1422e08cfd4bSMasami Hiramatsu Dwarf_Addr _addr = 0, baseaddr = 0; 1423e08cfd4bSMasami Hiramatsu const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; 14241d46ea2aSMasami Hiramatsu int baseline = 0, lineno = 0, ret = 0; 1425fb1587d8SMasami Hiramatsu 1426fb1587d8SMasami Hiramatsu /* Find cu die */ 14270104fe69SMasami Hiramatsu if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { 14280e43e5d2SMasami Hiramatsu pr_warning("Failed to find debug information for address %lx\n", 14290e43e5d2SMasami Hiramatsu addr); 143075ec5a24SMasami Hiramatsu ret = -EINVAL; 143175ec5a24SMasami Hiramatsu goto end; 143275ec5a24SMasami Hiramatsu } 1433fb1587d8SMasami Hiramatsu 14341d46ea2aSMasami Hiramatsu /* Find a corresponding line (filename and lineno) */ 14351d46ea2aSMasami Hiramatsu cu_find_lineinfo(&cudie, addr, &fname, &lineno); 14361d46ea2aSMasami Hiramatsu /* Don't care whether it failed or not */ 1437fb1587d8SMasami Hiramatsu 14381d46ea2aSMasami Hiramatsu /* Find a corresponding function (name, baseline and baseaddr) */ 1439e0d153c6SMasami Hiramatsu if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 14401d46ea2aSMasami Hiramatsu /* Get function entry information */ 1441e08cfd4bSMasami Hiramatsu func = basefunc = dwarf_diename(&spdie); 1442e08cfd4bSMasami Hiramatsu if (!func || 14431d46ea2aSMasami Hiramatsu dwarf_entrypc(&spdie, &baseaddr) != 0 || 1444e08cfd4bSMasami Hiramatsu dwarf_decl_line(&spdie, &baseline) != 0) { 1445e08cfd4bSMasami Hiramatsu lineno = 0; 14461d46ea2aSMasami Hiramatsu goto post; 1447e08cfd4bSMasami Hiramatsu } 1448fb1587d8SMasami Hiramatsu 14491b286bddSMasami Hiramatsu fname = dwarf_decl_file(&spdie); 1450e08cfd4bSMasami Hiramatsu if (addr == (unsigned long)baseaddr) { 14511d46ea2aSMasami Hiramatsu /* Function entry - Relative line number is 0 */ 14521d46ea2aSMasami Hiramatsu lineno = baseline; 1453e08cfd4bSMasami Hiramatsu goto post; 1454e08cfd4bSMasami Hiramatsu } 1455e08cfd4bSMasami Hiramatsu 1456e08cfd4bSMasami Hiramatsu /* Track down the inline functions step by step */ 1457e08cfd4bSMasami Hiramatsu while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, 1458b55a87adSMasami Hiramatsu &indie)) { 1459e08cfd4bSMasami Hiramatsu /* There is an inline function */ 14601d46ea2aSMasami Hiramatsu if (dwarf_entrypc(&indie, &_addr) == 0 && 1461e08cfd4bSMasami Hiramatsu _addr == addr) { 14621d46ea2aSMasami Hiramatsu /* 14631d46ea2aSMasami Hiramatsu * addr is at an inline function entry. 14641d46ea2aSMasami Hiramatsu * In this case, lineno should be the call-site 1465e08cfd4bSMasami Hiramatsu * line number. (overwrite lineinfo) 14661d46ea2aSMasami Hiramatsu */ 14671d46ea2aSMasami Hiramatsu lineno = die_get_call_lineno(&indie); 1468e08cfd4bSMasami Hiramatsu fname = die_get_call_file(&indie); 1469e08cfd4bSMasami Hiramatsu break; 1470e08cfd4bSMasami Hiramatsu } else { 14711d46ea2aSMasami Hiramatsu /* 14721d46ea2aSMasami Hiramatsu * addr is in an inline function body. 14731d46ea2aSMasami Hiramatsu * Since lineno points one of the lines 14741d46ea2aSMasami Hiramatsu * of the inline function, baseline should 14751d46ea2aSMasami Hiramatsu * be the entry line of the inline function. 14761d46ea2aSMasami Hiramatsu */ 1477fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&indie); 1478e08cfd4bSMasami Hiramatsu if (!tmp || 1479e08cfd4bSMasami Hiramatsu dwarf_decl_line(&indie, &baseline) != 0) 1480e08cfd4bSMasami Hiramatsu break; 14811d46ea2aSMasami Hiramatsu func = tmp; 1482e08cfd4bSMasami Hiramatsu spdie = indie; 1483b55a87adSMasami Hiramatsu } 1484b55a87adSMasami Hiramatsu } 1485e08cfd4bSMasami Hiramatsu /* Verify the lineno and baseline are in a same file */ 1486e08cfd4bSMasami Hiramatsu tmp = dwarf_decl_file(&spdie); 1487e08cfd4bSMasami Hiramatsu if (!tmp || strcmp(tmp, fname) != 0) 1488e08cfd4bSMasami Hiramatsu lineno = 0; 14891d46ea2aSMasami Hiramatsu } 14901d46ea2aSMasami Hiramatsu 14911d46ea2aSMasami Hiramatsu post: 14921d46ea2aSMasami Hiramatsu /* Make a relative line number or an offset */ 14931d46ea2aSMasami Hiramatsu if (lineno) 14941d46ea2aSMasami Hiramatsu ppt->line = lineno - baseline; 1495e08cfd4bSMasami Hiramatsu else if (basefunc) { 14961d46ea2aSMasami Hiramatsu ppt->offset = addr - (unsigned long)baseaddr; 1497e08cfd4bSMasami Hiramatsu func = basefunc; 1498e08cfd4bSMasami Hiramatsu } 14991d46ea2aSMasami Hiramatsu 15001d46ea2aSMasami Hiramatsu /* Duplicate strings */ 15011d46ea2aSMasami Hiramatsu if (func) { 15021d46ea2aSMasami Hiramatsu ppt->function = strdup(func); 150302b95dadSMasami Hiramatsu if (ppt->function == NULL) { 150402b95dadSMasami Hiramatsu ret = -ENOMEM; 150502b95dadSMasami Hiramatsu goto end; 150602b95dadSMasami Hiramatsu } 1507fb1587d8SMasami Hiramatsu } 15081d46ea2aSMasami Hiramatsu if (fname) { 15091d46ea2aSMasami Hiramatsu ppt->file = strdup(fname); 15101d46ea2aSMasami Hiramatsu if (ppt->file == NULL) { 151104662523SArnaldo Carvalho de Melo zfree(&ppt->function); 15121d46ea2aSMasami Hiramatsu ret = -ENOMEM; 15131d46ea2aSMasami Hiramatsu goto end; 15141d46ea2aSMasami Hiramatsu } 15151d46ea2aSMasami Hiramatsu } 1516fb1587d8SMasami Hiramatsu end: 15171d46ea2aSMasami Hiramatsu if (ret == 0 && (fname || func)) 15181d46ea2aSMasami Hiramatsu ret = 1; /* Found a point */ 1519fb1587d8SMasami Hiramatsu return ret; 1520fb1587d8SMasami Hiramatsu } 1521fb1587d8SMasami Hiramatsu 1522f6c903f5SMasami Hiramatsu /* Add a line and store the src path */ 1523f6c903f5SMasami Hiramatsu static int line_range_add_line(const char *src, unsigned int lineno, 1524f6c903f5SMasami Hiramatsu struct line_range *lr) 1525f6c903f5SMasami Hiramatsu { 15267cf0b79eSMasami Hiramatsu /* Copy source path */ 1527f6c903f5SMasami Hiramatsu if (!lr->path) { 15287cf0b79eSMasami Hiramatsu lr->path = strdup(src); 15297cf0b79eSMasami Hiramatsu if (lr->path == NULL) 15307cf0b79eSMasami Hiramatsu return -ENOMEM; 1531f6c903f5SMasami Hiramatsu } 15325a62257aSMasami Hiramatsu return intlist__add(lr->line_list, lineno); 1533f6c903f5SMasami Hiramatsu } 1534f6c903f5SMasami Hiramatsu 15354cc9cec6SMasami Hiramatsu static int line_range_walk_cb(const char *fname, int lineno, 15361d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused, 15374cc9cec6SMasami Hiramatsu void *data) 1538f6c903f5SMasami Hiramatsu { 15394cc9cec6SMasami Hiramatsu struct line_finder *lf = data; 1540202c7c12SNamhyung Kim int err; 1541f6c903f5SMasami Hiramatsu 15424cc9cec6SMasami Hiramatsu if ((strtailcmp(fname, lf->fname) != 0) || 1543f6c903f5SMasami Hiramatsu (lf->lno_s > lineno || lf->lno_e < lineno)) 15444cc9cec6SMasami Hiramatsu return 0; 1545f6c903f5SMasami Hiramatsu 1546202c7c12SNamhyung Kim err = line_range_add_line(fname, lineno, lf->lr); 1547202c7c12SNamhyung Kim if (err < 0 && err != -EEXIST) 1548202c7c12SNamhyung Kim return err; 1549f6c903f5SMasami Hiramatsu 15504cc9cec6SMasami Hiramatsu return 0; 1551f6c903f5SMasami Hiramatsu } 1552fb1587d8SMasami Hiramatsu 1553631c9defSMasami Hiramatsu /* Find line range from its line number */ 1554b55a87adSMasami Hiramatsu static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1555631c9defSMasami Hiramatsu { 15564cc9cec6SMasami Hiramatsu int ret; 1557631c9defSMasami Hiramatsu 15584cc9cec6SMasami Hiramatsu ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1559f6c903f5SMasami Hiramatsu 1560804b3606SMasami Hiramatsu /* Update status */ 1561f6c903f5SMasami Hiramatsu if (ret >= 0) 15625a62257aSMasami Hiramatsu if (!intlist__empty(lf->lr->line_list)) 1563f6c903f5SMasami Hiramatsu ret = lf->found = 1; 1564f6c903f5SMasami Hiramatsu else 1565f6c903f5SMasami Hiramatsu ret = 0; /* Lines are not found */ 1566804b3606SMasami Hiramatsu else { 156704662523SArnaldo Carvalho de Melo zfree(&lf->lr->path); 1568804b3606SMasami Hiramatsu } 1569f6c903f5SMasami Hiramatsu return ret; 1570631c9defSMasami Hiramatsu } 1571631c9defSMasami Hiramatsu 1572161a26b0SMasami Hiramatsu static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1573161a26b0SMasami Hiramatsu { 1574182c228eSMasami Hiramatsu int ret = find_line_range_by_line(in_die, data); 157536c0c588SMasami Hiramatsu 157636c0c588SMasami Hiramatsu /* 157736c0c588SMasami Hiramatsu * We have to check all instances of inlined function, because 157836c0c588SMasami Hiramatsu * some execution paths can be optimized out depends on the 1579182c228eSMasami Hiramatsu * function argument of instances. However, if an error occurs, 1580182c228eSMasami Hiramatsu * it should be handled by the caller. 158136c0c588SMasami Hiramatsu */ 1582182c228eSMasami Hiramatsu return ret < 0 ? ret : 0; 1583161a26b0SMasami Hiramatsu } 1584161a26b0SMasami Hiramatsu 15850dbb1cacSMasami Hiramatsu /* Search function definition from function name */ 1586e92b85e1SMasami Hiramatsu static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1587631c9defSMasami Hiramatsu { 1588b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1589b55a87adSMasami Hiramatsu struct line_finder *lf = param->data; 1590631c9defSMasami Hiramatsu struct line_range *lr = lf->lr; 1591631c9defSMasami Hiramatsu 15927d21635aSMasami Hiramatsu /* Check declared file */ 15937d21635aSMasami Hiramatsu if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 15947d21635aSMasami Hiramatsu return DWARF_CB_OK; 15957d21635aSMasami Hiramatsu 15960dbb1cacSMasami Hiramatsu if (die_is_func_def(sp_die) && 15974c859351SMasami Hiramatsu die_match_name(sp_die, lr->function)) { 1598e92b85e1SMasami Hiramatsu lf->fname = dwarf_decl_file(sp_die); 1599e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &lr->offset); 1600804b3606SMasami Hiramatsu pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1601631c9defSMasami Hiramatsu lf->lno_s = lr->offset + lr->start; 1602d3b63d7aSMasami Hiramatsu if (lf->lno_s < 0) /* Overflow */ 1603d3b63d7aSMasami Hiramatsu lf->lno_s = INT_MAX; 1604631c9defSMasami Hiramatsu lf->lno_e = lr->offset + lr->end; 1605d3b63d7aSMasami Hiramatsu if (lf->lno_e < 0) /* Overflow */ 1606d3b63d7aSMasami Hiramatsu lf->lno_e = INT_MAX; 1607d3b63d7aSMasami Hiramatsu pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1608631c9defSMasami Hiramatsu lr->start = lf->lno_s; 1609631c9defSMasami Hiramatsu lr->end = lf->lno_e; 1610e1ecbbc3SMasami Hiramatsu if (!die_is_func_instance(sp_die)) 1611db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1612db0d2c64SMasami Hiramatsu line_range_inline_cb, lf); 1613db0d2c64SMasami Hiramatsu else 1614b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(sp_die, lf); 1615b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1616631c9defSMasami Hiramatsu } 1617b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1618631c9defSMasami Hiramatsu } 1619631c9defSMasami Hiramatsu 1620b55a87adSMasami Hiramatsu static int find_line_range_by_func(struct line_finder *lf) 1621631c9defSMasami Hiramatsu { 1622b55a87adSMasami Hiramatsu struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1623b55a87adSMasami Hiramatsu dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1624b55a87adSMasami Hiramatsu return param.retval; 1625631c9defSMasami Hiramatsu } 1626631c9defSMasami Hiramatsu 1627316c7136SArnaldo Carvalho de Melo int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr) 1628631c9defSMasami Hiramatsu { 1629804b3606SMasami Hiramatsu struct line_finder lf = {.lr = lr, .found = 0}; 1630b55a87adSMasami Hiramatsu int ret = 0; 1631804b3606SMasami Hiramatsu Dwarf_Off off = 0, noff; 1632804b3606SMasami Hiramatsu size_t cuhl; 1633804b3606SMasami Hiramatsu Dwarf_Die *diep; 16346a330a3cSMasami Hiramatsu const char *comp_dir; 1635631c9defSMasami Hiramatsu 1636cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1637cd25f8bcSLin Ming if (lr->function) { 1638cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1639cd25f8bcSLin Ming .function = lr->function, .file = lr->file, 1640cd25f8bcSLin Ming .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1641cd25f8bcSLin Ming struct dwarf_callback_param line_range_param = { 1642cd25f8bcSLin Ming .data = (void *)&lf, .retval = 0}; 1643cd25f8bcSLin Ming 1644316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1645ff741783SMasami Hiramatsu &pubname_param, 0); 1646cd25f8bcSLin Ming if (pubname_param.found) { 1647cd25f8bcSLin Ming line_range_search_cb(&lf.sp_die, &line_range_param); 1648cd25f8bcSLin Ming if (lf.found) 1649cd25f8bcSLin Ming goto found; 1650cd25f8bcSLin Ming } 1651cd25f8bcSLin Ming } 1652cd25f8bcSLin Ming 1653804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1654b55a87adSMasami Hiramatsu while (!lf.found && ret >= 0) { 1655316c7136SArnaldo Carvalho de Melo if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, 1656ff741783SMasami Hiramatsu NULL, NULL, NULL) != 0) 1657631c9defSMasami Hiramatsu break; 1658631c9defSMasami Hiramatsu 1659631c9defSMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1660316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die); 1661804b3606SMasami Hiramatsu if (!diep) 1662804b3606SMasami Hiramatsu continue; 1663631c9defSMasami Hiramatsu 1664631c9defSMasami Hiramatsu /* Check if target file is included. */ 1665631c9defSMasami Hiramatsu if (lr->file) 16662a9c8c36SMasami Hiramatsu lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1667804b3606SMasami Hiramatsu else 16682a9c8c36SMasami Hiramatsu lf.fname = 0; 1669631c9defSMasami Hiramatsu 16702a9c8c36SMasami Hiramatsu if (!lr->file || lf.fname) { 1671631c9defSMasami Hiramatsu if (lr->function) 1672b55a87adSMasami Hiramatsu ret = find_line_range_by_func(&lf); 1673631c9defSMasami Hiramatsu else { 1674631c9defSMasami Hiramatsu lf.lno_s = lr->start; 1675631c9defSMasami Hiramatsu lf.lno_e = lr->end; 1676b55a87adSMasami Hiramatsu ret = find_line_range_by_line(NULL, &lf); 1677631c9defSMasami Hiramatsu } 1678631c9defSMasami Hiramatsu } 1679804b3606SMasami Hiramatsu off = noff; 1680631c9defSMasami Hiramatsu } 16816a330a3cSMasami Hiramatsu 1682cd25f8bcSLin Ming found: 16836a330a3cSMasami Hiramatsu /* Store comp_dir */ 16846a330a3cSMasami Hiramatsu if (lf.found) { 16856a330a3cSMasami Hiramatsu comp_dir = cu_get_comp_dir(&lf.cu_die); 16866a330a3cSMasami Hiramatsu if (comp_dir) { 16876a330a3cSMasami Hiramatsu lr->comp_dir = strdup(comp_dir); 16886a330a3cSMasami Hiramatsu if (!lr->comp_dir) 16896a330a3cSMasami Hiramatsu ret = -ENOMEM; 16906a330a3cSMasami Hiramatsu } 16916a330a3cSMasami Hiramatsu } 16926a330a3cSMasami Hiramatsu 16937cf0b79eSMasami Hiramatsu pr_debug("path: %s\n", lr->path); 1694b55a87adSMasami Hiramatsu return (ret < 0) ? ret : lf.found; 1695631c9defSMasami Hiramatsu } 1696631c9defSMasami Hiramatsu 169709ed8975SNaohiro Aota /* 169809ed8975SNaohiro Aota * Find a src file from a DWARF tag path. Prepend optional source path prefix 169909ed8975SNaohiro Aota * and chop off leading directories that do not exist. Result is passed back as 170009ed8975SNaohiro Aota * a newly allocated path on success. 170109ed8975SNaohiro Aota * Return 0 if file was found and readable, -errno otherwise. 170209ed8975SNaohiro Aota */ 170309ed8975SNaohiro Aota int get_real_path(const char *raw_path, const char *comp_dir, 170409ed8975SNaohiro Aota char **new_path) 170509ed8975SNaohiro Aota { 170609ed8975SNaohiro Aota const char *prefix = symbol_conf.source_prefix; 170709ed8975SNaohiro Aota 170809ed8975SNaohiro Aota if (!prefix) { 170909ed8975SNaohiro Aota if (raw_path[0] != '/' && comp_dir) 171009ed8975SNaohiro Aota /* If not an absolute path, try to use comp_dir */ 171109ed8975SNaohiro Aota prefix = comp_dir; 171209ed8975SNaohiro Aota else { 171309ed8975SNaohiro Aota if (access(raw_path, R_OK) == 0) { 171409ed8975SNaohiro Aota *new_path = strdup(raw_path); 171509ed8975SNaohiro Aota return *new_path ? 0 : -ENOMEM; 171609ed8975SNaohiro Aota } else 171709ed8975SNaohiro Aota return -errno; 171809ed8975SNaohiro Aota } 171909ed8975SNaohiro Aota } 172009ed8975SNaohiro Aota 172109ed8975SNaohiro Aota *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 172209ed8975SNaohiro Aota if (!*new_path) 172309ed8975SNaohiro Aota return -ENOMEM; 172409ed8975SNaohiro Aota 172509ed8975SNaohiro Aota for (;;) { 172609ed8975SNaohiro Aota sprintf(*new_path, "%s/%s", prefix, raw_path); 172709ed8975SNaohiro Aota 172809ed8975SNaohiro Aota if (access(*new_path, R_OK) == 0) 172909ed8975SNaohiro Aota return 0; 173009ed8975SNaohiro Aota 173109ed8975SNaohiro Aota if (!symbol_conf.source_prefix) { 173209ed8975SNaohiro Aota /* In case of searching comp_dir, don't retry */ 173309ed8975SNaohiro Aota zfree(new_path); 173409ed8975SNaohiro Aota return -errno; 173509ed8975SNaohiro Aota } 173609ed8975SNaohiro Aota 173709ed8975SNaohiro Aota switch (errno) { 173809ed8975SNaohiro Aota case ENAMETOOLONG: 173909ed8975SNaohiro Aota case ENOENT: 174009ed8975SNaohiro Aota case EROFS: 174109ed8975SNaohiro Aota case EFAULT: 174209ed8975SNaohiro Aota raw_path = strchr(++raw_path, '/'); 174309ed8975SNaohiro Aota if (!raw_path) { 174409ed8975SNaohiro Aota zfree(new_path); 174509ed8975SNaohiro Aota return -ENOENT; 174609ed8975SNaohiro Aota } 174709ed8975SNaohiro Aota continue; 174809ed8975SNaohiro Aota 174909ed8975SNaohiro Aota default: 175009ed8975SNaohiro Aota zfree(new_path); 175109ed8975SNaohiro Aota return -errno; 175209ed8975SNaohiro Aota } 175309ed8975SNaohiro Aota } 175409ed8975SNaohiro Aota } 1755