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 739135949dSMasami Hiramatsu dwfl_report_begin(dbg->dwfl); 74316c7136SArnaldo Carvalho de Melo dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); 75316c7136SArnaldo Carvalho de Melo if (!dbg->mod) 76469b9b88SMasami Hiramatsu goto error; 77469b9b88SMasami Hiramatsu 78316c7136SArnaldo Carvalho de Melo dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); 79316c7136SArnaldo Carvalho de Melo if (!dbg->dbg) 80ff741783SMasami Hiramatsu goto error; 81ff741783SMasami Hiramatsu 829135949dSMasami Hiramatsu dwfl_report_end(dbg->dwfl, NULL, NULL); 839135949dSMasami Hiramatsu 84ff741783SMasami Hiramatsu return 0; 85469b9b88SMasami Hiramatsu error: 86316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 87316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 88ff741783SMasami Hiramatsu else 89ff741783SMasami Hiramatsu close(fd); 90316c7136SArnaldo Carvalho de Melo memset(dbg, 0, sizeof(*dbg)); 91ff741783SMasami Hiramatsu 92ff741783SMasami Hiramatsu return -ENOENT; 93469b9b88SMasami Hiramatsu } 94469b9b88SMasami Hiramatsu 95a15ad2f5SMasami Hiramatsu static struct debuginfo *__debuginfo__new(const char *path) 96ff741783SMasami Hiramatsu { 97316c7136SArnaldo Carvalho de Melo struct debuginfo *dbg = zalloc(sizeof(*dbg)); 98316c7136SArnaldo Carvalho de Melo if (!dbg) 99ff741783SMasami Hiramatsu return NULL; 100ff741783SMasami Hiramatsu 10104662523SArnaldo Carvalho de Melo if (debuginfo__init_offline_dwarf(dbg, path) < 0) 10204662523SArnaldo Carvalho de Melo zfree(&dbg); 103a15ad2f5SMasami Hiramatsu if (dbg) 104a15ad2f5SMasami Hiramatsu pr_debug("Open Debuginfo file: %s\n", path); 105316c7136SArnaldo Carvalho de Melo return dbg; 106ff741783SMasami Hiramatsu } 107ff741783SMasami Hiramatsu 108a15ad2f5SMasami Hiramatsu enum dso_binary_type distro_dwarf_types[] = { 109a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 110a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 111a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 112a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 113a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__NOT_FOUND, 114a15ad2f5SMasami Hiramatsu }; 115a15ad2f5SMasami Hiramatsu 116a15ad2f5SMasami Hiramatsu struct debuginfo *debuginfo__new(const char *path) 117a15ad2f5SMasami Hiramatsu { 118a15ad2f5SMasami Hiramatsu enum dso_binary_type *type; 119a15ad2f5SMasami Hiramatsu char buf[PATH_MAX], nil = '\0'; 120a15ad2f5SMasami Hiramatsu struct dso *dso; 121a15ad2f5SMasami Hiramatsu struct debuginfo *dinfo = NULL; 122a15ad2f5SMasami Hiramatsu 123a15ad2f5SMasami Hiramatsu /* Try to open distro debuginfo files */ 124a15ad2f5SMasami Hiramatsu dso = dso__new(path); 125a15ad2f5SMasami Hiramatsu if (!dso) 126a15ad2f5SMasami Hiramatsu goto out; 127a15ad2f5SMasami Hiramatsu 128a15ad2f5SMasami Hiramatsu for (type = distro_dwarf_types; 129a15ad2f5SMasami Hiramatsu !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; 130a15ad2f5SMasami Hiramatsu type++) { 131a15ad2f5SMasami Hiramatsu if (dso__read_binary_type_filename(dso, *type, &nil, 132a15ad2f5SMasami Hiramatsu buf, PATH_MAX) < 0) 133a15ad2f5SMasami Hiramatsu continue; 134a15ad2f5SMasami Hiramatsu dinfo = __debuginfo__new(buf); 135a15ad2f5SMasami Hiramatsu } 136d3a7c489SArnaldo Carvalho de Melo dso__put(dso); 137a15ad2f5SMasami Hiramatsu 138a15ad2f5SMasami Hiramatsu out: 139a15ad2f5SMasami Hiramatsu /* if failed to open all distro debuginfo, open given binary */ 140a15ad2f5SMasami Hiramatsu return dinfo ? : __debuginfo__new(path); 141a15ad2f5SMasami Hiramatsu } 142a15ad2f5SMasami Hiramatsu 143316c7136SArnaldo Carvalho de Melo void debuginfo__delete(struct debuginfo *dbg) 144ff741783SMasami Hiramatsu { 145316c7136SArnaldo Carvalho de Melo if (dbg) { 146316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 147316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 148316c7136SArnaldo Carvalho de Melo free(dbg); 149ff741783SMasami Hiramatsu } 150ff741783SMasami Hiramatsu } 151ff741783SMasami Hiramatsu 1524ea42b18SMasami Hiramatsu /* 1534ea42b18SMasami Hiramatsu * Probe finder related functions 1544ea42b18SMasami Hiramatsu */ 1554ea42b18SMasami Hiramatsu 1560e60836bSSrikar Dronamraju static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 1574ea42b18SMasami Hiramatsu { 1580e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref; 1590e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 160b7dcb857SMasami Hiramatsu if (ref != NULL) 161b7dcb857SMasami Hiramatsu ref->offset = offs; 162b7dcb857SMasami Hiramatsu return ref; 163b7dcb857SMasami Hiramatsu } 164b7dcb857SMasami Hiramatsu 165cf6eb489SMasami Hiramatsu /* 166cf6eb489SMasami Hiramatsu * Convert a location into trace_arg. 167cf6eb489SMasami Hiramatsu * If tvar == NULL, this just checks variable can be converted. 1683d918a12SMasami Hiramatsu * If fentry == true and vr_die is a parameter, do huristic search 1693d918a12SMasami Hiramatsu * for the location fuzzed by function entry mcount. 170cf6eb489SMasami Hiramatsu */ 171cf6eb489SMasami Hiramatsu static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 1723d918a12SMasami Hiramatsu Dwarf_Op *fb_ops, Dwarf_Die *sp_die, 173cf6eb489SMasami Hiramatsu struct probe_trace_arg *tvar) 174b7dcb857SMasami Hiramatsu { 175b7dcb857SMasami Hiramatsu Dwarf_Attribute attr; 1763d918a12SMasami Hiramatsu Dwarf_Addr tmp = 0; 177b7dcb857SMasami Hiramatsu Dwarf_Op *op; 178b7dcb857SMasami Hiramatsu size_t nops; 179804b3606SMasami Hiramatsu unsigned int regn; 180804b3606SMasami Hiramatsu Dwarf_Word offs = 0; 1814235b045SMasami Hiramatsu bool ref = false; 1824ea42b18SMasami Hiramatsu const char *regs; 183349e8d26SHe Kuang int ret, ret2 = 0; 184b7dcb857SMasami Hiramatsu 185632941c4SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 186632941c4SMasami Hiramatsu goto static_var; 187632941c4SMasami Hiramatsu 188b7dcb857SMasami Hiramatsu /* TODO: handle more than 1 exprs */ 1893d918a12SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 1903d918a12SMasami Hiramatsu return -EINVAL; /* Broken DIE ? */ 1913d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { 1923d918a12SMasami Hiramatsu ret = dwarf_entrypc(sp_die, &tmp); 193349e8d26SHe Kuang if (ret) 194349e8d26SHe Kuang return -ENOENT; 195349e8d26SHe Kuang 196349e8d26SHe Kuang if (probe_conf.show_location_range && 197349e8d26SHe Kuang (dwarf_tag(vr_die) == DW_TAG_variable)) { 198349e8d26SHe Kuang ret2 = -ERANGE; 199349e8d26SHe Kuang } else if (addr != tmp || 200349e8d26SHe Kuang dwarf_tag(vr_die) != DW_TAG_formal_parameter) { 201349e8d26SHe Kuang return -ENOENT; 202349e8d26SHe Kuang } 203349e8d26SHe Kuang 204349e8d26SHe Kuang ret = dwarf_highpc(sp_die, &tmp); 205349e8d26SHe Kuang if (ret) 2063d918a12SMasami Hiramatsu return -ENOENT; 2073d918a12SMasami Hiramatsu /* 2083d918a12SMasami Hiramatsu * This is fuzzed by fentry mcount. We try to find the 2093d918a12SMasami Hiramatsu * parameter location at the earliest address. 2103d918a12SMasami Hiramatsu */ 2113d918a12SMasami Hiramatsu for (addr += 1; addr <= tmp; addr++) { 2123d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, 2133d918a12SMasami Hiramatsu &nops, 1) > 0) 2143d918a12SMasami Hiramatsu goto found; 2153d918a12SMasami Hiramatsu } 216b7dcb857SMasami Hiramatsu return -ENOENT; 217b7dcb857SMasami Hiramatsu } 2183d918a12SMasami Hiramatsu found: 2193d918a12SMasami Hiramatsu if (nops == 0) 2203d918a12SMasami Hiramatsu /* TODO: Support const_value */ 2213d918a12SMasami Hiramatsu return -ENOENT; 222b7dcb857SMasami Hiramatsu 223b7dcb857SMasami Hiramatsu if (op->atom == DW_OP_addr) { 224632941c4SMasami Hiramatsu static_var: 225cf6eb489SMasami Hiramatsu if (!tvar) 226349e8d26SHe Kuang return ret2; 227b7dcb857SMasami Hiramatsu /* Static variables on memory (not stack), make @varname */ 228b7dcb857SMasami Hiramatsu ret = strlen(dwarf_diename(vr_die)); 229b7dcb857SMasami Hiramatsu tvar->value = zalloc(ret + 2); 230b7dcb857SMasami Hiramatsu if (tvar->value == NULL) 231b7dcb857SMasami Hiramatsu return -ENOMEM; 232b7dcb857SMasami Hiramatsu snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 233b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 234b7dcb857SMasami Hiramatsu if (tvar->ref == NULL) 235b7dcb857SMasami Hiramatsu return -ENOMEM; 236349e8d26SHe Kuang return ret2; 237b7dcb857SMasami Hiramatsu } 2384ea42b18SMasami Hiramatsu 2394ea42b18SMasami Hiramatsu /* If this is based on frame buffer, set the offset */ 240804b3606SMasami Hiramatsu if (op->atom == DW_OP_fbreg) { 241cf6eb489SMasami Hiramatsu if (fb_ops == NULL) 242b55a87adSMasami Hiramatsu return -ENOTSUP; 2434235b045SMasami Hiramatsu ref = true; 244804b3606SMasami Hiramatsu offs = op->number; 245cf6eb489SMasami Hiramatsu op = &fb_ops[0]; 246804b3606SMasami Hiramatsu } 2474ea42b18SMasami Hiramatsu 248804b3606SMasami Hiramatsu if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 249804b3606SMasami Hiramatsu regn = op->atom - DW_OP_breg0; 250804b3606SMasami Hiramatsu offs += op->number; 2514235b045SMasami Hiramatsu ref = true; 252804b3606SMasami Hiramatsu } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 253804b3606SMasami Hiramatsu regn = op->atom - DW_OP_reg0; 254804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_bregx) { 255804b3606SMasami Hiramatsu regn = op->number; 256804b3606SMasami Hiramatsu offs += op->number2; 2574235b045SMasami Hiramatsu ref = true; 258804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_regx) { 259804b3606SMasami Hiramatsu regn = op->number; 260b55a87adSMasami Hiramatsu } else { 261cf6eb489SMasami Hiramatsu pr_debug("DW_OP %x is not supported.\n", op->atom); 262b55a87adSMasami Hiramatsu return -ENOTSUP; 263b55a87adSMasami Hiramatsu } 2644ea42b18SMasami Hiramatsu 265cf6eb489SMasami Hiramatsu if (!tvar) 266349e8d26SHe Kuang return ret2; 267cf6eb489SMasami Hiramatsu 2684ea42b18SMasami Hiramatsu regs = get_arch_regstr(regn); 269b55a87adSMasami Hiramatsu if (!regs) { 270cf6eb489SMasami Hiramatsu /* This should be a bug in DWARF or this tool */ 2710e43e5d2SMasami Hiramatsu pr_warning("Mapping for the register number %u " 2720e43e5d2SMasami Hiramatsu "missing on this architecture.\n", regn); 273349e8d26SHe Kuang return -ENOTSUP; 274b55a87adSMasami Hiramatsu } 2754ea42b18SMasami Hiramatsu 27602b95dadSMasami Hiramatsu tvar->value = strdup(regs); 27702b95dadSMasami Hiramatsu if (tvar->value == NULL) 27802b95dadSMasami Hiramatsu return -ENOMEM; 27902b95dadSMasami Hiramatsu 2804235b045SMasami Hiramatsu if (ref) { 281b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 282e334016fSMasami Hiramatsu if (tvar->ref == NULL) 283e334016fSMasami Hiramatsu return -ENOMEM; 2844235b045SMasami Hiramatsu } 285349e8d26SHe Kuang return ret2; 2864ea42b18SMasami Hiramatsu } 2874ea42b18SMasami Hiramatsu 288124bb83cSMasami Hiramatsu #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 289124bb83cSMasami Hiramatsu 290b55a87adSMasami Hiramatsu static int convert_variable_type(Dwarf_Die *vr_die, 2910e60836bSSrikar Dronamraju struct probe_trace_arg *tvar, 29273317b95SMasami Hiramatsu const char *cast) 2934984912eSMasami Hiramatsu { 2940e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 2954984912eSMasami Hiramatsu Dwarf_Die type; 2964984912eSMasami Hiramatsu char buf[16]; 2975f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 298bcfc0821SMasami Hiramatsu int bsize, boffs, total; 2994984912eSMasami Hiramatsu int ret; 3004984912eSMasami Hiramatsu 30173317b95SMasami Hiramatsu /* TODO: check all types */ 30273317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") != 0) { 30373317b95SMasami Hiramatsu /* Non string type is OK */ 30473317b95SMasami Hiramatsu tvar->type = strdup(cast); 30573317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 30673317b95SMasami Hiramatsu } 30773317b95SMasami Hiramatsu 308bcfc0821SMasami Hiramatsu bsize = dwarf_bitsize(vr_die); 309bcfc0821SMasami Hiramatsu if (bsize > 0) { 310124bb83cSMasami Hiramatsu /* This is a bitfield */ 311bcfc0821SMasami Hiramatsu boffs = dwarf_bitoffset(vr_die); 312bcfc0821SMasami Hiramatsu total = dwarf_bytesize(vr_die); 313bcfc0821SMasami Hiramatsu if (boffs < 0 || total < 0) 314bcfc0821SMasami Hiramatsu return -ENOENT; 315bcfc0821SMasami Hiramatsu ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 316bcfc0821SMasami Hiramatsu BYTES_TO_BITS(total)); 317124bb83cSMasami Hiramatsu goto formatted; 318124bb83cSMasami Hiramatsu } 319124bb83cSMasami Hiramatsu 320b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 321b55a87adSMasami Hiramatsu pr_warning("Failed to get a type information of %s.\n", 3224984912eSMasami Hiramatsu dwarf_diename(vr_die)); 323b55a87adSMasami Hiramatsu return -ENOENT; 324b55a87adSMasami Hiramatsu } 3254984912eSMasami Hiramatsu 326b2a3c12bSMasami Hiramatsu pr_debug("%s type is %s.\n", 327b2a3c12bSMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 328b2a3c12bSMasami Hiramatsu 32973317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") == 0) { /* String type */ 33073317b95SMasami Hiramatsu ret = dwarf_tag(&type); 33173317b95SMasami Hiramatsu if (ret != DW_TAG_pointer_type && 33273317b95SMasami Hiramatsu ret != DW_TAG_array_type) { 33373317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3340e43e5d2SMasami Hiramatsu "%s(%s) is not a pointer nor array.\n", 33573317b95SMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 33673317b95SMasami Hiramatsu return -EINVAL; 33773317b95SMasami Hiramatsu } 33873317b95SMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 3390e43e5d2SMasami Hiramatsu pr_warning("Failed to get a type" 3400e43e5d2SMasami Hiramatsu " information.\n"); 34173317b95SMasami Hiramatsu return -ENOENT; 34273317b95SMasami Hiramatsu } 3437ce28b5bSHyeoncheol Lee if (ret == DW_TAG_pointer_type) { 34473317b95SMasami Hiramatsu while (*ref_ptr) 34573317b95SMasami Hiramatsu ref_ptr = &(*ref_ptr)->next; 34673317b95SMasami Hiramatsu /* Add new reference with offset +0 */ 3470e60836bSSrikar Dronamraju *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 34873317b95SMasami Hiramatsu if (*ref_ptr == NULL) { 34973317b95SMasami Hiramatsu pr_warning("Out of memory error\n"); 35073317b95SMasami Hiramatsu return -ENOMEM; 35173317b95SMasami Hiramatsu } 35273317b95SMasami Hiramatsu } 35382175633SMasami Hiramatsu if (!die_compare_name(&type, "char") && 35482175633SMasami Hiramatsu !die_compare_name(&type, "unsigned char")) { 35573317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3560e43e5d2SMasami Hiramatsu "%s is not (unsigned) char *.\n", 35773317b95SMasami Hiramatsu dwarf_diename(vr_die)); 35873317b95SMasami Hiramatsu return -EINVAL; 35973317b95SMasami Hiramatsu } 36073317b95SMasami Hiramatsu tvar->type = strdup(cast); 36173317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 36273317b95SMasami Hiramatsu } 36373317b95SMasami Hiramatsu 364bcfc0821SMasami Hiramatsu ret = dwarf_bytesize(&type); 365bcfc0821SMasami Hiramatsu if (ret <= 0) 366124bb83cSMasami Hiramatsu /* No size ... try to use default type */ 367124bb83cSMasami Hiramatsu return 0; 368bcfc0821SMasami Hiramatsu ret = BYTES_TO_BITS(ret); 369124bb83cSMasami Hiramatsu 3704984912eSMasami Hiramatsu /* Check the bitwidth */ 3714984912eSMasami Hiramatsu if (ret > MAX_BASIC_TYPE_BITS) { 372124bb83cSMasami Hiramatsu pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 3734984912eSMasami Hiramatsu dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 3744984912eSMasami Hiramatsu ret = MAX_BASIC_TYPE_BITS; 3754984912eSMasami Hiramatsu } 3764984912eSMasami Hiramatsu ret = snprintf(buf, 16, "%c%d", 3774984912eSMasami Hiramatsu die_is_signed_type(&type) ? 's' : 'u', ret); 378124bb83cSMasami Hiramatsu 379124bb83cSMasami Hiramatsu formatted: 380b55a87adSMasami Hiramatsu if (ret < 0 || ret >= 16) { 381b55a87adSMasami Hiramatsu if (ret >= 16) 382b55a87adSMasami Hiramatsu ret = -E2BIG; 383b55a87adSMasami Hiramatsu pr_warning("Failed to convert variable type: %s\n", 3845f03cba4SMasami Hiramatsu strerror_r(-ret, sbuf, sizeof(sbuf))); 385b55a87adSMasami Hiramatsu return ret; 386b55a87adSMasami Hiramatsu } 38773317b95SMasami Hiramatsu tvar->type = strdup(buf); 38873317b95SMasami Hiramatsu if (tvar->type == NULL) 38902b95dadSMasami Hiramatsu return -ENOMEM; 390b55a87adSMasami Hiramatsu return 0; 3914984912eSMasami Hiramatsu } 3924984912eSMasami Hiramatsu 393b55a87adSMasami Hiramatsu static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 3947df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, 3950e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr, 3964984912eSMasami Hiramatsu Dwarf_Die *die_mem) 3977df2f329SMasami Hiramatsu { 3980e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = *ref_ptr; 3997df2f329SMasami Hiramatsu Dwarf_Die type; 4007df2f329SMasami Hiramatsu Dwarf_Word offs; 401b2a3c12bSMasami Hiramatsu int ret, tag; 4027df2f329SMasami Hiramatsu 4037df2f329SMasami Hiramatsu pr_debug("converting %s in %s\n", field->name, varname); 404b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 405b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 406b55a87adSMasami Hiramatsu return -ENOENT; 407b55a87adSMasami Hiramatsu } 408b2a3c12bSMasami Hiramatsu pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); 409b2a3c12bSMasami Hiramatsu tag = dwarf_tag(&type); 4107df2f329SMasami Hiramatsu 411b2a3c12bSMasami Hiramatsu if (field->name[0] == '[' && 412b2a3c12bSMasami Hiramatsu (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 413b2a3c12bSMasami Hiramatsu if (field->next) 414b2a3c12bSMasami Hiramatsu /* Save original type for next field */ 415b2a3c12bSMasami Hiramatsu memcpy(die_mem, &type, sizeof(*die_mem)); 416b2a3c12bSMasami Hiramatsu /* Get the type of this array */ 417b2a3c12bSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 418b2a3c12bSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 419b2a3c12bSMasami Hiramatsu return -ENOENT; 420b2a3c12bSMasami Hiramatsu } 421b2a3c12bSMasami Hiramatsu pr_debug2("Array real type: (%x)\n", 422b2a3c12bSMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 423b2a3c12bSMasami Hiramatsu if (tag == DW_TAG_pointer_type) { 4240e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 425b2a3c12bSMasami Hiramatsu if (ref == NULL) 426b2a3c12bSMasami Hiramatsu return -ENOMEM; 427b2a3c12bSMasami Hiramatsu if (*ref_ptr) 428b2a3c12bSMasami Hiramatsu (*ref_ptr)->next = ref; 429b2a3c12bSMasami Hiramatsu else 430b2a3c12bSMasami Hiramatsu *ref_ptr = ref; 431b2a3c12bSMasami Hiramatsu } 432bcfc0821SMasami Hiramatsu ref->offset += dwarf_bytesize(&type) * field->index; 433b2a3c12bSMasami Hiramatsu if (!field->next) 434b2a3c12bSMasami Hiramatsu /* Save vr_die for converting types */ 435b2a3c12bSMasami Hiramatsu memcpy(die_mem, vr_die, sizeof(*die_mem)); 436b2a3c12bSMasami Hiramatsu goto next; 437b2a3c12bSMasami Hiramatsu } else if (tag == DW_TAG_pointer_type) { 4387df2f329SMasami Hiramatsu /* Check the pointer and dereference */ 439b55a87adSMasami Hiramatsu if (!field->ref) { 440b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '->'\n", 4417df2f329SMasami Hiramatsu field->name); 442b55a87adSMasami Hiramatsu return -EINVAL; 443b55a87adSMasami Hiramatsu } 4447df2f329SMasami Hiramatsu /* Get the type pointed by this pointer */ 445b55a87adSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 446b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 447b55a87adSMasami Hiramatsu return -ENOENT; 448b55a87adSMasami Hiramatsu } 44912e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4507b0295b3SHyeoncheol Lee tag = dwarf_tag(&type); 4517b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 4527b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 4537b0295b3SHyeoncheol Lee varname); 454b55a87adSMasami Hiramatsu return -EINVAL; 455b55a87adSMasami Hiramatsu } 45612e5a7aeSMasami Hiramatsu 4570e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 458e334016fSMasami Hiramatsu if (ref == NULL) 459e334016fSMasami Hiramatsu return -ENOMEM; 4607df2f329SMasami Hiramatsu if (*ref_ptr) 4617df2f329SMasami Hiramatsu (*ref_ptr)->next = ref; 4627df2f329SMasami Hiramatsu else 4637df2f329SMasami Hiramatsu *ref_ptr = ref; 4647df2f329SMasami Hiramatsu } else { 46512e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4667b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 4677b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 4687b0295b3SHyeoncheol Lee varname); 469b55a87adSMasami Hiramatsu return -EINVAL; 470b55a87adSMasami Hiramatsu } 471b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') { 472d939be3aSMasanari Iida pr_err("Semantic error: %s is not a pointer" 4730e43e5d2SMasami Hiramatsu " nor array.\n", varname); 474b2a3c12bSMasami Hiramatsu return -EINVAL; 475b2a3c12bSMasami Hiramatsu } 476c7273835SMasami Hiramatsu /* While prcessing unnamed field, we don't care about this */ 477c7273835SMasami Hiramatsu if (field->ref && dwarf_diename(vr_die)) { 478b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '.'\n", 4797df2f329SMasami Hiramatsu field->name); 480b55a87adSMasami Hiramatsu return -EINVAL; 481b55a87adSMasami Hiramatsu } 482b55a87adSMasami Hiramatsu if (!ref) { 483b55a87adSMasami Hiramatsu pr_warning("Structure on a register is not " 484b55a87adSMasami Hiramatsu "supported yet.\n"); 485b55a87adSMasami Hiramatsu return -ENOTSUP; 486b55a87adSMasami Hiramatsu } 4877df2f329SMasami Hiramatsu } 4887df2f329SMasami Hiramatsu 489b55a87adSMasami Hiramatsu if (die_find_member(&type, field->name, die_mem) == NULL) { 4909ef0438aSArnaldo Carvalho de Melo pr_warning("%s(type:%s) has no member %s.\n", varname, 4917df2f329SMasami Hiramatsu dwarf_diename(&type), field->name); 492b55a87adSMasami Hiramatsu return -EINVAL; 493b55a87adSMasami Hiramatsu } 4947df2f329SMasami Hiramatsu 4957df2f329SMasami Hiramatsu /* Get the offset of the field */ 4967b0295b3SHyeoncheol Lee if (tag == DW_TAG_union_type) { 4977b0295b3SHyeoncheol Lee offs = 0; 4987b0295b3SHyeoncheol Lee } else { 499de1439d8SMasami Hiramatsu ret = die_get_data_member_location(die_mem, &offs); 500de1439d8SMasami Hiramatsu if (ret < 0) { 5017b0295b3SHyeoncheol Lee pr_warning("Failed to get the offset of %s.\n", 5027b0295b3SHyeoncheol Lee field->name); 503de1439d8SMasami Hiramatsu return ret; 504b55a87adSMasami Hiramatsu } 5057b0295b3SHyeoncheol Lee } 5067df2f329SMasami Hiramatsu ref->offset += (long)offs; 5077df2f329SMasami Hiramatsu 508c7273835SMasami Hiramatsu /* If this member is unnamed, we need to reuse this field */ 509c7273835SMasami Hiramatsu if (!dwarf_diename(die_mem)) 510c7273835SMasami Hiramatsu return convert_variable_fields(die_mem, varname, field, 511c7273835SMasami Hiramatsu &ref, die_mem); 512c7273835SMasami Hiramatsu 513b2a3c12bSMasami Hiramatsu next: 5147df2f329SMasami Hiramatsu /* Converting next field */ 5157df2f329SMasami Hiramatsu if (field->next) 516b55a87adSMasami Hiramatsu return convert_variable_fields(die_mem, field->name, 517b55a87adSMasami Hiramatsu field->next, &ref, die_mem); 518b55a87adSMasami Hiramatsu else 519b55a87adSMasami Hiramatsu return 0; 5207df2f329SMasami Hiramatsu } 5217df2f329SMasami Hiramatsu 5224ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */ 523b55a87adSMasami Hiramatsu static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 5244ea42b18SMasami Hiramatsu { 5254984912eSMasami Hiramatsu Dwarf_Die die_mem; 5264ea42b18SMasami Hiramatsu int ret; 5274ea42b18SMasami Hiramatsu 528b7dcb857SMasami Hiramatsu pr_debug("Converting variable %s into trace event.\n", 529b7dcb857SMasami Hiramatsu dwarf_diename(vr_die)); 530804b3606SMasami Hiramatsu 531cf6eb489SMasami Hiramatsu ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 5323d918a12SMasami Hiramatsu &pf->sp_die, pf->tvar); 5337d5eaba9SHe Kuang if (ret == -ENOENT || ret == -EINVAL) { 5347d5eaba9SHe Kuang pr_err("Failed to find the location of the '%s' variable at this address.\n" 5357d5eaba9SHe Kuang " Perhaps it has been optimized out.\n" 5367d5eaba9SHe Kuang " Use -V with the --range option to show '%s' location range.\n", 5377d5eaba9SHe Kuang pf->pvar->var, pf->pvar->var); 5387d5eaba9SHe Kuang } else if (ret == -ENOTSUP) 539cf6eb489SMasami Hiramatsu pr_err("Sorry, we don't support this variable location yet.\n"); 5400c188a07SMasami Hiramatsu else if (ret == 0 && pf->pvar->field) { 541b55a87adSMasami Hiramatsu ret = convert_variable_fields(vr_die, pf->pvar->var, 5424984912eSMasami Hiramatsu pf->pvar->field, &pf->tvar->ref, 5434984912eSMasami Hiramatsu &die_mem); 5444984912eSMasami Hiramatsu vr_die = &die_mem; 5454984912eSMasami Hiramatsu } 54673317b95SMasami Hiramatsu if (ret == 0) 54773317b95SMasami Hiramatsu ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); 548804b3606SMasami Hiramatsu /* *expr will be cached in libdw. Don't free it. */ 549b55a87adSMasami Hiramatsu return ret; 5504ea42b18SMasami Hiramatsu } 5514ea42b18SMasami Hiramatsu 552221d0611SMasami Hiramatsu /* Find a variable in a scope DIE */ 553221d0611SMasami Hiramatsu static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 5544ea42b18SMasami Hiramatsu { 555f182e3e1SMasami Hiramatsu Dwarf_Die vr_die; 55611a1ca35SMasami Hiramatsu char buf[32], *ptr; 557f182e3e1SMasami Hiramatsu int ret = 0; 5584ea42b18SMasami Hiramatsu 559367e94c1SMasami Hiramatsu /* Copy raw parameters */ 560da15bd9dSWang Nan if (!is_c_varname(pf->pvar->var)) 561da15bd9dSWang Nan return copy_to_probe_trace_arg(pf->tvar, pf->pvar); 562367e94c1SMasami Hiramatsu 56348481938SMasami Hiramatsu if (pf->pvar->name) 56402b95dadSMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 56548481938SMasami Hiramatsu else { 56602b95dadSMasami Hiramatsu ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); 56702b95dadSMasami Hiramatsu if (ret < 0) 56802b95dadSMasami Hiramatsu return ret; 56911a1ca35SMasami Hiramatsu ptr = strchr(buf, ':'); /* Change type separator to _ */ 57011a1ca35SMasami Hiramatsu if (ptr) 57111a1ca35SMasami Hiramatsu *ptr = '_'; 57202b95dadSMasami Hiramatsu pf->tvar->name = strdup(buf); 57348481938SMasami Hiramatsu } 57402b95dadSMasami Hiramatsu if (pf->tvar->name == NULL) 57502b95dadSMasami Hiramatsu return -ENOMEM; 57648481938SMasami Hiramatsu 577f182e3e1SMasami Hiramatsu pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 5784ea42b18SMasami Hiramatsu /* Search child die for local variables and parameters. */ 579f182e3e1SMasami Hiramatsu if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 580f182e3e1SMasami Hiramatsu /* Search again in global variables */ 581d13855efSHe Kuang if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 582d13855efSHe Kuang 0, &vr_die)) { 58336d789a4SMasami Hiramatsu pr_warning("Failed to find '%s' in this function.\n", 58436d789a4SMasami Hiramatsu pf->pvar->var); 5858afa2a70SMasami Hiramatsu ret = -ENOENT; 586f182e3e1SMasami Hiramatsu } 587d13855efSHe Kuang } 588f66fedcbSMasami Hiramatsu if (ret >= 0) 589b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 590f182e3e1SMasami Hiramatsu 591b7dcb857SMasami Hiramatsu return ret; 5924ea42b18SMasami Hiramatsu } 5934ea42b18SMasami Hiramatsu 594cf6eb489SMasami Hiramatsu /* Convert subprogram DIE to trace point */ 595576b5237SMasami Hiramatsu static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, 596576b5237SMasami Hiramatsu Dwarf_Addr paddr, bool retprobe, 5976cca13bdSMasami Hiramatsu const char *function, 598576b5237SMasami Hiramatsu struct probe_trace_point *tp) 5994ea42b18SMasami Hiramatsu { 60026b79524SPrashanth Nageshappa Dwarf_Addr eaddr, highaddr; 601576b5237SMasami Hiramatsu GElf_Sym sym; 602576b5237SMasami Hiramatsu const char *symbol; 603cf6eb489SMasami Hiramatsu 604576b5237SMasami Hiramatsu /* Verify the address is correct */ 605cf6eb489SMasami Hiramatsu if (dwarf_entrypc(sp_die, &eaddr) != 0) { 6060e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s\n", 607cf6eb489SMasami Hiramatsu dwarf_diename(sp_die)); 608cf6eb489SMasami Hiramatsu return -ENOENT; 609cf6eb489SMasami Hiramatsu } 61026b79524SPrashanth Nageshappa if (dwarf_highpc(sp_die, &highaddr) != 0) { 61126b79524SPrashanth Nageshappa pr_warning("Failed to get end address of %s\n", 61226b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 61326b79524SPrashanth Nageshappa return -ENOENT; 61426b79524SPrashanth Nageshappa } 61526b79524SPrashanth Nageshappa if (paddr > highaddr) { 61626b79524SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 61726b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 61826b79524SPrashanth Nageshappa return -EINVAL; 61926b79524SPrashanth Nageshappa } 620576b5237SMasami Hiramatsu 621664fee3dSMasami Hiramatsu symbol = dwarf_diename(sp_die); 622664fee3dSMasami Hiramatsu if (!symbol) { 623664fee3dSMasami Hiramatsu /* Try to get the symbol name from symtab */ 624576b5237SMasami Hiramatsu symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); 625576b5237SMasami Hiramatsu if (!symbol) { 626576b5237SMasami Hiramatsu pr_warning("Failed to find symbol at 0x%lx\n", 627576b5237SMasami Hiramatsu (unsigned long)paddr); 628576b5237SMasami Hiramatsu return -ENOENT; 629576b5237SMasami Hiramatsu } 630664fee3dSMasami Hiramatsu eaddr = sym.st_value; 631664fee3dSMasami Hiramatsu } 632664fee3dSMasami Hiramatsu tp->offset = (unsigned long)(paddr - eaddr); 633fb7345bbSMasami Hiramatsu tp->address = (unsigned long)paddr; 634576b5237SMasami Hiramatsu tp->symbol = strdup(symbol); 635576b5237SMasami Hiramatsu if (!tp->symbol) 636cf6eb489SMasami Hiramatsu return -ENOMEM; 637cf6eb489SMasami Hiramatsu 638cf6eb489SMasami Hiramatsu /* Return probe must be on the head of a subprogram */ 639cf6eb489SMasami Hiramatsu if (retprobe) { 640cf6eb489SMasami Hiramatsu if (eaddr != paddr) { 6416cca13bdSMasami Hiramatsu pr_warning("Failed to find \"%s%%return\",\n" 6426cca13bdSMasami Hiramatsu " because %s is an inlined function and" 6436cca13bdSMasami Hiramatsu " has no return point.\n", function, 6446cca13bdSMasami Hiramatsu function); 645cf6eb489SMasami Hiramatsu return -EINVAL; 646cf6eb489SMasami Hiramatsu } 647cf6eb489SMasami Hiramatsu tp->retprobe = true; 648cf6eb489SMasami Hiramatsu } 649cf6eb489SMasami Hiramatsu 650cf6eb489SMasami Hiramatsu return 0; 651cf6eb489SMasami Hiramatsu } 652cf6eb489SMasami Hiramatsu 653221d0611SMasami Hiramatsu /* Call probe_finder callback with scope DIE */ 654221d0611SMasami Hiramatsu static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 655cf6eb489SMasami Hiramatsu { 656804b3606SMasami Hiramatsu Dwarf_Attribute fb_attr; 6574d3b1626SMasami Hiramatsu Dwarf_Frame *frame = NULL; 658804b3606SMasami Hiramatsu size_t nops; 659cf6eb489SMasami Hiramatsu int ret; 6604235b045SMasami Hiramatsu 661221d0611SMasami Hiramatsu if (!sc_die) { 662221d0611SMasami Hiramatsu pr_err("Caller must pass a scope DIE. Program error.\n"); 663221d0611SMasami Hiramatsu return -EINVAL; 664221d0611SMasami Hiramatsu } 665221d0611SMasami Hiramatsu 666221d0611SMasami Hiramatsu /* If not a real subprogram, find a real one */ 6670dbb1cacSMasami Hiramatsu if (!die_is_func_def(sc_die)) { 668221d0611SMasami Hiramatsu if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 669d4c537e6SNaveen N. Rao if (die_find_tailfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 670d4c537e6SNaveen N. Rao pr_warning("Ignoring tail call from %s\n", 671d4c537e6SNaveen N. Rao dwarf_diename(&pf->sp_die)); 672d4c537e6SNaveen N. Rao return 0; 673d4c537e6SNaveen N. Rao } else { 674b55a87adSMasami Hiramatsu pr_warning("Failed to find probe point in any " 675b55a87adSMasami Hiramatsu "functions.\n"); 676b55a87adSMasami Hiramatsu return -ENOENT; 677b55a87adSMasami Hiramatsu } 678d4c537e6SNaveen N. Rao } 679221d0611SMasami Hiramatsu } else 680221d0611SMasami Hiramatsu memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 681e92b85e1SMasami Hiramatsu 682221d0611SMasami Hiramatsu /* Get the frame base attribute/ops from subprogram */ 683221d0611SMasami Hiramatsu dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 684d0cb4260SMasami Hiramatsu ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 685a34a9854SMasami Hiramatsu if (ret <= 0 || nops == 0) { 686804b3606SMasami Hiramatsu pf->fb_ops = NULL; 6877752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 688a34a9854SMasami Hiramatsu } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 689*270bde1eSHemant Kumar (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) { 690*270bde1eSHemant Kumar if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 && 691*270bde1eSHemant Kumar (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) || 692b55a87adSMasami Hiramatsu dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 6930e43e5d2SMasami Hiramatsu pr_warning("Failed to get call frame on 0x%jx\n", 694b55a87adSMasami Hiramatsu (uintmax_t)pf->addr); 69505c8d802SMasami Hiramatsu free(frame); 6964d3b1626SMasami Hiramatsu return -ENOENT; 6974d3b1626SMasami Hiramatsu } 6987752f1b0SMasami Hiramatsu #endif 699a34a9854SMasami Hiramatsu } 700804b3606SMasami Hiramatsu 701cf6eb489SMasami Hiramatsu /* Call finder's callback handler */ 702221d0611SMasami Hiramatsu ret = pf->callback(sc_die, pf); 703804b3606SMasami Hiramatsu 7044d3b1626SMasami Hiramatsu /* Since *pf->fb_ops can be a part of frame. we should free it here. */ 7054d3b1626SMasami Hiramatsu free(frame); 706804b3606SMasami Hiramatsu pf->fb_ops = NULL; 707cf6eb489SMasami Hiramatsu 708cf6eb489SMasami Hiramatsu return ret; 7094ea42b18SMasami Hiramatsu } 7104ea42b18SMasami Hiramatsu 711221d0611SMasami Hiramatsu struct find_scope_param { 712221d0611SMasami Hiramatsu const char *function; 713221d0611SMasami Hiramatsu const char *file; 714221d0611SMasami Hiramatsu int line; 715221d0611SMasami Hiramatsu int diff; 716221d0611SMasami Hiramatsu Dwarf_Die *die_mem; 717221d0611SMasami Hiramatsu bool found; 718221d0611SMasami Hiramatsu }; 719221d0611SMasami Hiramatsu 720221d0611SMasami Hiramatsu static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 721221d0611SMasami Hiramatsu { 722221d0611SMasami Hiramatsu struct find_scope_param *fsp = data; 723221d0611SMasami Hiramatsu const char *file; 724221d0611SMasami Hiramatsu int lno; 725221d0611SMasami Hiramatsu 726221d0611SMasami Hiramatsu /* Skip if declared file name does not match */ 727221d0611SMasami Hiramatsu if (fsp->file) { 728221d0611SMasami Hiramatsu file = dwarf_decl_file(fn_die); 729221d0611SMasami Hiramatsu if (!file || strcmp(fsp->file, file) != 0) 730221d0611SMasami Hiramatsu return 0; 731221d0611SMasami Hiramatsu } 732221d0611SMasami Hiramatsu /* If the function name is given, that's what user expects */ 733221d0611SMasami Hiramatsu if (fsp->function) { 7344c859351SMasami Hiramatsu if (die_match_name(fn_die, fsp->function)) { 735221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 736221d0611SMasami Hiramatsu fsp->found = true; 737221d0611SMasami Hiramatsu return 1; 738221d0611SMasami Hiramatsu } 739221d0611SMasami Hiramatsu } else { 740221d0611SMasami Hiramatsu /* With the line number, find the nearest declared DIE */ 741221d0611SMasami Hiramatsu dwarf_decl_line(fn_die, &lno); 742221d0611SMasami Hiramatsu if (lno < fsp->line && fsp->diff > fsp->line - lno) { 743221d0611SMasami Hiramatsu /* Keep a candidate and continue */ 744221d0611SMasami Hiramatsu fsp->diff = fsp->line - lno; 745221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 746221d0611SMasami Hiramatsu fsp->found = true; 747221d0611SMasami Hiramatsu } 748221d0611SMasami Hiramatsu } 749221d0611SMasami Hiramatsu return 0; 750221d0611SMasami Hiramatsu } 751221d0611SMasami Hiramatsu 752221d0611SMasami Hiramatsu /* Find an appropriate scope fits to given conditions */ 753221d0611SMasami Hiramatsu static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 754221d0611SMasami Hiramatsu { 755221d0611SMasami Hiramatsu struct find_scope_param fsp = { 756221d0611SMasami Hiramatsu .function = pf->pev->point.function, 757221d0611SMasami Hiramatsu .file = pf->fname, 758221d0611SMasami Hiramatsu .line = pf->lno, 759221d0611SMasami Hiramatsu .diff = INT_MAX, 760221d0611SMasami Hiramatsu .die_mem = die_mem, 761221d0611SMasami Hiramatsu .found = false, 762221d0611SMasami Hiramatsu }; 763221d0611SMasami Hiramatsu 764221d0611SMasami Hiramatsu cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 765221d0611SMasami Hiramatsu 766221d0611SMasami Hiramatsu return fsp.found ? die_mem : NULL; 767221d0611SMasami Hiramatsu } 768221d0611SMasami Hiramatsu 7694cc9cec6SMasami Hiramatsu static int probe_point_line_walker(const char *fname, int lineno, 7704cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 7714cc9cec6SMasami Hiramatsu { 7724cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 773221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 7744cc9cec6SMasami Hiramatsu int ret; 7754cc9cec6SMasami Hiramatsu 7764cc9cec6SMasami Hiramatsu if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 7774cc9cec6SMasami Hiramatsu return 0; 7784cc9cec6SMasami Hiramatsu 7794cc9cec6SMasami Hiramatsu pf->addr = addr; 780221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 781221d0611SMasami Hiramatsu if (!sc_die) { 782221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 783221d0611SMasami Hiramatsu return -ENOENT; 784221d0611SMasami Hiramatsu } 785221d0611SMasami Hiramatsu 786221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 7874cc9cec6SMasami Hiramatsu 7884cc9cec6SMasami Hiramatsu /* Continue if no error, because the line will be in inline function */ 789fbee632dSArnaldo Carvalho de Melo return ret < 0 ? ret : 0; 7904cc9cec6SMasami Hiramatsu } 7914cc9cec6SMasami Hiramatsu 7924ea42b18SMasami Hiramatsu /* Find probe point from its line number */ 793b55a87adSMasami Hiramatsu static int find_probe_point_by_line(struct probe_finder *pf) 7944ea42b18SMasami Hiramatsu { 7954cc9cec6SMasami Hiramatsu return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 7964ea42b18SMasami Hiramatsu } 7974ea42b18SMasami Hiramatsu 7982a9c8c36SMasami Hiramatsu /* Find lines which match lazy pattern */ 7995a62257aSMasami Hiramatsu static int find_lazy_match_lines(struct intlist *list, 8002a9c8c36SMasami Hiramatsu const char *fname, const char *pat) 8012a9c8c36SMasami Hiramatsu { 802f50c2169SFranck Bui-Huu FILE *fp; 803f50c2169SFranck Bui-Huu char *line = NULL; 804f50c2169SFranck Bui-Huu size_t line_len; 805f50c2169SFranck Bui-Huu ssize_t len; 806f50c2169SFranck Bui-Huu int count = 0, linenum = 1; 8075f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 8082a9c8c36SMasami Hiramatsu 809f50c2169SFranck Bui-Huu fp = fopen(fname, "r"); 810f50c2169SFranck Bui-Huu if (!fp) { 8115f03cba4SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", fname, 8125f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 813b448c4b6SArnaldo Carvalho de Melo return -errno; 814b55a87adSMasami Hiramatsu } 815b55a87adSMasami Hiramatsu 816f50c2169SFranck Bui-Huu while ((len = getline(&line, &line_len, fp)) > 0) { 817f50c2169SFranck Bui-Huu 818f50c2169SFranck Bui-Huu if (line[len - 1] == '\n') 819f50c2169SFranck Bui-Huu line[len - 1] = '\0'; 820f50c2169SFranck Bui-Huu 821f50c2169SFranck Bui-Huu if (strlazymatch(line, pat)) { 8225a62257aSMasami Hiramatsu intlist__add(list, linenum); 823f50c2169SFranck Bui-Huu count++; 824f50c2169SFranck Bui-Huu } 825f50c2169SFranck Bui-Huu linenum++; 826b55a87adSMasami Hiramatsu } 827b448c4b6SArnaldo Carvalho de Melo 828f50c2169SFranck Bui-Huu if (ferror(fp)) 829f50c2169SFranck Bui-Huu count = -errno; 830f50c2169SFranck Bui-Huu free(line); 831f50c2169SFranck Bui-Huu fclose(fp); 832f50c2169SFranck Bui-Huu 833f50c2169SFranck Bui-Huu if (count == 0) 834f50c2169SFranck Bui-Huu pr_debug("No matched lines found in %s.\n", fname); 835f50c2169SFranck Bui-Huu return count; 8362a9c8c36SMasami Hiramatsu } 8372a9c8c36SMasami Hiramatsu 8384cc9cec6SMasami Hiramatsu static int probe_point_lazy_walker(const char *fname, int lineno, 8394cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 8404cc9cec6SMasami Hiramatsu { 8414cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 842221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 8434cc9cec6SMasami Hiramatsu int ret; 8444cc9cec6SMasami Hiramatsu 8455a62257aSMasami Hiramatsu if (!intlist__has_entry(pf->lcache, lineno) || 8464cc9cec6SMasami Hiramatsu strtailcmp(fname, pf->fname) != 0) 8474cc9cec6SMasami Hiramatsu return 0; 8484cc9cec6SMasami Hiramatsu 8494cc9cec6SMasami Hiramatsu pr_debug("Probe line found: line:%d addr:0x%llx\n", 8504cc9cec6SMasami Hiramatsu lineno, (unsigned long long)addr); 8514cc9cec6SMasami Hiramatsu pf->addr = addr; 852221d0611SMasami Hiramatsu pf->lno = lineno; 853221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 854221d0611SMasami Hiramatsu if (!sc_die) { 855221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 856221d0611SMasami Hiramatsu return -ENOENT; 857221d0611SMasami Hiramatsu } 858221d0611SMasami Hiramatsu 859221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8604cc9cec6SMasami Hiramatsu 8614cc9cec6SMasami Hiramatsu /* 8624cc9cec6SMasami Hiramatsu * Continue if no error, because the lazy pattern will match 8634cc9cec6SMasami Hiramatsu * to other lines 8644cc9cec6SMasami Hiramatsu */ 8655e814dd5SIngo Molnar return ret < 0 ? ret : 0; 8664cc9cec6SMasami Hiramatsu } 8674cc9cec6SMasami Hiramatsu 8682a9c8c36SMasami Hiramatsu /* Find probe points from lazy pattern */ 869b55a87adSMasami Hiramatsu static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 8702a9c8c36SMasami Hiramatsu { 871b55a87adSMasami Hiramatsu int ret = 0; 87209ed8975SNaohiro Aota char *fpath; 8732a9c8c36SMasami Hiramatsu 8745a62257aSMasami Hiramatsu if (intlist__empty(pf->lcache)) { 87509ed8975SNaohiro Aota const char *comp_dir; 87609ed8975SNaohiro Aota 87709ed8975SNaohiro Aota comp_dir = cu_get_comp_dir(&pf->cu_die); 87809ed8975SNaohiro Aota ret = get_real_path(pf->fname, comp_dir, &fpath); 87909ed8975SNaohiro Aota if (ret < 0) { 88009ed8975SNaohiro Aota pr_warning("Failed to find source file path.\n"); 88109ed8975SNaohiro Aota return ret; 88209ed8975SNaohiro Aota } 88309ed8975SNaohiro Aota 8842a9c8c36SMasami Hiramatsu /* Matching lazy line pattern */ 88509ed8975SNaohiro Aota ret = find_lazy_match_lines(pf->lcache, fpath, 8864235b045SMasami Hiramatsu pf->pev->point.lazy_line); 88709ed8975SNaohiro Aota free(fpath); 888f50c2169SFranck Bui-Huu if (ret <= 0) 889b55a87adSMasami Hiramatsu return ret; 8902a9c8c36SMasami Hiramatsu } 8912a9c8c36SMasami Hiramatsu 8924cc9cec6SMasami Hiramatsu return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 8932a9c8c36SMasami Hiramatsu } 8942a9c8c36SMasami Hiramatsu 895e92b85e1SMasami Hiramatsu static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 8964ea42b18SMasami Hiramatsu { 897db0d2c64SMasami Hiramatsu struct probe_finder *pf = data; 8984235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 899b55a87adSMasami Hiramatsu Dwarf_Addr addr; 900db0d2c64SMasami Hiramatsu int ret; 9014ea42b18SMasami Hiramatsu 9022a9c8c36SMasami Hiramatsu if (pp->lazy_line) 903db0d2c64SMasami Hiramatsu ret = find_probe_point_lazy(in_die, pf); 9042a9c8c36SMasami Hiramatsu else { 905e92b85e1SMasami Hiramatsu /* Get probe address */ 906b55a87adSMasami Hiramatsu if (dwarf_entrypc(in_die, &addr) != 0) { 9070e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s.\n", 908b55a87adSMasami Hiramatsu dwarf_diename(in_die)); 909db0d2c64SMasami Hiramatsu return -ENOENT; 910b55a87adSMasami Hiramatsu } 911b55a87adSMasami Hiramatsu pf->addr = addr; 912e92b85e1SMasami Hiramatsu pf->addr += pp->offset; 9132a9c8c36SMasami Hiramatsu pr_debug("found inline addr: 0x%jx\n", 9142a9c8c36SMasami Hiramatsu (uintmax_t)pf->addr); 915e92b85e1SMasami Hiramatsu 916db0d2c64SMasami Hiramatsu ret = call_probe_finder(in_die, pf); 9172a9c8c36SMasami Hiramatsu } 9182a9c8c36SMasami Hiramatsu 919db0d2c64SMasami Hiramatsu return ret; 920e92b85e1SMasami Hiramatsu } 921e92b85e1SMasami Hiramatsu 922db0d2c64SMasami Hiramatsu /* Callback parameter with return value for libdw */ 923db0d2c64SMasami Hiramatsu struct dwarf_callback_param { 924db0d2c64SMasami Hiramatsu void *data; 925db0d2c64SMasami Hiramatsu int retval; 926db0d2c64SMasami Hiramatsu }; 927db0d2c64SMasami Hiramatsu 928e92b85e1SMasami Hiramatsu /* Search function from function name */ 929e92b85e1SMasami Hiramatsu static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 930e92b85e1SMasami Hiramatsu { 931b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 932b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 9334235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 934e92b85e1SMasami Hiramatsu 935e92b85e1SMasami Hiramatsu /* Check tag and diename */ 9360dbb1cacSMasami Hiramatsu if (!die_is_func_def(sp_die) || 9374c859351SMasami Hiramatsu !die_match_name(sp_die, pp->function)) 938b55a87adSMasami Hiramatsu return DWARF_CB_OK; 939e92b85e1SMasami Hiramatsu 9407d21635aSMasami Hiramatsu /* Check declared file */ 9417d21635aSMasami Hiramatsu if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 9427d21635aSMasami Hiramatsu return DWARF_CB_OK; 9437d21635aSMasami Hiramatsu 9444c859351SMasami Hiramatsu pr_debug("Matched function: %s\n", dwarf_diename(sp_die)); 945e92b85e1SMasami Hiramatsu pf->fname = dwarf_decl_file(sp_die); 9462a9c8c36SMasami Hiramatsu if (pp->line) { /* Function relative line */ 947e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &pf->lno); 948804b3606SMasami Hiramatsu pf->lno += pp->line; 949b55a87adSMasami Hiramatsu param->retval = find_probe_point_by_line(pf); 950e1ecbbc3SMasami Hiramatsu } else if (die_is_func_instance(sp_die)) { 951e1ecbbc3SMasami Hiramatsu /* Instances always have the entry address */ 952e1ecbbc3SMasami Hiramatsu dwarf_entrypc(sp_die, &pf->addr); 953e92b85e1SMasami Hiramatsu /* Real function */ 9542a9c8c36SMasami Hiramatsu if (pp->lazy_line) 955b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(sp_die, pf); 9562a9c8c36SMasami Hiramatsu else { 9574ea42b18SMasami Hiramatsu pf->addr += pp->offset; 9584ea42b18SMasami Hiramatsu /* TODO: Check the address in this function */ 959cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(sp_die, pf); 9602a9c8c36SMasami Hiramatsu } 9614c859351SMasami Hiramatsu } else if (!probe_conf.no_inlines) { 962e92b85e1SMasami Hiramatsu /* Inlined function: search instances */ 963db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 964db0d2c64SMasami Hiramatsu probe_point_inline_cb, (void *)pf); 9654c859351SMasami Hiramatsu /* This could be a non-existed inline definition */ 9664c859351SMasami Hiramatsu if (param->retval == -ENOENT && strisglob(pp->function)) 9674c859351SMasami Hiramatsu param->retval = 0; 9684c859351SMasami Hiramatsu } 9694c859351SMasami Hiramatsu 9704c859351SMasami Hiramatsu /* We need to find other candidates */ 9714c859351SMasami Hiramatsu if (strisglob(pp->function) && param->retval >= 0) { 9724c859351SMasami Hiramatsu param->retval = 0; /* We have to clear the result */ 9734c859351SMasami Hiramatsu return DWARF_CB_OK; 9744c859351SMasami Hiramatsu } 9754ea42b18SMasami Hiramatsu 976b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 977b55a87adSMasami Hiramatsu } 978b55a87adSMasami Hiramatsu 979b55a87adSMasami Hiramatsu static int find_probe_point_by_func(struct probe_finder *pf) 9804ea42b18SMasami Hiramatsu { 981b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 982b55a87adSMasami Hiramatsu .retval = 0}; 983b55a87adSMasami Hiramatsu dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 984b55a87adSMasami Hiramatsu return _param.retval; 9854ea42b18SMasami Hiramatsu } 9864ea42b18SMasami Hiramatsu 987cd25f8bcSLin Ming struct pubname_callback_param { 988cd25f8bcSLin Ming char *function; 989cd25f8bcSLin Ming char *file; 990cd25f8bcSLin Ming Dwarf_Die *cu_die; 991cd25f8bcSLin Ming Dwarf_Die *sp_die; 992cd25f8bcSLin Ming int found; 993cd25f8bcSLin Ming }; 994cd25f8bcSLin Ming 995cd25f8bcSLin Ming static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 996cd25f8bcSLin Ming { 997cd25f8bcSLin Ming struct pubname_callback_param *param = data; 998cd25f8bcSLin Ming 999cd25f8bcSLin Ming if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1000cd25f8bcSLin Ming if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1001cd25f8bcSLin Ming return DWARF_CB_OK; 1002cd25f8bcSLin Ming 10034c859351SMasami Hiramatsu if (die_match_name(param->sp_die, param->function)) { 1004cd25f8bcSLin Ming if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1005cd25f8bcSLin Ming return DWARF_CB_OK; 1006cd25f8bcSLin Ming 1007cd25f8bcSLin Ming if (param->file && 1008cd25f8bcSLin Ming strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1009cd25f8bcSLin Ming return DWARF_CB_OK; 1010cd25f8bcSLin Ming 1011cd25f8bcSLin Ming param->found = 1; 1012cd25f8bcSLin Ming return DWARF_CB_ABORT; 1013cd25f8bcSLin Ming } 1014cd25f8bcSLin Ming } 1015cd25f8bcSLin Ming 1016cd25f8bcSLin Ming return DWARF_CB_OK; 1017cd25f8bcSLin Ming } 1018cd25f8bcSLin Ming 1019*270bde1eSHemant Kumar static int debuginfo__find_probe_location(struct debuginfo *dbg, 1020ff741783SMasami Hiramatsu struct probe_finder *pf) 10214ea42b18SMasami Hiramatsu { 1022cf6eb489SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1023804b3606SMasami Hiramatsu Dwarf_Off off, noff; 1024804b3606SMasami Hiramatsu size_t cuhl; 1025804b3606SMasami Hiramatsu Dwarf_Die *diep; 1026b55a87adSMasami Hiramatsu int ret = 0; 10274ea42b18SMasami Hiramatsu 1028804b3606SMasami Hiramatsu off = 0; 10295a62257aSMasami Hiramatsu pf->lcache = intlist__new(NULL); 10305a62257aSMasami Hiramatsu if (!pf->lcache) 10315a62257aSMasami Hiramatsu return -ENOMEM; 1032cd25f8bcSLin Ming 1033cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 10344c859351SMasami Hiramatsu if (pp->function && !strisglob(pp->function)) { 1035cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1036cd25f8bcSLin Ming .function = pp->function, 1037cd25f8bcSLin Ming .file = pp->file, 1038cd25f8bcSLin Ming .cu_die = &pf->cu_die, 1039cd25f8bcSLin Ming .sp_die = &pf->sp_die, 10402b348a77SLin Ming .found = 0, 1041cd25f8bcSLin Ming }; 1042cd25f8bcSLin Ming struct dwarf_callback_param probe_param = { 1043cd25f8bcSLin Ming .data = pf, 1044cd25f8bcSLin Ming }; 1045cd25f8bcSLin Ming 1046316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1047ff741783SMasami Hiramatsu &pubname_param, 0); 1048cd25f8bcSLin Ming if (pubname_param.found) { 1049cd25f8bcSLin Ming ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1050cd25f8bcSLin Ming if (ret) 1051cd25f8bcSLin Ming goto found; 1052cd25f8bcSLin Ming } 1053cd25f8bcSLin Ming } 1054cd25f8bcSLin Ming 1055804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1056316c7136SArnaldo Carvalho de Melo while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 10574ea42b18SMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1058316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die); 1059804b3606SMasami Hiramatsu if (!diep) 1060804b3606SMasami Hiramatsu continue; 10614ea42b18SMasami Hiramatsu 10624ea42b18SMasami Hiramatsu /* Check if target file is included. */ 10634ea42b18SMasami Hiramatsu if (pp->file) 1064cf6eb489SMasami Hiramatsu pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1065804b3606SMasami Hiramatsu else 1066cf6eb489SMasami Hiramatsu pf->fname = NULL; 10674ea42b18SMasami Hiramatsu 1068cf6eb489SMasami Hiramatsu if (!pp->file || pf->fname) { 10694ea42b18SMasami Hiramatsu if (pp->function) 1070cf6eb489SMasami Hiramatsu ret = find_probe_point_by_func(pf); 10712a9c8c36SMasami Hiramatsu else if (pp->lazy_line) 1072f19e80c6SHe Kuang ret = find_probe_point_lazy(&pf->cu_die, pf); 1073b0ef0732SMasami Hiramatsu else { 1074cf6eb489SMasami Hiramatsu pf->lno = pp->line; 1075cf6eb489SMasami Hiramatsu ret = find_probe_point_by_line(pf); 10764ea42b18SMasami Hiramatsu } 10778635bf6eSArnaldo Carvalho de Melo if (ret < 0) 1078fbee632dSArnaldo Carvalho de Melo break; 1079b0ef0732SMasami Hiramatsu } 1080804b3606SMasami Hiramatsu off = noff; 10814ea42b18SMasami Hiramatsu } 1082cd25f8bcSLin Ming 1083cd25f8bcSLin Ming found: 10845a62257aSMasami Hiramatsu intlist__delete(pf->lcache); 10855a62257aSMasami Hiramatsu pf->lcache = NULL; 10864ea42b18SMasami Hiramatsu 1087cf6eb489SMasami Hiramatsu return ret; 1088cf6eb489SMasami Hiramatsu } 1089cf6eb489SMasami Hiramatsu 1090*270bde1eSHemant Kumar /* Find probe points from debuginfo */ 1091*270bde1eSHemant Kumar static int debuginfo__find_probes(struct debuginfo *dbg, 1092*270bde1eSHemant Kumar struct probe_finder *pf) 1093*270bde1eSHemant Kumar { 1094*270bde1eSHemant Kumar int ret = 0; 1095*270bde1eSHemant Kumar 1096*270bde1eSHemant Kumar #if _ELFUTILS_PREREQ(0, 142) 1097*270bde1eSHemant Kumar Elf *elf; 1098*270bde1eSHemant Kumar GElf_Ehdr ehdr; 1099*270bde1eSHemant Kumar GElf_Shdr shdr; 1100*270bde1eSHemant Kumar 1101*270bde1eSHemant Kumar if (pf->cfi_eh || pf->cfi_dbg) 1102*270bde1eSHemant Kumar return debuginfo__find_probe_location(dbg, pf); 1103*270bde1eSHemant Kumar 1104*270bde1eSHemant Kumar /* Get the call frame information from this dwarf */ 1105*270bde1eSHemant Kumar elf = dwarf_getelf(dbg->dbg); 1106*270bde1eSHemant Kumar if (elf == NULL) 1107*270bde1eSHemant Kumar return -EINVAL; 1108*270bde1eSHemant Kumar 1109*270bde1eSHemant Kumar if (gelf_getehdr(elf, &ehdr) == NULL) 1110*270bde1eSHemant Kumar return -EINVAL; 1111*270bde1eSHemant Kumar 1112*270bde1eSHemant Kumar if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && 1113*270bde1eSHemant Kumar shdr.sh_type == SHT_PROGBITS) 1114*270bde1eSHemant Kumar pf->cfi_eh = dwarf_getcfi_elf(elf); 1115*270bde1eSHemant Kumar 1116*270bde1eSHemant Kumar pf->cfi_dbg = dwarf_getcfi(dbg->dbg); 1117*270bde1eSHemant Kumar #endif 1118*270bde1eSHemant Kumar 1119*270bde1eSHemant Kumar ret = debuginfo__find_probe_location(dbg, pf); 1120*270bde1eSHemant Kumar return ret; 1121*270bde1eSHemant Kumar } 1122*270bde1eSHemant Kumar 11237969ec77SMasami Hiramatsu struct local_vars_finder { 11247969ec77SMasami Hiramatsu struct probe_finder *pf; 11257969ec77SMasami Hiramatsu struct perf_probe_arg *args; 1126f8bffbf1SMasami Hiramatsu bool vars; 11277969ec77SMasami Hiramatsu int max_args; 11287969ec77SMasami Hiramatsu int nargs; 11297969ec77SMasami Hiramatsu int ret; 11307969ec77SMasami Hiramatsu }; 11317969ec77SMasami Hiramatsu 11327969ec77SMasami Hiramatsu /* Collect available variables in this scope */ 11337969ec77SMasami Hiramatsu static int copy_variables_cb(Dwarf_Die *die_mem, void *data) 11347969ec77SMasami Hiramatsu { 11357969ec77SMasami Hiramatsu struct local_vars_finder *vf = data; 11363d918a12SMasami Hiramatsu struct probe_finder *pf = vf->pf; 11377969ec77SMasami Hiramatsu int tag; 11387969ec77SMasami Hiramatsu 11397969ec77SMasami Hiramatsu tag = dwarf_tag(die_mem); 11407969ec77SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1141f8bffbf1SMasami Hiramatsu (tag == DW_TAG_variable && vf->vars)) { 11427969ec77SMasami Hiramatsu if (convert_variable_location(die_mem, vf->pf->addr, 11433d918a12SMasami Hiramatsu vf->pf->fb_ops, &pf->sp_die, 11443d918a12SMasami Hiramatsu NULL) == 0) { 11457969ec77SMasami Hiramatsu vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); 11467969ec77SMasami Hiramatsu if (vf->args[vf->nargs].var == NULL) { 11477969ec77SMasami Hiramatsu vf->ret = -ENOMEM; 11487969ec77SMasami Hiramatsu return DIE_FIND_CB_END; 11497969ec77SMasami Hiramatsu } 11507969ec77SMasami Hiramatsu pr_debug(" %s", vf->args[vf->nargs].var); 11517969ec77SMasami Hiramatsu vf->nargs++; 11527969ec77SMasami Hiramatsu } 11537969ec77SMasami Hiramatsu } 11547969ec77SMasami Hiramatsu 11557969ec77SMasami Hiramatsu if (dwarf_haspc(die_mem, vf->pf->addr)) 11567969ec77SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 11577969ec77SMasami Hiramatsu else 11587969ec77SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 11597969ec77SMasami Hiramatsu } 11607969ec77SMasami Hiramatsu 11617969ec77SMasami Hiramatsu static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, 11627969ec77SMasami Hiramatsu struct perf_probe_arg *args) 11637969ec77SMasami Hiramatsu { 11647969ec77SMasami Hiramatsu Dwarf_Die die_mem; 11657969ec77SMasami Hiramatsu int i; 11667969ec77SMasami Hiramatsu int n = 0; 1167f8bffbf1SMasami Hiramatsu struct local_vars_finder vf = {.pf = pf, .args = args, .vars = false, 11687969ec77SMasami Hiramatsu .max_args = MAX_PROBE_ARGS, .ret = 0}; 11697969ec77SMasami Hiramatsu 11707969ec77SMasami Hiramatsu for (i = 0; i < pf->pev->nargs; i++) { 11717969ec77SMasami Hiramatsu /* var never be NULL */ 1172f8bffbf1SMasami Hiramatsu if (strcmp(pf->pev->args[i].var, PROBE_ARG_VARS) == 0) 1173f8bffbf1SMasami Hiramatsu vf.vars = true; 1174f8bffbf1SMasami Hiramatsu else if (strcmp(pf->pev->args[i].var, PROBE_ARG_PARAMS) != 0) { 1175f8bffbf1SMasami Hiramatsu /* Copy normal argument */ 1176f8bffbf1SMasami Hiramatsu args[n] = pf->pev->args[i]; 1177f8bffbf1SMasami Hiramatsu n++; 1178f8bffbf1SMasami Hiramatsu continue; 1179f8bffbf1SMasami Hiramatsu } 1180f8bffbf1SMasami Hiramatsu pr_debug("Expanding %s into:", pf->pev->args[i].var); 11817969ec77SMasami Hiramatsu vf.nargs = n; 11827969ec77SMasami Hiramatsu /* Special local variables */ 11837969ec77SMasami Hiramatsu die_find_child(sc_die, copy_variables_cb, (void *)&vf, 11847969ec77SMasami Hiramatsu &die_mem); 11857969ec77SMasami Hiramatsu pr_debug(" (%d)\n", vf.nargs - n); 11867969ec77SMasami Hiramatsu if (vf.ret < 0) 11877969ec77SMasami Hiramatsu return vf.ret; 11887969ec77SMasami Hiramatsu n = vf.nargs; 11897969ec77SMasami Hiramatsu } 11907969ec77SMasami Hiramatsu return n; 11917969ec77SMasami Hiramatsu } 11927969ec77SMasami Hiramatsu 1193cf6eb489SMasami Hiramatsu /* Add a found probe point into trace event list */ 1194221d0611SMasami Hiramatsu static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1195cf6eb489SMasami Hiramatsu { 1196cf6eb489SMasami Hiramatsu struct trace_event_finder *tf = 1197cf6eb489SMasami Hiramatsu container_of(pf, struct trace_event_finder, pf); 11986cca13bdSMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1199cf6eb489SMasami Hiramatsu struct probe_trace_event *tev; 1200092b1f0bSWang Nan struct perf_probe_arg *args = NULL; 1201cf6eb489SMasami Hiramatsu int ret, i; 1202cf6eb489SMasami Hiramatsu 1203cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1204cf6eb489SMasami Hiramatsu if (tf->ntevs == tf->max_tevs) { 1205cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", 1206cf6eb489SMasami Hiramatsu tf->max_tevs); 1207cf6eb489SMasami Hiramatsu return -ERANGE; 1208cf6eb489SMasami Hiramatsu } 1209cf6eb489SMasami Hiramatsu tev = &tf->tevs[tf->ntevs++]; 1210cf6eb489SMasami Hiramatsu 1211221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1212576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 12136cca13bdSMasami Hiramatsu pp->retprobe, pp->function, &tev->point); 1214cf6eb489SMasami Hiramatsu if (ret < 0) 1215092b1f0bSWang Nan goto end; 1216cf6eb489SMasami Hiramatsu 12174c859351SMasami Hiramatsu tev->point.realname = strdup(dwarf_diename(sc_die)); 1218092b1f0bSWang Nan if (!tev->point.realname) { 1219092b1f0bSWang Nan ret = -ENOMEM; 1220092b1f0bSWang Nan goto end; 1221092b1f0bSWang Nan } 12224c859351SMasami Hiramatsu 1223cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1224cf6eb489SMasami Hiramatsu tev->point.offset); 1225cf6eb489SMasami Hiramatsu 12267969ec77SMasami Hiramatsu /* Expand special probe argument if exist */ 12277969ec77SMasami Hiramatsu args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); 1228092b1f0bSWang Nan if (args == NULL) { 1229092b1f0bSWang Nan ret = -ENOMEM; 1230092b1f0bSWang Nan goto end; 1231092b1f0bSWang Nan } 12327969ec77SMasami Hiramatsu 12337969ec77SMasami Hiramatsu ret = expand_probe_args(sc_die, pf, args); 12347969ec77SMasami Hiramatsu if (ret < 0) 12357969ec77SMasami Hiramatsu goto end; 12367969ec77SMasami Hiramatsu 12377969ec77SMasami Hiramatsu tev->nargs = ret; 12387969ec77SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 12397969ec77SMasami Hiramatsu if (tev->args == NULL) { 12407969ec77SMasami Hiramatsu ret = -ENOMEM; 12417969ec77SMasami Hiramatsu goto end; 12427969ec77SMasami Hiramatsu } 12437969ec77SMasami Hiramatsu 12447969ec77SMasami Hiramatsu /* Find each argument */ 12457969ec77SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 12467969ec77SMasami Hiramatsu pf->pvar = &args[i]; 1247cf6eb489SMasami Hiramatsu pf->tvar = &tev->args[i]; 1248221d0611SMasami Hiramatsu /* Variable should be found from scope DIE */ 1249221d0611SMasami Hiramatsu ret = find_variable(sc_die, pf); 1250cf6eb489SMasami Hiramatsu if (ret != 0) 12517969ec77SMasami Hiramatsu break; 1252cf6eb489SMasami Hiramatsu } 1253cf6eb489SMasami Hiramatsu 12547969ec77SMasami Hiramatsu end: 1255092b1f0bSWang Nan if (ret) { 1256092b1f0bSWang Nan clear_probe_trace_event(tev); 1257092b1f0bSWang Nan tf->ntevs--; 1258092b1f0bSWang Nan } 12597969ec77SMasami Hiramatsu free(args); 12607969ec77SMasami Hiramatsu return ret; 1261cf6eb489SMasami Hiramatsu } 1262cf6eb489SMasami Hiramatsu 1263cf6eb489SMasami Hiramatsu /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1264316c7136SArnaldo Carvalho de Melo int debuginfo__find_trace_events(struct debuginfo *dbg, 1265ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1266ddb2f58fSMasami Hiramatsu struct probe_trace_event **tevs) 1267cf6eb489SMasami Hiramatsu { 1268cf6eb489SMasami Hiramatsu struct trace_event_finder tf = { 1269cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_probe_trace_event}, 1270ddb2f58fSMasami Hiramatsu .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; 12710196e787SMasami Hiramatsu int ret, i; 1272cf6eb489SMasami Hiramatsu 1273cf6eb489SMasami Hiramatsu /* Allocate result tevs array */ 1274ddb2f58fSMasami Hiramatsu *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); 1275cf6eb489SMasami Hiramatsu if (*tevs == NULL) 1276cf6eb489SMasami Hiramatsu return -ENOMEM; 1277cf6eb489SMasami Hiramatsu 1278cf6eb489SMasami Hiramatsu tf.tevs = *tevs; 1279cf6eb489SMasami Hiramatsu tf.ntevs = 0; 1280cf6eb489SMasami Hiramatsu 1281316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &tf.pf); 1282cf6eb489SMasami Hiramatsu if (ret < 0) { 12830196e787SMasami Hiramatsu for (i = 0; i < tf.ntevs; i++) 12840196e787SMasami Hiramatsu clear_probe_trace_event(&tf.tevs[i]); 128504662523SArnaldo Carvalho de Melo zfree(tevs); 1286cf6eb489SMasami Hiramatsu return ret; 1287cf6eb489SMasami Hiramatsu } 1288cf6eb489SMasami Hiramatsu 1289cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : tf.ntevs; 1290cf6eb489SMasami Hiramatsu } 1291cf6eb489SMasami Hiramatsu 1292cf6eb489SMasami Hiramatsu /* Collect available variables in this scope */ 1293cf6eb489SMasami Hiramatsu static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1294cf6eb489SMasami Hiramatsu { 1295cf6eb489SMasami Hiramatsu struct available_var_finder *af = data; 1296cf6eb489SMasami Hiramatsu struct variable_list *vl; 1297cf6eb489SMasami Hiramatsu int tag, ret; 1298cf6eb489SMasami Hiramatsu 1299cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls - 1]; 1300cf6eb489SMasami Hiramatsu 1301cf6eb489SMasami Hiramatsu tag = dwarf_tag(die_mem); 1302cf6eb489SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1303cf6eb489SMasami Hiramatsu tag == DW_TAG_variable) { 1304cf6eb489SMasami Hiramatsu ret = convert_variable_location(die_mem, af->pf.addr, 13053d918a12SMasami Hiramatsu af->pf.fb_ops, &af->pf.sp_die, 13063d918a12SMasami Hiramatsu NULL); 1307349e8d26SHe Kuang if (ret == 0 || ret == -ERANGE) { 1308349e8d26SHe Kuang int ret2; 1309349e8d26SHe Kuang bool externs = !af->child; 1310fb9596d1SHe Kuang struct strbuf buf; 1311fb9596d1SHe Kuang 1312fb9596d1SHe Kuang strbuf_init(&buf, 64); 1313349e8d26SHe Kuang 1314349e8d26SHe Kuang if (probe_conf.show_location_range) { 1315349e8d26SHe Kuang if (!externs) { 1316349e8d26SHe Kuang if (ret) 1317349e8d26SHe Kuang strbuf_addf(&buf, "[INV]\t"); 1318349e8d26SHe Kuang else 1319349e8d26SHe Kuang strbuf_addf(&buf, "[VAL]\t"); 1320349e8d26SHe Kuang } else 1321349e8d26SHe Kuang strbuf_addf(&buf, "[EXT]\t"); 1322349e8d26SHe Kuang } 1323349e8d26SHe Kuang 1324349e8d26SHe Kuang ret2 = die_get_varname(die_mem, &buf); 1325349e8d26SHe Kuang 1326349e8d26SHe Kuang if (!ret2 && probe_conf.show_location_range && 1327349e8d26SHe Kuang !externs) { 1328349e8d26SHe Kuang strbuf_addf(&buf, "\t"); 1329349e8d26SHe Kuang ret2 = die_get_var_range(&af->pf.sp_die, 1330349e8d26SHe Kuang die_mem, &buf); 1331349e8d26SHe Kuang } 1332349e8d26SHe Kuang 1333349e8d26SHe Kuang pr_debug("Add new var: %s\n", buf.buf); 1334349e8d26SHe Kuang if (ret2 == 0) { 1335fb9596d1SHe Kuang strlist__add(vl->vars, 1336fb9596d1SHe Kuang strbuf_detach(&buf, NULL)); 1337fb9596d1SHe Kuang } 1338fb9596d1SHe Kuang strbuf_release(&buf); 1339cf6eb489SMasami Hiramatsu } 1340cf6eb489SMasami Hiramatsu } 1341cf6eb489SMasami Hiramatsu 1342fb8c5a56SMasami Hiramatsu if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1343cf6eb489SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 1344cf6eb489SMasami Hiramatsu else 1345cf6eb489SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 1346cf6eb489SMasami Hiramatsu } 1347cf6eb489SMasami Hiramatsu 1348cf6eb489SMasami Hiramatsu /* Add a found vars into available variables list */ 1349221d0611SMasami Hiramatsu static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1350cf6eb489SMasami Hiramatsu { 1351cf6eb489SMasami Hiramatsu struct available_var_finder *af = 1352cf6eb489SMasami Hiramatsu container_of(pf, struct available_var_finder, pf); 13536cca13bdSMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1354cf6eb489SMasami Hiramatsu struct variable_list *vl; 1355f182e3e1SMasami Hiramatsu Dwarf_Die die_mem; 1356f182e3e1SMasami Hiramatsu int ret; 1357cf6eb489SMasami Hiramatsu 1358cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1359cf6eb489SMasami Hiramatsu if (af->nvls == af->max_vls) { 1360cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1361cf6eb489SMasami Hiramatsu return -ERANGE; 1362cf6eb489SMasami Hiramatsu } 1363cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls++]; 1364cf6eb489SMasami Hiramatsu 1365221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1366576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, 13676cca13bdSMasami Hiramatsu pp->retprobe, pp->function, &vl->point); 1368cf6eb489SMasami Hiramatsu if (ret < 0) 1369cf6eb489SMasami Hiramatsu return ret; 1370cf6eb489SMasami Hiramatsu 1371cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1372cf6eb489SMasami Hiramatsu vl->point.offset); 1373cf6eb489SMasami Hiramatsu 1374cf6eb489SMasami Hiramatsu /* Find local variables */ 13754a77e218SArnaldo Carvalho de Melo vl->vars = strlist__new(NULL, NULL); 1376cf6eb489SMasami Hiramatsu if (vl->vars == NULL) 1377cf6eb489SMasami Hiramatsu return -ENOMEM; 1378fb8c5a56SMasami Hiramatsu af->child = true; 1379221d0611SMasami Hiramatsu die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1380cf6eb489SMasami Hiramatsu 1381fb8c5a56SMasami Hiramatsu /* Find external variables */ 1382ddb2f58fSMasami Hiramatsu if (!probe_conf.show_ext_vars) 1383fb8c5a56SMasami Hiramatsu goto out; 1384ddb2f58fSMasami Hiramatsu /* Don't need to search child DIE for external vars. */ 1385fb8c5a56SMasami Hiramatsu af->child = false; 1386f182e3e1SMasami Hiramatsu die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1387fb8c5a56SMasami Hiramatsu 1388fb8c5a56SMasami Hiramatsu out: 1389cf6eb489SMasami Hiramatsu if (strlist__empty(vl->vars)) { 1390cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 1391cf6eb489SMasami Hiramatsu vl->vars = NULL; 1392cf6eb489SMasami Hiramatsu } 1393cf6eb489SMasami Hiramatsu 1394cf6eb489SMasami Hiramatsu return ret; 1395cf6eb489SMasami Hiramatsu } 1396cf6eb489SMasami Hiramatsu 139769e96eaaSMasami Hiramatsu /* 139869e96eaaSMasami Hiramatsu * Find available variables at given probe point 139969e96eaaSMasami Hiramatsu * Return the number of found probe points. Return 0 if there is no 140069e96eaaSMasami Hiramatsu * matched probe point. Return <0 if an error occurs. 140169e96eaaSMasami Hiramatsu */ 1402316c7136SArnaldo Carvalho de Melo int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1403ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1404ddb2f58fSMasami Hiramatsu struct variable_list **vls) 1405cf6eb489SMasami Hiramatsu { 1406cf6eb489SMasami Hiramatsu struct available_var_finder af = { 1407cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_available_vars}, 1408316c7136SArnaldo Carvalho de Melo .mod = dbg->mod, 1409ddb2f58fSMasami Hiramatsu .max_vls = probe_conf.max_probes}; 1410cf6eb489SMasami Hiramatsu int ret; 1411cf6eb489SMasami Hiramatsu 1412cf6eb489SMasami Hiramatsu /* Allocate result vls array */ 1413ddb2f58fSMasami Hiramatsu *vls = zalloc(sizeof(struct variable_list) * af.max_vls); 1414cf6eb489SMasami Hiramatsu if (*vls == NULL) 1415cf6eb489SMasami Hiramatsu return -ENOMEM; 1416cf6eb489SMasami Hiramatsu 1417cf6eb489SMasami Hiramatsu af.vls = *vls; 1418cf6eb489SMasami Hiramatsu af.nvls = 0; 1419cf6eb489SMasami Hiramatsu 1420316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &af.pf); 1421cf6eb489SMasami Hiramatsu if (ret < 0) { 1422cf6eb489SMasami Hiramatsu /* Free vlist for error */ 1423cf6eb489SMasami Hiramatsu while (af.nvls--) { 142474cf249dSArnaldo Carvalho de Melo zfree(&af.vls[af.nvls].point.symbol); 1425cf6eb489SMasami Hiramatsu strlist__delete(af.vls[af.nvls].vars); 1426cf6eb489SMasami Hiramatsu } 142704662523SArnaldo Carvalho de Melo zfree(vls); 1428cf6eb489SMasami Hiramatsu return ret; 1429cf6eb489SMasami Hiramatsu } 1430cf6eb489SMasami Hiramatsu 1431cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : af.nvls; 14324ea42b18SMasami Hiramatsu } 14334ea42b18SMasami Hiramatsu 14349b239a12SMasami Hiramatsu /* For the kernel module, we need a special code to get a DIE */ 14359b239a12SMasami Hiramatsu static int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs) 14369b239a12SMasami Hiramatsu { 14379b239a12SMasami Hiramatsu int n, i; 14389b239a12SMasami Hiramatsu Elf32_Word shndx; 14399b239a12SMasami Hiramatsu Elf_Scn *scn; 14409b239a12SMasami Hiramatsu Elf *elf; 14419b239a12SMasami Hiramatsu GElf_Shdr mem, *shdr; 14429b239a12SMasami Hiramatsu const char *p; 14439b239a12SMasami Hiramatsu 14449b239a12SMasami Hiramatsu elf = dwfl_module_getelf(dbg->mod, &dbg->bias); 14459b239a12SMasami Hiramatsu if (!elf) 14469b239a12SMasami Hiramatsu return -EINVAL; 14479b239a12SMasami Hiramatsu 14489b239a12SMasami Hiramatsu /* Get the number of relocations */ 14499b239a12SMasami Hiramatsu n = dwfl_module_relocations(dbg->mod); 14509b239a12SMasami Hiramatsu if (n < 0) 14519b239a12SMasami Hiramatsu return -ENOENT; 14529b239a12SMasami Hiramatsu /* Search the relocation related .text section */ 14539b239a12SMasami Hiramatsu for (i = 0; i < n; i++) { 14549b239a12SMasami Hiramatsu p = dwfl_module_relocation_info(dbg->mod, i, &shndx); 14559b239a12SMasami Hiramatsu if (strcmp(p, ".text") == 0) { 14569b239a12SMasami Hiramatsu /* OK, get the section header */ 14579b239a12SMasami Hiramatsu scn = elf_getscn(elf, shndx); 14589b239a12SMasami Hiramatsu if (!scn) 14599b239a12SMasami Hiramatsu return -ENOENT; 14609b239a12SMasami Hiramatsu shdr = gelf_getshdr(scn, &mem); 14619b239a12SMasami Hiramatsu if (!shdr) 14629b239a12SMasami Hiramatsu return -ENOENT; 14639b239a12SMasami Hiramatsu *offs = shdr->sh_addr; 14649b239a12SMasami Hiramatsu } 14659b239a12SMasami Hiramatsu } 14669b239a12SMasami Hiramatsu return 0; 14679b239a12SMasami Hiramatsu } 14689b239a12SMasami Hiramatsu 1469fb1587d8SMasami Hiramatsu /* Reverse search */ 1470316c7136SArnaldo Carvalho de Melo int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, 1471ff741783SMasami Hiramatsu struct perf_probe_point *ppt) 1472fb1587d8SMasami Hiramatsu { 1473fb1587d8SMasami Hiramatsu Dwarf_Die cudie, spdie, indie; 1474e08cfd4bSMasami Hiramatsu Dwarf_Addr _addr = 0, baseaddr = 0; 1475e08cfd4bSMasami Hiramatsu const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; 14761d46ea2aSMasami Hiramatsu int baseline = 0, lineno = 0, ret = 0; 14779b239a12SMasami Hiramatsu bool reloc = false; 1478fb1587d8SMasami Hiramatsu 14799b239a12SMasami Hiramatsu retry: 1480fb1587d8SMasami Hiramatsu /* Find cu die */ 14810104fe69SMasami Hiramatsu if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { 14829b239a12SMasami Hiramatsu if (!reloc && debuginfo__get_text_offset(dbg, &baseaddr) == 0) { 14839b239a12SMasami Hiramatsu addr += baseaddr; 14849b239a12SMasami Hiramatsu reloc = true; 14859b239a12SMasami Hiramatsu goto retry; 14869b239a12SMasami Hiramatsu } 14870e43e5d2SMasami Hiramatsu pr_warning("Failed to find debug information for address %lx\n", 14880e43e5d2SMasami Hiramatsu addr); 148975ec5a24SMasami Hiramatsu ret = -EINVAL; 149075ec5a24SMasami Hiramatsu goto end; 149175ec5a24SMasami Hiramatsu } 1492fb1587d8SMasami Hiramatsu 14931d46ea2aSMasami Hiramatsu /* Find a corresponding line (filename and lineno) */ 14941d46ea2aSMasami Hiramatsu cu_find_lineinfo(&cudie, addr, &fname, &lineno); 14951d46ea2aSMasami Hiramatsu /* Don't care whether it failed or not */ 1496fb1587d8SMasami Hiramatsu 14971d46ea2aSMasami Hiramatsu /* Find a corresponding function (name, baseline and baseaddr) */ 1498e0d153c6SMasami Hiramatsu if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 14991d46ea2aSMasami Hiramatsu /* Get function entry information */ 1500e08cfd4bSMasami Hiramatsu func = basefunc = dwarf_diename(&spdie); 1501e08cfd4bSMasami Hiramatsu if (!func || 15021d46ea2aSMasami Hiramatsu dwarf_entrypc(&spdie, &baseaddr) != 0 || 1503e08cfd4bSMasami Hiramatsu dwarf_decl_line(&spdie, &baseline) != 0) { 1504e08cfd4bSMasami Hiramatsu lineno = 0; 15051d46ea2aSMasami Hiramatsu goto post; 1506e08cfd4bSMasami Hiramatsu } 1507fb1587d8SMasami Hiramatsu 15081b286bddSMasami Hiramatsu fname = dwarf_decl_file(&spdie); 1509e08cfd4bSMasami Hiramatsu if (addr == (unsigned long)baseaddr) { 15101d46ea2aSMasami Hiramatsu /* Function entry - Relative line number is 0 */ 15111d46ea2aSMasami Hiramatsu lineno = baseline; 1512e08cfd4bSMasami Hiramatsu goto post; 1513e08cfd4bSMasami Hiramatsu } 1514e08cfd4bSMasami Hiramatsu 1515e08cfd4bSMasami Hiramatsu /* Track down the inline functions step by step */ 1516e08cfd4bSMasami Hiramatsu while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, 1517b55a87adSMasami Hiramatsu &indie)) { 1518e08cfd4bSMasami Hiramatsu /* There is an inline function */ 15191d46ea2aSMasami Hiramatsu if (dwarf_entrypc(&indie, &_addr) == 0 && 1520e08cfd4bSMasami Hiramatsu _addr == addr) { 15211d46ea2aSMasami Hiramatsu /* 15221d46ea2aSMasami Hiramatsu * addr is at an inline function entry. 15231d46ea2aSMasami Hiramatsu * In this case, lineno should be the call-site 1524e08cfd4bSMasami Hiramatsu * line number. (overwrite lineinfo) 15251d46ea2aSMasami Hiramatsu */ 15261d46ea2aSMasami Hiramatsu lineno = die_get_call_lineno(&indie); 1527e08cfd4bSMasami Hiramatsu fname = die_get_call_file(&indie); 1528e08cfd4bSMasami Hiramatsu break; 1529e08cfd4bSMasami Hiramatsu } else { 15301d46ea2aSMasami Hiramatsu /* 15311d46ea2aSMasami Hiramatsu * addr is in an inline function body. 15321d46ea2aSMasami Hiramatsu * Since lineno points one of the lines 15331d46ea2aSMasami Hiramatsu * of the inline function, baseline should 15341d46ea2aSMasami Hiramatsu * be the entry line of the inline function. 15351d46ea2aSMasami Hiramatsu */ 1536fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&indie); 1537e08cfd4bSMasami Hiramatsu if (!tmp || 1538e08cfd4bSMasami Hiramatsu dwarf_decl_line(&indie, &baseline) != 0) 1539e08cfd4bSMasami Hiramatsu break; 15401d46ea2aSMasami Hiramatsu func = tmp; 1541e08cfd4bSMasami Hiramatsu spdie = indie; 1542b55a87adSMasami Hiramatsu } 1543b55a87adSMasami Hiramatsu } 1544e08cfd4bSMasami Hiramatsu /* Verify the lineno and baseline are in a same file */ 1545e08cfd4bSMasami Hiramatsu tmp = dwarf_decl_file(&spdie); 1546e08cfd4bSMasami Hiramatsu if (!tmp || strcmp(tmp, fname) != 0) 1547e08cfd4bSMasami Hiramatsu lineno = 0; 15481d46ea2aSMasami Hiramatsu } 15491d46ea2aSMasami Hiramatsu 15501d46ea2aSMasami Hiramatsu post: 15511d46ea2aSMasami Hiramatsu /* Make a relative line number or an offset */ 15521d46ea2aSMasami Hiramatsu if (lineno) 15531d46ea2aSMasami Hiramatsu ppt->line = lineno - baseline; 1554e08cfd4bSMasami Hiramatsu else if (basefunc) { 15551d46ea2aSMasami Hiramatsu ppt->offset = addr - (unsigned long)baseaddr; 1556e08cfd4bSMasami Hiramatsu func = basefunc; 1557e08cfd4bSMasami Hiramatsu } 15581d46ea2aSMasami Hiramatsu 15591d46ea2aSMasami Hiramatsu /* Duplicate strings */ 15601d46ea2aSMasami Hiramatsu if (func) { 15611d46ea2aSMasami Hiramatsu ppt->function = strdup(func); 156202b95dadSMasami Hiramatsu if (ppt->function == NULL) { 156302b95dadSMasami Hiramatsu ret = -ENOMEM; 156402b95dadSMasami Hiramatsu goto end; 156502b95dadSMasami Hiramatsu } 1566fb1587d8SMasami Hiramatsu } 15671d46ea2aSMasami Hiramatsu if (fname) { 15681d46ea2aSMasami Hiramatsu ppt->file = strdup(fname); 15691d46ea2aSMasami Hiramatsu if (ppt->file == NULL) { 157004662523SArnaldo Carvalho de Melo zfree(&ppt->function); 15711d46ea2aSMasami Hiramatsu ret = -ENOMEM; 15721d46ea2aSMasami Hiramatsu goto end; 15731d46ea2aSMasami Hiramatsu } 15741d46ea2aSMasami Hiramatsu } 1575fb1587d8SMasami Hiramatsu end: 15761d46ea2aSMasami Hiramatsu if (ret == 0 && (fname || func)) 15771d46ea2aSMasami Hiramatsu ret = 1; /* Found a point */ 1578fb1587d8SMasami Hiramatsu return ret; 1579fb1587d8SMasami Hiramatsu } 1580fb1587d8SMasami Hiramatsu 1581f6c903f5SMasami Hiramatsu /* Add a line and store the src path */ 1582f6c903f5SMasami Hiramatsu static int line_range_add_line(const char *src, unsigned int lineno, 1583f6c903f5SMasami Hiramatsu struct line_range *lr) 1584f6c903f5SMasami Hiramatsu { 15857cf0b79eSMasami Hiramatsu /* Copy source path */ 1586f6c903f5SMasami Hiramatsu if (!lr->path) { 15877cf0b79eSMasami Hiramatsu lr->path = strdup(src); 15887cf0b79eSMasami Hiramatsu if (lr->path == NULL) 15897cf0b79eSMasami Hiramatsu return -ENOMEM; 1590f6c903f5SMasami Hiramatsu } 15915a62257aSMasami Hiramatsu return intlist__add(lr->line_list, lineno); 1592f6c903f5SMasami Hiramatsu } 1593f6c903f5SMasami Hiramatsu 15944cc9cec6SMasami Hiramatsu static int line_range_walk_cb(const char *fname, int lineno, 15951d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused, 15964cc9cec6SMasami Hiramatsu void *data) 1597f6c903f5SMasami Hiramatsu { 15984cc9cec6SMasami Hiramatsu struct line_finder *lf = data; 1599202c7c12SNamhyung Kim int err; 1600f6c903f5SMasami Hiramatsu 16014cc9cec6SMasami Hiramatsu if ((strtailcmp(fname, lf->fname) != 0) || 1602f6c903f5SMasami Hiramatsu (lf->lno_s > lineno || lf->lno_e < lineno)) 16034cc9cec6SMasami Hiramatsu return 0; 1604f6c903f5SMasami Hiramatsu 1605202c7c12SNamhyung Kim err = line_range_add_line(fname, lineno, lf->lr); 1606202c7c12SNamhyung Kim if (err < 0 && err != -EEXIST) 1607202c7c12SNamhyung Kim return err; 1608f6c903f5SMasami Hiramatsu 16094cc9cec6SMasami Hiramatsu return 0; 1610f6c903f5SMasami Hiramatsu } 1611fb1587d8SMasami Hiramatsu 1612631c9defSMasami Hiramatsu /* Find line range from its line number */ 1613b55a87adSMasami Hiramatsu static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1614631c9defSMasami Hiramatsu { 16154cc9cec6SMasami Hiramatsu int ret; 1616631c9defSMasami Hiramatsu 16174cc9cec6SMasami Hiramatsu ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1618f6c903f5SMasami Hiramatsu 1619804b3606SMasami Hiramatsu /* Update status */ 1620f6c903f5SMasami Hiramatsu if (ret >= 0) 16215a62257aSMasami Hiramatsu if (!intlist__empty(lf->lr->line_list)) 1622f6c903f5SMasami Hiramatsu ret = lf->found = 1; 1623f6c903f5SMasami Hiramatsu else 1624f6c903f5SMasami Hiramatsu ret = 0; /* Lines are not found */ 1625804b3606SMasami Hiramatsu else { 162604662523SArnaldo Carvalho de Melo zfree(&lf->lr->path); 1627804b3606SMasami Hiramatsu } 1628f6c903f5SMasami Hiramatsu return ret; 1629631c9defSMasami Hiramatsu } 1630631c9defSMasami Hiramatsu 1631161a26b0SMasami Hiramatsu static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1632161a26b0SMasami Hiramatsu { 1633182c228eSMasami Hiramatsu int ret = find_line_range_by_line(in_die, data); 163436c0c588SMasami Hiramatsu 163536c0c588SMasami Hiramatsu /* 163636c0c588SMasami Hiramatsu * We have to check all instances of inlined function, because 163736c0c588SMasami Hiramatsu * some execution paths can be optimized out depends on the 1638182c228eSMasami Hiramatsu * function argument of instances. However, if an error occurs, 1639182c228eSMasami Hiramatsu * it should be handled by the caller. 164036c0c588SMasami Hiramatsu */ 1641182c228eSMasami Hiramatsu return ret < 0 ? ret : 0; 1642161a26b0SMasami Hiramatsu } 1643161a26b0SMasami Hiramatsu 16440dbb1cacSMasami Hiramatsu /* Search function definition from function name */ 1645e92b85e1SMasami Hiramatsu static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1646631c9defSMasami Hiramatsu { 1647b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1648b55a87adSMasami Hiramatsu struct line_finder *lf = param->data; 1649631c9defSMasami Hiramatsu struct line_range *lr = lf->lr; 1650631c9defSMasami Hiramatsu 16517d21635aSMasami Hiramatsu /* Check declared file */ 16527d21635aSMasami Hiramatsu if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 16537d21635aSMasami Hiramatsu return DWARF_CB_OK; 16547d21635aSMasami Hiramatsu 16550dbb1cacSMasami Hiramatsu if (die_is_func_def(sp_die) && 16564c859351SMasami Hiramatsu die_match_name(sp_die, lr->function)) { 1657e92b85e1SMasami Hiramatsu lf->fname = dwarf_decl_file(sp_die); 1658e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &lr->offset); 1659804b3606SMasami Hiramatsu pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1660631c9defSMasami Hiramatsu lf->lno_s = lr->offset + lr->start; 1661d3b63d7aSMasami Hiramatsu if (lf->lno_s < 0) /* Overflow */ 1662d3b63d7aSMasami Hiramatsu lf->lno_s = INT_MAX; 1663631c9defSMasami Hiramatsu lf->lno_e = lr->offset + lr->end; 1664d3b63d7aSMasami Hiramatsu if (lf->lno_e < 0) /* Overflow */ 1665d3b63d7aSMasami Hiramatsu lf->lno_e = INT_MAX; 1666d3b63d7aSMasami Hiramatsu pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1667631c9defSMasami Hiramatsu lr->start = lf->lno_s; 1668631c9defSMasami Hiramatsu lr->end = lf->lno_e; 1669e1ecbbc3SMasami Hiramatsu if (!die_is_func_instance(sp_die)) 1670db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1671db0d2c64SMasami Hiramatsu line_range_inline_cb, lf); 1672db0d2c64SMasami Hiramatsu else 1673b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(sp_die, lf); 1674b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1675631c9defSMasami Hiramatsu } 1676b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1677631c9defSMasami Hiramatsu } 1678631c9defSMasami Hiramatsu 1679b55a87adSMasami Hiramatsu static int find_line_range_by_func(struct line_finder *lf) 1680631c9defSMasami Hiramatsu { 1681b55a87adSMasami Hiramatsu struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1682b55a87adSMasami Hiramatsu dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1683b55a87adSMasami Hiramatsu return param.retval; 1684631c9defSMasami Hiramatsu } 1685631c9defSMasami Hiramatsu 1686316c7136SArnaldo Carvalho de Melo int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr) 1687631c9defSMasami Hiramatsu { 1688804b3606SMasami Hiramatsu struct line_finder lf = {.lr = lr, .found = 0}; 1689b55a87adSMasami Hiramatsu int ret = 0; 1690804b3606SMasami Hiramatsu Dwarf_Off off = 0, noff; 1691804b3606SMasami Hiramatsu size_t cuhl; 1692804b3606SMasami Hiramatsu Dwarf_Die *diep; 16936a330a3cSMasami Hiramatsu const char *comp_dir; 1694631c9defSMasami Hiramatsu 1695cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1696cd25f8bcSLin Ming if (lr->function) { 1697cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1698cd25f8bcSLin Ming .function = lr->function, .file = lr->file, 1699cd25f8bcSLin Ming .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1700cd25f8bcSLin Ming struct dwarf_callback_param line_range_param = { 1701cd25f8bcSLin Ming .data = (void *)&lf, .retval = 0}; 1702cd25f8bcSLin Ming 1703316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1704ff741783SMasami Hiramatsu &pubname_param, 0); 1705cd25f8bcSLin Ming if (pubname_param.found) { 1706cd25f8bcSLin Ming line_range_search_cb(&lf.sp_die, &line_range_param); 1707cd25f8bcSLin Ming if (lf.found) 1708cd25f8bcSLin Ming goto found; 1709cd25f8bcSLin Ming } 1710cd25f8bcSLin Ming } 1711cd25f8bcSLin Ming 1712804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1713b55a87adSMasami Hiramatsu while (!lf.found && ret >= 0) { 1714316c7136SArnaldo Carvalho de Melo if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, 1715ff741783SMasami Hiramatsu NULL, NULL, NULL) != 0) 1716631c9defSMasami Hiramatsu break; 1717631c9defSMasami Hiramatsu 1718631c9defSMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1719316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die); 1720804b3606SMasami Hiramatsu if (!diep) 1721804b3606SMasami Hiramatsu continue; 1722631c9defSMasami Hiramatsu 1723631c9defSMasami Hiramatsu /* Check if target file is included. */ 1724631c9defSMasami Hiramatsu if (lr->file) 17252a9c8c36SMasami Hiramatsu lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1726804b3606SMasami Hiramatsu else 17272a9c8c36SMasami Hiramatsu lf.fname = 0; 1728631c9defSMasami Hiramatsu 17292a9c8c36SMasami Hiramatsu if (!lr->file || lf.fname) { 1730631c9defSMasami Hiramatsu if (lr->function) 1731b55a87adSMasami Hiramatsu ret = find_line_range_by_func(&lf); 1732631c9defSMasami Hiramatsu else { 1733631c9defSMasami Hiramatsu lf.lno_s = lr->start; 1734631c9defSMasami Hiramatsu lf.lno_e = lr->end; 1735b55a87adSMasami Hiramatsu ret = find_line_range_by_line(NULL, &lf); 1736631c9defSMasami Hiramatsu } 1737631c9defSMasami Hiramatsu } 1738804b3606SMasami Hiramatsu off = noff; 1739631c9defSMasami Hiramatsu } 17406a330a3cSMasami Hiramatsu 1741cd25f8bcSLin Ming found: 17426a330a3cSMasami Hiramatsu /* Store comp_dir */ 17436a330a3cSMasami Hiramatsu if (lf.found) { 17446a330a3cSMasami Hiramatsu comp_dir = cu_get_comp_dir(&lf.cu_die); 17456a330a3cSMasami Hiramatsu if (comp_dir) { 17466a330a3cSMasami Hiramatsu lr->comp_dir = strdup(comp_dir); 17476a330a3cSMasami Hiramatsu if (!lr->comp_dir) 17486a330a3cSMasami Hiramatsu ret = -ENOMEM; 17496a330a3cSMasami Hiramatsu } 17506a330a3cSMasami Hiramatsu } 17516a330a3cSMasami Hiramatsu 17527cf0b79eSMasami Hiramatsu pr_debug("path: %s\n", lr->path); 1753b55a87adSMasami Hiramatsu return (ret < 0) ? ret : lf.found; 1754631c9defSMasami Hiramatsu } 1755631c9defSMasami Hiramatsu 175609ed8975SNaohiro Aota /* 175709ed8975SNaohiro Aota * Find a src file from a DWARF tag path. Prepend optional source path prefix 175809ed8975SNaohiro Aota * and chop off leading directories that do not exist. Result is passed back as 175909ed8975SNaohiro Aota * a newly allocated path on success. 176009ed8975SNaohiro Aota * Return 0 if file was found and readable, -errno otherwise. 176109ed8975SNaohiro Aota */ 176209ed8975SNaohiro Aota int get_real_path(const char *raw_path, const char *comp_dir, 176309ed8975SNaohiro Aota char **new_path) 176409ed8975SNaohiro Aota { 176509ed8975SNaohiro Aota const char *prefix = symbol_conf.source_prefix; 176609ed8975SNaohiro Aota 176709ed8975SNaohiro Aota if (!prefix) { 176809ed8975SNaohiro Aota if (raw_path[0] != '/' && comp_dir) 176909ed8975SNaohiro Aota /* If not an absolute path, try to use comp_dir */ 177009ed8975SNaohiro Aota prefix = comp_dir; 177109ed8975SNaohiro Aota else { 177209ed8975SNaohiro Aota if (access(raw_path, R_OK) == 0) { 177309ed8975SNaohiro Aota *new_path = strdup(raw_path); 177409ed8975SNaohiro Aota return *new_path ? 0 : -ENOMEM; 177509ed8975SNaohiro Aota } else 177609ed8975SNaohiro Aota return -errno; 177709ed8975SNaohiro Aota } 177809ed8975SNaohiro Aota } 177909ed8975SNaohiro Aota 178009ed8975SNaohiro Aota *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 178109ed8975SNaohiro Aota if (!*new_path) 178209ed8975SNaohiro Aota return -ENOMEM; 178309ed8975SNaohiro Aota 178409ed8975SNaohiro Aota for (;;) { 178509ed8975SNaohiro Aota sprintf(*new_path, "%s/%s", prefix, raw_path); 178609ed8975SNaohiro Aota 178709ed8975SNaohiro Aota if (access(*new_path, R_OK) == 0) 178809ed8975SNaohiro Aota return 0; 178909ed8975SNaohiro Aota 179009ed8975SNaohiro Aota if (!symbol_conf.source_prefix) { 179109ed8975SNaohiro Aota /* In case of searching comp_dir, don't retry */ 179209ed8975SNaohiro Aota zfree(new_path); 179309ed8975SNaohiro Aota return -errno; 179409ed8975SNaohiro Aota } 179509ed8975SNaohiro Aota 179609ed8975SNaohiro Aota switch (errno) { 179709ed8975SNaohiro Aota case ENAMETOOLONG: 179809ed8975SNaohiro Aota case ENOENT: 179909ed8975SNaohiro Aota case EROFS: 180009ed8975SNaohiro Aota case EFAULT: 180109ed8975SNaohiro Aota raw_path = strchr(++raw_path, '/'); 180209ed8975SNaohiro Aota if (!raw_path) { 180309ed8975SNaohiro Aota zfree(new_path); 180409ed8975SNaohiro Aota return -ENOENT; 180509ed8975SNaohiro Aota } 180609ed8975SNaohiro Aota continue; 180709ed8975SNaohiro Aota 180809ed8975SNaohiro Aota default: 180909ed8975SNaohiro Aota zfree(new_path); 181009ed8975SNaohiro Aota return -errno; 181109ed8975SNaohiro Aota } 181209ed8975SNaohiro Aota } 181309ed8975SNaohiro Aota } 1814