11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 24ea42b18SMasami Hiramatsu /* 34ea42b18SMasami Hiramatsu * probe-finder.c : C expression to kprobe event converter 44ea42b18SMasami Hiramatsu * 54ea42b18SMasami Hiramatsu * Written by Masami Hiramatsu <mhiramat@redhat.com> 64ea42b18SMasami Hiramatsu */ 74ea42b18SMasami Hiramatsu 8fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 94ea42b18SMasami Hiramatsu #include <sys/utsname.h> 104ea42b18SMasami Hiramatsu #include <sys/types.h> 114ea42b18SMasami Hiramatsu #include <sys/stat.h> 124ea42b18SMasami Hiramatsu #include <fcntl.h> 134ea42b18SMasami Hiramatsu #include <errno.h> 144ea42b18SMasami Hiramatsu #include <stdio.h> 154ea42b18SMasami Hiramatsu #include <unistd.h> 164ea42b18SMasami Hiramatsu #include <stdlib.h> 174ea42b18SMasami Hiramatsu #include <string.h> 184ea42b18SMasami Hiramatsu #include <stdarg.h> 19cd932c59SIan Munsie #include <dwarf-regs.h> 20074fc0e4SMasami Hiramatsu 21124bb83cSMasami Hiramatsu #include <linux/bitops.h> 227f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 2389c69c0eSMasami Hiramatsu #include "event.h" 24a15ad2f5SMasami Hiramatsu #include "dso.h" 2589c69c0eSMasami Hiramatsu #include "debug.h" 265a62257aSMasami Hiramatsu #include "intlist.h" 27*8520a98dSArnaldo Carvalho de Melo #include "strbuf.h" 288ec20b17SArnaldo Carvalho de Melo #include "strlist.h" 299ed7e1b8SChase Douglas #include "symbol.h" 304ea42b18SMasami Hiramatsu #include "probe-finder.h" 31180b2061SMasami Hiramatsu #include "probe-file.h" 32a067558eSArnaldo Carvalho de Melo #include "string2.h" 334ea42b18SMasami Hiramatsu 344984912eSMasami Hiramatsu /* Kprobe tracer basic type is up to u64 */ 354984912eSMasami Hiramatsu #define MAX_BASIC_TYPE_BITS 64 364984912eSMasami Hiramatsu 37469b9b88SMasami Hiramatsu /* Dwarf FL wrappers */ 38469b9b88SMasami Hiramatsu static char *debuginfo_path; /* Currently dummy */ 39469b9b88SMasami Hiramatsu 40469b9b88SMasami Hiramatsu static const Dwfl_Callbacks offline_callbacks = { 41469b9b88SMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 42469b9b88SMasami Hiramatsu .debuginfo_path = &debuginfo_path, 43469b9b88SMasami Hiramatsu 44469b9b88SMasami Hiramatsu .section_address = dwfl_offline_section_address, 45469b9b88SMasami Hiramatsu 46469b9b88SMasami Hiramatsu /* We use this table for core files too. */ 47469b9b88SMasami Hiramatsu .find_elf = dwfl_build_id_find_elf, 48469b9b88SMasami Hiramatsu }; 49469b9b88SMasami Hiramatsu 50469b9b88SMasami Hiramatsu /* Get a Dwarf from offline image */ 51316c7136SArnaldo Carvalho de Melo static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, 52ff741783SMasami Hiramatsu const char *path) 53469b9b88SMasami Hiramatsu { 54ff741783SMasami Hiramatsu int fd; 55469b9b88SMasami Hiramatsu 56ff741783SMasami Hiramatsu fd = open(path, O_RDONLY); 57ff741783SMasami Hiramatsu if (fd < 0) 58ff741783SMasami Hiramatsu return fd; 59469b9b88SMasami Hiramatsu 60316c7136SArnaldo Carvalho de Melo dbg->dwfl = dwfl_begin(&offline_callbacks); 61316c7136SArnaldo Carvalho de Melo if (!dbg->dwfl) 62ff741783SMasami Hiramatsu goto error; 63469b9b88SMasami Hiramatsu 649135949dSMasami Hiramatsu dwfl_report_begin(dbg->dwfl); 65316c7136SArnaldo Carvalho de Melo dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); 66316c7136SArnaldo Carvalho de Melo if (!dbg->mod) 67469b9b88SMasami Hiramatsu goto error; 68469b9b88SMasami Hiramatsu 69316c7136SArnaldo Carvalho de Melo dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); 70316c7136SArnaldo Carvalho de Melo if (!dbg->dbg) 71ff741783SMasami Hiramatsu goto error; 72ff741783SMasami Hiramatsu 739135949dSMasami Hiramatsu dwfl_report_end(dbg->dwfl, NULL, NULL); 749135949dSMasami Hiramatsu 75ff741783SMasami Hiramatsu return 0; 76469b9b88SMasami Hiramatsu error: 77316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 78316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 79ff741783SMasami Hiramatsu else 80ff741783SMasami Hiramatsu close(fd); 81316c7136SArnaldo Carvalho de Melo memset(dbg, 0, sizeof(*dbg)); 82ff741783SMasami Hiramatsu 83ff741783SMasami Hiramatsu return -ENOENT; 84469b9b88SMasami Hiramatsu } 85469b9b88SMasami Hiramatsu 86a15ad2f5SMasami Hiramatsu static struct debuginfo *__debuginfo__new(const char *path) 87ff741783SMasami Hiramatsu { 88316c7136SArnaldo Carvalho de Melo struct debuginfo *dbg = zalloc(sizeof(*dbg)); 89316c7136SArnaldo Carvalho de Melo if (!dbg) 90ff741783SMasami Hiramatsu return NULL; 91ff741783SMasami Hiramatsu 9204662523SArnaldo Carvalho de Melo if (debuginfo__init_offline_dwarf(dbg, path) < 0) 9304662523SArnaldo Carvalho de Melo zfree(&dbg); 94a15ad2f5SMasami Hiramatsu if (dbg) 95a15ad2f5SMasami Hiramatsu pr_debug("Open Debuginfo file: %s\n", path); 96316c7136SArnaldo Carvalho de Melo return dbg; 97ff741783SMasami Hiramatsu } 98ff741783SMasami Hiramatsu 99a15ad2f5SMasami Hiramatsu enum dso_binary_type distro_dwarf_types[] = { 100a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 101a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 102a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 103a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 104a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__NOT_FOUND, 105a15ad2f5SMasami Hiramatsu }; 106a15ad2f5SMasami Hiramatsu 107a15ad2f5SMasami Hiramatsu struct debuginfo *debuginfo__new(const char *path) 108a15ad2f5SMasami Hiramatsu { 109a15ad2f5SMasami Hiramatsu enum dso_binary_type *type; 110a15ad2f5SMasami Hiramatsu char buf[PATH_MAX], nil = '\0'; 111a15ad2f5SMasami Hiramatsu struct dso *dso; 112a15ad2f5SMasami Hiramatsu struct debuginfo *dinfo = NULL; 113a15ad2f5SMasami Hiramatsu 114a15ad2f5SMasami Hiramatsu /* Try to open distro debuginfo files */ 115a15ad2f5SMasami Hiramatsu dso = dso__new(path); 116a15ad2f5SMasami Hiramatsu if (!dso) 117a15ad2f5SMasami Hiramatsu goto out; 118a15ad2f5SMasami Hiramatsu 119a15ad2f5SMasami Hiramatsu for (type = distro_dwarf_types; 120a15ad2f5SMasami Hiramatsu !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; 121a15ad2f5SMasami Hiramatsu type++) { 122a15ad2f5SMasami Hiramatsu if (dso__read_binary_type_filename(dso, *type, &nil, 123a15ad2f5SMasami Hiramatsu buf, PATH_MAX) < 0) 124a15ad2f5SMasami Hiramatsu continue; 125a15ad2f5SMasami Hiramatsu dinfo = __debuginfo__new(buf); 126a15ad2f5SMasami Hiramatsu } 127d3a7c489SArnaldo Carvalho de Melo dso__put(dso); 128a15ad2f5SMasami Hiramatsu 129a15ad2f5SMasami Hiramatsu out: 130a15ad2f5SMasami Hiramatsu /* if failed to open all distro debuginfo, open given binary */ 131a15ad2f5SMasami Hiramatsu return dinfo ? : __debuginfo__new(path); 132a15ad2f5SMasami Hiramatsu } 133a15ad2f5SMasami Hiramatsu 134316c7136SArnaldo Carvalho de Melo void debuginfo__delete(struct debuginfo *dbg) 135ff741783SMasami Hiramatsu { 136316c7136SArnaldo Carvalho de Melo if (dbg) { 137316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 138316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 139316c7136SArnaldo Carvalho de Melo free(dbg); 140ff741783SMasami Hiramatsu } 141ff741783SMasami Hiramatsu } 142ff741783SMasami Hiramatsu 1434ea42b18SMasami Hiramatsu /* 1444ea42b18SMasami Hiramatsu * Probe finder related functions 1454ea42b18SMasami Hiramatsu */ 1464ea42b18SMasami Hiramatsu 1470e60836bSSrikar Dronamraju static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 1484ea42b18SMasami Hiramatsu { 1490e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref; 1500e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 151b7dcb857SMasami Hiramatsu if (ref != NULL) 152b7dcb857SMasami Hiramatsu ref->offset = offs; 153b7dcb857SMasami Hiramatsu return ref; 154b7dcb857SMasami Hiramatsu } 155b7dcb857SMasami Hiramatsu 156cf6eb489SMasami Hiramatsu /* 157cf6eb489SMasami Hiramatsu * Convert a location into trace_arg. 158cf6eb489SMasami Hiramatsu * If tvar == NULL, this just checks variable can be converted. 1593d918a12SMasami Hiramatsu * If fentry == true and vr_die is a parameter, do huristic search 1603d918a12SMasami Hiramatsu * for the location fuzzed by function entry mcount. 161cf6eb489SMasami Hiramatsu */ 162cf6eb489SMasami Hiramatsu static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 1633d918a12SMasami Hiramatsu Dwarf_Op *fb_ops, Dwarf_Die *sp_die, 164293d5b43SMasami Hiramatsu unsigned int machine, 165cf6eb489SMasami Hiramatsu struct probe_trace_arg *tvar) 166b7dcb857SMasami Hiramatsu { 167b7dcb857SMasami Hiramatsu Dwarf_Attribute attr; 1683d918a12SMasami Hiramatsu Dwarf_Addr tmp = 0; 169b7dcb857SMasami Hiramatsu Dwarf_Op *op; 170b7dcb857SMasami Hiramatsu size_t nops; 171804b3606SMasami Hiramatsu unsigned int regn; 172804b3606SMasami Hiramatsu Dwarf_Word offs = 0; 1734235b045SMasami Hiramatsu bool ref = false; 1744ea42b18SMasami Hiramatsu const char *regs; 175349e8d26SHe Kuang int ret, ret2 = 0; 176b7dcb857SMasami Hiramatsu 177632941c4SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 178632941c4SMasami Hiramatsu goto static_var; 179632941c4SMasami Hiramatsu 180b7dcb857SMasami Hiramatsu /* TODO: handle more than 1 exprs */ 1813d918a12SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 1823d918a12SMasami Hiramatsu return -EINVAL; /* Broken DIE ? */ 1833d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { 1843d918a12SMasami Hiramatsu ret = dwarf_entrypc(sp_die, &tmp); 185349e8d26SHe Kuang if (ret) 186349e8d26SHe Kuang return -ENOENT; 187349e8d26SHe Kuang 188349e8d26SHe Kuang if (probe_conf.show_location_range && 189349e8d26SHe Kuang (dwarf_tag(vr_die) == DW_TAG_variable)) { 190349e8d26SHe Kuang ret2 = -ERANGE; 191349e8d26SHe Kuang } else if (addr != tmp || 192349e8d26SHe Kuang dwarf_tag(vr_die) != DW_TAG_formal_parameter) { 193349e8d26SHe Kuang return -ENOENT; 194349e8d26SHe Kuang } 195349e8d26SHe Kuang 196349e8d26SHe Kuang ret = dwarf_highpc(sp_die, &tmp); 197349e8d26SHe Kuang if (ret) 1983d918a12SMasami Hiramatsu return -ENOENT; 1993d918a12SMasami Hiramatsu /* 2003d918a12SMasami Hiramatsu * This is fuzzed by fentry mcount. We try to find the 2013d918a12SMasami Hiramatsu * parameter location at the earliest address. 2023d918a12SMasami Hiramatsu */ 2033d918a12SMasami Hiramatsu for (addr += 1; addr <= tmp; addr++) { 2043d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, 2053d918a12SMasami Hiramatsu &nops, 1) > 0) 2063d918a12SMasami Hiramatsu goto found; 2073d918a12SMasami Hiramatsu } 208b7dcb857SMasami Hiramatsu return -ENOENT; 209b7dcb857SMasami Hiramatsu } 2103d918a12SMasami Hiramatsu found: 2113d918a12SMasami Hiramatsu if (nops == 0) 2123d918a12SMasami Hiramatsu /* TODO: Support const_value */ 2133d918a12SMasami Hiramatsu return -ENOENT; 214b7dcb857SMasami Hiramatsu 215b7dcb857SMasami Hiramatsu if (op->atom == DW_OP_addr) { 216632941c4SMasami Hiramatsu static_var: 217cf6eb489SMasami Hiramatsu if (!tvar) 218349e8d26SHe Kuang return ret2; 219b7dcb857SMasami Hiramatsu /* Static variables on memory (not stack), make @varname */ 220b7dcb857SMasami Hiramatsu ret = strlen(dwarf_diename(vr_die)); 221b7dcb857SMasami Hiramatsu tvar->value = zalloc(ret + 2); 222b7dcb857SMasami Hiramatsu if (tvar->value == NULL) 223b7dcb857SMasami Hiramatsu return -ENOMEM; 224b7dcb857SMasami Hiramatsu snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 225b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 226b7dcb857SMasami Hiramatsu if (tvar->ref == NULL) 227b7dcb857SMasami Hiramatsu return -ENOMEM; 228349e8d26SHe Kuang return ret2; 229b7dcb857SMasami Hiramatsu } 2304ea42b18SMasami Hiramatsu 2314ea42b18SMasami Hiramatsu /* If this is based on frame buffer, set the offset */ 232804b3606SMasami Hiramatsu if (op->atom == DW_OP_fbreg) { 233cf6eb489SMasami Hiramatsu if (fb_ops == NULL) 234b55a87adSMasami Hiramatsu return -ENOTSUP; 2354235b045SMasami Hiramatsu ref = true; 236804b3606SMasami Hiramatsu offs = op->number; 237cf6eb489SMasami Hiramatsu op = &fb_ops[0]; 238804b3606SMasami Hiramatsu } 2394ea42b18SMasami Hiramatsu 240804b3606SMasami Hiramatsu if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 241804b3606SMasami Hiramatsu regn = op->atom - DW_OP_breg0; 242804b3606SMasami Hiramatsu offs += op->number; 2434235b045SMasami Hiramatsu ref = true; 244804b3606SMasami Hiramatsu } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 245804b3606SMasami Hiramatsu regn = op->atom - DW_OP_reg0; 246804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_bregx) { 247804b3606SMasami Hiramatsu regn = op->number; 248804b3606SMasami Hiramatsu offs += op->number2; 2494235b045SMasami Hiramatsu ref = true; 250804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_regx) { 251804b3606SMasami Hiramatsu regn = op->number; 252b55a87adSMasami Hiramatsu } else { 253cf6eb489SMasami Hiramatsu pr_debug("DW_OP %x is not supported.\n", op->atom); 254b55a87adSMasami Hiramatsu return -ENOTSUP; 255b55a87adSMasami Hiramatsu } 2564ea42b18SMasami Hiramatsu 257cf6eb489SMasami Hiramatsu if (!tvar) 258349e8d26SHe Kuang return ret2; 259cf6eb489SMasami Hiramatsu 260293d5b43SMasami Hiramatsu regs = get_dwarf_regstr(regn, machine); 261b55a87adSMasami Hiramatsu if (!regs) { 262cf6eb489SMasami Hiramatsu /* This should be a bug in DWARF or this tool */ 2630e43e5d2SMasami Hiramatsu pr_warning("Mapping for the register number %u " 2640e43e5d2SMasami Hiramatsu "missing on this architecture.\n", regn); 265349e8d26SHe Kuang return -ENOTSUP; 266b55a87adSMasami Hiramatsu } 2674ea42b18SMasami Hiramatsu 26802b95dadSMasami Hiramatsu tvar->value = strdup(regs); 26902b95dadSMasami Hiramatsu if (tvar->value == NULL) 27002b95dadSMasami Hiramatsu return -ENOMEM; 27102b95dadSMasami Hiramatsu 2724235b045SMasami Hiramatsu if (ref) { 273b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 274e334016fSMasami Hiramatsu if (tvar->ref == NULL) 275e334016fSMasami Hiramatsu return -ENOMEM; 2764235b045SMasami Hiramatsu } 277349e8d26SHe Kuang return ret2; 2784ea42b18SMasami Hiramatsu } 2794ea42b18SMasami Hiramatsu 280124bb83cSMasami Hiramatsu #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 281124bb83cSMasami Hiramatsu 282b55a87adSMasami Hiramatsu static int convert_variable_type(Dwarf_Die *vr_die, 2830e60836bSSrikar Dronamraju struct probe_trace_arg *tvar, 2841e032f7cSMasami Hiramatsu const char *cast, bool user_access) 2854984912eSMasami Hiramatsu { 2860e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 2874984912eSMasami Hiramatsu Dwarf_Die type; 2884984912eSMasami Hiramatsu char buf[16]; 2895f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 290bcfc0821SMasami Hiramatsu int bsize, boffs, total; 2914984912eSMasami Hiramatsu int ret; 29292543787SMasami Hiramatsu char prefix; 2934984912eSMasami Hiramatsu 29473317b95SMasami Hiramatsu /* TODO: check all types */ 29592543787SMasami Hiramatsu if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 && 29619f00b01SNaohiro Aota strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) { 29773317b95SMasami Hiramatsu /* Non string type is OK */ 29892543787SMasami Hiramatsu /* and respect signedness/hexadecimal cast */ 29973317b95SMasami Hiramatsu tvar->type = strdup(cast); 30073317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 30173317b95SMasami Hiramatsu } 30273317b95SMasami Hiramatsu 303bcfc0821SMasami Hiramatsu bsize = dwarf_bitsize(vr_die); 304bcfc0821SMasami Hiramatsu if (bsize > 0) { 305124bb83cSMasami Hiramatsu /* This is a bitfield */ 306bcfc0821SMasami Hiramatsu boffs = dwarf_bitoffset(vr_die); 307bcfc0821SMasami Hiramatsu total = dwarf_bytesize(vr_die); 308bcfc0821SMasami Hiramatsu if (boffs < 0 || total < 0) 309bcfc0821SMasami Hiramatsu return -ENOENT; 310bcfc0821SMasami Hiramatsu ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 311bcfc0821SMasami Hiramatsu BYTES_TO_BITS(total)); 312124bb83cSMasami Hiramatsu goto formatted; 313124bb83cSMasami Hiramatsu } 314124bb83cSMasami Hiramatsu 315b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 316b55a87adSMasami Hiramatsu pr_warning("Failed to get a type information of %s.\n", 3174984912eSMasami Hiramatsu dwarf_diename(vr_die)); 318b55a87adSMasami Hiramatsu return -ENOENT; 319b55a87adSMasami Hiramatsu } 3204984912eSMasami Hiramatsu 321b2a3c12bSMasami Hiramatsu pr_debug("%s type is %s.\n", 322b2a3c12bSMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 323b2a3c12bSMasami Hiramatsu 3241e032f7cSMasami Hiramatsu if (cast && (!strcmp(cast, "string") || !strcmp(cast, "ustring"))) { 3251e032f7cSMasami Hiramatsu /* String type */ 32673317b95SMasami Hiramatsu ret = dwarf_tag(&type); 32773317b95SMasami Hiramatsu if (ret != DW_TAG_pointer_type && 32873317b95SMasami Hiramatsu ret != DW_TAG_array_type) { 32973317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3300e43e5d2SMasami Hiramatsu "%s(%s) is not a pointer nor array.\n", 33173317b95SMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 33273317b95SMasami Hiramatsu return -EINVAL; 33373317b95SMasami Hiramatsu } 33473317b95SMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 3350e43e5d2SMasami Hiramatsu pr_warning("Failed to get a type" 3360e43e5d2SMasami Hiramatsu " information.\n"); 33773317b95SMasami Hiramatsu return -ENOENT; 33873317b95SMasami Hiramatsu } 3397ce28b5bSHyeoncheol Lee if (ret == DW_TAG_pointer_type) { 34073317b95SMasami Hiramatsu while (*ref_ptr) 34173317b95SMasami Hiramatsu ref_ptr = &(*ref_ptr)->next; 34273317b95SMasami Hiramatsu /* Add new reference with offset +0 */ 3430e60836bSSrikar Dronamraju *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 34473317b95SMasami Hiramatsu if (*ref_ptr == NULL) { 34573317b95SMasami Hiramatsu pr_warning("Out of memory error\n"); 34673317b95SMasami Hiramatsu return -ENOMEM; 34773317b95SMasami Hiramatsu } 3481e032f7cSMasami Hiramatsu (*ref_ptr)->user_access = user_access; 34973317b95SMasami Hiramatsu } 35082175633SMasami Hiramatsu if (!die_compare_name(&type, "char") && 35182175633SMasami Hiramatsu !die_compare_name(&type, "unsigned char")) { 35273317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3530e43e5d2SMasami Hiramatsu "%s is not (unsigned) char *.\n", 35473317b95SMasami Hiramatsu dwarf_diename(vr_die)); 35573317b95SMasami Hiramatsu return -EINVAL; 35673317b95SMasami Hiramatsu } 35773317b95SMasami Hiramatsu tvar->type = strdup(cast); 35873317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 35973317b95SMasami Hiramatsu } 36073317b95SMasami Hiramatsu 36119f00b01SNaohiro Aota if (cast && (strcmp(cast, "u") == 0)) 36292543787SMasami Hiramatsu prefix = 'u'; 36319f00b01SNaohiro Aota else if (cast && (strcmp(cast, "s") == 0)) 36492543787SMasami Hiramatsu prefix = 's'; 36592543787SMasami Hiramatsu else if (cast && (strcmp(cast, "x") == 0) && 36692543787SMasami Hiramatsu probe_type_is_available(PROBE_TYPE_X)) 36792543787SMasami Hiramatsu prefix = 'x'; 36819f00b01SNaohiro Aota else 3699880ce4aSMasami Hiramatsu prefix = die_is_signed_type(&type) ? 's' : 3709880ce4aSMasami Hiramatsu probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u'; 37119f00b01SNaohiro Aota 372bcfc0821SMasami Hiramatsu ret = dwarf_bytesize(&type); 373bcfc0821SMasami Hiramatsu if (ret <= 0) 374124bb83cSMasami Hiramatsu /* No size ... try to use default type */ 375124bb83cSMasami Hiramatsu return 0; 376bcfc0821SMasami Hiramatsu ret = BYTES_TO_BITS(ret); 377124bb83cSMasami Hiramatsu 3784984912eSMasami Hiramatsu /* Check the bitwidth */ 3794984912eSMasami Hiramatsu if (ret > MAX_BASIC_TYPE_BITS) { 380124bb83cSMasami Hiramatsu pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 3814984912eSMasami Hiramatsu dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 3824984912eSMasami Hiramatsu ret = MAX_BASIC_TYPE_BITS; 3834984912eSMasami Hiramatsu } 38492543787SMasami Hiramatsu ret = snprintf(buf, 16, "%c%d", prefix, ret); 385124bb83cSMasami Hiramatsu 386124bb83cSMasami Hiramatsu formatted: 387b55a87adSMasami Hiramatsu if (ret < 0 || ret >= 16) { 388b55a87adSMasami Hiramatsu if (ret >= 16) 389b55a87adSMasami Hiramatsu ret = -E2BIG; 390b55a87adSMasami Hiramatsu pr_warning("Failed to convert variable type: %s\n", 391c8b5f2c9SArnaldo Carvalho de Melo str_error_r(-ret, sbuf, sizeof(sbuf))); 392b55a87adSMasami Hiramatsu return ret; 393b55a87adSMasami Hiramatsu } 39473317b95SMasami Hiramatsu tvar->type = strdup(buf); 39573317b95SMasami Hiramatsu if (tvar->type == NULL) 39602b95dadSMasami Hiramatsu return -ENOMEM; 397b55a87adSMasami Hiramatsu return 0; 3984984912eSMasami Hiramatsu } 3994984912eSMasami Hiramatsu 400b55a87adSMasami Hiramatsu static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 4017df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, 4020e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr, 4031e032f7cSMasami Hiramatsu Dwarf_Die *die_mem, bool user_access) 4047df2f329SMasami Hiramatsu { 4050e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = *ref_ptr; 4067df2f329SMasami Hiramatsu Dwarf_Die type; 4077df2f329SMasami Hiramatsu Dwarf_Word offs; 408b2a3c12bSMasami Hiramatsu int ret, tag; 4097df2f329SMasami Hiramatsu 4107df2f329SMasami Hiramatsu pr_debug("converting %s in %s\n", field->name, varname); 411b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 412b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 413b55a87adSMasami Hiramatsu return -ENOENT; 414b55a87adSMasami Hiramatsu } 415d0461794SMasami Hiramatsu pr_debug2("Var real type: %s (%x)\n", dwarf_diename(&type), 416d0461794SMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 417b2a3c12bSMasami Hiramatsu tag = dwarf_tag(&type); 4187df2f329SMasami Hiramatsu 419b2a3c12bSMasami Hiramatsu if (field->name[0] == '[' && 420b2a3c12bSMasami Hiramatsu (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 421d0461794SMasami Hiramatsu /* Save original type for next field or type */ 422b2a3c12bSMasami Hiramatsu memcpy(die_mem, &type, sizeof(*die_mem)); 423b2a3c12bSMasami Hiramatsu /* Get the type of this array */ 424b2a3c12bSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 425b2a3c12bSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 426b2a3c12bSMasami Hiramatsu return -ENOENT; 427b2a3c12bSMasami Hiramatsu } 428d0461794SMasami Hiramatsu pr_debug2("Array real type: %s (%x)\n", dwarf_diename(&type), 429b2a3c12bSMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 430b2a3c12bSMasami Hiramatsu if (tag == DW_TAG_pointer_type) { 4310e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 432b2a3c12bSMasami Hiramatsu if (ref == NULL) 433b2a3c12bSMasami Hiramatsu return -ENOMEM; 434b2a3c12bSMasami Hiramatsu if (*ref_ptr) 435b2a3c12bSMasami Hiramatsu (*ref_ptr)->next = ref; 436b2a3c12bSMasami Hiramatsu else 437b2a3c12bSMasami Hiramatsu *ref_ptr = ref; 438b2a3c12bSMasami Hiramatsu } 439bcfc0821SMasami Hiramatsu ref->offset += dwarf_bytesize(&type) * field->index; 4401e032f7cSMasami Hiramatsu ref->user_access = user_access; 441b2a3c12bSMasami Hiramatsu goto next; 442b2a3c12bSMasami Hiramatsu } else if (tag == DW_TAG_pointer_type) { 4437df2f329SMasami Hiramatsu /* Check the pointer and dereference */ 444b55a87adSMasami Hiramatsu if (!field->ref) { 445b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '->'\n", 4467df2f329SMasami Hiramatsu field->name); 447b55a87adSMasami Hiramatsu return -EINVAL; 448b55a87adSMasami Hiramatsu } 4497df2f329SMasami Hiramatsu /* Get the type pointed by this pointer */ 450b55a87adSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 451b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 452b55a87adSMasami Hiramatsu return -ENOENT; 453b55a87adSMasami Hiramatsu } 45412e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4557b0295b3SHyeoncheol Lee tag = dwarf_tag(&type); 4567b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 45703440c4eSMasahiro Yamada pr_warning("%s is not a data structure nor a union.\n", 4587b0295b3SHyeoncheol Lee varname); 459b55a87adSMasami Hiramatsu return -EINVAL; 460b55a87adSMasami Hiramatsu } 46112e5a7aeSMasami Hiramatsu 4620e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 463e334016fSMasami Hiramatsu if (ref == NULL) 464e334016fSMasami Hiramatsu return -ENOMEM; 4657df2f329SMasami Hiramatsu if (*ref_ptr) 4667df2f329SMasami Hiramatsu (*ref_ptr)->next = ref; 4677df2f329SMasami Hiramatsu else 4687df2f329SMasami Hiramatsu *ref_ptr = ref; 4697df2f329SMasami Hiramatsu } else { 47012e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4717b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 47203440c4eSMasahiro Yamada pr_warning("%s is not a data structure nor a union.\n", 4737b0295b3SHyeoncheol Lee varname); 474b55a87adSMasami Hiramatsu return -EINVAL; 475b55a87adSMasami Hiramatsu } 476b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') { 477d939be3aSMasanari Iida pr_err("Semantic error: %s is not a pointer" 4780e43e5d2SMasami Hiramatsu " nor array.\n", varname); 479b2a3c12bSMasami Hiramatsu return -EINVAL; 480b2a3c12bSMasami Hiramatsu } 481c7273835SMasami Hiramatsu /* While prcessing unnamed field, we don't care about this */ 482c7273835SMasami Hiramatsu if (field->ref && dwarf_diename(vr_die)) { 483b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '.'\n", 4847df2f329SMasami Hiramatsu field->name); 485b55a87adSMasami Hiramatsu return -EINVAL; 486b55a87adSMasami Hiramatsu } 487b55a87adSMasami Hiramatsu if (!ref) { 488b55a87adSMasami Hiramatsu pr_warning("Structure on a register is not " 489b55a87adSMasami Hiramatsu "supported yet.\n"); 490b55a87adSMasami Hiramatsu return -ENOTSUP; 491b55a87adSMasami Hiramatsu } 4927df2f329SMasami Hiramatsu } 4937df2f329SMasami Hiramatsu 494b55a87adSMasami Hiramatsu if (die_find_member(&type, field->name, die_mem) == NULL) { 4959ef0438aSArnaldo Carvalho de Melo pr_warning("%s(type:%s) has no member %s.\n", varname, 4967df2f329SMasami Hiramatsu dwarf_diename(&type), field->name); 497b55a87adSMasami Hiramatsu return -EINVAL; 498b55a87adSMasami Hiramatsu } 4997df2f329SMasami Hiramatsu 5007df2f329SMasami Hiramatsu /* Get the offset of the field */ 5017b0295b3SHyeoncheol Lee if (tag == DW_TAG_union_type) { 5027b0295b3SHyeoncheol Lee offs = 0; 5037b0295b3SHyeoncheol Lee } else { 504de1439d8SMasami Hiramatsu ret = die_get_data_member_location(die_mem, &offs); 505de1439d8SMasami Hiramatsu if (ret < 0) { 5067b0295b3SHyeoncheol Lee pr_warning("Failed to get the offset of %s.\n", 5077b0295b3SHyeoncheol Lee field->name); 508de1439d8SMasami Hiramatsu return ret; 509b55a87adSMasami Hiramatsu } 5107b0295b3SHyeoncheol Lee } 5117df2f329SMasami Hiramatsu ref->offset += (long)offs; 5121e032f7cSMasami Hiramatsu ref->user_access = user_access; 5137df2f329SMasami Hiramatsu 514c7273835SMasami Hiramatsu /* If this member is unnamed, we need to reuse this field */ 515c7273835SMasami Hiramatsu if (!dwarf_diename(die_mem)) 516c7273835SMasami Hiramatsu return convert_variable_fields(die_mem, varname, field, 5171e032f7cSMasami Hiramatsu &ref, die_mem, user_access); 518c7273835SMasami Hiramatsu 519b2a3c12bSMasami Hiramatsu next: 5207df2f329SMasami Hiramatsu /* Converting next field */ 5217df2f329SMasami Hiramatsu if (field->next) 522b55a87adSMasami Hiramatsu return convert_variable_fields(die_mem, field->name, 5231e032f7cSMasami Hiramatsu field->next, &ref, die_mem, user_access); 524b55a87adSMasami Hiramatsu else 525b55a87adSMasami Hiramatsu return 0; 5267df2f329SMasami Hiramatsu } 5277df2f329SMasami Hiramatsu 5284ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */ 529b55a87adSMasami Hiramatsu static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 5304ea42b18SMasami Hiramatsu { 5314984912eSMasami Hiramatsu Dwarf_Die die_mem; 5324ea42b18SMasami Hiramatsu int ret; 5334ea42b18SMasami Hiramatsu 534b7dcb857SMasami Hiramatsu pr_debug("Converting variable %s into trace event.\n", 535b7dcb857SMasami Hiramatsu dwarf_diename(vr_die)); 536804b3606SMasami Hiramatsu 537cf6eb489SMasami Hiramatsu ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 538293d5b43SMasami Hiramatsu &pf->sp_die, pf->machine, pf->tvar); 5397d5eaba9SHe Kuang if (ret == -ENOENT || ret == -EINVAL) { 5407d5eaba9SHe Kuang pr_err("Failed to find the location of the '%s' variable at this address.\n" 5417d5eaba9SHe Kuang " Perhaps it has been optimized out.\n" 5427d5eaba9SHe Kuang " Use -V with the --range option to show '%s' location range.\n", 5437d5eaba9SHe Kuang pf->pvar->var, pf->pvar->var); 5447d5eaba9SHe Kuang } else if (ret == -ENOTSUP) 545cf6eb489SMasami Hiramatsu pr_err("Sorry, we don't support this variable location yet.\n"); 5460c188a07SMasami Hiramatsu else if (ret == 0 && pf->pvar->field) { 547b55a87adSMasami Hiramatsu ret = convert_variable_fields(vr_die, pf->pvar->var, 5484984912eSMasami Hiramatsu pf->pvar->field, &pf->tvar->ref, 5491e032f7cSMasami Hiramatsu &die_mem, pf->pvar->user_access); 5504984912eSMasami Hiramatsu vr_die = &die_mem; 5514984912eSMasami Hiramatsu } 55273317b95SMasami Hiramatsu if (ret == 0) 5531e032f7cSMasami Hiramatsu ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type, 5541e032f7cSMasami Hiramatsu pf->pvar->user_access); 555804b3606SMasami Hiramatsu /* *expr will be cached in libdw. Don't free it. */ 556b55a87adSMasami Hiramatsu return ret; 5574ea42b18SMasami Hiramatsu } 5584ea42b18SMasami Hiramatsu 559221d0611SMasami Hiramatsu /* Find a variable in a scope DIE */ 560221d0611SMasami Hiramatsu static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 5614ea42b18SMasami Hiramatsu { 562f182e3e1SMasami Hiramatsu Dwarf_Die vr_die; 563909b0360SMasami Hiramatsu char *buf, *ptr; 564f182e3e1SMasami Hiramatsu int ret = 0; 5654ea42b18SMasami Hiramatsu 566367e94c1SMasami Hiramatsu /* Copy raw parameters */ 567da15bd9dSWang Nan if (!is_c_varname(pf->pvar->var)) 568da15bd9dSWang Nan return copy_to_probe_trace_arg(pf->tvar, pf->pvar); 569367e94c1SMasami Hiramatsu 57048481938SMasami Hiramatsu if (pf->pvar->name) 57102b95dadSMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 57248481938SMasami Hiramatsu else { 573909b0360SMasami Hiramatsu buf = synthesize_perf_probe_arg(pf->pvar); 574909b0360SMasami Hiramatsu if (!buf) 575909b0360SMasami Hiramatsu return -ENOMEM; 57611a1ca35SMasami Hiramatsu ptr = strchr(buf, ':'); /* Change type separator to _ */ 57711a1ca35SMasami Hiramatsu if (ptr) 57811a1ca35SMasami Hiramatsu *ptr = '_'; 579909b0360SMasami Hiramatsu pf->tvar->name = buf; 58048481938SMasami Hiramatsu } 58102b95dadSMasami Hiramatsu if (pf->tvar->name == NULL) 58202b95dadSMasami Hiramatsu return -ENOMEM; 58348481938SMasami Hiramatsu 584f182e3e1SMasami Hiramatsu pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 5854ea42b18SMasami Hiramatsu /* Search child die for local variables and parameters. */ 586f182e3e1SMasami Hiramatsu if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 587f182e3e1SMasami Hiramatsu /* Search again in global variables */ 588d13855efSHe Kuang if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 589d13855efSHe Kuang 0, &vr_die)) { 59036d789a4SMasami Hiramatsu pr_warning("Failed to find '%s' in this function.\n", 59136d789a4SMasami Hiramatsu pf->pvar->var); 5928afa2a70SMasami Hiramatsu ret = -ENOENT; 593f182e3e1SMasami Hiramatsu } 594d13855efSHe Kuang } 595f66fedcbSMasami Hiramatsu if (ret >= 0) 596b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 597f182e3e1SMasami Hiramatsu 598b7dcb857SMasami Hiramatsu return ret; 5994ea42b18SMasami Hiramatsu } 6004ea42b18SMasami Hiramatsu 601cf6eb489SMasami Hiramatsu /* Convert subprogram DIE to trace point */ 602576b5237SMasami Hiramatsu static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, 603576b5237SMasami Hiramatsu Dwarf_Addr paddr, bool retprobe, 6046cca13bdSMasami Hiramatsu const char *function, 605576b5237SMasami Hiramatsu struct probe_trace_point *tp) 6064ea42b18SMasami Hiramatsu { 60726b79524SPrashanth Nageshappa Dwarf_Addr eaddr, highaddr; 608576b5237SMasami Hiramatsu GElf_Sym sym; 609576b5237SMasami Hiramatsu const char *symbol; 610cf6eb489SMasami Hiramatsu 611576b5237SMasami Hiramatsu /* Verify the address is correct */ 612cf6eb489SMasami Hiramatsu if (dwarf_entrypc(sp_die, &eaddr) != 0) { 6130e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s\n", 614cf6eb489SMasami Hiramatsu dwarf_diename(sp_die)); 615cf6eb489SMasami Hiramatsu return -ENOENT; 616cf6eb489SMasami Hiramatsu } 61726b79524SPrashanth Nageshappa if (dwarf_highpc(sp_die, &highaddr) != 0) { 61826b79524SPrashanth Nageshappa pr_warning("Failed to get end address of %s\n", 61926b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 62026b79524SPrashanth Nageshappa return -ENOENT; 62126b79524SPrashanth Nageshappa } 62226b79524SPrashanth Nageshappa if (paddr > highaddr) { 62326b79524SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 62426b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 62526b79524SPrashanth Nageshappa return -EINVAL; 62626b79524SPrashanth Nageshappa } 627576b5237SMasami Hiramatsu 628664fee3dSMasami Hiramatsu symbol = dwarf_diename(sp_die); 629664fee3dSMasami Hiramatsu if (!symbol) { 630664fee3dSMasami Hiramatsu /* Try to get the symbol name from symtab */ 631576b5237SMasami Hiramatsu symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); 632576b5237SMasami Hiramatsu if (!symbol) { 633576b5237SMasami Hiramatsu pr_warning("Failed to find symbol at 0x%lx\n", 634576b5237SMasami Hiramatsu (unsigned long)paddr); 635576b5237SMasami Hiramatsu return -ENOENT; 636576b5237SMasami Hiramatsu } 637664fee3dSMasami Hiramatsu eaddr = sym.st_value; 638664fee3dSMasami Hiramatsu } 639664fee3dSMasami Hiramatsu tp->offset = (unsigned long)(paddr - eaddr); 640fb7345bbSMasami Hiramatsu tp->address = (unsigned long)paddr; 641576b5237SMasami Hiramatsu tp->symbol = strdup(symbol); 642576b5237SMasami Hiramatsu if (!tp->symbol) 643cf6eb489SMasami Hiramatsu return -ENOMEM; 644cf6eb489SMasami Hiramatsu 645cf6eb489SMasami Hiramatsu /* Return probe must be on the head of a subprogram */ 646cf6eb489SMasami Hiramatsu if (retprobe) { 647cf6eb489SMasami Hiramatsu if (eaddr != paddr) { 6486cca13bdSMasami Hiramatsu pr_warning("Failed to find \"%s%%return\",\n" 6496cca13bdSMasami Hiramatsu " because %s is an inlined function and" 6506cca13bdSMasami Hiramatsu " has no return point.\n", function, 6516cca13bdSMasami Hiramatsu function); 652cf6eb489SMasami Hiramatsu return -EINVAL; 653cf6eb489SMasami Hiramatsu } 654cf6eb489SMasami Hiramatsu tp->retprobe = true; 655cf6eb489SMasami Hiramatsu } 656cf6eb489SMasami Hiramatsu 657cf6eb489SMasami Hiramatsu return 0; 658cf6eb489SMasami Hiramatsu } 659cf6eb489SMasami Hiramatsu 660221d0611SMasami Hiramatsu /* Call probe_finder callback with scope DIE */ 661221d0611SMasami Hiramatsu static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 662cf6eb489SMasami Hiramatsu { 663804b3606SMasami Hiramatsu Dwarf_Attribute fb_attr; 6644d3b1626SMasami Hiramatsu Dwarf_Frame *frame = NULL; 665804b3606SMasami Hiramatsu size_t nops; 666cf6eb489SMasami Hiramatsu int ret; 6674235b045SMasami Hiramatsu 668221d0611SMasami Hiramatsu if (!sc_die) { 669221d0611SMasami Hiramatsu pr_err("Caller must pass a scope DIE. Program error.\n"); 670221d0611SMasami Hiramatsu return -EINVAL; 671221d0611SMasami Hiramatsu } 672221d0611SMasami Hiramatsu 673221d0611SMasami Hiramatsu /* If not a real subprogram, find a real one */ 6740dbb1cacSMasami Hiramatsu if (!die_is_func_def(sc_die)) { 675221d0611SMasami Hiramatsu if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 676d4c537e6SNaveen N. Rao if (die_find_tailfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 677d4c537e6SNaveen N. Rao pr_warning("Ignoring tail call from %s\n", 678d4c537e6SNaveen N. Rao dwarf_diename(&pf->sp_die)); 679d4c537e6SNaveen N. Rao return 0; 680d4c537e6SNaveen N. Rao } else { 681b55a87adSMasami Hiramatsu pr_warning("Failed to find probe point in any " 682b55a87adSMasami Hiramatsu "functions.\n"); 683b55a87adSMasami Hiramatsu return -ENOENT; 684b55a87adSMasami Hiramatsu } 685d4c537e6SNaveen N. Rao } 686221d0611SMasami Hiramatsu } else 687221d0611SMasami Hiramatsu memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 688e92b85e1SMasami Hiramatsu 689221d0611SMasami Hiramatsu /* Get the frame base attribute/ops from subprogram */ 690221d0611SMasami Hiramatsu dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 691d0cb4260SMasami Hiramatsu ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 692a34a9854SMasami Hiramatsu if (ret <= 0 || nops == 0) { 693804b3606SMasami Hiramatsu pf->fb_ops = NULL; 6947752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 695a34a9854SMasami Hiramatsu } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 696270bde1eSHemant Kumar (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) { 697270bde1eSHemant Kumar if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 && 698270bde1eSHemant Kumar (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) || 699b55a87adSMasami Hiramatsu dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 7000e43e5d2SMasami Hiramatsu pr_warning("Failed to get call frame on 0x%jx\n", 701b55a87adSMasami Hiramatsu (uintmax_t)pf->addr); 70205c8d802SMasami Hiramatsu free(frame); 7034d3b1626SMasami Hiramatsu return -ENOENT; 7044d3b1626SMasami Hiramatsu } 7057752f1b0SMasami Hiramatsu #endif 706a34a9854SMasami Hiramatsu } 707804b3606SMasami Hiramatsu 708cf6eb489SMasami Hiramatsu /* Call finder's callback handler */ 709221d0611SMasami Hiramatsu ret = pf->callback(sc_die, pf); 710804b3606SMasami Hiramatsu 7114d3b1626SMasami Hiramatsu /* Since *pf->fb_ops can be a part of frame. we should free it here. */ 7124d3b1626SMasami Hiramatsu free(frame); 713804b3606SMasami Hiramatsu pf->fb_ops = NULL; 714cf6eb489SMasami Hiramatsu 715cf6eb489SMasami Hiramatsu return ret; 7164ea42b18SMasami Hiramatsu } 7174ea42b18SMasami Hiramatsu 718221d0611SMasami Hiramatsu struct find_scope_param { 719221d0611SMasami Hiramatsu const char *function; 720221d0611SMasami Hiramatsu const char *file; 721221d0611SMasami Hiramatsu int line; 722221d0611SMasami Hiramatsu int diff; 723221d0611SMasami Hiramatsu Dwarf_Die *die_mem; 724221d0611SMasami Hiramatsu bool found; 725221d0611SMasami Hiramatsu }; 726221d0611SMasami Hiramatsu 727221d0611SMasami Hiramatsu static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 728221d0611SMasami Hiramatsu { 729221d0611SMasami Hiramatsu struct find_scope_param *fsp = data; 730221d0611SMasami Hiramatsu const char *file; 731221d0611SMasami Hiramatsu int lno; 732221d0611SMasami Hiramatsu 733221d0611SMasami Hiramatsu /* Skip if declared file name does not match */ 734221d0611SMasami Hiramatsu if (fsp->file) { 735221d0611SMasami Hiramatsu file = dwarf_decl_file(fn_die); 736221d0611SMasami Hiramatsu if (!file || strcmp(fsp->file, file) != 0) 737221d0611SMasami Hiramatsu return 0; 738221d0611SMasami Hiramatsu } 739221d0611SMasami Hiramatsu /* If the function name is given, that's what user expects */ 740221d0611SMasami Hiramatsu if (fsp->function) { 7414c859351SMasami Hiramatsu if (die_match_name(fn_die, fsp->function)) { 742221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 743221d0611SMasami Hiramatsu fsp->found = true; 744221d0611SMasami Hiramatsu return 1; 745221d0611SMasami Hiramatsu } 746221d0611SMasami Hiramatsu } else { 747221d0611SMasami Hiramatsu /* With the line number, find the nearest declared DIE */ 748221d0611SMasami Hiramatsu dwarf_decl_line(fn_die, &lno); 749221d0611SMasami Hiramatsu if (lno < fsp->line && fsp->diff > fsp->line - lno) { 750221d0611SMasami Hiramatsu /* Keep a candidate and continue */ 751221d0611SMasami Hiramatsu fsp->diff = fsp->line - lno; 752221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 753221d0611SMasami Hiramatsu fsp->found = true; 754221d0611SMasami Hiramatsu } 755221d0611SMasami Hiramatsu } 756221d0611SMasami Hiramatsu return 0; 757221d0611SMasami Hiramatsu } 758221d0611SMasami Hiramatsu 759221d0611SMasami Hiramatsu /* Find an appropriate scope fits to given conditions */ 760221d0611SMasami Hiramatsu static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 761221d0611SMasami Hiramatsu { 762221d0611SMasami Hiramatsu struct find_scope_param fsp = { 763221d0611SMasami Hiramatsu .function = pf->pev->point.function, 764221d0611SMasami Hiramatsu .file = pf->fname, 765221d0611SMasami Hiramatsu .line = pf->lno, 766221d0611SMasami Hiramatsu .diff = INT_MAX, 767221d0611SMasami Hiramatsu .die_mem = die_mem, 768221d0611SMasami Hiramatsu .found = false, 769221d0611SMasami Hiramatsu }; 770221d0611SMasami Hiramatsu 771221d0611SMasami Hiramatsu cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 772221d0611SMasami Hiramatsu 773221d0611SMasami Hiramatsu return fsp.found ? die_mem : NULL; 774221d0611SMasami Hiramatsu } 775221d0611SMasami Hiramatsu 7764cc9cec6SMasami Hiramatsu static int probe_point_line_walker(const char *fname, int lineno, 7774cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 7784cc9cec6SMasami Hiramatsu { 7794cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 780221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 7814cc9cec6SMasami Hiramatsu int ret; 7824cc9cec6SMasami Hiramatsu 7834cc9cec6SMasami Hiramatsu if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 7844cc9cec6SMasami Hiramatsu return 0; 7854cc9cec6SMasami Hiramatsu 7864cc9cec6SMasami Hiramatsu pf->addr = addr; 787221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 788221d0611SMasami Hiramatsu if (!sc_die) { 789221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 790221d0611SMasami Hiramatsu return -ENOENT; 791221d0611SMasami Hiramatsu } 792221d0611SMasami Hiramatsu 793221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 7944cc9cec6SMasami Hiramatsu 7954cc9cec6SMasami Hiramatsu /* Continue if no error, because the line will be in inline function */ 796fbee632dSArnaldo Carvalho de Melo return ret < 0 ? ret : 0; 7974cc9cec6SMasami Hiramatsu } 7984cc9cec6SMasami Hiramatsu 7994ea42b18SMasami Hiramatsu /* Find probe point from its line number */ 800b55a87adSMasami Hiramatsu static int find_probe_point_by_line(struct probe_finder *pf) 8014ea42b18SMasami Hiramatsu { 8024cc9cec6SMasami Hiramatsu return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 8034ea42b18SMasami Hiramatsu } 8044ea42b18SMasami Hiramatsu 8052a9c8c36SMasami Hiramatsu /* Find lines which match lazy pattern */ 8065a62257aSMasami Hiramatsu static int find_lazy_match_lines(struct intlist *list, 8072a9c8c36SMasami Hiramatsu const char *fname, const char *pat) 8082a9c8c36SMasami Hiramatsu { 809f50c2169SFranck Bui-Huu FILE *fp; 810f50c2169SFranck Bui-Huu char *line = NULL; 811f50c2169SFranck Bui-Huu size_t line_len; 812f50c2169SFranck Bui-Huu ssize_t len; 813f50c2169SFranck Bui-Huu int count = 0, linenum = 1; 8145f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 8152a9c8c36SMasami Hiramatsu 816f50c2169SFranck Bui-Huu fp = fopen(fname, "r"); 817f50c2169SFranck Bui-Huu if (!fp) { 8185f03cba4SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", fname, 819c8b5f2c9SArnaldo Carvalho de Melo str_error_r(errno, sbuf, sizeof(sbuf))); 820b448c4b6SArnaldo Carvalho de Melo return -errno; 821b55a87adSMasami Hiramatsu } 822b55a87adSMasami Hiramatsu 823f50c2169SFranck Bui-Huu while ((len = getline(&line, &line_len, fp)) > 0) { 824f50c2169SFranck Bui-Huu 825f50c2169SFranck Bui-Huu if (line[len - 1] == '\n') 826f50c2169SFranck Bui-Huu line[len - 1] = '\0'; 827f50c2169SFranck Bui-Huu 828f50c2169SFranck Bui-Huu if (strlazymatch(line, pat)) { 8295a62257aSMasami Hiramatsu intlist__add(list, linenum); 830f50c2169SFranck Bui-Huu count++; 831f50c2169SFranck Bui-Huu } 832f50c2169SFranck Bui-Huu linenum++; 833b55a87adSMasami Hiramatsu } 834b448c4b6SArnaldo Carvalho de Melo 835f50c2169SFranck Bui-Huu if (ferror(fp)) 836f50c2169SFranck Bui-Huu count = -errno; 837f50c2169SFranck Bui-Huu free(line); 838f50c2169SFranck Bui-Huu fclose(fp); 839f50c2169SFranck Bui-Huu 840f50c2169SFranck Bui-Huu if (count == 0) 841f50c2169SFranck Bui-Huu pr_debug("No matched lines found in %s.\n", fname); 842f50c2169SFranck Bui-Huu return count; 8432a9c8c36SMasami Hiramatsu } 8442a9c8c36SMasami Hiramatsu 8454cc9cec6SMasami Hiramatsu static int probe_point_lazy_walker(const char *fname, int lineno, 8464cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 8474cc9cec6SMasami Hiramatsu { 8484cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 849221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 8504cc9cec6SMasami Hiramatsu int ret; 8514cc9cec6SMasami Hiramatsu 8525a62257aSMasami Hiramatsu if (!intlist__has_entry(pf->lcache, lineno) || 8534cc9cec6SMasami Hiramatsu strtailcmp(fname, pf->fname) != 0) 8544cc9cec6SMasami Hiramatsu return 0; 8554cc9cec6SMasami Hiramatsu 8564cc9cec6SMasami Hiramatsu pr_debug("Probe line found: line:%d addr:0x%llx\n", 8574cc9cec6SMasami Hiramatsu lineno, (unsigned long long)addr); 8584cc9cec6SMasami Hiramatsu pf->addr = addr; 859221d0611SMasami Hiramatsu pf->lno = lineno; 860221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 861221d0611SMasami Hiramatsu if (!sc_die) { 862221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 863221d0611SMasami Hiramatsu return -ENOENT; 864221d0611SMasami Hiramatsu } 865221d0611SMasami Hiramatsu 866221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8674cc9cec6SMasami Hiramatsu 8684cc9cec6SMasami Hiramatsu /* 8694cc9cec6SMasami Hiramatsu * Continue if no error, because the lazy pattern will match 8704cc9cec6SMasami Hiramatsu * to other lines 8714cc9cec6SMasami Hiramatsu */ 8725e814dd5SIngo Molnar return ret < 0 ? ret : 0; 8734cc9cec6SMasami Hiramatsu } 8744cc9cec6SMasami Hiramatsu 8752a9c8c36SMasami Hiramatsu /* Find probe points from lazy pattern */ 876b55a87adSMasami Hiramatsu static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 8772a9c8c36SMasami Hiramatsu { 878b55a87adSMasami Hiramatsu int ret = 0; 87909ed8975SNaohiro Aota char *fpath; 8802a9c8c36SMasami Hiramatsu 8815a62257aSMasami Hiramatsu if (intlist__empty(pf->lcache)) { 88209ed8975SNaohiro Aota const char *comp_dir; 88309ed8975SNaohiro Aota 88409ed8975SNaohiro Aota comp_dir = cu_get_comp_dir(&pf->cu_die); 88509ed8975SNaohiro Aota ret = get_real_path(pf->fname, comp_dir, &fpath); 88609ed8975SNaohiro Aota if (ret < 0) { 88709ed8975SNaohiro Aota pr_warning("Failed to find source file path.\n"); 88809ed8975SNaohiro Aota return ret; 88909ed8975SNaohiro Aota } 89009ed8975SNaohiro Aota 8912a9c8c36SMasami Hiramatsu /* Matching lazy line pattern */ 89209ed8975SNaohiro Aota ret = find_lazy_match_lines(pf->lcache, fpath, 8934235b045SMasami Hiramatsu pf->pev->point.lazy_line); 89409ed8975SNaohiro Aota free(fpath); 895f50c2169SFranck Bui-Huu if (ret <= 0) 896b55a87adSMasami Hiramatsu return ret; 8972a9c8c36SMasami Hiramatsu } 8982a9c8c36SMasami Hiramatsu 8994cc9cec6SMasami Hiramatsu return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 9002a9c8c36SMasami Hiramatsu } 9012a9c8c36SMasami Hiramatsu 902e47392bfSRavi Bangoria static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) 903e47392bfSRavi Bangoria { 904e47392bfSRavi Bangoria struct perf_probe_point *pp = &pf->pev->point; 905e47392bfSRavi Bangoria 906e47392bfSRavi Bangoria /* Not uprobe? */ 907e47392bfSRavi Bangoria if (!pf->pev->uprobes) 908e47392bfSRavi Bangoria return; 909e47392bfSRavi Bangoria 910e47392bfSRavi Bangoria /* Compiled with optimization? */ 9116243b9dcSRavi Bangoria if (die_is_optimized_target(&pf->cu_die)) 912e47392bfSRavi Bangoria return; 913e47392bfSRavi Bangoria 914e47392bfSRavi Bangoria /* Don't know entrypc? */ 915e47392bfSRavi Bangoria if (!pf->addr) 916e47392bfSRavi Bangoria return; 917e47392bfSRavi Bangoria 918e47392bfSRavi Bangoria /* Only FUNC and FUNC@SRC are eligible. */ 919e47392bfSRavi Bangoria if (!pp->function || pp->line || pp->retprobe || pp->lazy_line || 920e47392bfSRavi Bangoria pp->offset || pp->abs_address) 921e47392bfSRavi Bangoria return; 922e47392bfSRavi Bangoria 923e47392bfSRavi Bangoria /* Not interested in func parameter? */ 924e47392bfSRavi Bangoria if (!perf_probe_with_var(pf->pev)) 925e47392bfSRavi Bangoria return; 926e47392bfSRavi Bangoria 927e47392bfSRavi Bangoria pr_info("Target program is compiled without optimization. Skipping prologue.\n" 928e47392bfSRavi Bangoria "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n", 929e47392bfSRavi Bangoria pf->addr); 930e47392bfSRavi Bangoria 9316243b9dcSRavi Bangoria die_skip_prologue(sp_die, &pf->cu_die, &pf->addr); 932e47392bfSRavi Bangoria } 933e47392bfSRavi Bangoria 934e92b85e1SMasami Hiramatsu static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 9354ea42b18SMasami Hiramatsu { 936db0d2c64SMasami Hiramatsu struct probe_finder *pf = data; 9374235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 938b55a87adSMasami Hiramatsu Dwarf_Addr addr; 939db0d2c64SMasami Hiramatsu int ret; 9404ea42b18SMasami Hiramatsu 9412a9c8c36SMasami Hiramatsu if (pp->lazy_line) 942db0d2c64SMasami Hiramatsu ret = find_probe_point_lazy(in_die, pf); 9432a9c8c36SMasami Hiramatsu else { 944e92b85e1SMasami Hiramatsu /* Get probe address */ 945b55a87adSMasami Hiramatsu if (dwarf_entrypc(in_die, &addr) != 0) { 9460e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s.\n", 947b55a87adSMasami Hiramatsu dwarf_diename(in_die)); 948db0d2c64SMasami Hiramatsu return -ENOENT; 949b55a87adSMasami Hiramatsu } 9500ad45b33SMasami Hiramatsu if (addr == 0) { 9510ad45b33SMasami Hiramatsu pr_debug("%s has no valid entry address. skipped.\n", 9520ad45b33SMasami Hiramatsu dwarf_diename(in_die)); 9530ad45b33SMasami Hiramatsu return -ENOENT; 9540ad45b33SMasami Hiramatsu } 955b55a87adSMasami Hiramatsu pf->addr = addr; 956e92b85e1SMasami Hiramatsu pf->addr += pp->offset; 9572a9c8c36SMasami Hiramatsu pr_debug("found inline addr: 0x%jx\n", 9582a9c8c36SMasami Hiramatsu (uintmax_t)pf->addr); 959e92b85e1SMasami Hiramatsu 960db0d2c64SMasami Hiramatsu ret = call_probe_finder(in_die, pf); 9612a9c8c36SMasami Hiramatsu } 9622a9c8c36SMasami Hiramatsu 963db0d2c64SMasami Hiramatsu return ret; 964e92b85e1SMasami Hiramatsu } 965e92b85e1SMasami Hiramatsu 966db0d2c64SMasami Hiramatsu /* Callback parameter with return value for libdw */ 967db0d2c64SMasami Hiramatsu struct dwarf_callback_param { 968db0d2c64SMasami Hiramatsu void *data; 969db0d2c64SMasami Hiramatsu int retval; 970db0d2c64SMasami Hiramatsu }; 971db0d2c64SMasami Hiramatsu 972e92b85e1SMasami Hiramatsu /* Search function from function name */ 973e92b85e1SMasami Hiramatsu static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 974e92b85e1SMasami Hiramatsu { 975b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 976b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 9774235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 978e92b85e1SMasami Hiramatsu 979e92b85e1SMasami Hiramatsu /* Check tag and diename */ 9800dbb1cacSMasami Hiramatsu if (!die_is_func_def(sp_die) || 9814c859351SMasami Hiramatsu !die_match_name(sp_die, pp->function)) 982b55a87adSMasami Hiramatsu return DWARF_CB_OK; 983e92b85e1SMasami Hiramatsu 9847d21635aSMasami Hiramatsu /* Check declared file */ 9857d21635aSMasami Hiramatsu if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 9867d21635aSMasami Hiramatsu return DWARF_CB_OK; 9877d21635aSMasami Hiramatsu 988f8da4b51SMasami Hiramatsu pr_debug("Matched function: %s [%lx]\n", dwarf_diename(sp_die), 989f8da4b51SMasami Hiramatsu (unsigned long)dwarf_dieoffset(sp_die)); 990e92b85e1SMasami Hiramatsu pf->fname = dwarf_decl_file(sp_die); 9912a9c8c36SMasami Hiramatsu if (pp->line) { /* Function relative line */ 992e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &pf->lno); 993804b3606SMasami Hiramatsu pf->lno += pp->line; 994b55a87adSMasami Hiramatsu param->retval = find_probe_point_by_line(pf); 995e1ecbbc3SMasami Hiramatsu } else if (die_is_func_instance(sp_die)) { 996e1ecbbc3SMasami Hiramatsu /* Instances always have the entry address */ 997e1ecbbc3SMasami Hiramatsu dwarf_entrypc(sp_die, &pf->addr); 9980ad45b33SMasami Hiramatsu /* But in some case the entry address is 0 */ 9990ad45b33SMasami Hiramatsu if (pf->addr == 0) { 10000ad45b33SMasami Hiramatsu pr_debug("%s has no entry PC. Skipped\n", 10010ad45b33SMasami Hiramatsu dwarf_diename(sp_die)); 10020ad45b33SMasami Hiramatsu param->retval = 0; 1003e92b85e1SMasami Hiramatsu /* Real function */ 10040ad45b33SMasami Hiramatsu } else if (pp->lazy_line) 1005b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(sp_die, pf); 10062a9c8c36SMasami Hiramatsu else { 1007e47392bfSRavi Bangoria skip_prologue(sp_die, pf); 10084ea42b18SMasami Hiramatsu pf->addr += pp->offset; 10094ea42b18SMasami Hiramatsu /* TODO: Check the address in this function */ 1010cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(sp_die, pf); 10112a9c8c36SMasami Hiramatsu } 10124c859351SMasami Hiramatsu } else if (!probe_conf.no_inlines) { 1013e92b85e1SMasami Hiramatsu /* Inlined function: search instances */ 1014db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1015db0d2c64SMasami Hiramatsu probe_point_inline_cb, (void *)pf); 10164c859351SMasami Hiramatsu /* This could be a non-existed inline definition */ 1017f8da4b51SMasami Hiramatsu if (param->retval == -ENOENT) 10184c859351SMasami Hiramatsu param->retval = 0; 10194c859351SMasami Hiramatsu } 10204c859351SMasami Hiramatsu 10214c859351SMasami Hiramatsu /* We need to find other candidates */ 10224c859351SMasami Hiramatsu if (strisglob(pp->function) && param->retval >= 0) { 10234c859351SMasami Hiramatsu param->retval = 0; /* We have to clear the result */ 10244c859351SMasami Hiramatsu return DWARF_CB_OK; 10254c859351SMasami Hiramatsu } 10264ea42b18SMasami Hiramatsu 1027b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1028b55a87adSMasami Hiramatsu } 1029b55a87adSMasami Hiramatsu 1030b55a87adSMasami Hiramatsu static int find_probe_point_by_func(struct probe_finder *pf) 10314ea42b18SMasami Hiramatsu { 1032b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 1033b55a87adSMasami Hiramatsu .retval = 0}; 1034b55a87adSMasami Hiramatsu dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 1035b55a87adSMasami Hiramatsu return _param.retval; 10364ea42b18SMasami Hiramatsu } 10374ea42b18SMasami Hiramatsu 1038cd25f8bcSLin Ming struct pubname_callback_param { 1039cd25f8bcSLin Ming char *function; 1040cd25f8bcSLin Ming char *file; 1041cd25f8bcSLin Ming Dwarf_Die *cu_die; 1042cd25f8bcSLin Ming Dwarf_Die *sp_die; 1043cd25f8bcSLin Ming int found; 1044cd25f8bcSLin Ming }; 1045cd25f8bcSLin Ming 1046cd25f8bcSLin Ming static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 1047cd25f8bcSLin Ming { 1048cd25f8bcSLin Ming struct pubname_callback_param *param = data; 1049cd25f8bcSLin Ming 1050cd25f8bcSLin Ming if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1051cd25f8bcSLin Ming if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1052cd25f8bcSLin Ming return DWARF_CB_OK; 1053cd25f8bcSLin Ming 10544c859351SMasami Hiramatsu if (die_match_name(param->sp_die, param->function)) { 1055cd25f8bcSLin Ming if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1056cd25f8bcSLin Ming return DWARF_CB_OK; 1057cd25f8bcSLin Ming 1058cd25f8bcSLin Ming if (param->file && 1059cd25f8bcSLin Ming strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1060cd25f8bcSLin Ming return DWARF_CB_OK; 1061cd25f8bcSLin Ming 1062cd25f8bcSLin Ming param->found = 1; 1063cd25f8bcSLin Ming return DWARF_CB_ABORT; 1064cd25f8bcSLin Ming } 1065cd25f8bcSLin Ming } 1066cd25f8bcSLin Ming 1067cd25f8bcSLin Ming return DWARF_CB_OK; 1068cd25f8bcSLin Ming } 1069cd25f8bcSLin Ming 1070270bde1eSHemant Kumar static int debuginfo__find_probe_location(struct debuginfo *dbg, 1071ff741783SMasami Hiramatsu struct probe_finder *pf) 10724ea42b18SMasami Hiramatsu { 1073cf6eb489SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1074804b3606SMasami Hiramatsu Dwarf_Off off, noff; 1075804b3606SMasami Hiramatsu size_t cuhl; 1076804b3606SMasami Hiramatsu Dwarf_Die *diep; 1077b55a87adSMasami Hiramatsu int ret = 0; 10784ea42b18SMasami Hiramatsu 1079804b3606SMasami Hiramatsu off = 0; 10805a62257aSMasami Hiramatsu pf->lcache = intlist__new(NULL); 10815a62257aSMasami Hiramatsu if (!pf->lcache) 10825a62257aSMasami Hiramatsu return -ENOMEM; 1083cd25f8bcSLin Ming 1084cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 10854c859351SMasami Hiramatsu if (pp->function && !strisglob(pp->function)) { 1086cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1087cd25f8bcSLin Ming .function = pp->function, 1088cd25f8bcSLin Ming .file = pp->file, 1089cd25f8bcSLin Ming .cu_die = &pf->cu_die, 1090cd25f8bcSLin Ming .sp_die = &pf->sp_die, 10912b348a77SLin Ming .found = 0, 1092cd25f8bcSLin Ming }; 1093cd25f8bcSLin Ming struct dwarf_callback_param probe_param = { 1094cd25f8bcSLin Ming .data = pf, 1095cd25f8bcSLin Ming }; 1096cd25f8bcSLin Ming 1097316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1098ff741783SMasami Hiramatsu &pubname_param, 0); 1099cd25f8bcSLin Ming if (pubname_param.found) { 1100cd25f8bcSLin Ming ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1101cd25f8bcSLin Ming if (ret) 1102cd25f8bcSLin Ming goto found; 1103cd25f8bcSLin Ming } 1104cd25f8bcSLin Ming } 1105cd25f8bcSLin Ming 1106804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1107316c7136SArnaldo Carvalho de Melo while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 11084ea42b18SMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1109316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die); 1110804b3606SMasami Hiramatsu if (!diep) 1111804b3606SMasami Hiramatsu continue; 11124ea42b18SMasami Hiramatsu 11134ea42b18SMasami Hiramatsu /* Check if target file is included. */ 11144ea42b18SMasami Hiramatsu if (pp->file) 1115cf6eb489SMasami Hiramatsu pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1116804b3606SMasami Hiramatsu else 1117cf6eb489SMasami Hiramatsu pf->fname = NULL; 11184ea42b18SMasami Hiramatsu 1119cf6eb489SMasami Hiramatsu if (!pp->file || pf->fname) { 11204ea42b18SMasami Hiramatsu if (pp->function) 1121cf6eb489SMasami Hiramatsu ret = find_probe_point_by_func(pf); 11222a9c8c36SMasami Hiramatsu else if (pp->lazy_line) 1123f19e80c6SHe Kuang ret = find_probe_point_lazy(&pf->cu_die, pf); 1124b0ef0732SMasami Hiramatsu else { 1125cf6eb489SMasami Hiramatsu pf->lno = pp->line; 1126cf6eb489SMasami Hiramatsu ret = find_probe_point_by_line(pf); 11274ea42b18SMasami Hiramatsu } 11288635bf6eSArnaldo Carvalho de Melo if (ret < 0) 1129fbee632dSArnaldo Carvalho de Melo break; 1130b0ef0732SMasami Hiramatsu } 1131804b3606SMasami Hiramatsu off = noff; 11324ea42b18SMasami Hiramatsu } 1133cd25f8bcSLin Ming 1134cd25f8bcSLin Ming found: 11355a62257aSMasami Hiramatsu intlist__delete(pf->lcache); 11365a62257aSMasami Hiramatsu pf->lcache = NULL; 11374ea42b18SMasami Hiramatsu 1138cf6eb489SMasami Hiramatsu return ret; 1139cf6eb489SMasami Hiramatsu } 1140cf6eb489SMasami Hiramatsu 1141270bde1eSHemant Kumar /* Find probe points from debuginfo */ 1142270bde1eSHemant Kumar static int debuginfo__find_probes(struct debuginfo *dbg, 1143270bde1eSHemant Kumar struct probe_finder *pf) 1144270bde1eSHemant Kumar { 1145270bde1eSHemant Kumar int ret = 0; 1146270bde1eSHemant Kumar Elf *elf; 1147270bde1eSHemant Kumar GElf_Ehdr ehdr; 1148270bde1eSHemant Kumar 1149270bde1eSHemant Kumar if (pf->cfi_eh || pf->cfi_dbg) 1150270bde1eSHemant Kumar return debuginfo__find_probe_location(dbg, pf); 1151270bde1eSHemant Kumar 1152270bde1eSHemant Kumar /* Get the call frame information from this dwarf */ 1153270bde1eSHemant Kumar elf = dwarf_getelf(dbg->dbg); 1154270bde1eSHemant Kumar if (elf == NULL) 1155270bde1eSHemant Kumar return -EINVAL; 1156270bde1eSHemant Kumar 1157270bde1eSHemant Kumar if (gelf_getehdr(elf, &ehdr) == NULL) 1158270bde1eSHemant Kumar return -EINVAL; 1159270bde1eSHemant Kumar 1160293d5b43SMasami Hiramatsu pf->machine = ehdr.e_machine; 1161293d5b43SMasami Hiramatsu 1162293d5b43SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 1163293d5b43SMasami Hiramatsu do { 1164293d5b43SMasami Hiramatsu GElf_Shdr shdr; 1165293d5b43SMasami Hiramatsu 1166270bde1eSHemant Kumar if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && 1167270bde1eSHemant Kumar shdr.sh_type == SHT_PROGBITS) 1168270bde1eSHemant Kumar pf->cfi_eh = dwarf_getcfi_elf(elf); 1169270bde1eSHemant Kumar 1170270bde1eSHemant Kumar pf->cfi_dbg = dwarf_getcfi(dbg->dbg); 1171293d5b43SMasami Hiramatsu } while (0); 1172270bde1eSHemant Kumar #endif 1173270bde1eSHemant Kumar 1174270bde1eSHemant Kumar ret = debuginfo__find_probe_location(dbg, pf); 1175270bde1eSHemant Kumar return ret; 1176270bde1eSHemant Kumar } 1177270bde1eSHemant Kumar 11787969ec77SMasami Hiramatsu struct local_vars_finder { 11797969ec77SMasami Hiramatsu struct probe_finder *pf; 11807969ec77SMasami Hiramatsu struct perf_probe_arg *args; 1181f8bffbf1SMasami Hiramatsu bool vars; 11827969ec77SMasami Hiramatsu int max_args; 11837969ec77SMasami Hiramatsu int nargs; 11847969ec77SMasami Hiramatsu int ret; 11857969ec77SMasami Hiramatsu }; 11867969ec77SMasami Hiramatsu 11877969ec77SMasami Hiramatsu /* Collect available variables in this scope */ 11887969ec77SMasami Hiramatsu static int copy_variables_cb(Dwarf_Die *die_mem, void *data) 11897969ec77SMasami Hiramatsu { 11907969ec77SMasami Hiramatsu struct local_vars_finder *vf = data; 11913d918a12SMasami Hiramatsu struct probe_finder *pf = vf->pf; 11927969ec77SMasami Hiramatsu int tag; 11937969ec77SMasami Hiramatsu 11947969ec77SMasami Hiramatsu tag = dwarf_tag(die_mem); 11957969ec77SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1196f8bffbf1SMasami Hiramatsu (tag == DW_TAG_variable && vf->vars)) { 11977969ec77SMasami Hiramatsu if (convert_variable_location(die_mem, vf->pf->addr, 11983d918a12SMasami Hiramatsu vf->pf->fb_ops, &pf->sp_die, 1199293d5b43SMasami Hiramatsu pf->machine, NULL) == 0) { 12007969ec77SMasami Hiramatsu vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); 12017969ec77SMasami Hiramatsu if (vf->args[vf->nargs].var == NULL) { 12027969ec77SMasami Hiramatsu vf->ret = -ENOMEM; 12037969ec77SMasami Hiramatsu return DIE_FIND_CB_END; 12047969ec77SMasami Hiramatsu } 12057969ec77SMasami Hiramatsu pr_debug(" %s", vf->args[vf->nargs].var); 12067969ec77SMasami Hiramatsu vf->nargs++; 12077969ec77SMasami Hiramatsu } 12087969ec77SMasami Hiramatsu } 12097969ec77SMasami Hiramatsu 12107969ec77SMasami Hiramatsu if (dwarf_haspc(die_mem, vf->pf->addr)) 12117969ec77SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 12127969ec77SMasami Hiramatsu else 12137969ec77SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 12147969ec77SMasami Hiramatsu } 12157969ec77SMasami Hiramatsu 12167969ec77SMasami Hiramatsu static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, 12177969ec77SMasami Hiramatsu struct perf_probe_arg *args) 12187969ec77SMasami Hiramatsu { 12197969ec77SMasami Hiramatsu Dwarf_Die die_mem; 12207969ec77SMasami Hiramatsu int i; 12217969ec77SMasami Hiramatsu int n = 0; 1222f8bffbf1SMasami Hiramatsu struct local_vars_finder vf = {.pf = pf, .args = args, .vars = false, 12237969ec77SMasami Hiramatsu .max_args = MAX_PROBE_ARGS, .ret = 0}; 12247969ec77SMasami Hiramatsu 12257969ec77SMasami Hiramatsu for (i = 0; i < pf->pev->nargs; i++) { 12267969ec77SMasami Hiramatsu /* var never be NULL */ 1227f8bffbf1SMasami Hiramatsu if (strcmp(pf->pev->args[i].var, PROBE_ARG_VARS) == 0) 1228f8bffbf1SMasami Hiramatsu vf.vars = true; 1229f8bffbf1SMasami Hiramatsu else if (strcmp(pf->pev->args[i].var, PROBE_ARG_PARAMS) != 0) { 1230f8bffbf1SMasami Hiramatsu /* Copy normal argument */ 1231f8bffbf1SMasami Hiramatsu args[n] = pf->pev->args[i]; 1232f8bffbf1SMasami Hiramatsu n++; 1233f8bffbf1SMasami Hiramatsu continue; 1234f8bffbf1SMasami Hiramatsu } 1235f8bffbf1SMasami Hiramatsu pr_debug("Expanding %s into:", pf->pev->args[i].var); 12367969ec77SMasami Hiramatsu vf.nargs = n; 12377969ec77SMasami Hiramatsu /* Special local variables */ 12387969ec77SMasami Hiramatsu die_find_child(sc_die, copy_variables_cb, (void *)&vf, 12397969ec77SMasami Hiramatsu &die_mem); 12407969ec77SMasami Hiramatsu pr_debug(" (%d)\n", vf.nargs - n); 12417969ec77SMasami Hiramatsu if (vf.ret < 0) 12427969ec77SMasami Hiramatsu return vf.ret; 12437969ec77SMasami Hiramatsu n = vf.nargs; 12447969ec77SMasami Hiramatsu } 12457969ec77SMasami Hiramatsu return n; 12467969ec77SMasami Hiramatsu } 12477969ec77SMasami Hiramatsu 1248cf6eb489SMasami Hiramatsu /* Add a found probe point into trace event list */ 1249221d0611SMasami Hiramatsu static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1250cf6eb489SMasami Hiramatsu { 1251cf6eb489SMasami Hiramatsu struct trace_event_finder *tf = 1252cf6eb489SMasami Hiramatsu container_of(pf, struct trace_event_finder, pf); 12536cca13bdSMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1254cf6eb489SMasami Hiramatsu struct probe_trace_event *tev; 1255092b1f0bSWang Nan struct perf_probe_arg *args = NULL; 1256cf6eb489SMasami Hiramatsu int ret, i; 1257cf6eb489SMasami Hiramatsu 1258cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1259cf6eb489SMasami Hiramatsu if (tf->ntevs == tf->max_tevs) { 1260cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", 1261cf6eb489SMasami Hiramatsu tf->max_tevs); 1262cf6eb489SMasami Hiramatsu return -ERANGE; 1263cf6eb489SMasami Hiramatsu } 1264cf6eb489SMasami Hiramatsu tev = &tf->tevs[tf->ntevs++]; 1265cf6eb489SMasami Hiramatsu 1266221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1267576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 12686cca13bdSMasami Hiramatsu pp->retprobe, pp->function, &tev->point); 1269cf6eb489SMasami Hiramatsu if (ret < 0) 1270092b1f0bSWang Nan goto end; 1271cf6eb489SMasami Hiramatsu 12724c859351SMasami Hiramatsu tev->point.realname = strdup(dwarf_diename(sc_die)); 1273092b1f0bSWang Nan if (!tev->point.realname) { 1274092b1f0bSWang Nan ret = -ENOMEM; 1275092b1f0bSWang Nan goto end; 1276092b1f0bSWang Nan } 12774c859351SMasami Hiramatsu 1278cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1279cf6eb489SMasami Hiramatsu tev->point.offset); 1280cf6eb489SMasami Hiramatsu 12817969ec77SMasami Hiramatsu /* Expand special probe argument if exist */ 12827969ec77SMasami Hiramatsu args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); 1283092b1f0bSWang Nan if (args == NULL) { 1284092b1f0bSWang Nan ret = -ENOMEM; 1285092b1f0bSWang Nan goto end; 1286092b1f0bSWang Nan } 12877969ec77SMasami Hiramatsu 12887969ec77SMasami Hiramatsu ret = expand_probe_args(sc_die, pf, args); 12897969ec77SMasami Hiramatsu if (ret < 0) 12907969ec77SMasami Hiramatsu goto end; 12917969ec77SMasami Hiramatsu 12927969ec77SMasami Hiramatsu tev->nargs = ret; 12937969ec77SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 12947969ec77SMasami Hiramatsu if (tev->args == NULL) { 12957969ec77SMasami Hiramatsu ret = -ENOMEM; 12967969ec77SMasami Hiramatsu goto end; 12977969ec77SMasami Hiramatsu } 12987969ec77SMasami Hiramatsu 12997969ec77SMasami Hiramatsu /* Find each argument */ 13007969ec77SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 13017969ec77SMasami Hiramatsu pf->pvar = &args[i]; 1302cf6eb489SMasami Hiramatsu pf->tvar = &tev->args[i]; 1303221d0611SMasami Hiramatsu /* Variable should be found from scope DIE */ 1304221d0611SMasami Hiramatsu ret = find_variable(sc_die, pf); 1305cf6eb489SMasami Hiramatsu if (ret != 0) 13067969ec77SMasami Hiramatsu break; 1307cf6eb489SMasami Hiramatsu } 1308cf6eb489SMasami Hiramatsu 13097969ec77SMasami Hiramatsu end: 1310092b1f0bSWang Nan if (ret) { 1311092b1f0bSWang Nan clear_probe_trace_event(tev); 1312092b1f0bSWang Nan tf->ntevs--; 1313092b1f0bSWang Nan } 13147969ec77SMasami Hiramatsu free(args); 13157969ec77SMasami Hiramatsu return ret; 1316cf6eb489SMasami Hiramatsu } 1317cf6eb489SMasami Hiramatsu 1318cf6eb489SMasami Hiramatsu /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1319316c7136SArnaldo Carvalho de Melo int debuginfo__find_trace_events(struct debuginfo *dbg, 1320ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1321ddb2f58fSMasami Hiramatsu struct probe_trace_event **tevs) 1322cf6eb489SMasami Hiramatsu { 1323cf6eb489SMasami Hiramatsu struct trace_event_finder tf = { 1324cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_probe_trace_event}, 1325ddb2f58fSMasami Hiramatsu .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; 13260196e787SMasami Hiramatsu int ret, i; 1327cf6eb489SMasami Hiramatsu 1328cf6eb489SMasami Hiramatsu /* Allocate result tevs array */ 1329ddb2f58fSMasami Hiramatsu *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); 1330cf6eb489SMasami Hiramatsu if (*tevs == NULL) 1331cf6eb489SMasami Hiramatsu return -ENOMEM; 1332cf6eb489SMasami Hiramatsu 1333cf6eb489SMasami Hiramatsu tf.tevs = *tevs; 1334cf6eb489SMasami Hiramatsu tf.ntevs = 0; 1335cf6eb489SMasami Hiramatsu 1336316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &tf.pf); 1337cf6eb489SMasami Hiramatsu if (ret < 0) { 13380196e787SMasami Hiramatsu for (i = 0; i < tf.ntevs; i++) 13390196e787SMasami Hiramatsu clear_probe_trace_event(&tf.tevs[i]); 134004662523SArnaldo Carvalho de Melo zfree(tevs); 1341cf6eb489SMasami Hiramatsu return ret; 1342cf6eb489SMasami Hiramatsu } 1343cf6eb489SMasami Hiramatsu 1344cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : tf.ntevs; 1345cf6eb489SMasami Hiramatsu } 1346cf6eb489SMasami Hiramatsu 1347cf6eb489SMasami Hiramatsu /* Collect available variables in this scope */ 1348cf6eb489SMasami Hiramatsu static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1349cf6eb489SMasami Hiramatsu { 1350cf6eb489SMasami Hiramatsu struct available_var_finder *af = data; 1351cf6eb489SMasami Hiramatsu struct variable_list *vl; 1352bf4d5f25SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1353cf6eb489SMasami Hiramatsu int tag, ret; 1354cf6eb489SMasami Hiramatsu 1355cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls - 1]; 1356cf6eb489SMasami Hiramatsu 1357cf6eb489SMasami Hiramatsu tag = dwarf_tag(die_mem); 1358cf6eb489SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1359cf6eb489SMasami Hiramatsu tag == DW_TAG_variable) { 1360cf6eb489SMasami Hiramatsu ret = convert_variable_location(die_mem, af->pf.addr, 13613d918a12SMasami Hiramatsu af->pf.fb_ops, &af->pf.sp_die, 1362293d5b43SMasami Hiramatsu af->pf.machine, NULL); 1363349e8d26SHe Kuang if (ret == 0 || ret == -ERANGE) { 1364349e8d26SHe Kuang int ret2; 1365349e8d26SHe Kuang bool externs = !af->child; 1366fb9596d1SHe Kuang 1367bf4d5f25SMasami Hiramatsu if (strbuf_init(&buf, 64) < 0) 1368bf4d5f25SMasami Hiramatsu goto error; 1369349e8d26SHe Kuang 1370349e8d26SHe Kuang if (probe_conf.show_location_range) { 1371bf4d5f25SMasami Hiramatsu if (!externs) 1372bf4d5f25SMasami Hiramatsu ret2 = strbuf_add(&buf, 1373bf4d5f25SMasami Hiramatsu ret ? "[INV]\t" : "[VAL]\t", 6); 1374349e8d26SHe Kuang else 1375bf4d5f25SMasami Hiramatsu ret2 = strbuf_add(&buf, "[EXT]\t", 6); 1376bf4d5f25SMasami Hiramatsu if (ret2) 1377bf4d5f25SMasami Hiramatsu goto error; 1378349e8d26SHe Kuang } 1379349e8d26SHe Kuang 1380349e8d26SHe Kuang ret2 = die_get_varname(die_mem, &buf); 1381349e8d26SHe Kuang 1382349e8d26SHe Kuang if (!ret2 && probe_conf.show_location_range && 1383349e8d26SHe Kuang !externs) { 1384bf4d5f25SMasami Hiramatsu if (strbuf_addch(&buf, '\t') < 0) 1385bf4d5f25SMasami Hiramatsu goto error; 1386349e8d26SHe Kuang ret2 = die_get_var_range(&af->pf.sp_die, 1387349e8d26SHe Kuang die_mem, &buf); 1388349e8d26SHe Kuang } 1389349e8d26SHe Kuang 1390349e8d26SHe Kuang pr_debug("Add new var: %s\n", buf.buf); 1391349e8d26SHe Kuang if (ret2 == 0) { 1392fb9596d1SHe Kuang strlist__add(vl->vars, 1393fb9596d1SHe Kuang strbuf_detach(&buf, NULL)); 1394bf4d5f25SMasami Hiramatsu } 1395fb9596d1SHe Kuang strbuf_release(&buf); 1396cf6eb489SMasami Hiramatsu } 1397cf6eb489SMasami Hiramatsu } 1398cf6eb489SMasami Hiramatsu 1399fb8c5a56SMasami Hiramatsu if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1400cf6eb489SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 1401cf6eb489SMasami Hiramatsu else 1402cf6eb489SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 1403bf4d5f25SMasami Hiramatsu error: 1404bf4d5f25SMasami Hiramatsu strbuf_release(&buf); 1405bf4d5f25SMasami Hiramatsu pr_debug("Error in strbuf\n"); 1406bf4d5f25SMasami Hiramatsu return DIE_FIND_CB_END; 1407cf6eb489SMasami Hiramatsu } 1408cf6eb489SMasami Hiramatsu 1409cf6eb489SMasami Hiramatsu /* Add a found vars into available variables list */ 1410221d0611SMasami Hiramatsu static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1411cf6eb489SMasami Hiramatsu { 1412cf6eb489SMasami Hiramatsu struct available_var_finder *af = 1413cf6eb489SMasami Hiramatsu container_of(pf, struct available_var_finder, pf); 14146cca13bdSMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1415cf6eb489SMasami Hiramatsu struct variable_list *vl; 1416f182e3e1SMasami Hiramatsu Dwarf_Die die_mem; 1417f182e3e1SMasami Hiramatsu int ret; 1418cf6eb489SMasami Hiramatsu 1419cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1420cf6eb489SMasami Hiramatsu if (af->nvls == af->max_vls) { 1421cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1422cf6eb489SMasami Hiramatsu return -ERANGE; 1423cf6eb489SMasami Hiramatsu } 1424cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls++]; 1425cf6eb489SMasami Hiramatsu 1426221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1427576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, 14286cca13bdSMasami Hiramatsu pp->retprobe, pp->function, &vl->point); 1429cf6eb489SMasami Hiramatsu if (ret < 0) 1430cf6eb489SMasami Hiramatsu return ret; 1431cf6eb489SMasami Hiramatsu 1432cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1433cf6eb489SMasami Hiramatsu vl->point.offset); 1434cf6eb489SMasami Hiramatsu 1435cf6eb489SMasami Hiramatsu /* Find local variables */ 14364a77e218SArnaldo Carvalho de Melo vl->vars = strlist__new(NULL, NULL); 1437cf6eb489SMasami Hiramatsu if (vl->vars == NULL) 1438cf6eb489SMasami Hiramatsu return -ENOMEM; 1439fb8c5a56SMasami Hiramatsu af->child = true; 1440221d0611SMasami Hiramatsu die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1441cf6eb489SMasami Hiramatsu 1442fb8c5a56SMasami Hiramatsu /* Find external variables */ 1443ddb2f58fSMasami Hiramatsu if (!probe_conf.show_ext_vars) 1444fb8c5a56SMasami Hiramatsu goto out; 1445ddb2f58fSMasami Hiramatsu /* Don't need to search child DIE for external vars. */ 1446fb8c5a56SMasami Hiramatsu af->child = false; 1447f182e3e1SMasami Hiramatsu die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1448fb8c5a56SMasami Hiramatsu 1449fb8c5a56SMasami Hiramatsu out: 1450cf6eb489SMasami Hiramatsu if (strlist__empty(vl->vars)) { 1451cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 1452cf6eb489SMasami Hiramatsu vl->vars = NULL; 1453cf6eb489SMasami Hiramatsu } 1454cf6eb489SMasami Hiramatsu 1455cf6eb489SMasami Hiramatsu return ret; 1456cf6eb489SMasami Hiramatsu } 1457cf6eb489SMasami Hiramatsu 145869e96eaaSMasami Hiramatsu /* 145969e96eaaSMasami Hiramatsu * Find available variables at given probe point 146069e96eaaSMasami Hiramatsu * Return the number of found probe points. Return 0 if there is no 146169e96eaaSMasami Hiramatsu * matched probe point. Return <0 if an error occurs. 146269e96eaaSMasami Hiramatsu */ 1463316c7136SArnaldo Carvalho de Melo int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1464ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1465ddb2f58fSMasami Hiramatsu struct variable_list **vls) 1466cf6eb489SMasami Hiramatsu { 1467cf6eb489SMasami Hiramatsu struct available_var_finder af = { 1468cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_available_vars}, 1469316c7136SArnaldo Carvalho de Melo .mod = dbg->mod, 1470ddb2f58fSMasami Hiramatsu .max_vls = probe_conf.max_probes}; 1471cf6eb489SMasami Hiramatsu int ret; 1472cf6eb489SMasami Hiramatsu 1473cf6eb489SMasami Hiramatsu /* Allocate result vls array */ 1474ddb2f58fSMasami Hiramatsu *vls = zalloc(sizeof(struct variable_list) * af.max_vls); 1475cf6eb489SMasami Hiramatsu if (*vls == NULL) 1476cf6eb489SMasami Hiramatsu return -ENOMEM; 1477cf6eb489SMasami Hiramatsu 1478cf6eb489SMasami Hiramatsu af.vls = *vls; 1479cf6eb489SMasami Hiramatsu af.nvls = 0; 1480cf6eb489SMasami Hiramatsu 1481316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &af.pf); 1482cf6eb489SMasami Hiramatsu if (ret < 0) { 1483cf6eb489SMasami Hiramatsu /* Free vlist for error */ 1484cf6eb489SMasami Hiramatsu while (af.nvls--) { 148574cf249dSArnaldo Carvalho de Melo zfree(&af.vls[af.nvls].point.symbol); 1486cf6eb489SMasami Hiramatsu strlist__delete(af.vls[af.nvls].vars); 1487cf6eb489SMasami Hiramatsu } 148804662523SArnaldo Carvalho de Melo zfree(vls); 1489cf6eb489SMasami Hiramatsu return ret; 1490cf6eb489SMasami Hiramatsu } 1491cf6eb489SMasami Hiramatsu 1492cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : af.nvls; 14934ea42b18SMasami Hiramatsu } 14944ea42b18SMasami Hiramatsu 14959b239a12SMasami Hiramatsu /* For the kernel module, we need a special code to get a DIE */ 1496613f050dSMasami Hiramatsu int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, 1497613f050dSMasami Hiramatsu bool adjust_offset) 14989b239a12SMasami Hiramatsu { 14999b239a12SMasami Hiramatsu int n, i; 15009b239a12SMasami Hiramatsu Elf32_Word shndx; 15019b239a12SMasami Hiramatsu Elf_Scn *scn; 15029b239a12SMasami Hiramatsu Elf *elf; 15039b239a12SMasami Hiramatsu GElf_Shdr mem, *shdr; 15049b239a12SMasami Hiramatsu const char *p; 15059b239a12SMasami Hiramatsu 15069b239a12SMasami Hiramatsu elf = dwfl_module_getelf(dbg->mod, &dbg->bias); 15079b239a12SMasami Hiramatsu if (!elf) 15089b239a12SMasami Hiramatsu return -EINVAL; 15099b239a12SMasami Hiramatsu 15109b239a12SMasami Hiramatsu /* Get the number of relocations */ 15119b239a12SMasami Hiramatsu n = dwfl_module_relocations(dbg->mod); 15129b239a12SMasami Hiramatsu if (n < 0) 15139b239a12SMasami Hiramatsu return -ENOENT; 15149b239a12SMasami Hiramatsu /* Search the relocation related .text section */ 15159b239a12SMasami Hiramatsu for (i = 0; i < n; i++) { 15169b239a12SMasami Hiramatsu p = dwfl_module_relocation_info(dbg->mod, i, &shndx); 15179b239a12SMasami Hiramatsu if (strcmp(p, ".text") == 0) { 15189b239a12SMasami Hiramatsu /* OK, get the section header */ 15199b239a12SMasami Hiramatsu scn = elf_getscn(elf, shndx); 15209b239a12SMasami Hiramatsu if (!scn) 15219b239a12SMasami Hiramatsu return -ENOENT; 15229b239a12SMasami Hiramatsu shdr = gelf_getshdr(scn, &mem); 15239b239a12SMasami Hiramatsu if (!shdr) 15249b239a12SMasami Hiramatsu return -ENOENT; 15259b239a12SMasami Hiramatsu *offs = shdr->sh_addr; 1526613f050dSMasami Hiramatsu if (adjust_offset) 1527613f050dSMasami Hiramatsu *offs -= shdr->sh_offset; 15289b239a12SMasami Hiramatsu } 15299b239a12SMasami Hiramatsu } 15309b239a12SMasami Hiramatsu return 0; 15319b239a12SMasami Hiramatsu } 15329b239a12SMasami Hiramatsu 1533fb1587d8SMasami Hiramatsu /* Reverse search */ 1534316c7136SArnaldo Carvalho de Melo int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, 1535ff741783SMasami Hiramatsu struct perf_probe_point *ppt) 1536fb1587d8SMasami Hiramatsu { 1537fb1587d8SMasami Hiramatsu Dwarf_Die cudie, spdie, indie; 1538e08cfd4bSMasami Hiramatsu Dwarf_Addr _addr = 0, baseaddr = 0; 1539e08cfd4bSMasami Hiramatsu const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; 15401d46ea2aSMasami Hiramatsu int baseline = 0, lineno = 0, ret = 0; 1541fb1587d8SMasami Hiramatsu 1542d2d4edbeSMasami Hiramatsu /* We always need to relocate the address for aranges */ 1543613f050dSMasami Hiramatsu if (debuginfo__get_text_offset(dbg, &baseaddr, false) == 0) 1544d2d4edbeSMasami Hiramatsu addr += baseaddr; 1545fb1587d8SMasami Hiramatsu /* Find cu die */ 15460104fe69SMasami Hiramatsu if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { 15470e43e5d2SMasami Hiramatsu pr_warning("Failed to find debug information for address %lx\n", 15480e43e5d2SMasami Hiramatsu addr); 154975ec5a24SMasami Hiramatsu ret = -EINVAL; 155075ec5a24SMasami Hiramatsu goto end; 155175ec5a24SMasami Hiramatsu } 1552fb1587d8SMasami Hiramatsu 15531d46ea2aSMasami Hiramatsu /* Find a corresponding line (filename and lineno) */ 15541d46ea2aSMasami Hiramatsu cu_find_lineinfo(&cudie, addr, &fname, &lineno); 15551d46ea2aSMasami Hiramatsu /* Don't care whether it failed or not */ 1556fb1587d8SMasami Hiramatsu 15571d46ea2aSMasami Hiramatsu /* Find a corresponding function (name, baseline and baseaddr) */ 1558e0d153c6SMasami Hiramatsu if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 15591d46ea2aSMasami Hiramatsu /* Get function entry information */ 1560e08cfd4bSMasami Hiramatsu func = basefunc = dwarf_diename(&spdie); 1561e08cfd4bSMasami Hiramatsu if (!func || 15621d46ea2aSMasami Hiramatsu dwarf_entrypc(&spdie, &baseaddr) != 0 || 1563e08cfd4bSMasami Hiramatsu dwarf_decl_line(&spdie, &baseline) != 0) { 1564e08cfd4bSMasami Hiramatsu lineno = 0; 15651d46ea2aSMasami Hiramatsu goto post; 1566e08cfd4bSMasami Hiramatsu } 1567fb1587d8SMasami Hiramatsu 15681b286bddSMasami Hiramatsu fname = dwarf_decl_file(&spdie); 1569e08cfd4bSMasami Hiramatsu if (addr == (unsigned long)baseaddr) { 15701d46ea2aSMasami Hiramatsu /* Function entry - Relative line number is 0 */ 15711d46ea2aSMasami Hiramatsu lineno = baseline; 1572e08cfd4bSMasami Hiramatsu goto post; 1573e08cfd4bSMasami Hiramatsu } 1574e08cfd4bSMasami Hiramatsu 1575e08cfd4bSMasami Hiramatsu /* Track down the inline functions step by step */ 1576e08cfd4bSMasami Hiramatsu while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, 1577b55a87adSMasami Hiramatsu &indie)) { 1578e08cfd4bSMasami Hiramatsu /* There is an inline function */ 15791d46ea2aSMasami Hiramatsu if (dwarf_entrypc(&indie, &_addr) == 0 && 1580e08cfd4bSMasami Hiramatsu _addr == addr) { 15811d46ea2aSMasami Hiramatsu /* 15821d46ea2aSMasami Hiramatsu * addr is at an inline function entry. 15831d46ea2aSMasami Hiramatsu * In this case, lineno should be the call-site 1584e08cfd4bSMasami Hiramatsu * line number. (overwrite lineinfo) 15851d46ea2aSMasami Hiramatsu */ 15861d46ea2aSMasami Hiramatsu lineno = die_get_call_lineno(&indie); 1587e08cfd4bSMasami Hiramatsu fname = die_get_call_file(&indie); 1588e08cfd4bSMasami Hiramatsu break; 1589e08cfd4bSMasami Hiramatsu } else { 15901d46ea2aSMasami Hiramatsu /* 15911d46ea2aSMasami Hiramatsu * addr is in an inline function body. 15921d46ea2aSMasami Hiramatsu * Since lineno points one of the lines 15931d46ea2aSMasami Hiramatsu * of the inline function, baseline should 15941d46ea2aSMasami Hiramatsu * be the entry line of the inline function. 15951d46ea2aSMasami Hiramatsu */ 1596fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&indie); 1597e08cfd4bSMasami Hiramatsu if (!tmp || 1598e08cfd4bSMasami Hiramatsu dwarf_decl_line(&indie, &baseline) != 0) 1599e08cfd4bSMasami Hiramatsu break; 16001d46ea2aSMasami Hiramatsu func = tmp; 1601e08cfd4bSMasami Hiramatsu spdie = indie; 1602b55a87adSMasami Hiramatsu } 1603b55a87adSMasami Hiramatsu } 1604e08cfd4bSMasami Hiramatsu /* Verify the lineno and baseline are in a same file */ 1605e08cfd4bSMasami Hiramatsu tmp = dwarf_decl_file(&spdie); 1606e08cfd4bSMasami Hiramatsu if (!tmp || strcmp(tmp, fname) != 0) 1607e08cfd4bSMasami Hiramatsu lineno = 0; 16081d46ea2aSMasami Hiramatsu } 16091d46ea2aSMasami Hiramatsu 16101d46ea2aSMasami Hiramatsu post: 16111d46ea2aSMasami Hiramatsu /* Make a relative line number or an offset */ 16121d46ea2aSMasami Hiramatsu if (lineno) 16131d46ea2aSMasami Hiramatsu ppt->line = lineno - baseline; 1614e08cfd4bSMasami Hiramatsu else if (basefunc) { 16151d46ea2aSMasami Hiramatsu ppt->offset = addr - (unsigned long)baseaddr; 1616e08cfd4bSMasami Hiramatsu func = basefunc; 1617e08cfd4bSMasami Hiramatsu } 16181d46ea2aSMasami Hiramatsu 16191d46ea2aSMasami Hiramatsu /* Duplicate strings */ 16201d46ea2aSMasami Hiramatsu if (func) { 16211d46ea2aSMasami Hiramatsu ppt->function = strdup(func); 162202b95dadSMasami Hiramatsu if (ppt->function == NULL) { 162302b95dadSMasami Hiramatsu ret = -ENOMEM; 162402b95dadSMasami Hiramatsu goto end; 162502b95dadSMasami Hiramatsu } 1626fb1587d8SMasami Hiramatsu } 16271d46ea2aSMasami Hiramatsu if (fname) { 16281d46ea2aSMasami Hiramatsu ppt->file = strdup(fname); 16291d46ea2aSMasami Hiramatsu if (ppt->file == NULL) { 163004662523SArnaldo Carvalho de Melo zfree(&ppt->function); 16311d46ea2aSMasami Hiramatsu ret = -ENOMEM; 16321d46ea2aSMasami Hiramatsu goto end; 16331d46ea2aSMasami Hiramatsu } 16341d46ea2aSMasami Hiramatsu } 1635fb1587d8SMasami Hiramatsu end: 16361d46ea2aSMasami Hiramatsu if (ret == 0 && (fname || func)) 16371d46ea2aSMasami Hiramatsu ret = 1; /* Found a point */ 1638fb1587d8SMasami Hiramatsu return ret; 1639fb1587d8SMasami Hiramatsu } 1640fb1587d8SMasami Hiramatsu 1641f6c903f5SMasami Hiramatsu /* Add a line and store the src path */ 1642f6c903f5SMasami Hiramatsu static int line_range_add_line(const char *src, unsigned int lineno, 1643f6c903f5SMasami Hiramatsu struct line_range *lr) 1644f6c903f5SMasami Hiramatsu { 16457cf0b79eSMasami Hiramatsu /* Copy source path */ 1646f6c903f5SMasami Hiramatsu if (!lr->path) { 16477cf0b79eSMasami Hiramatsu lr->path = strdup(src); 16487cf0b79eSMasami Hiramatsu if (lr->path == NULL) 16497cf0b79eSMasami Hiramatsu return -ENOMEM; 1650f6c903f5SMasami Hiramatsu } 16515a62257aSMasami Hiramatsu return intlist__add(lr->line_list, lineno); 1652f6c903f5SMasami Hiramatsu } 1653f6c903f5SMasami Hiramatsu 16544cc9cec6SMasami Hiramatsu static int line_range_walk_cb(const char *fname, int lineno, 16551d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused, 16564cc9cec6SMasami Hiramatsu void *data) 1657f6c903f5SMasami Hiramatsu { 16584cc9cec6SMasami Hiramatsu struct line_finder *lf = data; 1659202c7c12SNamhyung Kim int err; 1660f6c903f5SMasami Hiramatsu 16614cc9cec6SMasami Hiramatsu if ((strtailcmp(fname, lf->fname) != 0) || 1662f6c903f5SMasami Hiramatsu (lf->lno_s > lineno || lf->lno_e < lineno)) 16634cc9cec6SMasami Hiramatsu return 0; 1664f6c903f5SMasami Hiramatsu 1665202c7c12SNamhyung Kim err = line_range_add_line(fname, lineno, lf->lr); 1666202c7c12SNamhyung Kim if (err < 0 && err != -EEXIST) 1667202c7c12SNamhyung Kim return err; 1668f6c903f5SMasami Hiramatsu 16694cc9cec6SMasami Hiramatsu return 0; 1670f6c903f5SMasami Hiramatsu } 1671fb1587d8SMasami Hiramatsu 1672631c9defSMasami Hiramatsu /* Find line range from its line number */ 1673b55a87adSMasami Hiramatsu static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1674631c9defSMasami Hiramatsu { 16754cc9cec6SMasami Hiramatsu int ret; 1676631c9defSMasami Hiramatsu 16774cc9cec6SMasami Hiramatsu ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1678f6c903f5SMasami Hiramatsu 1679804b3606SMasami Hiramatsu /* Update status */ 1680f6c903f5SMasami Hiramatsu if (ret >= 0) 16815a62257aSMasami Hiramatsu if (!intlist__empty(lf->lr->line_list)) 1682f6c903f5SMasami Hiramatsu ret = lf->found = 1; 1683f6c903f5SMasami Hiramatsu else 1684f6c903f5SMasami Hiramatsu ret = 0; /* Lines are not found */ 1685804b3606SMasami Hiramatsu else { 168604662523SArnaldo Carvalho de Melo zfree(&lf->lr->path); 1687804b3606SMasami Hiramatsu } 1688f6c903f5SMasami Hiramatsu return ret; 1689631c9defSMasami Hiramatsu } 1690631c9defSMasami Hiramatsu 1691161a26b0SMasami Hiramatsu static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1692161a26b0SMasami Hiramatsu { 1693182c228eSMasami Hiramatsu int ret = find_line_range_by_line(in_die, data); 169436c0c588SMasami Hiramatsu 169536c0c588SMasami Hiramatsu /* 169636c0c588SMasami Hiramatsu * We have to check all instances of inlined function, because 169736c0c588SMasami Hiramatsu * some execution paths can be optimized out depends on the 1698182c228eSMasami Hiramatsu * function argument of instances. However, if an error occurs, 1699182c228eSMasami Hiramatsu * it should be handled by the caller. 170036c0c588SMasami Hiramatsu */ 1701182c228eSMasami Hiramatsu return ret < 0 ? ret : 0; 1702161a26b0SMasami Hiramatsu } 1703161a26b0SMasami Hiramatsu 17040dbb1cacSMasami Hiramatsu /* Search function definition from function name */ 1705e92b85e1SMasami Hiramatsu static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1706631c9defSMasami Hiramatsu { 1707b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1708b55a87adSMasami Hiramatsu struct line_finder *lf = param->data; 1709631c9defSMasami Hiramatsu struct line_range *lr = lf->lr; 1710631c9defSMasami Hiramatsu 17117d21635aSMasami Hiramatsu /* Check declared file */ 17127d21635aSMasami Hiramatsu if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 17137d21635aSMasami Hiramatsu return DWARF_CB_OK; 17147d21635aSMasami Hiramatsu 17150dbb1cacSMasami Hiramatsu if (die_is_func_def(sp_die) && 17164c859351SMasami Hiramatsu die_match_name(sp_die, lr->function)) { 1717e92b85e1SMasami Hiramatsu lf->fname = dwarf_decl_file(sp_die); 1718e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &lr->offset); 1719804b3606SMasami Hiramatsu pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1720631c9defSMasami Hiramatsu lf->lno_s = lr->offset + lr->start; 1721d3b63d7aSMasami Hiramatsu if (lf->lno_s < 0) /* Overflow */ 1722d3b63d7aSMasami Hiramatsu lf->lno_s = INT_MAX; 1723631c9defSMasami Hiramatsu lf->lno_e = lr->offset + lr->end; 1724d3b63d7aSMasami Hiramatsu if (lf->lno_e < 0) /* Overflow */ 1725d3b63d7aSMasami Hiramatsu lf->lno_e = INT_MAX; 1726d3b63d7aSMasami Hiramatsu pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1727631c9defSMasami Hiramatsu lr->start = lf->lno_s; 1728631c9defSMasami Hiramatsu lr->end = lf->lno_e; 1729e1ecbbc3SMasami Hiramatsu if (!die_is_func_instance(sp_die)) 1730db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1731db0d2c64SMasami Hiramatsu line_range_inline_cb, lf); 1732db0d2c64SMasami Hiramatsu else 1733b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(sp_die, lf); 1734b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1735631c9defSMasami Hiramatsu } 1736b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1737631c9defSMasami Hiramatsu } 1738631c9defSMasami Hiramatsu 1739b55a87adSMasami Hiramatsu static int find_line_range_by_func(struct line_finder *lf) 1740631c9defSMasami Hiramatsu { 1741b55a87adSMasami Hiramatsu struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1742b55a87adSMasami Hiramatsu dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1743b55a87adSMasami Hiramatsu return param.retval; 1744631c9defSMasami Hiramatsu } 1745631c9defSMasami Hiramatsu 1746316c7136SArnaldo Carvalho de Melo int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr) 1747631c9defSMasami Hiramatsu { 1748804b3606SMasami Hiramatsu struct line_finder lf = {.lr = lr, .found = 0}; 1749b55a87adSMasami Hiramatsu int ret = 0; 1750804b3606SMasami Hiramatsu Dwarf_Off off = 0, noff; 1751804b3606SMasami Hiramatsu size_t cuhl; 1752804b3606SMasami Hiramatsu Dwarf_Die *diep; 17536a330a3cSMasami Hiramatsu const char *comp_dir; 1754631c9defSMasami Hiramatsu 1755cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1756cd25f8bcSLin Ming if (lr->function) { 1757cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1758cd25f8bcSLin Ming .function = lr->function, .file = lr->file, 1759cd25f8bcSLin Ming .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1760cd25f8bcSLin Ming struct dwarf_callback_param line_range_param = { 1761cd25f8bcSLin Ming .data = (void *)&lf, .retval = 0}; 1762cd25f8bcSLin Ming 1763316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1764ff741783SMasami Hiramatsu &pubname_param, 0); 1765cd25f8bcSLin Ming if (pubname_param.found) { 1766cd25f8bcSLin Ming line_range_search_cb(&lf.sp_die, &line_range_param); 1767cd25f8bcSLin Ming if (lf.found) 1768cd25f8bcSLin Ming goto found; 1769cd25f8bcSLin Ming } 1770cd25f8bcSLin Ming } 1771cd25f8bcSLin Ming 1772804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1773b55a87adSMasami Hiramatsu while (!lf.found && ret >= 0) { 1774316c7136SArnaldo Carvalho de Melo if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, 1775ff741783SMasami Hiramatsu NULL, NULL, NULL) != 0) 1776631c9defSMasami Hiramatsu break; 1777631c9defSMasami Hiramatsu 1778631c9defSMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1779316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die); 1780804b3606SMasami Hiramatsu if (!diep) 1781804b3606SMasami Hiramatsu continue; 1782631c9defSMasami Hiramatsu 1783631c9defSMasami Hiramatsu /* Check if target file is included. */ 1784631c9defSMasami Hiramatsu if (lr->file) 17852a9c8c36SMasami Hiramatsu lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1786804b3606SMasami Hiramatsu else 17872a9c8c36SMasami Hiramatsu lf.fname = 0; 1788631c9defSMasami Hiramatsu 17892a9c8c36SMasami Hiramatsu if (!lr->file || lf.fname) { 1790631c9defSMasami Hiramatsu if (lr->function) 1791b55a87adSMasami Hiramatsu ret = find_line_range_by_func(&lf); 1792631c9defSMasami Hiramatsu else { 1793631c9defSMasami Hiramatsu lf.lno_s = lr->start; 1794631c9defSMasami Hiramatsu lf.lno_e = lr->end; 1795b55a87adSMasami Hiramatsu ret = find_line_range_by_line(NULL, &lf); 1796631c9defSMasami Hiramatsu } 1797631c9defSMasami Hiramatsu } 1798804b3606SMasami Hiramatsu off = noff; 1799631c9defSMasami Hiramatsu } 18006a330a3cSMasami Hiramatsu 1801cd25f8bcSLin Ming found: 18026a330a3cSMasami Hiramatsu /* Store comp_dir */ 18036a330a3cSMasami Hiramatsu if (lf.found) { 18046a330a3cSMasami Hiramatsu comp_dir = cu_get_comp_dir(&lf.cu_die); 18056a330a3cSMasami Hiramatsu if (comp_dir) { 18066a330a3cSMasami Hiramatsu lr->comp_dir = strdup(comp_dir); 18076a330a3cSMasami Hiramatsu if (!lr->comp_dir) 18086a330a3cSMasami Hiramatsu ret = -ENOMEM; 18096a330a3cSMasami Hiramatsu } 18106a330a3cSMasami Hiramatsu } 18116a330a3cSMasami Hiramatsu 18127cf0b79eSMasami Hiramatsu pr_debug("path: %s\n", lr->path); 1813b55a87adSMasami Hiramatsu return (ret < 0) ? ret : lf.found; 1814631c9defSMasami Hiramatsu } 1815631c9defSMasami Hiramatsu 181609ed8975SNaohiro Aota /* 181709ed8975SNaohiro Aota * Find a src file from a DWARF tag path. Prepend optional source path prefix 181809ed8975SNaohiro Aota * and chop off leading directories that do not exist. Result is passed back as 181909ed8975SNaohiro Aota * a newly allocated path on success. 182009ed8975SNaohiro Aota * Return 0 if file was found and readable, -errno otherwise. 182109ed8975SNaohiro Aota */ 182209ed8975SNaohiro Aota int get_real_path(const char *raw_path, const char *comp_dir, 182309ed8975SNaohiro Aota char **new_path) 182409ed8975SNaohiro Aota { 182509ed8975SNaohiro Aota const char *prefix = symbol_conf.source_prefix; 182609ed8975SNaohiro Aota 182709ed8975SNaohiro Aota if (!prefix) { 182809ed8975SNaohiro Aota if (raw_path[0] != '/' && comp_dir) 182909ed8975SNaohiro Aota /* If not an absolute path, try to use comp_dir */ 183009ed8975SNaohiro Aota prefix = comp_dir; 183109ed8975SNaohiro Aota else { 183209ed8975SNaohiro Aota if (access(raw_path, R_OK) == 0) { 183309ed8975SNaohiro Aota *new_path = strdup(raw_path); 183409ed8975SNaohiro Aota return *new_path ? 0 : -ENOMEM; 183509ed8975SNaohiro Aota } else 183609ed8975SNaohiro Aota return -errno; 183709ed8975SNaohiro Aota } 183809ed8975SNaohiro Aota } 183909ed8975SNaohiro Aota 184009ed8975SNaohiro Aota *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 184109ed8975SNaohiro Aota if (!*new_path) 184209ed8975SNaohiro Aota return -ENOMEM; 184309ed8975SNaohiro Aota 184409ed8975SNaohiro Aota for (;;) { 184509ed8975SNaohiro Aota sprintf(*new_path, "%s/%s", prefix, raw_path); 184609ed8975SNaohiro Aota 184709ed8975SNaohiro Aota if (access(*new_path, R_OK) == 0) 184809ed8975SNaohiro Aota return 0; 184909ed8975SNaohiro Aota 185009ed8975SNaohiro Aota if (!symbol_conf.source_prefix) { 185109ed8975SNaohiro Aota /* In case of searching comp_dir, don't retry */ 185209ed8975SNaohiro Aota zfree(new_path); 185309ed8975SNaohiro Aota return -errno; 185409ed8975SNaohiro Aota } 185509ed8975SNaohiro Aota 185609ed8975SNaohiro Aota switch (errno) { 185709ed8975SNaohiro Aota case ENAMETOOLONG: 185809ed8975SNaohiro Aota case ENOENT: 185909ed8975SNaohiro Aota case EROFS: 186009ed8975SNaohiro Aota case EFAULT: 186109ed8975SNaohiro Aota raw_path = strchr(++raw_path, '/'); 186209ed8975SNaohiro Aota if (!raw_path) { 186309ed8975SNaohiro Aota zfree(new_path); 186409ed8975SNaohiro Aota return -ENOENT; 186509ed8975SNaohiro Aota } 186609ed8975SNaohiro Aota continue; 186709ed8975SNaohiro Aota 186809ed8975SNaohiro Aota default: 186909ed8975SNaohiro Aota zfree(new_path); 187009ed8975SNaohiro Aota return -errno; 187109ed8975SNaohiro Aota } 187209ed8975SNaohiro Aota } 187309ed8975SNaohiro Aota } 1874