14ea42b18SMasami Hiramatsu /* 24ea42b18SMasami Hiramatsu * probe-finder.c : C expression to kprobe event converter 34ea42b18SMasami Hiramatsu * 44ea42b18SMasami Hiramatsu * Written by Masami Hiramatsu <mhiramat@redhat.com> 54ea42b18SMasami Hiramatsu * 64ea42b18SMasami Hiramatsu * This program is free software; you can redistribute it and/or modify 74ea42b18SMasami Hiramatsu * it under the terms of the GNU General Public License as published by 84ea42b18SMasami Hiramatsu * the Free Software Foundation; either version 2 of the License, or 94ea42b18SMasami Hiramatsu * (at your option) any later version. 104ea42b18SMasami Hiramatsu * 114ea42b18SMasami Hiramatsu * This program is distributed in the hope that it will be useful, 124ea42b18SMasami Hiramatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 134ea42b18SMasami Hiramatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 144ea42b18SMasami Hiramatsu * GNU General Public License for more details. 154ea42b18SMasami Hiramatsu * 164ea42b18SMasami Hiramatsu * You should have received a copy of the GNU General Public License 174ea42b18SMasami Hiramatsu * along with this program; if not, write to the Free Software 184ea42b18SMasami Hiramatsu * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 194ea42b18SMasami Hiramatsu * 204ea42b18SMasami Hiramatsu */ 214ea42b18SMasami Hiramatsu 22fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 234ea42b18SMasami Hiramatsu #include <sys/utsname.h> 244ea42b18SMasami Hiramatsu #include <sys/types.h> 254ea42b18SMasami Hiramatsu #include <sys/stat.h> 264ea42b18SMasami Hiramatsu #include <fcntl.h> 274ea42b18SMasami Hiramatsu #include <errno.h> 284ea42b18SMasami Hiramatsu #include <stdio.h> 294ea42b18SMasami Hiramatsu #include <unistd.h> 304ea42b18SMasami Hiramatsu #include <stdlib.h> 314ea42b18SMasami Hiramatsu #include <string.h> 324ea42b18SMasami Hiramatsu #include <stdarg.h> 33cd932c59SIan Munsie #include <dwarf-regs.h> 34074fc0e4SMasami Hiramatsu 35124bb83cSMasami Hiramatsu #include <linux/bitops.h> 3689c69c0eSMasami Hiramatsu #include "event.h" 37a15ad2f5SMasami Hiramatsu #include "dso.h" 3889c69c0eSMasami Hiramatsu #include "debug.h" 395a62257aSMasami Hiramatsu #include "intlist.h" 40074fc0e4SMasami Hiramatsu #include "util.h" 418ec20b17SArnaldo Carvalho de Melo #include "strlist.h" 429ed7e1b8SChase Douglas #include "symbol.h" 434ea42b18SMasami Hiramatsu #include "probe-finder.h" 44180b2061SMasami Hiramatsu #include "probe-file.h" 45a067558eSArnaldo Carvalho de Melo #include "string2.h" 464ea42b18SMasami Hiramatsu 474984912eSMasami Hiramatsu /* Kprobe tracer basic type is up to u64 */ 484984912eSMasami Hiramatsu #define MAX_BASIC_TYPE_BITS 64 494984912eSMasami Hiramatsu 50469b9b88SMasami Hiramatsu /* Dwarf FL wrappers */ 51469b9b88SMasami Hiramatsu static char *debuginfo_path; /* Currently dummy */ 52469b9b88SMasami Hiramatsu 53469b9b88SMasami Hiramatsu static const Dwfl_Callbacks offline_callbacks = { 54469b9b88SMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 55469b9b88SMasami Hiramatsu .debuginfo_path = &debuginfo_path, 56469b9b88SMasami Hiramatsu 57469b9b88SMasami Hiramatsu .section_address = dwfl_offline_section_address, 58469b9b88SMasami Hiramatsu 59469b9b88SMasami Hiramatsu /* We use this table for core files too. */ 60469b9b88SMasami Hiramatsu .find_elf = dwfl_build_id_find_elf, 61469b9b88SMasami Hiramatsu }; 62469b9b88SMasami Hiramatsu 63469b9b88SMasami Hiramatsu /* Get a Dwarf from offline image */ 64316c7136SArnaldo Carvalho de Melo static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, 65ff741783SMasami Hiramatsu const char *path) 66469b9b88SMasami Hiramatsu { 67ff741783SMasami Hiramatsu int fd; 68469b9b88SMasami Hiramatsu 69ff741783SMasami Hiramatsu fd = open(path, O_RDONLY); 70ff741783SMasami Hiramatsu if (fd < 0) 71ff741783SMasami Hiramatsu return fd; 72469b9b88SMasami Hiramatsu 73316c7136SArnaldo Carvalho de Melo dbg->dwfl = dwfl_begin(&offline_callbacks); 74316c7136SArnaldo Carvalho de Melo if (!dbg->dwfl) 75ff741783SMasami Hiramatsu goto error; 76469b9b88SMasami Hiramatsu 779135949dSMasami Hiramatsu dwfl_report_begin(dbg->dwfl); 78316c7136SArnaldo Carvalho de Melo dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); 79316c7136SArnaldo Carvalho de Melo if (!dbg->mod) 80469b9b88SMasami Hiramatsu goto error; 81469b9b88SMasami Hiramatsu 82316c7136SArnaldo Carvalho de Melo dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); 83316c7136SArnaldo Carvalho de Melo if (!dbg->dbg) 84ff741783SMasami Hiramatsu goto error; 85ff741783SMasami Hiramatsu 869135949dSMasami Hiramatsu dwfl_report_end(dbg->dwfl, NULL, NULL); 879135949dSMasami Hiramatsu 88ff741783SMasami Hiramatsu return 0; 89469b9b88SMasami Hiramatsu error: 90316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 91316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 92ff741783SMasami Hiramatsu else 93ff741783SMasami Hiramatsu close(fd); 94316c7136SArnaldo Carvalho de Melo memset(dbg, 0, sizeof(*dbg)); 95ff741783SMasami Hiramatsu 96ff741783SMasami Hiramatsu return -ENOENT; 97469b9b88SMasami Hiramatsu } 98469b9b88SMasami Hiramatsu 99a15ad2f5SMasami Hiramatsu static struct debuginfo *__debuginfo__new(const char *path) 100ff741783SMasami Hiramatsu { 101316c7136SArnaldo Carvalho de Melo struct debuginfo *dbg = zalloc(sizeof(*dbg)); 102316c7136SArnaldo Carvalho de Melo if (!dbg) 103ff741783SMasami Hiramatsu return NULL; 104ff741783SMasami Hiramatsu 10504662523SArnaldo Carvalho de Melo if (debuginfo__init_offline_dwarf(dbg, path) < 0) 10604662523SArnaldo Carvalho de Melo zfree(&dbg); 107a15ad2f5SMasami Hiramatsu if (dbg) 108a15ad2f5SMasami Hiramatsu pr_debug("Open Debuginfo file: %s\n", path); 109316c7136SArnaldo Carvalho de Melo return dbg; 110ff741783SMasami Hiramatsu } 111ff741783SMasami Hiramatsu 112a15ad2f5SMasami Hiramatsu enum dso_binary_type distro_dwarf_types[] = { 113a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 114a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 115a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 116a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 117a15ad2f5SMasami Hiramatsu DSO_BINARY_TYPE__NOT_FOUND, 118a15ad2f5SMasami Hiramatsu }; 119a15ad2f5SMasami Hiramatsu 120a15ad2f5SMasami Hiramatsu struct debuginfo *debuginfo__new(const char *path) 121a15ad2f5SMasami Hiramatsu { 122a15ad2f5SMasami Hiramatsu enum dso_binary_type *type; 123a15ad2f5SMasami Hiramatsu char buf[PATH_MAX], nil = '\0'; 124a15ad2f5SMasami Hiramatsu struct dso *dso; 125a15ad2f5SMasami Hiramatsu struct debuginfo *dinfo = NULL; 126a15ad2f5SMasami Hiramatsu 127a15ad2f5SMasami Hiramatsu /* Try to open distro debuginfo files */ 128a15ad2f5SMasami Hiramatsu dso = dso__new(path); 129a15ad2f5SMasami Hiramatsu if (!dso) 130a15ad2f5SMasami Hiramatsu goto out; 131a15ad2f5SMasami Hiramatsu 132a15ad2f5SMasami Hiramatsu for (type = distro_dwarf_types; 133a15ad2f5SMasami Hiramatsu !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; 134a15ad2f5SMasami Hiramatsu type++) { 135a15ad2f5SMasami Hiramatsu if (dso__read_binary_type_filename(dso, *type, &nil, 136a15ad2f5SMasami Hiramatsu buf, PATH_MAX) < 0) 137a15ad2f5SMasami Hiramatsu continue; 138a15ad2f5SMasami Hiramatsu dinfo = __debuginfo__new(buf); 139a15ad2f5SMasami Hiramatsu } 140d3a7c489SArnaldo Carvalho de Melo dso__put(dso); 141a15ad2f5SMasami Hiramatsu 142a15ad2f5SMasami Hiramatsu out: 143a15ad2f5SMasami Hiramatsu /* if failed to open all distro debuginfo, open given binary */ 144a15ad2f5SMasami Hiramatsu return dinfo ? : __debuginfo__new(path); 145a15ad2f5SMasami Hiramatsu } 146a15ad2f5SMasami Hiramatsu 147316c7136SArnaldo Carvalho de Melo void debuginfo__delete(struct debuginfo *dbg) 148ff741783SMasami Hiramatsu { 149316c7136SArnaldo Carvalho de Melo if (dbg) { 150316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 151316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 152316c7136SArnaldo Carvalho de Melo free(dbg); 153ff741783SMasami Hiramatsu } 154ff741783SMasami Hiramatsu } 155ff741783SMasami Hiramatsu 1564ea42b18SMasami Hiramatsu /* 1574ea42b18SMasami Hiramatsu * Probe finder related functions 1584ea42b18SMasami Hiramatsu */ 1594ea42b18SMasami Hiramatsu 1600e60836bSSrikar Dronamraju static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 1614ea42b18SMasami Hiramatsu { 1620e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref; 1630e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 164b7dcb857SMasami Hiramatsu if (ref != NULL) 165b7dcb857SMasami Hiramatsu ref->offset = offs; 166b7dcb857SMasami Hiramatsu return ref; 167b7dcb857SMasami Hiramatsu } 168b7dcb857SMasami Hiramatsu 169cf6eb489SMasami Hiramatsu /* 170cf6eb489SMasami Hiramatsu * Convert a location into trace_arg. 171cf6eb489SMasami Hiramatsu * If tvar == NULL, this just checks variable can be converted. 1723d918a12SMasami Hiramatsu * If fentry == true and vr_die is a parameter, do huristic search 1733d918a12SMasami Hiramatsu * for the location fuzzed by function entry mcount. 174cf6eb489SMasami Hiramatsu */ 175cf6eb489SMasami Hiramatsu static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 1763d918a12SMasami Hiramatsu Dwarf_Op *fb_ops, Dwarf_Die *sp_die, 177293d5b43SMasami Hiramatsu unsigned int machine, 178cf6eb489SMasami Hiramatsu struct probe_trace_arg *tvar) 179b7dcb857SMasami Hiramatsu { 180b7dcb857SMasami Hiramatsu Dwarf_Attribute attr; 1813d918a12SMasami Hiramatsu Dwarf_Addr tmp = 0; 182b7dcb857SMasami Hiramatsu Dwarf_Op *op; 183b7dcb857SMasami Hiramatsu size_t nops; 184804b3606SMasami Hiramatsu unsigned int regn; 185804b3606SMasami Hiramatsu Dwarf_Word offs = 0; 1864235b045SMasami Hiramatsu bool ref = false; 1874ea42b18SMasami Hiramatsu const char *regs; 188349e8d26SHe Kuang int ret, ret2 = 0; 189b7dcb857SMasami Hiramatsu 190632941c4SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 191632941c4SMasami Hiramatsu goto static_var; 192632941c4SMasami Hiramatsu 193b7dcb857SMasami Hiramatsu /* TODO: handle more than 1 exprs */ 1943d918a12SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 1953d918a12SMasami Hiramatsu return -EINVAL; /* Broken DIE ? */ 1963d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { 1973d918a12SMasami Hiramatsu ret = dwarf_entrypc(sp_die, &tmp); 198349e8d26SHe Kuang if (ret) 199349e8d26SHe Kuang return -ENOENT; 200349e8d26SHe Kuang 201349e8d26SHe Kuang if (probe_conf.show_location_range && 202349e8d26SHe Kuang (dwarf_tag(vr_die) == DW_TAG_variable)) { 203349e8d26SHe Kuang ret2 = -ERANGE; 204349e8d26SHe Kuang } else if (addr != tmp || 205349e8d26SHe Kuang dwarf_tag(vr_die) != DW_TAG_formal_parameter) { 206349e8d26SHe Kuang return -ENOENT; 207349e8d26SHe Kuang } 208349e8d26SHe Kuang 209349e8d26SHe Kuang ret = dwarf_highpc(sp_die, &tmp); 210349e8d26SHe Kuang if (ret) 2113d918a12SMasami Hiramatsu return -ENOENT; 2123d918a12SMasami Hiramatsu /* 2133d918a12SMasami Hiramatsu * This is fuzzed by fentry mcount. We try to find the 2143d918a12SMasami Hiramatsu * parameter location at the earliest address. 2153d918a12SMasami Hiramatsu */ 2163d918a12SMasami Hiramatsu for (addr += 1; addr <= tmp; addr++) { 2173d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, 2183d918a12SMasami Hiramatsu &nops, 1) > 0) 2193d918a12SMasami Hiramatsu goto found; 2203d918a12SMasami Hiramatsu } 221b7dcb857SMasami Hiramatsu return -ENOENT; 222b7dcb857SMasami Hiramatsu } 2233d918a12SMasami Hiramatsu found: 2243d918a12SMasami Hiramatsu if (nops == 0) 2253d918a12SMasami Hiramatsu /* TODO: Support const_value */ 2263d918a12SMasami Hiramatsu return -ENOENT; 227b7dcb857SMasami Hiramatsu 228b7dcb857SMasami Hiramatsu if (op->atom == DW_OP_addr) { 229632941c4SMasami Hiramatsu static_var: 230cf6eb489SMasami Hiramatsu if (!tvar) 231349e8d26SHe Kuang return ret2; 232b7dcb857SMasami Hiramatsu /* Static variables on memory (not stack), make @varname */ 233b7dcb857SMasami Hiramatsu ret = strlen(dwarf_diename(vr_die)); 234b7dcb857SMasami Hiramatsu tvar->value = zalloc(ret + 2); 235b7dcb857SMasami Hiramatsu if (tvar->value == NULL) 236b7dcb857SMasami Hiramatsu return -ENOMEM; 237b7dcb857SMasami Hiramatsu snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 238b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 239b7dcb857SMasami Hiramatsu if (tvar->ref == NULL) 240b7dcb857SMasami Hiramatsu return -ENOMEM; 241349e8d26SHe Kuang return ret2; 242b7dcb857SMasami Hiramatsu } 2434ea42b18SMasami Hiramatsu 2444ea42b18SMasami Hiramatsu /* If this is based on frame buffer, set the offset */ 245804b3606SMasami Hiramatsu if (op->atom == DW_OP_fbreg) { 246cf6eb489SMasami Hiramatsu if (fb_ops == NULL) 247b55a87adSMasami Hiramatsu return -ENOTSUP; 2484235b045SMasami Hiramatsu ref = true; 249804b3606SMasami Hiramatsu offs = op->number; 250cf6eb489SMasami Hiramatsu op = &fb_ops[0]; 251804b3606SMasami Hiramatsu } 2524ea42b18SMasami Hiramatsu 253804b3606SMasami Hiramatsu if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 254804b3606SMasami Hiramatsu regn = op->atom - DW_OP_breg0; 255804b3606SMasami Hiramatsu offs += op->number; 2564235b045SMasami Hiramatsu ref = true; 257804b3606SMasami Hiramatsu } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 258804b3606SMasami Hiramatsu regn = op->atom - DW_OP_reg0; 259804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_bregx) { 260804b3606SMasami Hiramatsu regn = op->number; 261804b3606SMasami Hiramatsu offs += op->number2; 2624235b045SMasami Hiramatsu ref = true; 263804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_regx) { 264804b3606SMasami Hiramatsu regn = op->number; 265b55a87adSMasami Hiramatsu } else { 266cf6eb489SMasami Hiramatsu pr_debug("DW_OP %x is not supported.\n", op->atom); 267b55a87adSMasami Hiramatsu return -ENOTSUP; 268b55a87adSMasami Hiramatsu } 2694ea42b18SMasami Hiramatsu 270cf6eb489SMasami Hiramatsu if (!tvar) 271349e8d26SHe Kuang return ret2; 272cf6eb489SMasami Hiramatsu 273293d5b43SMasami Hiramatsu regs = get_dwarf_regstr(regn, machine); 274b55a87adSMasami Hiramatsu if (!regs) { 275cf6eb489SMasami Hiramatsu /* This should be a bug in DWARF or this tool */ 2760e43e5d2SMasami Hiramatsu pr_warning("Mapping for the register number %u " 2770e43e5d2SMasami Hiramatsu "missing on this architecture.\n", regn); 278349e8d26SHe Kuang return -ENOTSUP; 279b55a87adSMasami Hiramatsu } 2804ea42b18SMasami Hiramatsu 28102b95dadSMasami Hiramatsu tvar->value = strdup(regs); 28202b95dadSMasami Hiramatsu if (tvar->value == NULL) 28302b95dadSMasami Hiramatsu return -ENOMEM; 28402b95dadSMasami Hiramatsu 2854235b045SMasami Hiramatsu if (ref) { 286b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 287e334016fSMasami Hiramatsu if (tvar->ref == NULL) 288e334016fSMasami Hiramatsu return -ENOMEM; 2894235b045SMasami Hiramatsu } 290349e8d26SHe Kuang return ret2; 2914ea42b18SMasami Hiramatsu } 2924ea42b18SMasami Hiramatsu 293124bb83cSMasami Hiramatsu #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 294124bb83cSMasami Hiramatsu 295b55a87adSMasami Hiramatsu static int convert_variable_type(Dwarf_Die *vr_die, 2960e60836bSSrikar Dronamraju struct probe_trace_arg *tvar, 297*1e032f7cSMasami Hiramatsu const char *cast, bool user_access) 2984984912eSMasami Hiramatsu { 2990e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 3004984912eSMasami Hiramatsu Dwarf_Die type; 3014984912eSMasami Hiramatsu char buf[16]; 3025f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 303bcfc0821SMasami Hiramatsu int bsize, boffs, total; 3044984912eSMasami Hiramatsu int ret; 30592543787SMasami Hiramatsu char prefix; 3064984912eSMasami Hiramatsu 30773317b95SMasami Hiramatsu /* TODO: check all types */ 30892543787SMasami Hiramatsu if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 && 30919f00b01SNaohiro Aota strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) { 31073317b95SMasami Hiramatsu /* Non string type is OK */ 31192543787SMasami Hiramatsu /* and respect signedness/hexadecimal cast */ 31273317b95SMasami Hiramatsu tvar->type = strdup(cast); 31373317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 31473317b95SMasami Hiramatsu } 31573317b95SMasami Hiramatsu 316bcfc0821SMasami Hiramatsu bsize = dwarf_bitsize(vr_die); 317bcfc0821SMasami Hiramatsu if (bsize > 0) { 318124bb83cSMasami Hiramatsu /* This is a bitfield */ 319bcfc0821SMasami Hiramatsu boffs = dwarf_bitoffset(vr_die); 320bcfc0821SMasami Hiramatsu total = dwarf_bytesize(vr_die); 321bcfc0821SMasami Hiramatsu if (boffs < 0 || total < 0) 322bcfc0821SMasami Hiramatsu return -ENOENT; 323bcfc0821SMasami Hiramatsu ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 324bcfc0821SMasami Hiramatsu BYTES_TO_BITS(total)); 325124bb83cSMasami Hiramatsu goto formatted; 326124bb83cSMasami Hiramatsu } 327124bb83cSMasami Hiramatsu 328b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 329b55a87adSMasami Hiramatsu pr_warning("Failed to get a type information of %s.\n", 3304984912eSMasami Hiramatsu dwarf_diename(vr_die)); 331b55a87adSMasami Hiramatsu return -ENOENT; 332b55a87adSMasami Hiramatsu } 3334984912eSMasami Hiramatsu 334b2a3c12bSMasami Hiramatsu pr_debug("%s type is %s.\n", 335b2a3c12bSMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 336b2a3c12bSMasami Hiramatsu 337*1e032f7cSMasami Hiramatsu if (cast && (!strcmp(cast, "string") || !strcmp(cast, "ustring"))) { 338*1e032f7cSMasami Hiramatsu /* String type */ 33973317b95SMasami Hiramatsu ret = dwarf_tag(&type); 34073317b95SMasami Hiramatsu if (ret != DW_TAG_pointer_type && 34173317b95SMasami Hiramatsu ret != DW_TAG_array_type) { 34273317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3430e43e5d2SMasami Hiramatsu "%s(%s) is not a pointer nor array.\n", 34473317b95SMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 34573317b95SMasami Hiramatsu return -EINVAL; 34673317b95SMasami Hiramatsu } 34773317b95SMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 3480e43e5d2SMasami Hiramatsu pr_warning("Failed to get a type" 3490e43e5d2SMasami Hiramatsu " information.\n"); 35073317b95SMasami Hiramatsu return -ENOENT; 35173317b95SMasami Hiramatsu } 3527ce28b5bSHyeoncheol Lee if (ret == DW_TAG_pointer_type) { 35373317b95SMasami Hiramatsu while (*ref_ptr) 35473317b95SMasami Hiramatsu ref_ptr = &(*ref_ptr)->next; 35573317b95SMasami Hiramatsu /* Add new reference with offset +0 */ 3560e60836bSSrikar Dronamraju *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 35773317b95SMasami Hiramatsu if (*ref_ptr == NULL) { 35873317b95SMasami Hiramatsu pr_warning("Out of memory error\n"); 35973317b95SMasami Hiramatsu return -ENOMEM; 36073317b95SMasami Hiramatsu } 361*1e032f7cSMasami Hiramatsu (*ref_ptr)->user_access = user_access; 36273317b95SMasami Hiramatsu } 36382175633SMasami Hiramatsu if (!die_compare_name(&type, "char") && 36482175633SMasami Hiramatsu !die_compare_name(&type, "unsigned char")) { 36573317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3660e43e5d2SMasami Hiramatsu "%s is not (unsigned) char *.\n", 36773317b95SMasami Hiramatsu dwarf_diename(vr_die)); 36873317b95SMasami Hiramatsu return -EINVAL; 36973317b95SMasami Hiramatsu } 37073317b95SMasami Hiramatsu tvar->type = strdup(cast); 37173317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 37273317b95SMasami Hiramatsu } 37373317b95SMasami Hiramatsu 37419f00b01SNaohiro Aota if (cast && (strcmp(cast, "u") == 0)) 37592543787SMasami Hiramatsu prefix = 'u'; 37619f00b01SNaohiro Aota else if (cast && (strcmp(cast, "s") == 0)) 37792543787SMasami Hiramatsu prefix = 's'; 37892543787SMasami Hiramatsu else if (cast && (strcmp(cast, "x") == 0) && 37992543787SMasami Hiramatsu probe_type_is_available(PROBE_TYPE_X)) 38092543787SMasami Hiramatsu prefix = 'x'; 38119f00b01SNaohiro Aota else 3829880ce4aSMasami Hiramatsu prefix = die_is_signed_type(&type) ? 's' : 3839880ce4aSMasami Hiramatsu probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u'; 38419f00b01SNaohiro Aota 385bcfc0821SMasami Hiramatsu ret = dwarf_bytesize(&type); 386bcfc0821SMasami Hiramatsu if (ret <= 0) 387124bb83cSMasami Hiramatsu /* No size ... try to use default type */ 388124bb83cSMasami Hiramatsu return 0; 389bcfc0821SMasami Hiramatsu ret = BYTES_TO_BITS(ret); 390124bb83cSMasami Hiramatsu 3914984912eSMasami Hiramatsu /* Check the bitwidth */ 3924984912eSMasami Hiramatsu if (ret > MAX_BASIC_TYPE_BITS) { 393124bb83cSMasami Hiramatsu pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 3944984912eSMasami Hiramatsu dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 3954984912eSMasami Hiramatsu ret = MAX_BASIC_TYPE_BITS; 3964984912eSMasami Hiramatsu } 39792543787SMasami Hiramatsu ret = snprintf(buf, 16, "%c%d", prefix, ret); 398124bb83cSMasami Hiramatsu 399124bb83cSMasami Hiramatsu formatted: 400b55a87adSMasami Hiramatsu if (ret < 0 || ret >= 16) { 401b55a87adSMasami Hiramatsu if (ret >= 16) 402b55a87adSMasami Hiramatsu ret = -E2BIG; 403b55a87adSMasami Hiramatsu pr_warning("Failed to convert variable type: %s\n", 404c8b5f2c9SArnaldo Carvalho de Melo str_error_r(-ret, sbuf, sizeof(sbuf))); 405b55a87adSMasami Hiramatsu return ret; 406b55a87adSMasami Hiramatsu } 40773317b95SMasami Hiramatsu tvar->type = strdup(buf); 40873317b95SMasami Hiramatsu if (tvar->type == NULL) 40902b95dadSMasami Hiramatsu return -ENOMEM; 410b55a87adSMasami Hiramatsu return 0; 4114984912eSMasami Hiramatsu } 4124984912eSMasami Hiramatsu 413b55a87adSMasami Hiramatsu static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 4147df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, 4150e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr, 416*1e032f7cSMasami Hiramatsu Dwarf_Die *die_mem, bool user_access) 4177df2f329SMasami Hiramatsu { 4180e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = *ref_ptr; 4197df2f329SMasami Hiramatsu Dwarf_Die type; 4207df2f329SMasami Hiramatsu Dwarf_Word offs; 421b2a3c12bSMasami Hiramatsu int ret, tag; 4227df2f329SMasami Hiramatsu 4237df2f329SMasami Hiramatsu pr_debug("converting %s in %s\n", field->name, varname); 424b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 425b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 426b55a87adSMasami Hiramatsu return -ENOENT; 427b55a87adSMasami Hiramatsu } 428d0461794SMasami Hiramatsu pr_debug2("Var real type: %s (%x)\n", dwarf_diename(&type), 429d0461794SMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 430b2a3c12bSMasami Hiramatsu tag = dwarf_tag(&type); 4317df2f329SMasami Hiramatsu 432b2a3c12bSMasami Hiramatsu if (field->name[0] == '[' && 433b2a3c12bSMasami Hiramatsu (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 434d0461794SMasami Hiramatsu /* Save original type for next field or type */ 435b2a3c12bSMasami Hiramatsu memcpy(die_mem, &type, sizeof(*die_mem)); 436b2a3c12bSMasami Hiramatsu /* Get the type of this array */ 437b2a3c12bSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 438b2a3c12bSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 439b2a3c12bSMasami Hiramatsu return -ENOENT; 440b2a3c12bSMasami Hiramatsu } 441d0461794SMasami Hiramatsu pr_debug2("Array real type: %s (%x)\n", dwarf_diename(&type), 442b2a3c12bSMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 443b2a3c12bSMasami Hiramatsu if (tag == DW_TAG_pointer_type) { 4440e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 445b2a3c12bSMasami Hiramatsu if (ref == NULL) 446b2a3c12bSMasami Hiramatsu return -ENOMEM; 447b2a3c12bSMasami Hiramatsu if (*ref_ptr) 448b2a3c12bSMasami Hiramatsu (*ref_ptr)->next = ref; 449b2a3c12bSMasami Hiramatsu else 450b2a3c12bSMasami Hiramatsu *ref_ptr = ref; 451b2a3c12bSMasami Hiramatsu } 452bcfc0821SMasami Hiramatsu ref->offset += dwarf_bytesize(&type) * field->index; 453*1e032f7cSMasami Hiramatsu ref->user_access = user_access; 454b2a3c12bSMasami Hiramatsu goto next; 455b2a3c12bSMasami Hiramatsu } else if (tag == DW_TAG_pointer_type) { 4567df2f329SMasami Hiramatsu /* Check the pointer and dereference */ 457b55a87adSMasami Hiramatsu if (!field->ref) { 458b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '->'\n", 4597df2f329SMasami Hiramatsu field->name); 460b55a87adSMasami Hiramatsu return -EINVAL; 461b55a87adSMasami Hiramatsu } 4627df2f329SMasami Hiramatsu /* Get the type pointed by this pointer */ 463b55a87adSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 464b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 465b55a87adSMasami Hiramatsu return -ENOENT; 466b55a87adSMasami Hiramatsu } 46712e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4687b0295b3SHyeoncheol Lee tag = dwarf_tag(&type); 4697b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 47003440c4eSMasahiro Yamada pr_warning("%s is not a data structure nor a union.\n", 4717b0295b3SHyeoncheol Lee varname); 472b55a87adSMasami Hiramatsu return -EINVAL; 473b55a87adSMasami Hiramatsu } 47412e5a7aeSMasami Hiramatsu 4750e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 476e334016fSMasami Hiramatsu if (ref == NULL) 477e334016fSMasami Hiramatsu return -ENOMEM; 4787df2f329SMasami Hiramatsu if (*ref_ptr) 4797df2f329SMasami Hiramatsu (*ref_ptr)->next = ref; 4807df2f329SMasami Hiramatsu else 4817df2f329SMasami Hiramatsu *ref_ptr = ref; 4827df2f329SMasami Hiramatsu } else { 48312e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4847b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 48503440c4eSMasahiro Yamada pr_warning("%s is not a data structure nor a union.\n", 4867b0295b3SHyeoncheol Lee varname); 487b55a87adSMasami Hiramatsu return -EINVAL; 488b55a87adSMasami Hiramatsu } 489b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') { 490d939be3aSMasanari Iida pr_err("Semantic error: %s is not a pointer" 4910e43e5d2SMasami Hiramatsu " nor array.\n", varname); 492b2a3c12bSMasami Hiramatsu return -EINVAL; 493b2a3c12bSMasami Hiramatsu } 494c7273835SMasami Hiramatsu /* While prcessing unnamed field, we don't care about this */ 495c7273835SMasami Hiramatsu if (field->ref && dwarf_diename(vr_die)) { 496b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '.'\n", 4977df2f329SMasami Hiramatsu field->name); 498b55a87adSMasami Hiramatsu return -EINVAL; 499b55a87adSMasami Hiramatsu } 500b55a87adSMasami Hiramatsu if (!ref) { 501b55a87adSMasami Hiramatsu pr_warning("Structure on a register is not " 502b55a87adSMasami Hiramatsu "supported yet.\n"); 503b55a87adSMasami Hiramatsu return -ENOTSUP; 504b55a87adSMasami Hiramatsu } 5057df2f329SMasami Hiramatsu } 5067df2f329SMasami Hiramatsu 507b55a87adSMasami Hiramatsu if (die_find_member(&type, field->name, die_mem) == NULL) { 5089ef0438aSArnaldo Carvalho de Melo pr_warning("%s(type:%s) has no member %s.\n", varname, 5097df2f329SMasami Hiramatsu dwarf_diename(&type), field->name); 510b55a87adSMasami Hiramatsu return -EINVAL; 511b55a87adSMasami Hiramatsu } 5127df2f329SMasami Hiramatsu 5137df2f329SMasami Hiramatsu /* Get the offset of the field */ 5147b0295b3SHyeoncheol Lee if (tag == DW_TAG_union_type) { 5157b0295b3SHyeoncheol Lee offs = 0; 5167b0295b3SHyeoncheol Lee } else { 517de1439d8SMasami Hiramatsu ret = die_get_data_member_location(die_mem, &offs); 518de1439d8SMasami Hiramatsu if (ret < 0) { 5197b0295b3SHyeoncheol Lee pr_warning("Failed to get the offset of %s.\n", 5207b0295b3SHyeoncheol Lee field->name); 521de1439d8SMasami Hiramatsu return ret; 522b55a87adSMasami Hiramatsu } 5237b0295b3SHyeoncheol Lee } 5247df2f329SMasami Hiramatsu ref->offset += (long)offs; 525*1e032f7cSMasami Hiramatsu ref->user_access = user_access; 5267df2f329SMasami Hiramatsu 527c7273835SMasami Hiramatsu /* If this member is unnamed, we need to reuse this field */ 528c7273835SMasami Hiramatsu if (!dwarf_diename(die_mem)) 529c7273835SMasami Hiramatsu return convert_variable_fields(die_mem, varname, field, 530*1e032f7cSMasami Hiramatsu &ref, die_mem, user_access); 531c7273835SMasami Hiramatsu 532b2a3c12bSMasami Hiramatsu next: 5337df2f329SMasami Hiramatsu /* Converting next field */ 5347df2f329SMasami Hiramatsu if (field->next) 535b55a87adSMasami Hiramatsu return convert_variable_fields(die_mem, field->name, 536*1e032f7cSMasami Hiramatsu field->next, &ref, die_mem, user_access); 537b55a87adSMasami Hiramatsu else 538b55a87adSMasami Hiramatsu return 0; 5397df2f329SMasami Hiramatsu } 5407df2f329SMasami Hiramatsu 5414ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */ 542b55a87adSMasami Hiramatsu static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 5434ea42b18SMasami Hiramatsu { 5444984912eSMasami Hiramatsu Dwarf_Die die_mem; 5454ea42b18SMasami Hiramatsu int ret; 5464ea42b18SMasami Hiramatsu 547b7dcb857SMasami Hiramatsu pr_debug("Converting variable %s into trace event.\n", 548b7dcb857SMasami Hiramatsu dwarf_diename(vr_die)); 549804b3606SMasami Hiramatsu 550cf6eb489SMasami Hiramatsu ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 551293d5b43SMasami Hiramatsu &pf->sp_die, pf->machine, pf->tvar); 5527d5eaba9SHe Kuang if (ret == -ENOENT || ret == -EINVAL) { 5537d5eaba9SHe Kuang pr_err("Failed to find the location of the '%s' variable at this address.\n" 5547d5eaba9SHe Kuang " Perhaps it has been optimized out.\n" 5557d5eaba9SHe Kuang " Use -V with the --range option to show '%s' location range.\n", 5567d5eaba9SHe Kuang pf->pvar->var, pf->pvar->var); 5577d5eaba9SHe Kuang } else if (ret == -ENOTSUP) 558cf6eb489SMasami Hiramatsu pr_err("Sorry, we don't support this variable location yet.\n"); 5590c188a07SMasami Hiramatsu else if (ret == 0 && pf->pvar->field) { 560b55a87adSMasami Hiramatsu ret = convert_variable_fields(vr_die, pf->pvar->var, 5614984912eSMasami Hiramatsu pf->pvar->field, &pf->tvar->ref, 562*1e032f7cSMasami Hiramatsu &die_mem, pf->pvar->user_access); 5634984912eSMasami Hiramatsu vr_die = &die_mem; 5644984912eSMasami Hiramatsu } 56573317b95SMasami Hiramatsu if (ret == 0) 566*1e032f7cSMasami Hiramatsu ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type, 567*1e032f7cSMasami Hiramatsu pf->pvar->user_access); 568804b3606SMasami Hiramatsu /* *expr will be cached in libdw. Don't free it. */ 569b55a87adSMasami Hiramatsu return ret; 5704ea42b18SMasami Hiramatsu } 5714ea42b18SMasami Hiramatsu 572221d0611SMasami Hiramatsu /* Find a variable in a scope DIE */ 573221d0611SMasami Hiramatsu static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 5744ea42b18SMasami Hiramatsu { 575f182e3e1SMasami Hiramatsu Dwarf_Die vr_die; 576909b0360SMasami Hiramatsu char *buf, *ptr; 577f182e3e1SMasami Hiramatsu int ret = 0; 5784ea42b18SMasami Hiramatsu 579367e94c1SMasami Hiramatsu /* Copy raw parameters */ 580da15bd9dSWang Nan if (!is_c_varname(pf->pvar->var)) 581da15bd9dSWang Nan return copy_to_probe_trace_arg(pf->tvar, pf->pvar); 582367e94c1SMasami Hiramatsu 58348481938SMasami Hiramatsu if (pf->pvar->name) 58402b95dadSMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 58548481938SMasami Hiramatsu else { 586909b0360SMasami Hiramatsu buf = synthesize_perf_probe_arg(pf->pvar); 587909b0360SMasami Hiramatsu if (!buf) 588909b0360SMasami Hiramatsu return -ENOMEM; 58911a1ca35SMasami Hiramatsu ptr = strchr(buf, ':'); /* Change type separator to _ */ 59011a1ca35SMasami Hiramatsu if (ptr) 59111a1ca35SMasami Hiramatsu *ptr = '_'; 592909b0360SMasami Hiramatsu pf->tvar->name = buf; 59348481938SMasami Hiramatsu } 59402b95dadSMasami Hiramatsu if (pf->tvar->name == NULL) 59502b95dadSMasami Hiramatsu return -ENOMEM; 59648481938SMasami Hiramatsu 597f182e3e1SMasami Hiramatsu pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 5984ea42b18SMasami Hiramatsu /* Search child die for local variables and parameters. */ 599f182e3e1SMasami Hiramatsu if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 600f182e3e1SMasami Hiramatsu /* Search again in global variables */ 601d13855efSHe Kuang if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 602d13855efSHe Kuang 0, &vr_die)) { 60336d789a4SMasami Hiramatsu pr_warning("Failed to find '%s' in this function.\n", 60436d789a4SMasami Hiramatsu pf->pvar->var); 6058afa2a70SMasami Hiramatsu ret = -ENOENT; 606f182e3e1SMasami Hiramatsu } 607d13855efSHe Kuang } 608f66fedcbSMasami Hiramatsu if (ret >= 0) 609b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 610f182e3e1SMasami Hiramatsu 611b7dcb857SMasami Hiramatsu return ret; 6124ea42b18SMasami Hiramatsu } 6134ea42b18SMasami Hiramatsu 614cf6eb489SMasami Hiramatsu /* Convert subprogram DIE to trace point */ 615576b5237SMasami Hiramatsu static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, 616576b5237SMasami Hiramatsu Dwarf_Addr paddr, bool retprobe, 6176cca13bdSMasami Hiramatsu const char *function, 618576b5237SMasami Hiramatsu struct probe_trace_point *tp) 6194ea42b18SMasami Hiramatsu { 62026b79524SPrashanth Nageshappa Dwarf_Addr eaddr, highaddr; 621576b5237SMasami Hiramatsu GElf_Sym sym; 622576b5237SMasami Hiramatsu const char *symbol; 623cf6eb489SMasami Hiramatsu 624576b5237SMasami Hiramatsu /* Verify the address is correct */ 625cf6eb489SMasami Hiramatsu if (dwarf_entrypc(sp_die, &eaddr) != 0) { 6260e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s\n", 627cf6eb489SMasami Hiramatsu dwarf_diename(sp_die)); 628cf6eb489SMasami Hiramatsu return -ENOENT; 629cf6eb489SMasami Hiramatsu } 63026b79524SPrashanth Nageshappa if (dwarf_highpc(sp_die, &highaddr) != 0) { 63126b79524SPrashanth Nageshappa pr_warning("Failed to get end address of %s\n", 63226b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 63326b79524SPrashanth Nageshappa return -ENOENT; 63426b79524SPrashanth Nageshappa } 63526b79524SPrashanth Nageshappa if (paddr > highaddr) { 63626b79524SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 63726b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 63826b79524SPrashanth Nageshappa return -EINVAL; 63926b79524SPrashanth Nageshappa } 640576b5237SMasami Hiramatsu 641664fee3dSMasami Hiramatsu symbol = dwarf_diename(sp_die); 642664fee3dSMasami Hiramatsu if (!symbol) { 643664fee3dSMasami Hiramatsu /* Try to get the symbol name from symtab */ 644576b5237SMasami Hiramatsu symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); 645576b5237SMasami Hiramatsu if (!symbol) { 646576b5237SMasami Hiramatsu pr_warning("Failed to find symbol at 0x%lx\n", 647576b5237SMasami Hiramatsu (unsigned long)paddr); 648576b5237SMasami Hiramatsu return -ENOENT; 649576b5237SMasami Hiramatsu } 650664fee3dSMasami Hiramatsu eaddr = sym.st_value; 651664fee3dSMasami Hiramatsu } 652664fee3dSMasami Hiramatsu tp->offset = (unsigned long)(paddr - eaddr); 653fb7345bbSMasami Hiramatsu tp->address = (unsigned long)paddr; 654576b5237SMasami Hiramatsu tp->symbol = strdup(symbol); 655576b5237SMasami Hiramatsu if (!tp->symbol) 656cf6eb489SMasami Hiramatsu return -ENOMEM; 657cf6eb489SMasami Hiramatsu 658cf6eb489SMasami Hiramatsu /* Return probe must be on the head of a subprogram */ 659cf6eb489SMasami Hiramatsu if (retprobe) { 660cf6eb489SMasami Hiramatsu if (eaddr != paddr) { 6616cca13bdSMasami Hiramatsu pr_warning("Failed to find \"%s%%return\",\n" 6626cca13bdSMasami Hiramatsu " because %s is an inlined function and" 6636cca13bdSMasami Hiramatsu " has no return point.\n", function, 6646cca13bdSMasami Hiramatsu function); 665cf6eb489SMasami Hiramatsu return -EINVAL; 666cf6eb489SMasami Hiramatsu } 667cf6eb489SMasami Hiramatsu tp->retprobe = true; 668cf6eb489SMasami Hiramatsu } 669cf6eb489SMasami Hiramatsu 670cf6eb489SMasami Hiramatsu return 0; 671cf6eb489SMasami Hiramatsu } 672cf6eb489SMasami Hiramatsu 673221d0611SMasami Hiramatsu /* Call probe_finder callback with scope DIE */ 674221d0611SMasami Hiramatsu static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 675cf6eb489SMasami Hiramatsu { 676804b3606SMasami Hiramatsu Dwarf_Attribute fb_attr; 6774d3b1626SMasami Hiramatsu Dwarf_Frame *frame = NULL; 678804b3606SMasami Hiramatsu size_t nops; 679cf6eb489SMasami Hiramatsu int ret; 6804235b045SMasami Hiramatsu 681221d0611SMasami Hiramatsu if (!sc_die) { 682221d0611SMasami Hiramatsu pr_err("Caller must pass a scope DIE. Program error.\n"); 683221d0611SMasami Hiramatsu return -EINVAL; 684221d0611SMasami Hiramatsu } 685221d0611SMasami Hiramatsu 686221d0611SMasami Hiramatsu /* If not a real subprogram, find a real one */ 6870dbb1cacSMasami Hiramatsu if (!die_is_func_def(sc_die)) { 688221d0611SMasami Hiramatsu if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 689d4c537e6SNaveen N. Rao if (die_find_tailfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 690d4c537e6SNaveen N. Rao pr_warning("Ignoring tail call from %s\n", 691d4c537e6SNaveen N. Rao dwarf_diename(&pf->sp_die)); 692d4c537e6SNaveen N. Rao return 0; 693d4c537e6SNaveen N. Rao } else { 694b55a87adSMasami Hiramatsu pr_warning("Failed to find probe point in any " 695b55a87adSMasami Hiramatsu "functions.\n"); 696b55a87adSMasami Hiramatsu return -ENOENT; 697b55a87adSMasami Hiramatsu } 698d4c537e6SNaveen N. Rao } 699221d0611SMasami Hiramatsu } else 700221d0611SMasami Hiramatsu memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 701e92b85e1SMasami Hiramatsu 702221d0611SMasami Hiramatsu /* Get the frame base attribute/ops from subprogram */ 703221d0611SMasami Hiramatsu dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 704d0cb4260SMasami Hiramatsu ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 705a34a9854SMasami Hiramatsu if (ret <= 0 || nops == 0) { 706804b3606SMasami Hiramatsu pf->fb_ops = NULL; 7077752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 708a34a9854SMasami Hiramatsu } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 709270bde1eSHemant Kumar (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) { 710270bde1eSHemant Kumar if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 && 711270bde1eSHemant Kumar (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) || 712b55a87adSMasami Hiramatsu dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 7130e43e5d2SMasami Hiramatsu pr_warning("Failed to get call frame on 0x%jx\n", 714b55a87adSMasami Hiramatsu (uintmax_t)pf->addr); 71505c8d802SMasami Hiramatsu free(frame); 7164d3b1626SMasami Hiramatsu return -ENOENT; 7174d3b1626SMasami Hiramatsu } 7187752f1b0SMasami Hiramatsu #endif 719a34a9854SMasami Hiramatsu } 720804b3606SMasami Hiramatsu 721cf6eb489SMasami Hiramatsu /* Call finder's callback handler */ 722221d0611SMasami Hiramatsu ret = pf->callback(sc_die, pf); 723804b3606SMasami Hiramatsu 7244d3b1626SMasami Hiramatsu /* Since *pf->fb_ops can be a part of frame. we should free it here. */ 7254d3b1626SMasami Hiramatsu free(frame); 726804b3606SMasami Hiramatsu pf->fb_ops = NULL; 727cf6eb489SMasami Hiramatsu 728cf6eb489SMasami Hiramatsu return ret; 7294ea42b18SMasami Hiramatsu } 7304ea42b18SMasami Hiramatsu 731221d0611SMasami Hiramatsu struct find_scope_param { 732221d0611SMasami Hiramatsu const char *function; 733221d0611SMasami Hiramatsu const char *file; 734221d0611SMasami Hiramatsu int line; 735221d0611SMasami Hiramatsu int diff; 736221d0611SMasami Hiramatsu Dwarf_Die *die_mem; 737221d0611SMasami Hiramatsu bool found; 738221d0611SMasami Hiramatsu }; 739221d0611SMasami Hiramatsu 740221d0611SMasami Hiramatsu static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 741221d0611SMasami Hiramatsu { 742221d0611SMasami Hiramatsu struct find_scope_param *fsp = data; 743221d0611SMasami Hiramatsu const char *file; 744221d0611SMasami Hiramatsu int lno; 745221d0611SMasami Hiramatsu 746221d0611SMasami Hiramatsu /* Skip if declared file name does not match */ 747221d0611SMasami Hiramatsu if (fsp->file) { 748221d0611SMasami Hiramatsu file = dwarf_decl_file(fn_die); 749221d0611SMasami Hiramatsu if (!file || strcmp(fsp->file, file) != 0) 750221d0611SMasami Hiramatsu return 0; 751221d0611SMasami Hiramatsu } 752221d0611SMasami Hiramatsu /* If the function name is given, that's what user expects */ 753221d0611SMasami Hiramatsu if (fsp->function) { 7544c859351SMasami Hiramatsu if (die_match_name(fn_die, fsp->function)) { 755221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 756221d0611SMasami Hiramatsu fsp->found = true; 757221d0611SMasami Hiramatsu return 1; 758221d0611SMasami Hiramatsu } 759221d0611SMasami Hiramatsu } else { 760221d0611SMasami Hiramatsu /* With the line number, find the nearest declared DIE */ 761221d0611SMasami Hiramatsu dwarf_decl_line(fn_die, &lno); 762221d0611SMasami Hiramatsu if (lno < fsp->line && fsp->diff > fsp->line - lno) { 763221d0611SMasami Hiramatsu /* Keep a candidate and continue */ 764221d0611SMasami Hiramatsu fsp->diff = fsp->line - lno; 765221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 766221d0611SMasami Hiramatsu fsp->found = true; 767221d0611SMasami Hiramatsu } 768221d0611SMasami Hiramatsu } 769221d0611SMasami Hiramatsu return 0; 770221d0611SMasami Hiramatsu } 771221d0611SMasami Hiramatsu 772221d0611SMasami Hiramatsu /* Find an appropriate scope fits to given conditions */ 773221d0611SMasami Hiramatsu static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 774221d0611SMasami Hiramatsu { 775221d0611SMasami Hiramatsu struct find_scope_param fsp = { 776221d0611SMasami Hiramatsu .function = pf->pev->point.function, 777221d0611SMasami Hiramatsu .file = pf->fname, 778221d0611SMasami Hiramatsu .line = pf->lno, 779221d0611SMasami Hiramatsu .diff = INT_MAX, 780221d0611SMasami Hiramatsu .die_mem = die_mem, 781221d0611SMasami Hiramatsu .found = false, 782221d0611SMasami Hiramatsu }; 783221d0611SMasami Hiramatsu 784221d0611SMasami Hiramatsu cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 785221d0611SMasami Hiramatsu 786221d0611SMasami Hiramatsu return fsp.found ? die_mem : NULL; 787221d0611SMasami Hiramatsu } 788221d0611SMasami Hiramatsu 7894cc9cec6SMasami Hiramatsu static int probe_point_line_walker(const char *fname, int lineno, 7904cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 7914cc9cec6SMasami Hiramatsu { 7924cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 793221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 7944cc9cec6SMasami Hiramatsu int ret; 7954cc9cec6SMasami Hiramatsu 7964cc9cec6SMasami Hiramatsu if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 7974cc9cec6SMasami Hiramatsu return 0; 7984cc9cec6SMasami Hiramatsu 7994cc9cec6SMasami Hiramatsu pf->addr = addr; 800221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 801221d0611SMasami Hiramatsu if (!sc_die) { 802221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 803221d0611SMasami Hiramatsu return -ENOENT; 804221d0611SMasami Hiramatsu } 805221d0611SMasami Hiramatsu 806221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8074cc9cec6SMasami Hiramatsu 8084cc9cec6SMasami Hiramatsu /* Continue if no error, because the line will be in inline function */ 809fbee632dSArnaldo Carvalho de Melo return ret < 0 ? ret : 0; 8104cc9cec6SMasami Hiramatsu } 8114cc9cec6SMasami Hiramatsu 8124ea42b18SMasami Hiramatsu /* Find probe point from its line number */ 813b55a87adSMasami Hiramatsu static int find_probe_point_by_line(struct probe_finder *pf) 8144ea42b18SMasami Hiramatsu { 8154cc9cec6SMasami Hiramatsu return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 8164ea42b18SMasami Hiramatsu } 8174ea42b18SMasami Hiramatsu 8182a9c8c36SMasami Hiramatsu /* Find lines which match lazy pattern */ 8195a62257aSMasami Hiramatsu static int find_lazy_match_lines(struct intlist *list, 8202a9c8c36SMasami Hiramatsu const char *fname, const char *pat) 8212a9c8c36SMasami Hiramatsu { 822f50c2169SFranck Bui-Huu FILE *fp; 823f50c2169SFranck Bui-Huu char *line = NULL; 824f50c2169SFranck Bui-Huu size_t line_len; 825f50c2169SFranck Bui-Huu ssize_t len; 826f50c2169SFranck Bui-Huu int count = 0, linenum = 1; 8275f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 8282a9c8c36SMasami Hiramatsu 829f50c2169SFranck Bui-Huu fp = fopen(fname, "r"); 830f50c2169SFranck Bui-Huu if (!fp) { 8315f03cba4SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", fname, 832c8b5f2c9SArnaldo Carvalho de Melo str_error_r(errno, sbuf, sizeof(sbuf))); 833b448c4b6SArnaldo Carvalho de Melo return -errno; 834b55a87adSMasami Hiramatsu } 835b55a87adSMasami Hiramatsu 836f50c2169SFranck Bui-Huu while ((len = getline(&line, &line_len, fp)) > 0) { 837f50c2169SFranck Bui-Huu 838f50c2169SFranck Bui-Huu if (line[len - 1] == '\n') 839f50c2169SFranck Bui-Huu line[len - 1] = '\0'; 840f50c2169SFranck Bui-Huu 841f50c2169SFranck Bui-Huu if (strlazymatch(line, pat)) { 8425a62257aSMasami Hiramatsu intlist__add(list, linenum); 843f50c2169SFranck Bui-Huu count++; 844f50c2169SFranck Bui-Huu } 845f50c2169SFranck Bui-Huu linenum++; 846b55a87adSMasami Hiramatsu } 847b448c4b6SArnaldo Carvalho de Melo 848f50c2169SFranck Bui-Huu if (ferror(fp)) 849f50c2169SFranck Bui-Huu count = -errno; 850f50c2169SFranck Bui-Huu free(line); 851f50c2169SFranck Bui-Huu fclose(fp); 852f50c2169SFranck Bui-Huu 853f50c2169SFranck Bui-Huu if (count == 0) 854f50c2169SFranck Bui-Huu pr_debug("No matched lines found in %s.\n", fname); 855f50c2169SFranck Bui-Huu return count; 8562a9c8c36SMasami Hiramatsu } 8572a9c8c36SMasami Hiramatsu 8584cc9cec6SMasami Hiramatsu static int probe_point_lazy_walker(const char *fname, int lineno, 8594cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 8604cc9cec6SMasami Hiramatsu { 8614cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 862221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 8634cc9cec6SMasami Hiramatsu int ret; 8644cc9cec6SMasami Hiramatsu 8655a62257aSMasami Hiramatsu if (!intlist__has_entry(pf->lcache, lineno) || 8664cc9cec6SMasami Hiramatsu strtailcmp(fname, pf->fname) != 0) 8674cc9cec6SMasami Hiramatsu return 0; 8684cc9cec6SMasami Hiramatsu 8694cc9cec6SMasami Hiramatsu pr_debug("Probe line found: line:%d addr:0x%llx\n", 8704cc9cec6SMasami Hiramatsu lineno, (unsigned long long)addr); 8714cc9cec6SMasami Hiramatsu pf->addr = addr; 872221d0611SMasami Hiramatsu pf->lno = lineno; 873221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 874221d0611SMasami Hiramatsu if (!sc_die) { 875221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 876221d0611SMasami Hiramatsu return -ENOENT; 877221d0611SMasami Hiramatsu } 878221d0611SMasami Hiramatsu 879221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8804cc9cec6SMasami Hiramatsu 8814cc9cec6SMasami Hiramatsu /* 8824cc9cec6SMasami Hiramatsu * Continue if no error, because the lazy pattern will match 8834cc9cec6SMasami Hiramatsu * to other lines 8844cc9cec6SMasami Hiramatsu */ 8855e814dd5SIngo Molnar return ret < 0 ? ret : 0; 8864cc9cec6SMasami Hiramatsu } 8874cc9cec6SMasami Hiramatsu 8882a9c8c36SMasami Hiramatsu /* Find probe points from lazy pattern */ 889b55a87adSMasami Hiramatsu static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 8902a9c8c36SMasami Hiramatsu { 891b55a87adSMasami Hiramatsu int ret = 0; 89209ed8975SNaohiro Aota char *fpath; 8932a9c8c36SMasami Hiramatsu 8945a62257aSMasami Hiramatsu if (intlist__empty(pf->lcache)) { 89509ed8975SNaohiro Aota const char *comp_dir; 89609ed8975SNaohiro Aota 89709ed8975SNaohiro Aota comp_dir = cu_get_comp_dir(&pf->cu_die); 89809ed8975SNaohiro Aota ret = get_real_path(pf->fname, comp_dir, &fpath); 89909ed8975SNaohiro Aota if (ret < 0) { 90009ed8975SNaohiro Aota pr_warning("Failed to find source file path.\n"); 90109ed8975SNaohiro Aota return ret; 90209ed8975SNaohiro Aota } 90309ed8975SNaohiro Aota 9042a9c8c36SMasami Hiramatsu /* Matching lazy line pattern */ 90509ed8975SNaohiro Aota ret = find_lazy_match_lines(pf->lcache, fpath, 9064235b045SMasami Hiramatsu pf->pev->point.lazy_line); 90709ed8975SNaohiro Aota free(fpath); 908f50c2169SFranck Bui-Huu if (ret <= 0) 909b55a87adSMasami Hiramatsu return ret; 9102a9c8c36SMasami Hiramatsu } 9112a9c8c36SMasami Hiramatsu 9124cc9cec6SMasami Hiramatsu return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 9132a9c8c36SMasami Hiramatsu } 9142a9c8c36SMasami Hiramatsu 915e47392bfSRavi Bangoria static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) 916e47392bfSRavi Bangoria { 917e47392bfSRavi Bangoria struct perf_probe_point *pp = &pf->pev->point; 918e47392bfSRavi Bangoria 919e47392bfSRavi Bangoria /* Not uprobe? */ 920e47392bfSRavi Bangoria if (!pf->pev->uprobes) 921e47392bfSRavi Bangoria return; 922e47392bfSRavi Bangoria 923e47392bfSRavi Bangoria /* Compiled with optimization? */ 9246243b9dcSRavi Bangoria if (die_is_optimized_target(&pf->cu_die)) 925e47392bfSRavi Bangoria return; 926e47392bfSRavi Bangoria 927e47392bfSRavi Bangoria /* Don't know entrypc? */ 928e47392bfSRavi Bangoria if (!pf->addr) 929e47392bfSRavi Bangoria return; 930e47392bfSRavi Bangoria 931e47392bfSRavi Bangoria /* Only FUNC and FUNC@SRC are eligible. */ 932e47392bfSRavi Bangoria if (!pp->function || pp->line || pp->retprobe || pp->lazy_line || 933e47392bfSRavi Bangoria pp->offset || pp->abs_address) 934e47392bfSRavi Bangoria return; 935e47392bfSRavi Bangoria 936e47392bfSRavi Bangoria /* Not interested in func parameter? */ 937e47392bfSRavi Bangoria if (!perf_probe_with_var(pf->pev)) 938e47392bfSRavi Bangoria return; 939e47392bfSRavi Bangoria 940e47392bfSRavi Bangoria pr_info("Target program is compiled without optimization. Skipping prologue.\n" 941e47392bfSRavi Bangoria "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n", 942e47392bfSRavi Bangoria pf->addr); 943e47392bfSRavi Bangoria 9446243b9dcSRavi Bangoria die_skip_prologue(sp_die, &pf->cu_die, &pf->addr); 945e47392bfSRavi Bangoria } 946e47392bfSRavi Bangoria 947e92b85e1SMasami Hiramatsu static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 9484ea42b18SMasami Hiramatsu { 949db0d2c64SMasami Hiramatsu struct probe_finder *pf = data; 9504235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 951b55a87adSMasami Hiramatsu Dwarf_Addr addr; 952db0d2c64SMasami Hiramatsu int ret; 9534ea42b18SMasami Hiramatsu 9542a9c8c36SMasami Hiramatsu if (pp->lazy_line) 955db0d2c64SMasami Hiramatsu ret = find_probe_point_lazy(in_die, pf); 9562a9c8c36SMasami Hiramatsu else { 957e92b85e1SMasami Hiramatsu /* Get probe address */ 958b55a87adSMasami Hiramatsu if (dwarf_entrypc(in_die, &addr) != 0) { 9590e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s.\n", 960b55a87adSMasami Hiramatsu dwarf_diename(in_die)); 961db0d2c64SMasami Hiramatsu return -ENOENT; 962b55a87adSMasami Hiramatsu } 9630ad45b33SMasami Hiramatsu if (addr == 0) { 9640ad45b33SMasami Hiramatsu pr_debug("%s has no valid entry address. skipped.\n", 9650ad45b33SMasami Hiramatsu dwarf_diename(in_die)); 9660ad45b33SMasami Hiramatsu return -ENOENT; 9670ad45b33SMasami Hiramatsu } 968b55a87adSMasami Hiramatsu pf->addr = addr; 969e92b85e1SMasami Hiramatsu pf->addr += pp->offset; 9702a9c8c36SMasami Hiramatsu pr_debug("found inline addr: 0x%jx\n", 9712a9c8c36SMasami Hiramatsu (uintmax_t)pf->addr); 972e92b85e1SMasami Hiramatsu 973db0d2c64SMasami Hiramatsu ret = call_probe_finder(in_die, pf); 9742a9c8c36SMasami Hiramatsu } 9752a9c8c36SMasami Hiramatsu 976db0d2c64SMasami Hiramatsu return ret; 977e92b85e1SMasami Hiramatsu } 978e92b85e1SMasami Hiramatsu 979db0d2c64SMasami Hiramatsu /* Callback parameter with return value for libdw */ 980db0d2c64SMasami Hiramatsu struct dwarf_callback_param { 981db0d2c64SMasami Hiramatsu void *data; 982db0d2c64SMasami Hiramatsu int retval; 983db0d2c64SMasami Hiramatsu }; 984db0d2c64SMasami Hiramatsu 985e92b85e1SMasami Hiramatsu /* Search function from function name */ 986e92b85e1SMasami Hiramatsu static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 987e92b85e1SMasami Hiramatsu { 988b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 989b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 9904235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 991e92b85e1SMasami Hiramatsu 992e92b85e1SMasami Hiramatsu /* Check tag and diename */ 9930dbb1cacSMasami Hiramatsu if (!die_is_func_def(sp_die) || 9944c859351SMasami Hiramatsu !die_match_name(sp_die, pp->function)) 995b55a87adSMasami Hiramatsu return DWARF_CB_OK; 996e92b85e1SMasami Hiramatsu 9977d21635aSMasami Hiramatsu /* Check declared file */ 9987d21635aSMasami Hiramatsu if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 9997d21635aSMasami Hiramatsu return DWARF_CB_OK; 10007d21635aSMasami Hiramatsu 1001f8da4b51SMasami Hiramatsu pr_debug("Matched function: %s [%lx]\n", dwarf_diename(sp_die), 1002f8da4b51SMasami Hiramatsu (unsigned long)dwarf_dieoffset(sp_die)); 1003e92b85e1SMasami Hiramatsu pf->fname = dwarf_decl_file(sp_die); 10042a9c8c36SMasami Hiramatsu if (pp->line) { /* Function relative line */ 1005e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &pf->lno); 1006804b3606SMasami Hiramatsu pf->lno += pp->line; 1007b55a87adSMasami Hiramatsu param->retval = find_probe_point_by_line(pf); 1008e1ecbbc3SMasami Hiramatsu } else if (die_is_func_instance(sp_die)) { 1009e1ecbbc3SMasami Hiramatsu /* Instances always have the entry address */ 1010e1ecbbc3SMasami Hiramatsu dwarf_entrypc(sp_die, &pf->addr); 10110ad45b33SMasami Hiramatsu /* But in some case the entry address is 0 */ 10120ad45b33SMasami Hiramatsu if (pf->addr == 0) { 10130ad45b33SMasami Hiramatsu pr_debug("%s has no entry PC. Skipped\n", 10140ad45b33SMasami Hiramatsu dwarf_diename(sp_die)); 10150ad45b33SMasami Hiramatsu param->retval = 0; 1016e92b85e1SMasami Hiramatsu /* Real function */ 10170ad45b33SMasami Hiramatsu } else if (pp->lazy_line) 1018b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(sp_die, pf); 10192a9c8c36SMasami Hiramatsu else { 1020e47392bfSRavi Bangoria skip_prologue(sp_die, pf); 10214ea42b18SMasami Hiramatsu pf->addr += pp->offset; 10224ea42b18SMasami Hiramatsu /* TODO: Check the address in this function */ 1023cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(sp_die, pf); 10242a9c8c36SMasami Hiramatsu } 10254c859351SMasami Hiramatsu } else if (!probe_conf.no_inlines) { 1026e92b85e1SMasami Hiramatsu /* Inlined function: search instances */ 1027db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1028db0d2c64SMasami Hiramatsu probe_point_inline_cb, (void *)pf); 10294c859351SMasami Hiramatsu /* This could be a non-existed inline definition */ 1030f8da4b51SMasami Hiramatsu if (param->retval == -ENOENT) 10314c859351SMasami Hiramatsu param->retval = 0; 10324c859351SMasami Hiramatsu } 10334c859351SMasami Hiramatsu 10344c859351SMasami Hiramatsu /* We need to find other candidates */ 10354c859351SMasami Hiramatsu if (strisglob(pp->function) && param->retval >= 0) { 10364c859351SMasami Hiramatsu param->retval = 0; /* We have to clear the result */ 10374c859351SMasami Hiramatsu return DWARF_CB_OK; 10384c859351SMasami Hiramatsu } 10394ea42b18SMasami Hiramatsu 1040b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1041b55a87adSMasami Hiramatsu } 1042b55a87adSMasami Hiramatsu 1043b55a87adSMasami Hiramatsu static int find_probe_point_by_func(struct probe_finder *pf) 10444ea42b18SMasami Hiramatsu { 1045b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 1046b55a87adSMasami Hiramatsu .retval = 0}; 1047b55a87adSMasami Hiramatsu dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 1048b55a87adSMasami Hiramatsu return _param.retval; 10494ea42b18SMasami Hiramatsu } 10504ea42b18SMasami Hiramatsu 1051cd25f8bcSLin Ming struct pubname_callback_param { 1052cd25f8bcSLin Ming char *function; 1053cd25f8bcSLin Ming char *file; 1054cd25f8bcSLin Ming Dwarf_Die *cu_die; 1055cd25f8bcSLin Ming Dwarf_Die *sp_die; 1056cd25f8bcSLin Ming int found; 1057cd25f8bcSLin Ming }; 1058cd25f8bcSLin Ming 1059cd25f8bcSLin Ming static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 1060cd25f8bcSLin Ming { 1061cd25f8bcSLin Ming struct pubname_callback_param *param = data; 1062cd25f8bcSLin Ming 1063cd25f8bcSLin Ming if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1064cd25f8bcSLin Ming if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1065cd25f8bcSLin Ming return DWARF_CB_OK; 1066cd25f8bcSLin Ming 10674c859351SMasami Hiramatsu if (die_match_name(param->sp_die, param->function)) { 1068cd25f8bcSLin Ming if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1069cd25f8bcSLin Ming return DWARF_CB_OK; 1070cd25f8bcSLin Ming 1071cd25f8bcSLin Ming if (param->file && 1072cd25f8bcSLin Ming strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1073cd25f8bcSLin Ming return DWARF_CB_OK; 1074cd25f8bcSLin Ming 1075cd25f8bcSLin Ming param->found = 1; 1076cd25f8bcSLin Ming return DWARF_CB_ABORT; 1077cd25f8bcSLin Ming } 1078cd25f8bcSLin Ming } 1079cd25f8bcSLin Ming 1080cd25f8bcSLin Ming return DWARF_CB_OK; 1081cd25f8bcSLin Ming } 1082cd25f8bcSLin Ming 1083270bde1eSHemant Kumar static int debuginfo__find_probe_location(struct debuginfo *dbg, 1084ff741783SMasami Hiramatsu struct probe_finder *pf) 10854ea42b18SMasami Hiramatsu { 1086cf6eb489SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1087804b3606SMasami Hiramatsu Dwarf_Off off, noff; 1088804b3606SMasami Hiramatsu size_t cuhl; 1089804b3606SMasami Hiramatsu Dwarf_Die *diep; 1090b55a87adSMasami Hiramatsu int ret = 0; 10914ea42b18SMasami Hiramatsu 1092804b3606SMasami Hiramatsu off = 0; 10935a62257aSMasami Hiramatsu pf->lcache = intlist__new(NULL); 10945a62257aSMasami Hiramatsu if (!pf->lcache) 10955a62257aSMasami Hiramatsu return -ENOMEM; 1096cd25f8bcSLin Ming 1097cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 10984c859351SMasami Hiramatsu if (pp->function && !strisglob(pp->function)) { 1099cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1100cd25f8bcSLin Ming .function = pp->function, 1101cd25f8bcSLin Ming .file = pp->file, 1102cd25f8bcSLin Ming .cu_die = &pf->cu_die, 1103cd25f8bcSLin Ming .sp_die = &pf->sp_die, 11042b348a77SLin Ming .found = 0, 1105cd25f8bcSLin Ming }; 1106cd25f8bcSLin Ming struct dwarf_callback_param probe_param = { 1107cd25f8bcSLin Ming .data = pf, 1108cd25f8bcSLin Ming }; 1109cd25f8bcSLin Ming 1110316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1111ff741783SMasami Hiramatsu &pubname_param, 0); 1112cd25f8bcSLin Ming if (pubname_param.found) { 1113cd25f8bcSLin Ming ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1114cd25f8bcSLin Ming if (ret) 1115cd25f8bcSLin Ming goto found; 1116cd25f8bcSLin Ming } 1117cd25f8bcSLin Ming } 1118cd25f8bcSLin Ming 1119804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1120316c7136SArnaldo Carvalho de Melo while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 11214ea42b18SMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1122316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die); 1123804b3606SMasami Hiramatsu if (!diep) 1124804b3606SMasami Hiramatsu continue; 11254ea42b18SMasami Hiramatsu 11264ea42b18SMasami Hiramatsu /* Check if target file is included. */ 11274ea42b18SMasami Hiramatsu if (pp->file) 1128cf6eb489SMasami Hiramatsu pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1129804b3606SMasami Hiramatsu else 1130cf6eb489SMasami Hiramatsu pf->fname = NULL; 11314ea42b18SMasami Hiramatsu 1132cf6eb489SMasami Hiramatsu if (!pp->file || pf->fname) { 11334ea42b18SMasami Hiramatsu if (pp->function) 1134cf6eb489SMasami Hiramatsu ret = find_probe_point_by_func(pf); 11352a9c8c36SMasami Hiramatsu else if (pp->lazy_line) 1136f19e80c6SHe Kuang ret = find_probe_point_lazy(&pf->cu_die, pf); 1137b0ef0732SMasami Hiramatsu else { 1138cf6eb489SMasami Hiramatsu pf->lno = pp->line; 1139cf6eb489SMasami Hiramatsu ret = find_probe_point_by_line(pf); 11404ea42b18SMasami Hiramatsu } 11418635bf6eSArnaldo Carvalho de Melo if (ret < 0) 1142fbee632dSArnaldo Carvalho de Melo break; 1143b0ef0732SMasami Hiramatsu } 1144804b3606SMasami Hiramatsu off = noff; 11454ea42b18SMasami Hiramatsu } 1146cd25f8bcSLin Ming 1147cd25f8bcSLin Ming found: 11485a62257aSMasami Hiramatsu intlist__delete(pf->lcache); 11495a62257aSMasami Hiramatsu pf->lcache = NULL; 11504ea42b18SMasami Hiramatsu 1151cf6eb489SMasami Hiramatsu return ret; 1152cf6eb489SMasami Hiramatsu } 1153cf6eb489SMasami Hiramatsu 1154270bde1eSHemant Kumar /* Find probe points from debuginfo */ 1155270bde1eSHemant Kumar static int debuginfo__find_probes(struct debuginfo *dbg, 1156270bde1eSHemant Kumar struct probe_finder *pf) 1157270bde1eSHemant Kumar { 1158270bde1eSHemant Kumar int ret = 0; 1159270bde1eSHemant Kumar Elf *elf; 1160270bde1eSHemant Kumar GElf_Ehdr ehdr; 1161270bde1eSHemant Kumar 1162270bde1eSHemant Kumar if (pf->cfi_eh || pf->cfi_dbg) 1163270bde1eSHemant Kumar return debuginfo__find_probe_location(dbg, pf); 1164270bde1eSHemant Kumar 1165270bde1eSHemant Kumar /* Get the call frame information from this dwarf */ 1166270bde1eSHemant Kumar elf = dwarf_getelf(dbg->dbg); 1167270bde1eSHemant Kumar if (elf == NULL) 1168270bde1eSHemant Kumar return -EINVAL; 1169270bde1eSHemant Kumar 1170270bde1eSHemant Kumar if (gelf_getehdr(elf, &ehdr) == NULL) 1171270bde1eSHemant Kumar return -EINVAL; 1172270bde1eSHemant Kumar 1173293d5b43SMasami Hiramatsu pf->machine = ehdr.e_machine; 1174293d5b43SMasami Hiramatsu 1175293d5b43SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 1176293d5b43SMasami Hiramatsu do { 1177293d5b43SMasami Hiramatsu GElf_Shdr shdr; 1178293d5b43SMasami Hiramatsu 1179270bde1eSHemant Kumar if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && 1180270bde1eSHemant Kumar shdr.sh_type == SHT_PROGBITS) 1181270bde1eSHemant Kumar pf->cfi_eh = dwarf_getcfi_elf(elf); 1182270bde1eSHemant Kumar 1183270bde1eSHemant Kumar pf->cfi_dbg = dwarf_getcfi(dbg->dbg); 1184293d5b43SMasami Hiramatsu } while (0); 1185270bde1eSHemant Kumar #endif 1186270bde1eSHemant Kumar 1187270bde1eSHemant Kumar ret = debuginfo__find_probe_location(dbg, pf); 1188270bde1eSHemant Kumar return ret; 1189270bde1eSHemant Kumar } 1190270bde1eSHemant Kumar 11917969ec77SMasami Hiramatsu struct local_vars_finder { 11927969ec77SMasami Hiramatsu struct probe_finder *pf; 11937969ec77SMasami Hiramatsu struct perf_probe_arg *args; 1194f8bffbf1SMasami Hiramatsu bool vars; 11957969ec77SMasami Hiramatsu int max_args; 11967969ec77SMasami Hiramatsu int nargs; 11977969ec77SMasami Hiramatsu int ret; 11987969ec77SMasami Hiramatsu }; 11997969ec77SMasami Hiramatsu 12007969ec77SMasami Hiramatsu /* Collect available variables in this scope */ 12017969ec77SMasami Hiramatsu static int copy_variables_cb(Dwarf_Die *die_mem, void *data) 12027969ec77SMasami Hiramatsu { 12037969ec77SMasami Hiramatsu struct local_vars_finder *vf = data; 12043d918a12SMasami Hiramatsu struct probe_finder *pf = vf->pf; 12057969ec77SMasami Hiramatsu int tag; 12067969ec77SMasami Hiramatsu 12077969ec77SMasami Hiramatsu tag = dwarf_tag(die_mem); 12087969ec77SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1209f8bffbf1SMasami Hiramatsu (tag == DW_TAG_variable && vf->vars)) { 12107969ec77SMasami Hiramatsu if (convert_variable_location(die_mem, vf->pf->addr, 12113d918a12SMasami Hiramatsu vf->pf->fb_ops, &pf->sp_die, 1212293d5b43SMasami Hiramatsu pf->machine, NULL) == 0) { 12137969ec77SMasami Hiramatsu vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); 12147969ec77SMasami Hiramatsu if (vf->args[vf->nargs].var == NULL) { 12157969ec77SMasami Hiramatsu vf->ret = -ENOMEM; 12167969ec77SMasami Hiramatsu return DIE_FIND_CB_END; 12177969ec77SMasami Hiramatsu } 12187969ec77SMasami Hiramatsu pr_debug(" %s", vf->args[vf->nargs].var); 12197969ec77SMasami Hiramatsu vf->nargs++; 12207969ec77SMasami Hiramatsu } 12217969ec77SMasami Hiramatsu } 12227969ec77SMasami Hiramatsu 12237969ec77SMasami Hiramatsu if (dwarf_haspc(die_mem, vf->pf->addr)) 12247969ec77SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 12257969ec77SMasami Hiramatsu else 12267969ec77SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 12277969ec77SMasami Hiramatsu } 12287969ec77SMasami Hiramatsu 12297969ec77SMasami Hiramatsu static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, 12307969ec77SMasami Hiramatsu struct perf_probe_arg *args) 12317969ec77SMasami Hiramatsu { 12327969ec77SMasami Hiramatsu Dwarf_Die die_mem; 12337969ec77SMasami Hiramatsu int i; 12347969ec77SMasami Hiramatsu int n = 0; 1235f8bffbf1SMasami Hiramatsu struct local_vars_finder vf = {.pf = pf, .args = args, .vars = false, 12367969ec77SMasami Hiramatsu .max_args = MAX_PROBE_ARGS, .ret = 0}; 12377969ec77SMasami Hiramatsu 12387969ec77SMasami Hiramatsu for (i = 0; i < pf->pev->nargs; i++) { 12397969ec77SMasami Hiramatsu /* var never be NULL */ 1240f8bffbf1SMasami Hiramatsu if (strcmp(pf->pev->args[i].var, PROBE_ARG_VARS) == 0) 1241f8bffbf1SMasami Hiramatsu vf.vars = true; 1242f8bffbf1SMasami Hiramatsu else if (strcmp(pf->pev->args[i].var, PROBE_ARG_PARAMS) != 0) { 1243f8bffbf1SMasami Hiramatsu /* Copy normal argument */ 1244f8bffbf1SMasami Hiramatsu args[n] = pf->pev->args[i]; 1245f8bffbf1SMasami Hiramatsu n++; 1246f8bffbf1SMasami Hiramatsu continue; 1247f8bffbf1SMasami Hiramatsu } 1248f8bffbf1SMasami Hiramatsu pr_debug("Expanding %s into:", pf->pev->args[i].var); 12497969ec77SMasami Hiramatsu vf.nargs = n; 12507969ec77SMasami Hiramatsu /* Special local variables */ 12517969ec77SMasami Hiramatsu die_find_child(sc_die, copy_variables_cb, (void *)&vf, 12527969ec77SMasami Hiramatsu &die_mem); 12537969ec77SMasami Hiramatsu pr_debug(" (%d)\n", vf.nargs - n); 12547969ec77SMasami Hiramatsu if (vf.ret < 0) 12557969ec77SMasami Hiramatsu return vf.ret; 12567969ec77SMasami Hiramatsu n = vf.nargs; 12577969ec77SMasami Hiramatsu } 12587969ec77SMasami Hiramatsu return n; 12597969ec77SMasami Hiramatsu } 12607969ec77SMasami Hiramatsu 1261cf6eb489SMasami Hiramatsu /* Add a found probe point into trace event list */ 1262221d0611SMasami Hiramatsu static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1263cf6eb489SMasami Hiramatsu { 1264cf6eb489SMasami Hiramatsu struct trace_event_finder *tf = 1265cf6eb489SMasami Hiramatsu container_of(pf, struct trace_event_finder, pf); 12666cca13bdSMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1267cf6eb489SMasami Hiramatsu struct probe_trace_event *tev; 1268092b1f0bSWang Nan struct perf_probe_arg *args = NULL; 1269cf6eb489SMasami Hiramatsu int ret, i; 1270cf6eb489SMasami Hiramatsu 1271cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1272cf6eb489SMasami Hiramatsu if (tf->ntevs == tf->max_tevs) { 1273cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", 1274cf6eb489SMasami Hiramatsu tf->max_tevs); 1275cf6eb489SMasami Hiramatsu return -ERANGE; 1276cf6eb489SMasami Hiramatsu } 1277cf6eb489SMasami Hiramatsu tev = &tf->tevs[tf->ntevs++]; 1278cf6eb489SMasami Hiramatsu 1279221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1280576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 12816cca13bdSMasami Hiramatsu pp->retprobe, pp->function, &tev->point); 1282cf6eb489SMasami Hiramatsu if (ret < 0) 1283092b1f0bSWang Nan goto end; 1284cf6eb489SMasami Hiramatsu 12854c859351SMasami Hiramatsu tev->point.realname = strdup(dwarf_diename(sc_die)); 1286092b1f0bSWang Nan if (!tev->point.realname) { 1287092b1f0bSWang Nan ret = -ENOMEM; 1288092b1f0bSWang Nan goto end; 1289092b1f0bSWang Nan } 12904c859351SMasami Hiramatsu 1291cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1292cf6eb489SMasami Hiramatsu tev->point.offset); 1293cf6eb489SMasami Hiramatsu 12947969ec77SMasami Hiramatsu /* Expand special probe argument if exist */ 12957969ec77SMasami Hiramatsu args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); 1296092b1f0bSWang Nan if (args == NULL) { 1297092b1f0bSWang Nan ret = -ENOMEM; 1298092b1f0bSWang Nan goto end; 1299092b1f0bSWang Nan } 13007969ec77SMasami Hiramatsu 13017969ec77SMasami Hiramatsu ret = expand_probe_args(sc_die, pf, args); 13027969ec77SMasami Hiramatsu if (ret < 0) 13037969ec77SMasami Hiramatsu goto end; 13047969ec77SMasami Hiramatsu 13057969ec77SMasami Hiramatsu tev->nargs = ret; 13067969ec77SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 13077969ec77SMasami Hiramatsu if (tev->args == NULL) { 13087969ec77SMasami Hiramatsu ret = -ENOMEM; 13097969ec77SMasami Hiramatsu goto end; 13107969ec77SMasami Hiramatsu } 13117969ec77SMasami Hiramatsu 13127969ec77SMasami Hiramatsu /* Find each argument */ 13137969ec77SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 13147969ec77SMasami Hiramatsu pf->pvar = &args[i]; 1315cf6eb489SMasami Hiramatsu pf->tvar = &tev->args[i]; 1316221d0611SMasami Hiramatsu /* Variable should be found from scope DIE */ 1317221d0611SMasami Hiramatsu ret = find_variable(sc_die, pf); 1318cf6eb489SMasami Hiramatsu if (ret != 0) 13197969ec77SMasami Hiramatsu break; 1320cf6eb489SMasami Hiramatsu } 1321cf6eb489SMasami Hiramatsu 13227969ec77SMasami Hiramatsu end: 1323092b1f0bSWang Nan if (ret) { 1324092b1f0bSWang Nan clear_probe_trace_event(tev); 1325092b1f0bSWang Nan tf->ntevs--; 1326092b1f0bSWang Nan } 13277969ec77SMasami Hiramatsu free(args); 13287969ec77SMasami Hiramatsu return ret; 1329cf6eb489SMasami Hiramatsu } 1330cf6eb489SMasami Hiramatsu 1331cf6eb489SMasami Hiramatsu /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1332316c7136SArnaldo Carvalho de Melo int debuginfo__find_trace_events(struct debuginfo *dbg, 1333ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1334ddb2f58fSMasami Hiramatsu struct probe_trace_event **tevs) 1335cf6eb489SMasami Hiramatsu { 1336cf6eb489SMasami Hiramatsu struct trace_event_finder tf = { 1337cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_probe_trace_event}, 1338ddb2f58fSMasami Hiramatsu .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; 13390196e787SMasami Hiramatsu int ret, i; 1340cf6eb489SMasami Hiramatsu 1341cf6eb489SMasami Hiramatsu /* Allocate result tevs array */ 1342ddb2f58fSMasami Hiramatsu *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); 1343cf6eb489SMasami Hiramatsu if (*tevs == NULL) 1344cf6eb489SMasami Hiramatsu return -ENOMEM; 1345cf6eb489SMasami Hiramatsu 1346cf6eb489SMasami Hiramatsu tf.tevs = *tevs; 1347cf6eb489SMasami Hiramatsu tf.ntevs = 0; 1348cf6eb489SMasami Hiramatsu 1349316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &tf.pf); 1350cf6eb489SMasami Hiramatsu if (ret < 0) { 13510196e787SMasami Hiramatsu for (i = 0; i < tf.ntevs; i++) 13520196e787SMasami Hiramatsu clear_probe_trace_event(&tf.tevs[i]); 135304662523SArnaldo Carvalho de Melo zfree(tevs); 1354cf6eb489SMasami Hiramatsu return ret; 1355cf6eb489SMasami Hiramatsu } 1356cf6eb489SMasami Hiramatsu 1357cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : tf.ntevs; 1358cf6eb489SMasami Hiramatsu } 1359cf6eb489SMasami Hiramatsu 1360cf6eb489SMasami Hiramatsu /* Collect available variables in this scope */ 1361cf6eb489SMasami Hiramatsu static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1362cf6eb489SMasami Hiramatsu { 1363cf6eb489SMasami Hiramatsu struct available_var_finder *af = data; 1364cf6eb489SMasami Hiramatsu struct variable_list *vl; 1365bf4d5f25SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1366cf6eb489SMasami Hiramatsu int tag, ret; 1367cf6eb489SMasami Hiramatsu 1368cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls - 1]; 1369cf6eb489SMasami Hiramatsu 1370cf6eb489SMasami Hiramatsu tag = dwarf_tag(die_mem); 1371cf6eb489SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1372cf6eb489SMasami Hiramatsu tag == DW_TAG_variable) { 1373cf6eb489SMasami Hiramatsu ret = convert_variable_location(die_mem, af->pf.addr, 13743d918a12SMasami Hiramatsu af->pf.fb_ops, &af->pf.sp_die, 1375293d5b43SMasami Hiramatsu af->pf.machine, NULL); 1376349e8d26SHe Kuang if (ret == 0 || ret == -ERANGE) { 1377349e8d26SHe Kuang int ret2; 1378349e8d26SHe Kuang bool externs = !af->child; 1379fb9596d1SHe Kuang 1380bf4d5f25SMasami Hiramatsu if (strbuf_init(&buf, 64) < 0) 1381bf4d5f25SMasami Hiramatsu goto error; 1382349e8d26SHe Kuang 1383349e8d26SHe Kuang if (probe_conf.show_location_range) { 1384bf4d5f25SMasami Hiramatsu if (!externs) 1385bf4d5f25SMasami Hiramatsu ret2 = strbuf_add(&buf, 1386bf4d5f25SMasami Hiramatsu ret ? "[INV]\t" : "[VAL]\t", 6); 1387349e8d26SHe Kuang else 1388bf4d5f25SMasami Hiramatsu ret2 = strbuf_add(&buf, "[EXT]\t", 6); 1389bf4d5f25SMasami Hiramatsu if (ret2) 1390bf4d5f25SMasami Hiramatsu goto error; 1391349e8d26SHe Kuang } 1392349e8d26SHe Kuang 1393349e8d26SHe Kuang ret2 = die_get_varname(die_mem, &buf); 1394349e8d26SHe Kuang 1395349e8d26SHe Kuang if (!ret2 && probe_conf.show_location_range && 1396349e8d26SHe Kuang !externs) { 1397bf4d5f25SMasami Hiramatsu if (strbuf_addch(&buf, '\t') < 0) 1398bf4d5f25SMasami Hiramatsu goto error; 1399349e8d26SHe Kuang ret2 = die_get_var_range(&af->pf.sp_die, 1400349e8d26SHe Kuang die_mem, &buf); 1401349e8d26SHe Kuang } 1402349e8d26SHe Kuang 1403349e8d26SHe Kuang pr_debug("Add new var: %s\n", buf.buf); 1404349e8d26SHe Kuang if (ret2 == 0) { 1405fb9596d1SHe Kuang strlist__add(vl->vars, 1406fb9596d1SHe Kuang strbuf_detach(&buf, NULL)); 1407bf4d5f25SMasami Hiramatsu } 1408fb9596d1SHe Kuang strbuf_release(&buf); 1409cf6eb489SMasami Hiramatsu } 1410cf6eb489SMasami Hiramatsu } 1411cf6eb489SMasami Hiramatsu 1412fb8c5a56SMasami Hiramatsu if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1413cf6eb489SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 1414cf6eb489SMasami Hiramatsu else 1415cf6eb489SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 1416bf4d5f25SMasami Hiramatsu error: 1417bf4d5f25SMasami Hiramatsu strbuf_release(&buf); 1418bf4d5f25SMasami Hiramatsu pr_debug("Error in strbuf\n"); 1419bf4d5f25SMasami Hiramatsu return DIE_FIND_CB_END; 1420cf6eb489SMasami Hiramatsu } 1421cf6eb489SMasami Hiramatsu 1422cf6eb489SMasami Hiramatsu /* Add a found vars into available variables list */ 1423221d0611SMasami Hiramatsu static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1424cf6eb489SMasami Hiramatsu { 1425cf6eb489SMasami Hiramatsu struct available_var_finder *af = 1426cf6eb489SMasami Hiramatsu container_of(pf, struct available_var_finder, pf); 14276cca13bdSMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1428cf6eb489SMasami Hiramatsu struct variable_list *vl; 1429f182e3e1SMasami Hiramatsu Dwarf_Die die_mem; 1430f182e3e1SMasami Hiramatsu int ret; 1431cf6eb489SMasami Hiramatsu 1432cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1433cf6eb489SMasami Hiramatsu if (af->nvls == af->max_vls) { 1434cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1435cf6eb489SMasami Hiramatsu return -ERANGE; 1436cf6eb489SMasami Hiramatsu } 1437cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls++]; 1438cf6eb489SMasami Hiramatsu 1439221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1440576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, 14416cca13bdSMasami Hiramatsu pp->retprobe, pp->function, &vl->point); 1442cf6eb489SMasami Hiramatsu if (ret < 0) 1443cf6eb489SMasami Hiramatsu return ret; 1444cf6eb489SMasami Hiramatsu 1445cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1446cf6eb489SMasami Hiramatsu vl->point.offset); 1447cf6eb489SMasami Hiramatsu 1448cf6eb489SMasami Hiramatsu /* Find local variables */ 14494a77e218SArnaldo Carvalho de Melo vl->vars = strlist__new(NULL, NULL); 1450cf6eb489SMasami Hiramatsu if (vl->vars == NULL) 1451cf6eb489SMasami Hiramatsu return -ENOMEM; 1452fb8c5a56SMasami Hiramatsu af->child = true; 1453221d0611SMasami Hiramatsu die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1454cf6eb489SMasami Hiramatsu 1455fb8c5a56SMasami Hiramatsu /* Find external variables */ 1456ddb2f58fSMasami Hiramatsu if (!probe_conf.show_ext_vars) 1457fb8c5a56SMasami Hiramatsu goto out; 1458ddb2f58fSMasami Hiramatsu /* Don't need to search child DIE for external vars. */ 1459fb8c5a56SMasami Hiramatsu af->child = false; 1460f182e3e1SMasami Hiramatsu die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1461fb8c5a56SMasami Hiramatsu 1462fb8c5a56SMasami Hiramatsu out: 1463cf6eb489SMasami Hiramatsu if (strlist__empty(vl->vars)) { 1464cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 1465cf6eb489SMasami Hiramatsu vl->vars = NULL; 1466cf6eb489SMasami Hiramatsu } 1467cf6eb489SMasami Hiramatsu 1468cf6eb489SMasami Hiramatsu return ret; 1469cf6eb489SMasami Hiramatsu } 1470cf6eb489SMasami Hiramatsu 147169e96eaaSMasami Hiramatsu /* 147269e96eaaSMasami Hiramatsu * Find available variables at given probe point 147369e96eaaSMasami Hiramatsu * Return the number of found probe points. Return 0 if there is no 147469e96eaaSMasami Hiramatsu * matched probe point. Return <0 if an error occurs. 147569e96eaaSMasami Hiramatsu */ 1476316c7136SArnaldo Carvalho de Melo int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1477ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1478ddb2f58fSMasami Hiramatsu struct variable_list **vls) 1479cf6eb489SMasami Hiramatsu { 1480cf6eb489SMasami Hiramatsu struct available_var_finder af = { 1481cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_available_vars}, 1482316c7136SArnaldo Carvalho de Melo .mod = dbg->mod, 1483ddb2f58fSMasami Hiramatsu .max_vls = probe_conf.max_probes}; 1484cf6eb489SMasami Hiramatsu int ret; 1485cf6eb489SMasami Hiramatsu 1486cf6eb489SMasami Hiramatsu /* Allocate result vls array */ 1487ddb2f58fSMasami Hiramatsu *vls = zalloc(sizeof(struct variable_list) * af.max_vls); 1488cf6eb489SMasami Hiramatsu if (*vls == NULL) 1489cf6eb489SMasami Hiramatsu return -ENOMEM; 1490cf6eb489SMasami Hiramatsu 1491cf6eb489SMasami Hiramatsu af.vls = *vls; 1492cf6eb489SMasami Hiramatsu af.nvls = 0; 1493cf6eb489SMasami Hiramatsu 1494316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &af.pf); 1495cf6eb489SMasami Hiramatsu if (ret < 0) { 1496cf6eb489SMasami Hiramatsu /* Free vlist for error */ 1497cf6eb489SMasami Hiramatsu while (af.nvls--) { 149874cf249dSArnaldo Carvalho de Melo zfree(&af.vls[af.nvls].point.symbol); 1499cf6eb489SMasami Hiramatsu strlist__delete(af.vls[af.nvls].vars); 1500cf6eb489SMasami Hiramatsu } 150104662523SArnaldo Carvalho de Melo zfree(vls); 1502cf6eb489SMasami Hiramatsu return ret; 1503cf6eb489SMasami Hiramatsu } 1504cf6eb489SMasami Hiramatsu 1505cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : af.nvls; 15064ea42b18SMasami Hiramatsu } 15074ea42b18SMasami Hiramatsu 15089b239a12SMasami Hiramatsu /* For the kernel module, we need a special code to get a DIE */ 1509613f050dSMasami Hiramatsu int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, 1510613f050dSMasami Hiramatsu bool adjust_offset) 15119b239a12SMasami Hiramatsu { 15129b239a12SMasami Hiramatsu int n, i; 15139b239a12SMasami Hiramatsu Elf32_Word shndx; 15149b239a12SMasami Hiramatsu Elf_Scn *scn; 15159b239a12SMasami Hiramatsu Elf *elf; 15169b239a12SMasami Hiramatsu GElf_Shdr mem, *shdr; 15179b239a12SMasami Hiramatsu const char *p; 15189b239a12SMasami Hiramatsu 15199b239a12SMasami Hiramatsu elf = dwfl_module_getelf(dbg->mod, &dbg->bias); 15209b239a12SMasami Hiramatsu if (!elf) 15219b239a12SMasami Hiramatsu return -EINVAL; 15229b239a12SMasami Hiramatsu 15239b239a12SMasami Hiramatsu /* Get the number of relocations */ 15249b239a12SMasami Hiramatsu n = dwfl_module_relocations(dbg->mod); 15259b239a12SMasami Hiramatsu if (n < 0) 15269b239a12SMasami Hiramatsu return -ENOENT; 15279b239a12SMasami Hiramatsu /* Search the relocation related .text section */ 15289b239a12SMasami Hiramatsu for (i = 0; i < n; i++) { 15299b239a12SMasami Hiramatsu p = dwfl_module_relocation_info(dbg->mod, i, &shndx); 15309b239a12SMasami Hiramatsu if (strcmp(p, ".text") == 0) { 15319b239a12SMasami Hiramatsu /* OK, get the section header */ 15329b239a12SMasami Hiramatsu scn = elf_getscn(elf, shndx); 15339b239a12SMasami Hiramatsu if (!scn) 15349b239a12SMasami Hiramatsu return -ENOENT; 15359b239a12SMasami Hiramatsu shdr = gelf_getshdr(scn, &mem); 15369b239a12SMasami Hiramatsu if (!shdr) 15379b239a12SMasami Hiramatsu return -ENOENT; 15389b239a12SMasami Hiramatsu *offs = shdr->sh_addr; 1539613f050dSMasami Hiramatsu if (adjust_offset) 1540613f050dSMasami Hiramatsu *offs -= shdr->sh_offset; 15419b239a12SMasami Hiramatsu } 15429b239a12SMasami Hiramatsu } 15439b239a12SMasami Hiramatsu return 0; 15449b239a12SMasami Hiramatsu } 15459b239a12SMasami Hiramatsu 1546fb1587d8SMasami Hiramatsu /* Reverse search */ 1547316c7136SArnaldo Carvalho de Melo int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, 1548ff741783SMasami Hiramatsu struct perf_probe_point *ppt) 1549fb1587d8SMasami Hiramatsu { 1550fb1587d8SMasami Hiramatsu Dwarf_Die cudie, spdie, indie; 1551e08cfd4bSMasami Hiramatsu Dwarf_Addr _addr = 0, baseaddr = 0; 1552e08cfd4bSMasami Hiramatsu const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; 15531d46ea2aSMasami Hiramatsu int baseline = 0, lineno = 0, ret = 0; 1554fb1587d8SMasami Hiramatsu 1555d2d4edbeSMasami Hiramatsu /* We always need to relocate the address for aranges */ 1556613f050dSMasami Hiramatsu if (debuginfo__get_text_offset(dbg, &baseaddr, false) == 0) 1557d2d4edbeSMasami Hiramatsu addr += baseaddr; 1558fb1587d8SMasami Hiramatsu /* Find cu die */ 15590104fe69SMasami Hiramatsu if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { 15600e43e5d2SMasami Hiramatsu pr_warning("Failed to find debug information for address %lx\n", 15610e43e5d2SMasami Hiramatsu addr); 156275ec5a24SMasami Hiramatsu ret = -EINVAL; 156375ec5a24SMasami Hiramatsu goto end; 156475ec5a24SMasami Hiramatsu } 1565fb1587d8SMasami Hiramatsu 15661d46ea2aSMasami Hiramatsu /* Find a corresponding line (filename and lineno) */ 15671d46ea2aSMasami Hiramatsu cu_find_lineinfo(&cudie, addr, &fname, &lineno); 15681d46ea2aSMasami Hiramatsu /* Don't care whether it failed or not */ 1569fb1587d8SMasami Hiramatsu 15701d46ea2aSMasami Hiramatsu /* Find a corresponding function (name, baseline and baseaddr) */ 1571e0d153c6SMasami Hiramatsu if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 15721d46ea2aSMasami Hiramatsu /* Get function entry information */ 1573e08cfd4bSMasami Hiramatsu func = basefunc = dwarf_diename(&spdie); 1574e08cfd4bSMasami Hiramatsu if (!func || 15751d46ea2aSMasami Hiramatsu dwarf_entrypc(&spdie, &baseaddr) != 0 || 1576e08cfd4bSMasami Hiramatsu dwarf_decl_line(&spdie, &baseline) != 0) { 1577e08cfd4bSMasami Hiramatsu lineno = 0; 15781d46ea2aSMasami Hiramatsu goto post; 1579e08cfd4bSMasami Hiramatsu } 1580fb1587d8SMasami Hiramatsu 15811b286bddSMasami Hiramatsu fname = dwarf_decl_file(&spdie); 1582e08cfd4bSMasami Hiramatsu if (addr == (unsigned long)baseaddr) { 15831d46ea2aSMasami Hiramatsu /* Function entry - Relative line number is 0 */ 15841d46ea2aSMasami Hiramatsu lineno = baseline; 1585e08cfd4bSMasami Hiramatsu goto post; 1586e08cfd4bSMasami Hiramatsu } 1587e08cfd4bSMasami Hiramatsu 1588e08cfd4bSMasami Hiramatsu /* Track down the inline functions step by step */ 1589e08cfd4bSMasami Hiramatsu while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, 1590b55a87adSMasami Hiramatsu &indie)) { 1591e08cfd4bSMasami Hiramatsu /* There is an inline function */ 15921d46ea2aSMasami Hiramatsu if (dwarf_entrypc(&indie, &_addr) == 0 && 1593e08cfd4bSMasami Hiramatsu _addr == addr) { 15941d46ea2aSMasami Hiramatsu /* 15951d46ea2aSMasami Hiramatsu * addr is at an inline function entry. 15961d46ea2aSMasami Hiramatsu * In this case, lineno should be the call-site 1597e08cfd4bSMasami Hiramatsu * line number. (overwrite lineinfo) 15981d46ea2aSMasami Hiramatsu */ 15991d46ea2aSMasami Hiramatsu lineno = die_get_call_lineno(&indie); 1600e08cfd4bSMasami Hiramatsu fname = die_get_call_file(&indie); 1601e08cfd4bSMasami Hiramatsu break; 1602e08cfd4bSMasami Hiramatsu } else { 16031d46ea2aSMasami Hiramatsu /* 16041d46ea2aSMasami Hiramatsu * addr is in an inline function body. 16051d46ea2aSMasami Hiramatsu * Since lineno points one of the lines 16061d46ea2aSMasami Hiramatsu * of the inline function, baseline should 16071d46ea2aSMasami Hiramatsu * be the entry line of the inline function. 16081d46ea2aSMasami Hiramatsu */ 1609fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&indie); 1610e08cfd4bSMasami Hiramatsu if (!tmp || 1611e08cfd4bSMasami Hiramatsu dwarf_decl_line(&indie, &baseline) != 0) 1612e08cfd4bSMasami Hiramatsu break; 16131d46ea2aSMasami Hiramatsu func = tmp; 1614e08cfd4bSMasami Hiramatsu spdie = indie; 1615b55a87adSMasami Hiramatsu } 1616b55a87adSMasami Hiramatsu } 1617e08cfd4bSMasami Hiramatsu /* Verify the lineno and baseline are in a same file */ 1618e08cfd4bSMasami Hiramatsu tmp = dwarf_decl_file(&spdie); 1619e08cfd4bSMasami Hiramatsu if (!tmp || strcmp(tmp, fname) != 0) 1620e08cfd4bSMasami Hiramatsu lineno = 0; 16211d46ea2aSMasami Hiramatsu } 16221d46ea2aSMasami Hiramatsu 16231d46ea2aSMasami Hiramatsu post: 16241d46ea2aSMasami Hiramatsu /* Make a relative line number or an offset */ 16251d46ea2aSMasami Hiramatsu if (lineno) 16261d46ea2aSMasami Hiramatsu ppt->line = lineno - baseline; 1627e08cfd4bSMasami Hiramatsu else if (basefunc) { 16281d46ea2aSMasami Hiramatsu ppt->offset = addr - (unsigned long)baseaddr; 1629e08cfd4bSMasami Hiramatsu func = basefunc; 1630e08cfd4bSMasami Hiramatsu } 16311d46ea2aSMasami Hiramatsu 16321d46ea2aSMasami Hiramatsu /* Duplicate strings */ 16331d46ea2aSMasami Hiramatsu if (func) { 16341d46ea2aSMasami Hiramatsu ppt->function = strdup(func); 163502b95dadSMasami Hiramatsu if (ppt->function == NULL) { 163602b95dadSMasami Hiramatsu ret = -ENOMEM; 163702b95dadSMasami Hiramatsu goto end; 163802b95dadSMasami Hiramatsu } 1639fb1587d8SMasami Hiramatsu } 16401d46ea2aSMasami Hiramatsu if (fname) { 16411d46ea2aSMasami Hiramatsu ppt->file = strdup(fname); 16421d46ea2aSMasami Hiramatsu if (ppt->file == NULL) { 164304662523SArnaldo Carvalho de Melo zfree(&ppt->function); 16441d46ea2aSMasami Hiramatsu ret = -ENOMEM; 16451d46ea2aSMasami Hiramatsu goto end; 16461d46ea2aSMasami Hiramatsu } 16471d46ea2aSMasami Hiramatsu } 1648fb1587d8SMasami Hiramatsu end: 16491d46ea2aSMasami Hiramatsu if (ret == 0 && (fname || func)) 16501d46ea2aSMasami Hiramatsu ret = 1; /* Found a point */ 1651fb1587d8SMasami Hiramatsu return ret; 1652fb1587d8SMasami Hiramatsu } 1653fb1587d8SMasami Hiramatsu 1654f6c903f5SMasami Hiramatsu /* Add a line and store the src path */ 1655f6c903f5SMasami Hiramatsu static int line_range_add_line(const char *src, unsigned int lineno, 1656f6c903f5SMasami Hiramatsu struct line_range *lr) 1657f6c903f5SMasami Hiramatsu { 16587cf0b79eSMasami Hiramatsu /* Copy source path */ 1659f6c903f5SMasami Hiramatsu if (!lr->path) { 16607cf0b79eSMasami Hiramatsu lr->path = strdup(src); 16617cf0b79eSMasami Hiramatsu if (lr->path == NULL) 16627cf0b79eSMasami Hiramatsu return -ENOMEM; 1663f6c903f5SMasami Hiramatsu } 16645a62257aSMasami Hiramatsu return intlist__add(lr->line_list, lineno); 1665f6c903f5SMasami Hiramatsu } 1666f6c903f5SMasami Hiramatsu 16674cc9cec6SMasami Hiramatsu static int line_range_walk_cb(const char *fname, int lineno, 16681d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused, 16694cc9cec6SMasami Hiramatsu void *data) 1670f6c903f5SMasami Hiramatsu { 16714cc9cec6SMasami Hiramatsu struct line_finder *lf = data; 1672202c7c12SNamhyung Kim int err; 1673f6c903f5SMasami Hiramatsu 16744cc9cec6SMasami Hiramatsu if ((strtailcmp(fname, lf->fname) != 0) || 1675f6c903f5SMasami Hiramatsu (lf->lno_s > lineno || lf->lno_e < lineno)) 16764cc9cec6SMasami Hiramatsu return 0; 1677f6c903f5SMasami Hiramatsu 1678202c7c12SNamhyung Kim err = line_range_add_line(fname, lineno, lf->lr); 1679202c7c12SNamhyung Kim if (err < 0 && err != -EEXIST) 1680202c7c12SNamhyung Kim return err; 1681f6c903f5SMasami Hiramatsu 16824cc9cec6SMasami Hiramatsu return 0; 1683f6c903f5SMasami Hiramatsu } 1684fb1587d8SMasami Hiramatsu 1685631c9defSMasami Hiramatsu /* Find line range from its line number */ 1686b55a87adSMasami Hiramatsu static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1687631c9defSMasami Hiramatsu { 16884cc9cec6SMasami Hiramatsu int ret; 1689631c9defSMasami Hiramatsu 16904cc9cec6SMasami Hiramatsu ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1691f6c903f5SMasami Hiramatsu 1692804b3606SMasami Hiramatsu /* Update status */ 1693f6c903f5SMasami Hiramatsu if (ret >= 0) 16945a62257aSMasami Hiramatsu if (!intlist__empty(lf->lr->line_list)) 1695f6c903f5SMasami Hiramatsu ret = lf->found = 1; 1696f6c903f5SMasami Hiramatsu else 1697f6c903f5SMasami Hiramatsu ret = 0; /* Lines are not found */ 1698804b3606SMasami Hiramatsu else { 169904662523SArnaldo Carvalho de Melo zfree(&lf->lr->path); 1700804b3606SMasami Hiramatsu } 1701f6c903f5SMasami Hiramatsu return ret; 1702631c9defSMasami Hiramatsu } 1703631c9defSMasami Hiramatsu 1704161a26b0SMasami Hiramatsu static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1705161a26b0SMasami Hiramatsu { 1706182c228eSMasami Hiramatsu int ret = find_line_range_by_line(in_die, data); 170736c0c588SMasami Hiramatsu 170836c0c588SMasami Hiramatsu /* 170936c0c588SMasami Hiramatsu * We have to check all instances of inlined function, because 171036c0c588SMasami Hiramatsu * some execution paths can be optimized out depends on the 1711182c228eSMasami Hiramatsu * function argument of instances. However, if an error occurs, 1712182c228eSMasami Hiramatsu * it should be handled by the caller. 171336c0c588SMasami Hiramatsu */ 1714182c228eSMasami Hiramatsu return ret < 0 ? ret : 0; 1715161a26b0SMasami Hiramatsu } 1716161a26b0SMasami Hiramatsu 17170dbb1cacSMasami Hiramatsu /* Search function definition from function name */ 1718e92b85e1SMasami Hiramatsu static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1719631c9defSMasami Hiramatsu { 1720b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1721b55a87adSMasami Hiramatsu struct line_finder *lf = param->data; 1722631c9defSMasami Hiramatsu struct line_range *lr = lf->lr; 1723631c9defSMasami Hiramatsu 17247d21635aSMasami Hiramatsu /* Check declared file */ 17257d21635aSMasami Hiramatsu if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 17267d21635aSMasami Hiramatsu return DWARF_CB_OK; 17277d21635aSMasami Hiramatsu 17280dbb1cacSMasami Hiramatsu if (die_is_func_def(sp_die) && 17294c859351SMasami Hiramatsu die_match_name(sp_die, lr->function)) { 1730e92b85e1SMasami Hiramatsu lf->fname = dwarf_decl_file(sp_die); 1731e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &lr->offset); 1732804b3606SMasami Hiramatsu pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1733631c9defSMasami Hiramatsu lf->lno_s = lr->offset + lr->start; 1734d3b63d7aSMasami Hiramatsu if (lf->lno_s < 0) /* Overflow */ 1735d3b63d7aSMasami Hiramatsu lf->lno_s = INT_MAX; 1736631c9defSMasami Hiramatsu lf->lno_e = lr->offset + lr->end; 1737d3b63d7aSMasami Hiramatsu if (lf->lno_e < 0) /* Overflow */ 1738d3b63d7aSMasami Hiramatsu lf->lno_e = INT_MAX; 1739d3b63d7aSMasami Hiramatsu pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1740631c9defSMasami Hiramatsu lr->start = lf->lno_s; 1741631c9defSMasami Hiramatsu lr->end = lf->lno_e; 1742e1ecbbc3SMasami Hiramatsu if (!die_is_func_instance(sp_die)) 1743db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1744db0d2c64SMasami Hiramatsu line_range_inline_cb, lf); 1745db0d2c64SMasami Hiramatsu else 1746b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(sp_die, lf); 1747b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1748631c9defSMasami Hiramatsu } 1749b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1750631c9defSMasami Hiramatsu } 1751631c9defSMasami Hiramatsu 1752b55a87adSMasami Hiramatsu static int find_line_range_by_func(struct line_finder *lf) 1753631c9defSMasami Hiramatsu { 1754b55a87adSMasami Hiramatsu struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1755b55a87adSMasami Hiramatsu dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1756b55a87adSMasami Hiramatsu return param.retval; 1757631c9defSMasami Hiramatsu } 1758631c9defSMasami Hiramatsu 1759316c7136SArnaldo Carvalho de Melo int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr) 1760631c9defSMasami Hiramatsu { 1761804b3606SMasami Hiramatsu struct line_finder lf = {.lr = lr, .found = 0}; 1762b55a87adSMasami Hiramatsu int ret = 0; 1763804b3606SMasami Hiramatsu Dwarf_Off off = 0, noff; 1764804b3606SMasami Hiramatsu size_t cuhl; 1765804b3606SMasami Hiramatsu Dwarf_Die *diep; 17666a330a3cSMasami Hiramatsu const char *comp_dir; 1767631c9defSMasami Hiramatsu 1768cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1769cd25f8bcSLin Ming if (lr->function) { 1770cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1771cd25f8bcSLin Ming .function = lr->function, .file = lr->file, 1772cd25f8bcSLin Ming .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1773cd25f8bcSLin Ming struct dwarf_callback_param line_range_param = { 1774cd25f8bcSLin Ming .data = (void *)&lf, .retval = 0}; 1775cd25f8bcSLin Ming 1776316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1777ff741783SMasami Hiramatsu &pubname_param, 0); 1778cd25f8bcSLin Ming if (pubname_param.found) { 1779cd25f8bcSLin Ming line_range_search_cb(&lf.sp_die, &line_range_param); 1780cd25f8bcSLin Ming if (lf.found) 1781cd25f8bcSLin Ming goto found; 1782cd25f8bcSLin Ming } 1783cd25f8bcSLin Ming } 1784cd25f8bcSLin Ming 1785804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1786b55a87adSMasami Hiramatsu while (!lf.found && ret >= 0) { 1787316c7136SArnaldo Carvalho de Melo if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, 1788ff741783SMasami Hiramatsu NULL, NULL, NULL) != 0) 1789631c9defSMasami Hiramatsu break; 1790631c9defSMasami Hiramatsu 1791631c9defSMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1792316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die); 1793804b3606SMasami Hiramatsu if (!diep) 1794804b3606SMasami Hiramatsu continue; 1795631c9defSMasami Hiramatsu 1796631c9defSMasami Hiramatsu /* Check if target file is included. */ 1797631c9defSMasami Hiramatsu if (lr->file) 17982a9c8c36SMasami Hiramatsu lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1799804b3606SMasami Hiramatsu else 18002a9c8c36SMasami Hiramatsu lf.fname = 0; 1801631c9defSMasami Hiramatsu 18022a9c8c36SMasami Hiramatsu if (!lr->file || lf.fname) { 1803631c9defSMasami Hiramatsu if (lr->function) 1804b55a87adSMasami Hiramatsu ret = find_line_range_by_func(&lf); 1805631c9defSMasami Hiramatsu else { 1806631c9defSMasami Hiramatsu lf.lno_s = lr->start; 1807631c9defSMasami Hiramatsu lf.lno_e = lr->end; 1808b55a87adSMasami Hiramatsu ret = find_line_range_by_line(NULL, &lf); 1809631c9defSMasami Hiramatsu } 1810631c9defSMasami Hiramatsu } 1811804b3606SMasami Hiramatsu off = noff; 1812631c9defSMasami Hiramatsu } 18136a330a3cSMasami Hiramatsu 1814cd25f8bcSLin Ming found: 18156a330a3cSMasami Hiramatsu /* Store comp_dir */ 18166a330a3cSMasami Hiramatsu if (lf.found) { 18176a330a3cSMasami Hiramatsu comp_dir = cu_get_comp_dir(&lf.cu_die); 18186a330a3cSMasami Hiramatsu if (comp_dir) { 18196a330a3cSMasami Hiramatsu lr->comp_dir = strdup(comp_dir); 18206a330a3cSMasami Hiramatsu if (!lr->comp_dir) 18216a330a3cSMasami Hiramatsu ret = -ENOMEM; 18226a330a3cSMasami Hiramatsu } 18236a330a3cSMasami Hiramatsu } 18246a330a3cSMasami Hiramatsu 18257cf0b79eSMasami Hiramatsu pr_debug("path: %s\n", lr->path); 1826b55a87adSMasami Hiramatsu return (ret < 0) ? ret : lf.found; 1827631c9defSMasami Hiramatsu } 1828631c9defSMasami Hiramatsu 182909ed8975SNaohiro Aota /* 183009ed8975SNaohiro Aota * Find a src file from a DWARF tag path. Prepend optional source path prefix 183109ed8975SNaohiro Aota * and chop off leading directories that do not exist. Result is passed back as 183209ed8975SNaohiro Aota * a newly allocated path on success. 183309ed8975SNaohiro Aota * Return 0 if file was found and readable, -errno otherwise. 183409ed8975SNaohiro Aota */ 183509ed8975SNaohiro Aota int get_real_path(const char *raw_path, const char *comp_dir, 183609ed8975SNaohiro Aota char **new_path) 183709ed8975SNaohiro Aota { 183809ed8975SNaohiro Aota const char *prefix = symbol_conf.source_prefix; 183909ed8975SNaohiro Aota 184009ed8975SNaohiro Aota if (!prefix) { 184109ed8975SNaohiro Aota if (raw_path[0] != '/' && comp_dir) 184209ed8975SNaohiro Aota /* If not an absolute path, try to use comp_dir */ 184309ed8975SNaohiro Aota prefix = comp_dir; 184409ed8975SNaohiro Aota else { 184509ed8975SNaohiro Aota if (access(raw_path, R_OK) == 0) { 184609ed8975SNaohiro Aota *new_path = strdup(raw_path); 184709ed8975SNaohiro Aota return *new_path ? 0 : -ENOMEM; 184809ed8975SNaohiro Aota } else 184909ed8975SNaohiro Aota return -errno; 185009ed8975SNaohiro Aota } 185109ed8975SNaohiro Aota } 185209ed8975SNaohiro Aota 185309ed8975SNaohiro Aota *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 185409ed8975SNaohiro Aota if (!*new_path) 185509ed8975SNaohiro Aota return -ENOMEM; 185609ed8975SNaohiro Aota 185709ed8975SNaohiro Aota for (;;) { 185809ed8975SNaohiro Aota sprintf(*new_path, "%s/%s", prefix, raw_path); 185909ed8975SNaohiro Aota 186009ed8975SNaohiro Aota if (access(*new_path, R_OK) == 0) 186109ed8975SNaohiro Aota return 0; 186209ed8975SNaohiro Aota 186309ed8975SNaohiro Aota if (!symbol_conf.source_prefix) { 186409ed8975SNaohiro Aota /* In case of searching comp_dir, don't retry */ 186509ed8975SNaohiro Aota zfree(new_path); 186609ed8975SNaohiro Aota return -errno; 186709ed8975SNaohiro Aota } 186809ed8975SNaohiro Aota 186909ed8975SNaohiro Aota switch (errno) { 187009ed8975SNaohiro Aota case ENAMETOOLONG: 187109ed8975SNaohiro Aota case ENOENT: 187209ed8975SNaohiro Aota case EROFS: 187309ed8975SNaohiro Aota case EFAULT: 187409ed8975SNaohiro Aota raw_path = strchr(++raw_path, '/'); 187509ed8975SNaohiro Aota if (!raw_path) { 187609ed8975SNaohiro Aota zfree(new_path); 187709ed8975SNaohiro Aota return -ENOENT; 187809ed8975SNaohiro Aota } 187909ed8975SNaohiro Aota continue; 188009ed8975SNaohiro Aota 188109ed8975SNaohiro Aota default: 188209ed8975SNaohiro Aota zfree(new_path); 188309ed8975SNaohiro Aota return -errno; 188409ed8975SNaohiro Aota } 188509ed8975SNaohiro Aota } 188609ed8975SNaohiro Aota } 1887