14ea42b18SMasami Hiramatsu /* 24ea42b18SMasami Hiramatsu * probe-finder.c : C expression to kprobe event converter 34ea42b18SMasami Hiramatsu * 44ea42b18SMasami Hiramatsu * Written by Masami Hiramatsu <mhiramat@redhat.com> 54ea42b18SMasami Hiramatsu * 64ea42b18SMasami Hiramatsu * This program is free software; you can redistribute it and/or modify 74ea42b18SMasami Hiramatsu * it under the terms of the GNU General Public License as published by 84ea42b18SMasami Hiramatsu * the Free Software Foundation; either version 2 of the License, or 94ea42b18SMasami Hiramatsu * (at your option) any later version. 104ea42b18SMasami Hiramatsu * 114ea42b18SMasami Hiramatsu * This program is distributed in the hope that it will be useful, 124ea42b18SMasami Hiramatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 134ea42b18SMasami Hiramatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 144ea42b18SMasami Hiramatsu * GNU General Public License for more details. 154ea42b18SMasami Hiramatsu * 164ea42b18SMasami Hiramatsu * You should have received a copy of the GNU General Public License 174ea42b18SMasami Hiramatsu * along with this program; if not, write to the Free Software 184ea42b18SMasami Hiramatsu * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 194ea42b18SMasami Hiramatsu * 204ea42b18SMasami Hiramatsu */ 214ea42b18SMasami Hiramatsu 224ea42b18SMasami Hiramatsu #include <sys/utsname.h> 234ea42b18SMasami Hiramatsu #include <sys/types.h> 244ea42b18SMasami Hiramatsu #include <sys/stat.h> 254ea42b18SMasami Hiramatsu #include <fcntl.h> 264ea42b18SMasami Hiramatsu #include <errno.h> 274ea42b18SMasami Hiramatsu #include <stdio.h> 284ea42b18SMasami Hiramatsu #include <unistd.h> 294ea42b18SMasami Hiramatsu #include <getopt.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" 3789c69c0eSMasami Hiramatsu #include "debug.h" 38*5a62257aSMasami Hiramatsu #include "intlist.h" 39074fc0e4SMasami Hiramatsu #include "util.h" 409ed7e1b8SChase Douglas #include "symbol.h" 414ea42b18SMasami Hiramatsu #include "probe-finder.h" 424ea42b18SMasami Hiramatsu 434984912eSMasami Hiramatsu /* Kprobe tracer basic type is up to u64 */ 444984912eSMasami Hiramatsu #define MAX_BASIC_TYPE_BITS 64 454984912eSMasami Hiramatsu 46469b9b88SMasami Hiramatsu /* Dwarf FL wrappers */ 47469b9b88SMasami Hiramatsu static char *debuginfo_path; /* Currently dummy */ 48469b9b88SMasami Hiramatsu 49469b9b88SMasami Hiramatsu static const Dwfl_Callbacks offline_callbacks = { 50469b9b88SMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 51469b9b88SMasami Hiramatsu .debuginfo_path = &debuginfo_path, 52469b9b88SMasami Hiramatsu 53469b9b88SMasami Hiramatsu .section_address = dwfl_offline_section_address, 54469b9b88SMasami Hiramatsu 55469b9b88SMasami Hiramatsu /* We use this table for core files too. */ 56469b9b88SMasami Hiramatsu .find_elf = dwfl_build_id_find_elf, 57469b9b88SMasami Hiramatsu }; 58469b9b88SMasami Hiramatsu 59469b9b88SMasami Hiramatsu /* Get a Dwarf from offline image */ 60316c7136SArnaldo Carvalho de Melo static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, 61ff741783SMasami Hiramatsu const char *path) 62469b9b88SMasami Hiramatsu { 63ff741783SMasami Hiramatsu int fd; 64469b9b88SMasami Hiramatsu 65ff741783SMasami Hiramatsu fd = open(path, O_RDONLY); 66ff741783SMasami Hiramatsu if (fd < 0) 67ff741783SMasami Hiramatsu return fd; 68469b9b88SMasami Hiramatsu 69316c7136SArnaldo Carvalho de Melo dbg->dwfl = dwfl_begin(&offline_callbacks); 70316c7136SArnaldo Carvalho de Melo if (!dbg->dwfl) 71ff741783SMasami Hiramatsu goto error; 72469b9b88SMasami Hiramatsu 73316c7136SArnaldo Carvalho de Melo dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); 74316c7136SArnaldo Carvalho de Melo if (!dbg->mod) 75469b9b88SMasami Hiramatsu goto error; 76469b9b88SMasami Hiramatsu 77316c7136SArnaldo Carvalho de Melo dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); 78316c7136SArnaldo Carvalho de Melo if (!dbg->dbg) 79ff741783SMasami Hiramatsu goto error; 80ff741783SMasami Hiramatsu 81ff741783SMasami Hiramatsu return 0; 82469b9b88SMasami Hiramatsu error: 83316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 84316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 85ff741783SMasami Hiramatsu else 86ff741783SMasami Hiramatsu close(fd); 87316c7136SArnaldo Carvalho de Melo memset(dbg, 0, sizeof(*dbg)); 88ff741783SMasami Hiramatsu 89ff741783SMasami Hiramatsu return -ENOENT; 90469b9b88SMasami Hiramatsu } 91469b9b88SMasami Hiramatsu 923b4694deSMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 148) 933b4694deSMasami Hiramatsu /* This method is buggy if elfutils is older than 0.148 */ 943b4694deSMasami Hiramatsu static int __linux_kernel_find_elf(Dwfl_Module *mod, 953b4694deSMasami Hiramatsu void **userdata, 963b4694deSMasami Hiramatsu const char *module_name, 973b4694deSMasami Hiramatsu Dwarf_Addr base, 983b4694deSMasami Hiramatsu char **file_name, Elf **elfp) 993b4694deSMasami Hiramatsu { 1003b4694deSMasami Hiramatsu int fd; 1013b4694deSMasami Hiramatsu const char *path = kernel_get_module_path(module_name); 1023b4694deSMasami Hiramatsu 1033b4694deSMasami Hiramatsu pr_debug2("Use file %s for %s\n", path, module_name); 1043b4694deSMasami Hiramatsu if (path) { 1053b4694deSMasami Hiramatsu fd = open(path, O_RDONLY); 1063b4694deSMasami Hiramatsu if (fd >= 0) { 1073b4694deSMasami Hiramatsu *file_name = strdup(path); 1083b4694deSMasami Hiramatsu return fd; 1093b4694deSMasami Hiramatsu } 1103b4694deSMasami Hiramatsu } 1113b4694deSMasami Hiramatsu /* If failed, try to call standard method */ 1123b4694deSMasami Hiramatsu return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, 1133b4694deSMasami Hiramatsu file_name, elfp); 1143b4694deSMasami Hiramatsu } 1153b4694deSMasami Hiramatsu 1163b4694deSMasami Hiramatsu static const Dwfl_Callbacks kernel_callbacks = { 1173b4694deSMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 1183b4694deSMasami Hiramatsu .debuginfo_path = &debuginfo_path, 1193b4694deSMasami Hiramatsu 1203b4694deSMasami Hiramatsu .find_elf = __linux_kernel_find_elf, 1213b4694deSMasami Hiramatsu .section_address = dwfl_linux_kernel_module_section_address, 1223b4694deSMasami Hiramatsu }; 1233b4694deSMasami Hiramatsu 124469b9b88SMasami Hiramatsu /* Get a Dwarf from live kernel image */ 125316c7136SArnaldo Carvalho de Melo static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg, 126ff741783SMasami Hiramatsu Dwarf_Addr addr) 127469b9b88SMasami Hiramatsu { 128316c7136SArnaldo Carvalho de Melo dbg->dwfl = dwfl_begin(&kernel_callbacks); 129316c7136SArnaldo Carvalho de Melo if (!dbg->dwfl) 130ff741783SMasami Hiramatsu return -EINVAL; 131469b9b88SMasami Hiramatsu 132469b9b88SMasami Hiramatsu /* Load the kernel dwarves: Don't care the result here */ 133316c7136SArnaldo Carvalho de Melo dwfl_linux_kernel_report_kernel(dbg->dwfl); 134316c7136SArnaldo Carvalho de Melo dwfl_linux_kernel_report_modules(dbg->dwfl); 135469b9b88SMasami Hiramatsu 136316c7136SArnaldo Carvalho de Melo dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias); 137469b9b88SMasami Hiramatsu /* Here, check whether we could get a real dwarf */ 138316c7136SArnaldo Carvalho de Melo if (!dbg->dbg) { 1393b4694deSMasami Hiramatsu pr_debug("Failed to find kernel dwarf at %lx\n", 1403b4694deSMasami Hiramatsu (unsigned long)addr); 141316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 142316c7136SArnaldo Carvalho de Melo memset(dbg, 0, sizeof(*dbg)); 143ff741783SMasami Hiramatsu return -ENOENT; 144469b9b88SMasami Hiramatsu } 145ff741783SMasami Hiramatsu 146ff741783SMasami Hiramatsu return 0; 147469b9b88SMasami Hiramatsu } 1483b4694deSMasami Hiramatsu #else 1493b4694deSMasami Hiramatsu /* With older elfutils, this just support kernel module... */ 150316c7136SArnaldo Carvalho de Melo static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg, 1511d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused) 1523b4694deSMasami Hiramatsu { 1533b4694deSMasami Hiramatsu const char *path = kernel_get_module_path("kernel"); 1543b4694deSMasami Hiramatsu 1553b4694deSMasami Hiramatsu if (!path) { 1563b4694deSMasami Hiramatsu pr_err("Failed to find vmlinux path\n"); 157ff741783SMasami Hiramatsu return -ENOENT; 1583b4694deSMasami Hiramatsu } 1593b4694deSMasami Hiramatsu 1603b4694deSMasami Hiramatsu pr_debug2("Use file %s for debuginfo\n", path); 161316c7136SArnaldo Carvalho de Melo return debuginfo__init_offline_dwarf(dbg, path); 1623b4694deSMasami Hiramatsu } 1633b4694deSMasami Hiramatsu #endif 164469b9b88SMasami Hiramatsu 165ff741783SMasami Hiramatsu struct debuginfo *debuginfo__new(const char *path) 166ff741783SMasami Hiramatsu { 167316c7136SArnaldo Carvalho de Melo struct debuginfo *dbg = zalloc(sizeof(*dbg)); 168316c7136SArnaldo Carvalho de Melo if (!dbg) 169ff741783SMasami Hiramatsu return NULL; 170ff741783SMasami Hiramatsu 17104662523SArnaldo Carvalho de Melo if (debuginfo__init_offline_dwarf(dbg, path) < 0) 17204662523SArnaldo Carvalho de Melo zfree(&dbg); 173ff741783SMasami Hiramatsu 174316c7136SArnaldo Carvalho de Melo return dbg; 175ff741783SMasami Hiramatsu } 176ff741783SMasami Hiramatsu 177ff741783SMasami Hiramatsu struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) 178ff741783SMasami Hiramatsu { 179316c7136SArnaldo Carvalho de Melo struct debuginfo *dbg = zalloc(sizeof(*dbg)); 180316c7136SArnaldo Carvalho de Melo 181316c7136SArnaldo Carvalho de Melo if (!dbg) 182ff741783SMasami Hiramatsu return NULL; 183ff741783SMasami Hiramatsu 18404662523SArnaldo Carvalho de Melo if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) 18504662523SArnaldo Carvalho de Melo zfree(&dbg); 186ff741783SMasami Hiramatsu 187316c7136SArnaldo Carvalho de Melo return dbg; 188ff741783SMasami Hiramatsu } 189ff741783SMasami Hiramatsu 190316c7136SArnaldo Carvalho de Melo void debuginfo__delete(struct debuginfo *dbg) 191ff741783SMasami Hiramatsu { 192316c7136SArnaldo Carvalho de Melo if (dbg) { 193316c7136SArnaldo Carvalho de Melo if (dbg->dwfl) 194316c7136SArnaldo Carvalho de Melo dwfl_end(dbg->dwfl); 195316c7136SArnaldo Carvalho de Melo free(dbg); 196ff741783SMasami Hiramatsu } 197ff741783SMasami Hiramatsu } 198ff741783SMasami Hiramatsu 1994ea42b18SMasami Hiramatsu /* 2004ea42b18SMasami Hiramatsu * Probe finder related functions 2014ea42b18SMasami Hiramatsu */ 2024ea42b18SMasami Hiramatsu 2030e60836bSSrikar Dronamraju static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 2044ea42b18SMasami Hiramatsu { 2050e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref; 2060e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 207b7dcb857SMasami Hiramatsu if (ref != NULL) 208b7dcb857SMasami Hiramatsu ref->offset = offs; 209b7dcb857SMasami Hiramatsu return ref; 210b7dcb857SMasami Hiramatsu } 211b7dcb857SMasami Hiramatsu 212cf6eb489SMasami Hiramatsu /* 213cf6eb489SMasami Hiramatsu * Convert a location into trace_arg. 214cf6eb489SMasami Hiramatsu * If tvar == NULL, this just checks variable can be converted. 2153d918a12SMasami Hiramatsu * If fentry == true and vr_die is a parameter, do huristic search 2163d918a12SMasami Hiramatsu * for the location fuzzed by function entry mcount. 217cf6eb489SMasami Hiramatsu */ 218cf6eb489SMasami Hiramatsu static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 2193d918a12SMasami Hiramatsu Dwarf_Op *fb_ops, Dwarf_Die *sp_die, 220cf6eb489SMasami Hiramatsu struct probe_trace_arg *tvar) 221b7dcb857SMasami Hiramatsu { 222b7dcb857SMasami Hiramatsu Dwarf_Attribute attr; 2233d918a12SMasami Hiramatsu Dwarf_Addr tmp = 0; 224b7dcb857SMasami Hiramatsu Dwarf_Op *op; 225b7dcb857SMasami Hiramatsu size_t nops; 226804b3606SMasami Hiramatsu unsigned int regn; 227804b3606SMasami Hiramatsu Dwarf_Word offs = 0; 2284235b045SMasami Hiramatsu bool ref = false; 2294ea42b18SMasami Hiramatsu const char *regs; 230b7dcb857SMasami Hiramatsu int ret; 231b7dcb857SMasami Hiramatsu 232632941c4SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 233632941c4SMasami Hiramatsu goto static_var; 234632941c4SMasami Hiramatsu 235b7dcb857SMasami Hiramatsu /* TODO: handle more than 1 exprs */ 2363d918a12SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 2373d918a12SMasami Hiramatsu return -EINVAL; /* Broken DIE ? */ 2383d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { 2393d918a12SMasami Hiramatsu ret = dwarf_entrypc(sp_die, &tmp); 2403d918a12SMasami Hiramatsu if (ret || addr != tmp || 2413d918a12SMasami Hiramatsu dwarf_tag(vr_die) != DW_TAG_formal_parameter || 2423d918a12SMasami Hiramatsu dwarf_highpc(sp_die, &tmp)) 2433d918a12SMasami Hiramatsu return -ENOENT; 2443d918a12SMasami Hiramatsu /* 2453d918a12SMasami Hiramatsu * This is fuzzed by fentry mcount. We try to find the 2463d918a12SMasami Hiramatsu * parameter location at the earliest address. 2473d918a12SMasami Hiramatsu */ 2483d918a12SMasami Hiramatsu for (addr += 1; addr <= tmp; addr++) { 2493d918a12SMasami Hiramatsu if (dwarf_getlocation_addr(&attr, addr, &op, 2503d918a12SMasami Hiramatsu &nops, 1) > 0) 2513d918a12SMasami Hiramatsu goto found; 2523d918a12SMasami Hiramatsu } 253b7dcb857SMasami Hiramatsu return -ENOENT; 254b7dcb857SMasami Hiramatsu } 2553d918a12SMasami Hiramatsu found: 2563d918a12SMasami Hiramatsu if (nops == 0) 2573d918a12SMasami Hiramatsu /* TODO: Support const_value */ 2583d918a12SMasami Hiramatsu return -ENOENT; 259b7dcb857SMasami Hiramatsu 260b7dcb857SMasami Hiramatsu if (op->atom == DW_OP_addr) { 261632941c4SMasami Hiramatsu static_var: 262cf6eb489SMasami Hiramatsu if (!tvar) 263cf6eb489SMasami Hiramatsu return 0; 264b7dcb857SMasami Hiramatsu /* Static variables on memory (not stack), make @varname */ 265b7dcb857SMasami Hiramatsu ret = strlen(dwarf_diename(vr_die)); 266b7dcb857SMasami Hiramatsu tvar->value = zalloc(ret + 2); 267b7dcb857SMasami Hiramatsu if (tvar->value == NULL) 268b7dcb857SMasami Hiramatsu return -ENOMEM; 269b7dcb857SMasami Hiramatsu snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 270b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 271b7dcb857SMasami Hiramatsu if (tvar->ref == NULL) 272b7dcb857SMasami Hiramatsu return -ENOMEM; 273b7dcb857SMasami Hiramatsu return 0; 274b7dcb857SMasami Hiramatsu } 2754ea42b18SMasami Hiramatsu 2764ea42b18SMasami Hiramatsu /* If this is based on frame buffer, set the offset */ 277804b3606SMasami Hiramatsu if (op->atom == DW_OP_fbreg) { 278cf6eb489SMasami Hiramatsu if (fb_ops == NULL) 279b55a87adSMasami Hiramatsu return -ENOTSUP; 2804235b045SMasami Hiramatsu ref = true; 281804b3606SMasami Hiramatsu offs = op->number; 282cf6eb489SMasami Hiramatsu op = &fb_ops[0]; 283804b3606SMasami Hiramatsu } 2844ea42b18SMasami Hiramatsu 285804b3606SMasami Hiramatsu if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 286804b3606SMasami Hiramatsu regn = op->atom - DW_OP_breg0; 287804b3606SMasami Hiramatsu offs += op->number; 2884235b045SMasami Hiramatsu ref = true; 289804b3606SMasami Hiramatsu } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 290804b3606SMasami Hiramatsu regn = op->atom - DW_OP_reg0; 291804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_bregx) { 292804b3606SMasami Hiramatsu regn = op->number; 293804b3606SMasami Hiramatsu offs += op->number2; 2944235b045SMasami Hiramatsu ref = true; 295804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_regx) { 296804b3606SMasami Hiramatsu regn = op->number; 297b55a87adSMasami Hiramatsu } else { 298cf6eb489SMasami Hiramatsu pr_debug("DW_OP %x is not supported.\n", op->atom); 299b55a87adSMasami Hiramatsu return -ENOTSUP; 300b55a87adSMasami Hiramatsu } 3014ea42b18SMasami Hiramatsu 302cf6eb489SMasami Hiramatsu if (!tvar) 303cf6eb489SMasami Hiramatsu return 0; 304cf6eb489SMasami Hiramatsu 3054ea42b18SMasami Hiramatsu regs = get_arch_regstr(regn); 306b55a87adSMasami Hiramatsu if (!regs) { 307cf6eb489SMasami Hiramatsu /* This should be a bug in DWARF or this tool */ 3080e43e5d2SMasami Hiramatsu pr_warning("Mapping for the register number %u " 3090e43e5d2SMasami Hiramatsu "missing on this architecture.\n", regn); 310b55a87adSMasami Hiramatsu return -ERANGE; 311b55a87adSMasami Hiramatsu } 3124ea42b18SMasami Hiramatsu 31302b95dadSMasami Hiramatsu tvar->value = strdup(regs); 31402b95dadSMasami Hiramatsu if (tvar->value == NULL) 31502b95dadSMasami Hiramatsu return -ENOMEM; 31602b95dadSMasami Hiramatsu 3174235b045SMasami Hiramatsu if (ref) { 318b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 319e334016fSMasami Hiramatsu if (tvar->ref == NULL) 320e334016fSMasami Hiramatsu return -ENOMEM; 3214235b045SMasami Hiramatsu } 322b55a87adSMasami Hiramatsu return 0; 3234ea42b18SMasami Hiramatsu } 3244ea42b18SMasami Hiramatsu 325124bb83cSMasami Hiramatsu #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 326124bb83cSMasami Hiramatsu 327b55a87adSMasami Hiramatsu static int convert_variable_type(Dwarf_Die *vr_die, 3280e60836bSSrikar Dronamraju struct probe_trace_arg *tvar, 32973317b95SMasami Hiramatsu const char *cast) 3304984912eSMasami Hiramatsu { 3310e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 3324984912eSMasami Hiramatsu Dwarf_Die type; 3334984912eSMasami Hiramatsu char buf[16]; 334bcfc0821SMasami Hiramatsu int bsize, boffs, total; 3354984912eSMasami Hiramatsu int ret; 3364984912eSMasami Hiramatsu 33773317b95SMasami Hiramatsu /* TODO: check all types */ 33873317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") != 0) { 33973317b95SMasami Hiramatsu /* Non string type is OK */ 34073317b95SMasami Hiramatsu tvar->type = strdup(cast); 34173317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 34273317b95SMasami Hiramatsu } 34373317b95SMasami Hiramatsu 344bcfc0821SMasami Hiramatsu bsize = dwarf_bitsize(vr_die); 345bcfc0821SMasami Hiramatsu if (bsize > 0) { 346124bb83cSMasami Hiramatsu /* This is a bitfield */ 347bcfc0821SMasami Hiramatsu boffs = dwarf_bitoffset(vr_die); 348bcfc0821SMasami Hiramatsu total = dwarf_bytesize(vr_die); 349bcfc0821SMasami Hiramatsu if (boffs < 0 || total < 0) 350bcfc0821SMasami Hiramatsu return -ENOENT; 351bcfc0821SMasami Hiramatsu ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 352bcfc0821SMasami Hiramatsu BYTES_TO_BITS(total)); 353124bb83cSMasami Hiramatsu goto formatted; 354124bb83cSMasami Hiramatsu } 355124bb83cSMasami Hiramatsu 356b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 357b55a87adSMasami Hiramatsu pr_warning("Failed to get a type information of %s.\n", 3584984912eSMasami Hiramatsu dwarf_diename(vr_die)); 359b55a87adSMasami Hiramatsu return -ENOENT; 360b55a87adSMasami Hiramatsu } 3614984912eSMasami Hiramatsu 362b2a3c12bSMasami Hiramatsu pr_debug("%s type is %s.\n", 363b2a3c12bSMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 364b2a3c12bSMasami Hiramatsu 36573317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") == 0) { /* String type */ 36673317b95SMasami Hiramatsu ret = dwarf_tag(&type); 36773317b95SMasami Hiramatsu if (ret != DW_TAG_pointer_type && 36873317b95SMasami Hiramatsu ret != DW_TAG_array_type) { 36973317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3700e43e5d2SMasami Hiramatsu "%s(%s) is not a pointer nor array.\n", 37173317b95SMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 37273317b95SMasami Hiramatsu return -EINVAL; 37373317b95SMasami Hiramatsu } 37473317b95SMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 3750e43e5d2SMasami Hiramatsu pr_warning("Failed to get a type" 3760e43e5d2SMasami Hiramatsu " information.\n"); 37773317b95SMasami Hiramatsu return -ENOENT; 37873317b95SMasami Hiramatsu } 3797ce28b5bSHyeoncheol Lee if (ret == DW_TAG_pointer_type) { 38073317b95SMasami Hiramatsu while (*ref_ptr) 38173317b95SMasami Hiramatsu ref_ptr = &(*ref_ptr)->next; 38273317b95SMasami Hiramatsu /* Add new reference with offset +0 */ 3830e60836bSSrikar Dronamraju *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 38473317b95SMasami Hiramatsu if (*ref_ptr == NULL) { 38573317b95SMasami Hiramatsu pr_warning("Out of memory error\n"); 38673317b95SMasami Hiramatsu return -ENOMEM; 38773317b95SMasami Hiramatsu } 38873317b95SMasami Hiramatsu } 38982175633SMasami Hiramatsu if (!die_compare_name(&type, "char") && 39082175633SMasami Hiramatsu !die_compare_name(&type, "unsigned char")) { 39173317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 3920e43e5d2SMasami Hiramatsu "%s is not (unsigned) char *.\n", 39373317b95SMasami Hiramatsu dwarf_diename(vr_die)); 39473317b95SMasami Hiramatsu return -EINVAL; 39573317b95SMasami Hiramatsu } 39673317b95SMasami Hiramatsu tvar->type = strdup(cast); 39773317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 39873317b95SMasami Hiramatsu } 39973317b95SMasami Hiramatsu 400bcfc0821SMasami Hiramatsu ret = dwarf_bytesize(&type); 401bcfc0821SMasami Hiramatsu if (ret <= 0) 402124bb83cSMasami Hiramatsu /* No size ... try to use default type */ 403124bb83cSMasami Hiramatsu return 0; 404bcfc0821SMasami Hiramatsu ret = BYTES_TO_BITS(ret); 405124bb83cSMasami Hiramatsu 4064984912eSMasami Hiramatsu /* Check the bitwidth */ 4074984912eSMasami Hiramatsu if (ret > MAX_BASIC_TYPE_BITS) { 408124bb83cSMasami Hiramatsu pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 4094984912eSMasami Hiramatsu dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 4104984912eSMasami Hiramatsu ret = MAX_BASIC_TYPE_BITS; 4114984912eSMasami Hiramatsu } 4124984912eSMasami Hiramatsu ret = snprintf(buf, 16, "%c%d", 4134984912eSMasami Hiramatsu die_is_signed_type(&type) ? 's' : 'u', ret); 414124bb83cSMasami Hiramatsu 415124bb83cSMasami Hiramatsu formatted: 416b55a87adSMasami Hiramatsu if (ret < 0 || ret >= 16) { 417b55a87adSMasami Hiramatsu if (ret >= 16) 418b55a87adSMasami Hiramatsu ret = -E2BIG; 419b55a87adSMasami Hiramatsu pr_warning("Failed to convert variable type: %s\n", 420b55a87adSMasami Hiramatsu strerror(-ret)); 421b55a87adSMasami Hiramatsu return ret; 422b55a87adSMasami Hiramatsu } 42373317b95SMasami Hiramatsu tvar->type = strdup(buf); 42473317b95SMasami Hiramatsu if (tvar->type == NULL) 42502b95dadSMasami Hiramatsu return -ENOMEM; 426b55a87adSMasami Hiramatsu return 0; 4274984912eSMasami Hiramatsu } 4284984912eSMasami Hiramatsu 429b55a87adSMasami Hiramatsu static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 4307df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, 4310e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr, 4324984912eSMasami Hiramatsu Dwarf_Die *die_mem) 4337df2f329SMasami Hiramatsu { 4340e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = *ref_ptr; 4357df2f329SMasami Hiramatsu Dwarf_Die type; 4367df2f329SMasami Hiramatsu Dwarf_Word offs; 437b2a3c12bSMasami Hiramatsu int ret, tag; 4387df2f329SMasami Hiramatsu 4397df2f329SMasami Hiramatsu pr_debug("converting %s in %s\n", field->name, varname); 440b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 441b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 442b55a87adSMasami Hiramatsu return -ENOENT; 443b55a87adSMasami Hiramatsu } 444b2a3c12bSMasami Hiramatsu pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); 445b2a3c12bSMasami Hiramatsu tag = dwarf_tag(&type); 4467df2f329SMasami Hiramatsu 447b2a3c12bSMasami Hiramatsu if (field->name[0] == '[' && 448b2a3c12bSMasami Hiramatsu (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 449b2a3c12bSMasami Hiramatsu if (field->next) 450b2a3c12bSMasami Hiramatsu /* Save original type for next field */ 451b2a3c12bSMasami Hiramatsu memcpy(die_mem, &type, sizeof(*die_mem)); 452b2a3c12bSMasami Hiramatsu /* Get the type of this array */ 453b2a3c12bSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 454b2a3c12bSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 455b2a3c12bSMasami Hiramatsu return -ENOENT; 456b2a3c12bSMasami Hiramatsu } 457b2a3c12bSMasami Hiramatsu pr_debug2("Array real type: (%x)\n", 458b2a3c12bSMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 459b2a3c12bSMasami Hiramatsu if (tag == DW_TAG_pointer_type) { 4600e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 461b2a3c12bSMasami Hiramatsu if (ref == NULL) 462b2a3c12bSMasami Hiramatsu return -ENOMEM; 463b2a3c12bSMasami Hiramatsu if (*ref_ptr) 464b2a3c12bSMasami Hiramatsu (*ref_ptr)->next = ref; 465b2a3c12bSMasami Hiramatsu else 466b2a3c12bSMasami Hiramatsu *ref_ptr = ref; 467b2a3c12bSMasami Hiramatsu } 468bcfc0821SMasami Hiramatsu ref->offset += dwarf_bytesize(&type) * field->index; 469b2a3c12bSMasami Hiramatsu if (!field->next) 470b2a3c12bSMasami Hiramatsu /* Save vr_die for converting types */ 471b2a3c12bSMasami Hiramatsu memcpy(die_mem, vr_die, sizeof(*die_mem)); 472b2a3c12bSMasami Hiramatsu goto next; 473b2a3c12bSMasami Hiramatsu } else if (tag == DW_TAG_pointer_type) { 4747df2f329SMasami Hiramatsu /* Check the pointer and dereference */ 475b55a87adSMasami Hiramatsu if (!field->ref) { 476b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '->'\n", 4777df2f329SMasami Hiramatsu field->name); 478b55a87adSMasami Hiramatsu return -EINVAL; 479b55a87adSMasami Hiramatsu } 4807df2f329SMasami Hiramatsu /* Get the type pointed by this pointer */ 481b55a87adSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 482b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 483b55a87adSMasami Hiramatsu return -ENOENT; 484b55a87adSMasami Hiramatsu } 48512e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 4867b0295b3SHyeoncheol Lee tag = dwarf_tag(&type); 4877b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 4887b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 4897b0295b3SHyeoncheol Lee varname); 490b55a87adSMasami Hiramatsu return -EINVAL; 491b55a87adSMasami Hiramatsu } 49212e5a7aeSMasami Hiramatsu 4930e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 494e334016fSMasami Hiramatsu if (ref == NULL) 495e334016fSMasami Hiramatsu return -ENOMEM; 4967df2f329SMasami Hiramatsu if (*ref_ptr) 4977df2f329SMasami Hiramatsu (*ref_ptr)->next = ref; 4987df2f329SMasami Hiramatsu else 4997df2f329SMasami Hiramatsu *ref_ptr = ref; 5007df2f329SMasami Hiramatsu } else { 50112e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 5027b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 5037b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 5047b0295b3SHyeoncheol Lee varname); 505b55a87adSMasami Hiramatsu return -EINVAL; 506b55a87adSMasami Hiramatsu } 507b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') { 5080e43e5d2SMasami Hiramatsu pr_err("Semantic error: %s is not a pointor" 5090e43e5d2SMasami Hiramatsu " nor array.\n", varname); 510b2a3c12bSMasami Hiramatsu return -EINVAL; 511b2a3c12bSMasami Hiramatsu } 512b55a87adSMasami Hiramatsu if (field->ref) { 513b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '.'\n", 5147df2f329SMasami Hiramatsu field->name); 515b55a87adSMasami Hiramatsu return -EINVAL; 516b55a87adSMasami Hiramatsu } 517b55a87adSMasami Hiramatsu if (!ref) { 518b55a87adSMasami Hiramatsu pr_warning("Structure on a register is not " 519b55a87adSMasami Hiramatsu "supported yet.\n"); 520b55a87adSMasami Hiramatsu return -ENOTSUP; 521b55a87adSMasami Hiramatsu } 5227df2f329SMasami Hiramatsu } 5237df2f329SMasami Hiramatsu 524b55a87adSMasami Hiramatsu if (die_find_member(&type, field->name, die_mem) == NULL) { 5259ef0438aSArnaldo Carvalho de Melo pr_warning("%s(type:%s) has no member %s.\n", varname, 5267df2f329SMasami Hiramatsu dwarf_diename(&type), field->name); 527b55a87adSMasami Hiramatsu return -EINVAL; 528b55a87adSMasami Hiramatsu } 5297df2f329SMasami Hiramatsu 5307df2f329SMasami Hiramatsu /* Get the offset of the field */ 5317b0295b3SHyeoncheol Lee if (tag == DW_TAG_union_type) { 5327b0295b3SHyeoncheol Lee offs = 0; 5337b0295b3SHyeoncheol Lee } else { 534de1439d8SMasami Hiramatsu ret = die_get_data_member_location(die_mem, &offs); 535de1439d8SMasami Hiramatsu if (ret < 0) { 5367b0295b3SHyeoncheol Lee pr_warning("Failed to get the offset of %s.\n", 5377b0295b3SHyeoncheol Lee field->name); 538de1439d8SMasami Hiramatsu return ret; 539b55a87adSMasami Hiramatsu } 5407b0295b3SHyeoncheol Lee } 5417df2f329SMasami Hiramatsu ref->offset += (long)offs; 5427df2f329SMasami Hiramatsu 543b2a3c12bSMasami Hiramatsu next: 5447df2f329SMasami Hiramatsu /* Converting next field */ 5457df2f329SMasami Hiramatsu if (field->next) 546b55a87adSMasami Hiramatsu return convert_variable_fields(die_mem, field->name, 547b55a87adSMasami Hiramatsu field->next, &ref, die_mem); 548b55a87adSMasami Hiramatsu else 549b55a87adSMasami Hiramatsu return 0; 5507df2f329SMasami Hiramatsu } 5517df2f329SMasami Hiramatsu 5524ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */ 553b55a87adSMasami Hiramatsu static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 5544ea42b18SMasami Hiramatsu { 5554984912eSMasami Hiramatsu Dwarf_Die die_mem; 5564ea42b18SMasami Hiramatsu int ret; 5574ea42b18SMasami Hiramatsu 558b7dcb857SMasami Hiramatsu pr_debug("Converting variable %s into trace event.\n", 559b7dcb857SMasami Hiramatsu dwarf_diename(vr_die)); 560804b3606SMasami Hiramatsu 561cf6eb489SMasami Hiramatsu ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 5623d918a12SMasami Hiramatsu &pf->sp_die, pf->tvar); 563cf6eb489SMasami Hiramatsu if (ret == -ENOENT) 564cf6eb489SMasami Hiramatsu pr_err("Failed to find the location of %s at this address.\n" 565cf6eb489SMasami Hiramatsu " Perhaps, it has been optimized out.\n", pf->pvar->var); 566cf6eb489SMasami Hiramatsu else if (ret == -ENOTSUP) 567cf6eb489SMasami Hiramatsu pr_err("Sorry, we don't support this variable location yet.\n"); 568cf6eb489SMasami Hiramatsu else if (pf->pvar->field) { 569b55a87adSMasami Hiramatsu ret = convert_variable_fields(vr_die, pf->pvar->var, 5704984912eSMasami Hiramatsu pf->pvar->field, &pf->tvar->ref, 5714984912eSMasami Hiramatsu &die_mem); 5724984912eSMasami Hiramatsu vr_die = &die_mem; 5734984912eSMasami Hiramatsu } 57473317b95SMasami Hiramatsu if (ret == 0) 57573317b95SMasami Hiramatsu ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); 576804b3606SMasami Hiramatsu /* *expr will be cached in libdw. Don't free it. */ 577b55a87adSMasami Hiramatsu return ret; 5784ea42b18SMasami Hiramatsu } 5794ea42b18SMasami Hiramatsu 580221d0611SMasami Hiramatsu /* Find a variable in a scope DIE */ 581221d0611SMasami Hiramatsu static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 5824ea42b18SMasami Hiramatsu { 583f182e3e1SMasami Hiramatsu Dwarf_Die vr_die; 58411a1ca35SMasami Hiramatsu char buf[32], *ptr; 585f182e3e1SMasami Hiramatsu int ret = 0; 5864ea42b18SMasami Hiramatsu 587367e94c1SMasami Hiramatsu if (!is_c_varname(pf->pvar->var)) { 588367e94c1SMasami Hiramatsu /* Copy raw parameters */ 589367e94c1SMasami Hiramatsu pf->tvar->value = strdup(pf->pvar->var); 590367e94c1SMasami Hiramatsu if (pf->tvar->value == NULL) 591367e94c1SMasami Hiramatsu return -ENOMEM; 592367e94c1SMasami Hiramatsu if (pf->pvar->type) { 593367e94c1SMasami Hiramatsu pf->tvar->type = strdup(pf->pvar->type); 594367e94c1SMasami Hiramatsu if (pf->tvar->type == NULL) 595367e94c1SMasami Hiramatsu return -ENOMEM; 596367e94c1SMasami Hiramatsu } 597367e94c1SMasami Hiramatsu if (pf->pvar->name) { 598367e94c1SMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 599367e94c1SMasami Hiramatsu if (pf->tvar->name == NULL) 600367e94c1SMasami Hiramatsu return -ENOMEM; 601367e94c1SMasami Hiramatsu } else 602367e94c1SMasami Hiramatsu pf->tvar->name = NULL; 603367e94c1SMasami Hiramatsu return 0; 604367e94c1SMasami Hiramatsu } 605367e94c1SMasami Hiramatsu 60648481938SMasami Hiramatsu if (pf->pvar->name) 60702b95dadSMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 60848481938SMasami Hiramatsu else { 60902b95dadSMasami Hiramatsu ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); 61002b95dadSMasami Hiramatsu if (ret < 0) 61102b95dadSMasami Hiramatsu return ret; 61211a1ca35SMasami Hiramatsu ptr = strchr(buf, ':'); /* Change type separator to _ */ 61311a1ca35SMasami Hiramatsu if (ptr) 61411a1ca35SMasami Hiramatsu *ptr = '_'; 61502b95dadSMasami Hiramatsu pf->tvar->name = strdup(buf); 61648481938SMasami Hiramatsu } 61702b95dadSMasami Hiramatsu if (pf->tvar->name == NULL) 61802b95dadSMasami Hiramatsu return -ENOMEM; 61948481938SMasami Hiramatsu 620f182e3e1SMasami Hiramatsu pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 6214ea42b18SMasami Hiramatsu /* Search child die for local variables and parameters. */ 622f182e3e1SMasami Hiramatsu if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 623f182e3e1SMasami Hiramatsu /* Search again in global variables */ 624f182e3e1SMasami Hiramatsu if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 6258afa2a70SMasami Hiramatsu ret = -ENOENT; 626f182e3e1SMasami Hiramatsu } 627f66fedcbSMasami Hiramatsu if (ret >= 0) 628b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 629f182e3e1SMasami Hiramatsu 630b7dcb857SMasami Hiramatsu if (ret < 0) 631b55a87adSMasami Hiramatsu pr_warning("Failed to find '%s' in this function.\n", 63248481938SMasami Hiramatsu pf->pvar->var); 633b7dcb857SMasami Hiramatsu return ret; 6344ea42b18SMasami Hiramatsu } 6354ea42b18SMasami Hiramatsu 636cf6eb489SMasami Hiramatsu /* Convert subprogram DIE to trace point */ 637576b5237SMasami Hiramatsu static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, 638576b5237SMasami Hiramatsu Dwarf_Addr paddr, bool retprobe, 639576b5237SMasami Hiramatsu struct probe_trace_point *tp) 6404ea42b18SMasami Hiramatsu { 64126b79524SPrashanth Nageshappa Dwarf_Addr eaddr, highaddr; 642576b5237SMasami Hiramatsu GElf_Sym sym; 643576b5237SMasami Hiramatsu const char *symbol; 644cf6eb489SMasami Hiramatsu 645576b5237SMasami Hiramatsu /* Verify the address is correct */ 646cf6eb489SMasami Hiramatsu if (dwarf_entrypc(sp_die, &eaddr) != 0) { 6470e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s\n", 648cf6eb489SMasami Hiramatsu dwarf_diename(sp_die)); 649cf6eb489SMasami Hiramatsu return -ENOENT; 650cf6eb489SMasami Hiramatsu } 65126b79524SPrashanth Nageshappa if (dwarf_highpc(sp_die, &highaddr) != 0) { 65226b79524SPrashanth Nageshappa pr_warning("Failed to get end address of %s\n", 65326b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 65426b79524SPrashanth Nageshappa return -ENOENT; 65526b79524SPrashanth Nageshappa } 65626b79524SPrashanth Nageshappa if (paddr > highaddr) { 65726b79524SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 65826b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 65926b79524SPrashanth Nageshappa return -EINVAL; 66026b79524SPrashanth Nageshappa } 661576b5237SMasami Hiramatsu 662576b5237SMasami Hiramatsu /* Get an appropriate symbol from symtab */ 663576b5237SMasami Hiramatsu symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); 664576b5237SMasami Hiramatsu if (!symbol) { 665576b5237SMasami Hiramatsu pr_warning("Failed to find symbol at 0x%lx\n", 666576b5237SMasami Hiramatsu (unsigned long)paddr); 667576b5237SMasami Hiramatsu return -ENOENT; 668576b5237SMasami Hiramatsu } 669576b5237SMasami Hiramatsu tp->offset = (unsigned long)(paddr - sym.st_value); 670fb7345bbSMasami Hiramatsu tp->address = (unsigned long)paddr; 671576b5237SMasami Hiramatsu tp->symbol = strdup(symbol); 672576b5237SMasami Hiramatsu if (!tp->symbol) 673cf6eb489SMasami Hiramatsu return -ENOMEM; 674cf6eb489SMasami Hiramatsu 675cf6eb489SMasami Hiramatsu /* Return probe must be on the head of a subprogram */ 676cf6eb489SMasami Hiramatsu if (retprobe) { 677cf6eb489SMasami Hiramatsu if (eaddr != paddr) { 678cf6eb489SMasami Hiramatsu pr_warning("Return probe must be on the head of" 6790e43e5d2SMasami Hiramatsu " a real function.\n"); 680cf6eb489SMasami Hiramatsu return -EINVAL; 681cf6eb489SMasami Hiramatsu } 682cf6eb489SMasami Hiramatsu tp->retprobe = true; 683cf6eb489SMasami Hiramatsu } 684cf6eb489SMasami Hiramatsu 685cf6eb489SMasami Hiramatsu return 0; 686cf6eb489SMasami Hiramatsu } 687cf6eb489SMasami Hiramatsu 688221d0611SMasami Hiramatsu /* Call probe_finder callback with scope DIE */ 689221d0611SMasami Hiramatsu static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 690cf6eb489SMasami Hiramatsu { 691804b3606SMasami Hiramatsu Dwarf_Attribute fb_attr; 692804b3606SMasami Hiramatsu size_t nops; 693cf6eb489SMasami Hiramatsu int ret; 6944235b045SMasami Hiramatsu 695221d0611SMasami Hiramatsu if (!sc_die) { 696221d0611SMasami Hiramatsu pr_err("Caller must pass a scope DIE. Program error.\n"); 697221d0611SMasami Hiramatsu return -EINVAL; 698221d0611SMasami Hiramatsu } 699221d0611SMasami Hiramatsu 700221d0611SMasami Hiramatsu /* If not a real subprogram, find a real one */ 7010dbb1cacSMasami Hiramatsu if (!die_is_func_def(sc_die)) { 702221d0611SMasami Hiramatsu if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 703b55a87adSMasami Hiramatsu pr_warning("Failed to find probe point in any " 704b55a87adSMasami Hiramatsu "functions.\n"); 705b55a87adSMasami Hiramatsu return -ENOENT; 706b55a87adSMasami Hiramatsu } 707221d0611SMasami Hiramatsu } else 708221d0611SMasami Hiramatsu memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 709e92b85e1SMasami Hiramatsu 710221d0611SMasami Hiramatsu /* Get the frame base attribute/ops from subprogram */ 711221d0611SMasami Hiramatsu dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 712d0cb4260SMasami Hiramatsu ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 713a34a9854SMasami Hiramatsu if (ret <= 0 || nops == 0) { 714804b3606SMasami Hiramatsu pf->fb_ops = NULL; 7157752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 716a34a9854SMasami Hiramatsu } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 717a34a9854SMasami Hiramatsu pf->cfi != NULL) { 718a34a9854SMasami Hiramatsu Dwarf_Frame *frame; 719b55a87adSMasami Hiramatsu if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 720b55a87adSMasami Hiramatsu dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 7210e43e5d2SMasami Hiramatsu pr_warning("Failed to get call frame on 0x%jx\n", 722b55a87adSMasami Hiramatsu (uintmax_t)pf->addr); 723b55a87adSMasami Hiramatsu return -ENOENT; 724b55a87adSMasami Hiramatsu } 7257752f1b0SMasami Hiramatsu #endif 726a34a9854SMasami Hiramatsu } 727804b3606SMasami Hiramatsu 728cf6eb489SMasami Hiramatsu /* Call finder's callback handler */ 729221d0611SMasami Hiramatsu ret = pf->callback(sc_die, pf); 730804b3606SMasami Hiramatsu 731804b3606SMasami Hiramatsu /* *pf->fb_ops will be cached in libdw. Don't free it. */ 732804b3606SMasami Hiramatsu pf->fb_ops = NULL; 733cf6eb489SMasami Hiramatsu 734cf6eb489SMasami Hiramatsu return ret; 7354ea42b18SMasami Hiramatsu } 7364ea42b18SMasami Hiramatsu 737221d0611SMasami Hiramatsu struct find_scope_param { 738221d0611SMasami Hiramatsu const char *function; 739221d0611SMasami Hiramatsu const char *file; 740221d0611SMasami Hiramatsu int line; 741221d0611SMasami Hiramatsu int diff; 742221d0611SMasami Hiramatsu Dwarf_Die *die_mem; 743221d0611SMasami Hiramatsu bool found; 744221d0611SMasami Hiramatsu }; 745221d0611SMasami Hiramatsu 746221d0611SMasami Hiramatsu static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 747221d0611SMasami Hiramatsu { 748221d0611SMasami Hiramatsu struct find_scope_param *fsp = data; 749221d0611SMasami Hiramatsu const char *file; 750221d0611SMasami Hiramatsu int lno; 751221d0611SMasami Hiramatsu 752221d0611SMasami Hiramatsu /* Skip if declared file name does not match */ 753221d0611SMasami Hiramatsu if (fsp->file) { 754221d0611SMasami Hiramatsu file = dwarf_decl_file(fn_die); 755221d0611SMasami Hiramatsu if (!file || strcmp(fsp->file, file) != 0) 756221d0611SMasami Hiramatsu return 0; 757221d0611SMasami Hiramatsu } 758221d0611SMasami Hiramatsu /* If the function name is given, that's what user expects */ 759221d0611SMasami Hiramatsu if (fsp->function) { 760221d0611SMasami Hiramatsu if (die_compare_name(fn_die, fsp->function)) { 761221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 762221d0611SMasami Hiramatsu fsp->found = true; 763221d0611SMasami Hiramatsu return 1; 764221d0611SMasami Hiramatsu } 765221d0611SMasami Hiramatsu } else { 766221d0611SMasami Hiramatsu /* With the line number, find the nearest declared DIE */ 767221d0611SMasami Hiramatsu dwarf_decl_line(fn_die, &lno); 768221d0611SMasami Hiramatsu if (lno < fsp->line && fsp->diff > fsp->line - lno) { 769221d0611SMasami Hiramatsu /* Keep a candidate and continue */ 770221d0611SMasami Hiramatsu fsp->diff = fsp->line - lno; 771221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 772221d0611SMasami Hiramatsu fsp->found = true; 773221d0611SMasami Hiramatsu } 774221d0611SMasami Hiramatsu } 775221d0611SMasami Hiramatsu return 0; 776221d0611SMasami Hiramatsu } 777221d0611SMasami Hiramatsu 778221d0611SMasami Hiramatsu /* Find an appropriate scope fits to given conditions */ 779221d0611SMasami Hiramatsu static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 780221d0611SMasami Hiramatsu { 781221d0611SMasami Hiramatsu struct find_scope_param fsp = { 782221d0611SMasami Hiramatsu .function = pf->pev->point.function, 783221d0611SMasami Hiramatsu .file = pf->fname, 784221d0611SMasami Hiramatsu .line = pf->lno, 785221d0611SMasami Hiramatsu .diff = INT_MAX, 786221d0611SMasami Hiramatsu .die_mem = die_mem, 787221d0611SMasami Hiramatsu .found = false, 788221d0611SMasami Hiramatsu }; 789221d0611SMasami Hiramatsu 790221d0611SMasami Hiramatsu cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 791221d0611SMasami Hiramatsu 792221d0611SMasami Hiramatsu return fsp.found ? die_mem : NULL; 793221d0611SMasami Hiramatsu } 794221d0611SMasami Hiramatsu 7954cc9cec6SMasami Hiramatsu static int probe_point_line_walker(const char *fname, int lineno, 7964cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 7974cc9cec6SMasami Hiramatsu { 7984cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 799221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 8004cc9cec6SMasami Hiramatsu int ret; 8014cc9cec6SMasami Hiramatsu 8024cc9cec6SMasami Hiramatsu if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 8034cc9cec6SMasami Hiramatsu return 0; 8044cc9cec6SMasami Hiramatsu 8054cc9cec6SMasami Hiramatsu pf->addr = addr; 806221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 807221d0611SMasami Hiramatsu if (!sc_die) { 808221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 809221d0611SMasami Hiramatsu return -ENOENT; 810221d0611SMasami Hiramatsu } 811221d0611SMasami Hiramatsu 812221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8134cc9cec6SMasami Hiramatsu 8144cc9cec6SMasami Hiramatsu /* Continue if no error, because the line will be in inline function */ 815fbee632dSArnaldo Carvalho de Melo return ret < 0 ? ret : 0; 8164cc9cec6SMasami Hiramatsu } 8174cc9cec6SMasami Hiramatsu 8184ea42b18SMasami Hiramatsu /* Find probe point from its line number */ 819b55a87adSMasami Hiramatsu static int find_probe_point_by_line(struct probe_finder *pf) 8204ea42b18SMasami Hiramatsu { 8214cc9cec6SMasami Hiramatsu return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 8224ea42b18SMasami Hiramatsu } 8234ea42b18SMasami Hiramatsu 8242a9c8c36SMasami Hiramatsu /* Find lines which match lazy pattern */ 825*5a62257aSMasami Hiramatsu static int find_lazy_match_lines(struct intlist *list, 8262a9c8c36SMasami Hiramatsu const char *fname, const char *pat) 8272a9c8c36SMasami Hiramatsu { 828f50c2169SFranck Bui-Huu FILE *fp; 829f50c2169SFranck Bui-Huu char *line = NULL; 830f50c2169SFranck Bui-Huu size_t line_len; 831f50c2169SFranck Bui-Huu ssize_t len; 832f50c2169SFranck Bui-Huu int count = 0, linenum = 1; 8332a9c8c36SMasami Hiramatsu 834f50c2169SFranck Bui-Huu fp = fopen(fname, "r"); 835f50c2169SFranck Bui-Huu if (!fp) { 836f50c2169SFranck Bui-Huu pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); 837b448c4b6SArnaldo Carvalho de Melo return -errno; 838b55a87adSMasami Hiramatsu } 839b55a87adSMasami Hiramatsu 840f50c2169SFranck Bui-Huu while ((len = getline(&line, &line_len, fp)) > 0) { 841f50c2169SFranck Bui-Huu 842f50c2169SFranck Bui-Huu if (line[len - 1] == '\n') 843f50c2169SFranck Bui-Huu line[len - 1] = '\0'; 844f50c2169SFranck Bui-Huu 845f50c2169SFranck Bui-Huu if (strlazymatch(line, pat)) { 846*5a62257aSMasami Hiramatsu intlist__add(list, linenum); 847f50c2169SFranck Bui-Huu count++; 848f50c2169SFranck Bui-Huu } 849f50c2169SFranck Bui-Huu linenum++; 850b55a87adSMasami Hiramatsu } 851b448c4b6SArnaldo Carvalho de Melo 852f50c2169SFranck Bui-Huu if (ferror(fp)) 853f50c2169SFranck Bui-Huu count = -errno; 854f50c2169SFranck Bui-Huu free(line); 855f50c2169SFranck Bui-Huu fclose(fp); 856f50c2169SFranck Bui-Huu 857f50c2169SFranck Bui-Huu if (count == 0) 858f50c2169SFranck Bui-Huu pr_debug("No matched lines found in %s.\n", fname); 859f50c2169SFranck Bui-Huu return count; 8602a9c8c36SMasami Hiramatsu } 8612a9c8c36SMasami Hiramatsu 8624cc9cec6SMasami Hiramatsu static int probe_point_lazy_walker(const char *fname, int lineno, 8634cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 8644cc9cec6SMasami Hiramatsu { 8654cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 866221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 8674cc9cec6SMasami Hiramatsu int ret; 8684cc9cec6SMasami Hiramatsu 869*5a62257aSMasami Hiramatsu if (!intlist__has_entry(pf->lcache, lineno) || 8704cc9cec6SMasami Hiramatsu strtailcmp(fname, pf->fname) != 0) 8714cc9cec6SMasami Hiramatsu return 0; 8724cc9cec6SMasami Hiramatsu 8734cc9cec6SMasami Hiramatsu pr_debug("Probe line found: line:%d addr:0x%llx\n", 8744cc9cec6SMasami Hiramatsu lineno, (unsigned long long)addr); 8754cc9cec6SMasami Hiramatsu pf->addr = addr; 876221d0611SMasami Hiramatsu pf->lno = lineno; 877221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 878221d0611SMasami Hiramatsu if (!sc_die) { 879221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 880221d0611SMasami Hiramatsu return -ENOENT; 881221d0611SMasami Hiramatsu } 882221d0611SMasami Hiramatsu 883221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8844cc9cec6SMasami Hiramatsu 8854cc9cec6SMasami Hiramatsu /* 8864cc9cec6SMasami Hiramatsu * Continue if no error, because the lazy pattern will match 8874cc9cec6SMasami Hiramatsu * to other lines 8884cc9cec6SMasami Hiramatsu */ 8895e814dd5SIngo Molnar return ret < 0 ? ret : 0; 8904cc9cec6SMasami Hiramatsu } 8914cc9cec6SMasami Hiramatsu 8922a9c8c36SMasami Hiramatsu /* Find probe points from lazy pattern */ 893b55a87adSMasami Hiramatsu static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 8942a9c8c36SMasami Hiramatsu { 895b55a87adSMasami Hiramatsu int ret = 0; 8962a9c8c36SMasami Hiramatsu 897*5a62257aSMasami Hiramatsu if (intlist__empty(pf->lcache)) { 8982a9c8c36SMasami Hiramatsu /* Matching lazy line pattern */ 899*5a62257aSMasami Hiramatsu ret = find_lazy_match_lines(pf->lcache, pf->fname, 9004235b045SMasami Hiramatsu pf->pev->point.lazy_line); 901f50c2169SFranck Bui-Huu if (ret <= 0) 902b55a87adSMasami Hiramatsu return ret; 9032a9c8c36SMasami Hiramatsu } 9042a9c8c36SMasami Hiramatsu 9054cc9cec6SMasami Hiramatsu return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 9062a9c8c36SMasami Hiramatsu } 9072a9c8c36SMasami Hiramatsu 908e92b85e1SMasami Hiramatsu static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 9094ea42b18SMasami Hiramatsu { 910db0d2c64SMasami Hiramatsu struct probe_finder *pf = data; 9114235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 912b55a87adSMasami Hiramatsu Dwarf_Addr addr; 913db0d2c64SMasami Hiramatsu int ret; 9144ea42b18SMasami Hiramatsu 9152a9c8c36SMasami Hiramatsu if (pp->lazy_line) 916db0d2c64SMasami Hiramatsu ret = find_probe_point_lazy(in_die, pf); 9172a9c8c36SMasami Hiramatsu else { 918e92b85e1SMasami Hiramatsu /* Get probe address */ 919b55a87adSMasami Hiramatsu if (dwarf_entrypc(in_die, &addr) != 0) { 9200e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s.\n", 921b55a87adSMasami Hiramatsu dwarf_diename(in_die)); 922db0d2c64SMasami Hiramatsu return -ENOENT; 923b55a87adSMasami Hiramatsu } 924b55a87adSMasami Hiramatsu pf->addr = addr; 925e92b85e1SMasami Hiramatsu pf->addr += pp->offset; 9262a9c8c36SMasami Hiramatsu pr_debug("found inline addr: 0x%jx\n", 9272a9c8c36SMasami Hiramatsu (uintmax_t)pf->addr); 928e92b85e1SMasami Hiramatsu 929db0d2c64SMasami Hiramatsu ret = call_probe_finder(in_die, pf); 9302a9c8c36SMasami Hiramatsu } 9312a9c8c36SMasami Hiramatsu 932db0d2c64SMasami Hiramatsu return ret; 933e92b85e1SMasami Hiramatsu } 934e92b85e1SMasami Hiramatsu 935db0d2c64SMasami Hiramatsu /* Callback parameter with return value for libdw */ 936db0d2c64SMasami Hiramatsu struct dwarf_callback_param { 937db0d2c64SMasami Hiramatsu void *data; 938db0d2c64SMasami Hiramatsu int retval; 939db0d2c64SMasami Hiramatsu }; 940db0d2c64SMasami Hiramatsu 941e92b85e1SMasami Hiramatsu /* Search function from function name */ 942e92b85e1SMasami Hiramatsu static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 943e92b85e1SMasami Hiramatsu { 944b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 945b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 9464235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 947e92b85e1SMasami Hiramatsu 948e92b85e1SMasami Hiramatsu /* Check tag and diename */ 9490dbb1cacSMasami Hiramatsu if (!die_is_func_def(sp_die) || 9500dbb1cacSMasami Hiramatsu !die_compare_name(sp_die, pp->function)) 951b55a87adSMasami Hiramatsu return DWARF_CB_OK; 952e92b85e1SMasami Hiramatsu 9537d21635aSMasami Hiramatsu /* Check declared file */ 9547d21635aSMasami Hiramatsu if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 9557d21635aSMasami Hiramatsu return DWARF_CB_OK; 9567d21635aSMasami Hiramatsu 957e92b85e1SMasami Hiramatsu pf->fname = dwarf_decl_file(sp_die); 9582a9c8c36SMasami Hiramatsu if (pp->line) { /* Function relative line */ 959e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &pf->lno); 960804b3606SMasami Hiramatsu pf->lno += pp->line; 961b55a87adSMasami Hiramatsu param->retval = find_probe_point_by_line(pf); 962e92b85e1SMasami Hiramatsu } else if (!dwarf_func_inline(sp_die)) { 963e92b85e1SMasami Hiramatsu /* Real function */ 9642a9c8c36SMasami Hiramatsu if (pp->lazy_line) 965b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(sp_die, pf); 9662a9c8c36SMasami Hiramatsu else { 967b55a87adSMasami Hiramatsu if (dwarf_entrypc(sp_die, &pf->addr) != 0) { 9680e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of " 9690e43e5d2SMasami Hiramatsu "%s.\n", dwarf_diename(sp_die)); 970b55a87adSMasami Hiramatsu param->retval = -ENOENT; 971b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 972b55a87adSMasami Hiramatsu } 9734ea42b18SMasami Hiramatsu pf->addr += pp->offset; 9744ea42b18SMasami Hiramatsu /* TODO: Check the address in this function */ 975cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(sp_die, pf); 9762a9c8c36SMasami Hiramatsu } 977db0d2c64SMasami Hiramatsu } else 978e92b85e1SMasami Hiramatsu /* Inlined function: search instances */ 979db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 980db0d2c64SMasami Hiramatsu probe_point_inline_cb, (void *)pf); 9814ea42b18SMasami Hiramatsu 982b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 983b55a87adSMasami Hiramatsu } 984b55a87adSMasami Hiramatsu 985b55a87adSMasami Hiramatsu static int find_probe_point_by_func(struct probe_finder *pf) 9864ea42b18SMasami Hiramatsu { 987b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 988b55a87adSMasami Hiramatsu .retval = 0}; 989b55a87adSMasami Hiramatsu dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 990b55a87adSMasami Hiramatsu return _param.retval; 9914ea42b18SMasami Hiramatsu } 9924ea42b18SMasami Hiramatsu 993cd25f8bcSLin Ming struct pubname_callback_param { 994cd25f8bcSLin Ming char *function; 995cd25f8bcSLin Ming char *file; 996cd25f8bcSLin Ming Dwarf_Die *cu_die; 997cd25f8bcSLin Ming Dwarf_Die *sp_die; 998cd25f8bcSLin Ming int found; 999cd25f8bcSLin Ming }; 1000cd25f8bcSLin Ming 1001cd25f8bcSLin Ming static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 1002cd25f8bcSLin Ming { 1003cd25f8bcSLin Ming struct pubname_callback_param *param = data; 1004cd25f8bcSLin Ming 1005cd25f8bcSLin Ming if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1006cd25f8bcSLin Ming if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1007cd25f8bcSLin Ming return DWARF_CB_OK; 1008cd25f8bcSLin Ming 1009cd25f8bcSLin Ming if (die_compare_name(param->sp_die, param->function)) { 1010cd25f8bcSLin Ming if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1011cd25f8bcSLin Ming return DWARF_CB_OK; 1012cd25f8bcSLin Ming 1013cd25f8bcSLin Ming if (param->file && 1014cd25f8bcSLin Ming strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1015cd25f8bcSLin Ming return DWARF_CB_OK; 1016cd25f8bcSLin Ming 1017cd25f8bcSLin Ming param->found = 1; 1018cd25f8bcSLin Ming return DWARF_CB_ABORT; 1019cd25f8bcSLin Ming } 1020cd25f8bcSLin Ming } 1021cd25f8bcSLin Ming 1022cd25f8bcSLin Ming return DWARF_CB_OK; 1023cd25f8bcSLin Ming } 1024cd25f8bcSLin Ming 1025cf6eb489SMasami Hiramatsu /* Find probe points from debuginfo */ 1026316c7136SArnaldo Carvalho de Melo static int debuginfo__find_probes(struct debuginfo *dbg, 1027ff741783SMasami Hiramatsu struct probe_finder *pf) 10284ea42b18SMasami Hiramatsu { 1029cf6eb489SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1030804b3606SMasami Hiramatsu Dwarf_Off off, noff; 1031804b3606SMasami Hiramatsu size_t cuhl; 1032804b3606SMasami Hiramatsu Dwarf_Die *diep; 1033b55a87adSMasami Hiramatsu int ret = 0; 10344ea42b18SMasami Hiramatsu 10357752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 1036a34a9854SMasami Hiramatsu /* Get the call frame information from this dwarf */ 1037316c7136SArnaldo Carvalho de Melo pf->cfi = dwarf_getcfi(dbg->dbg); 10387752f1b0SMasami Hiramatsu #endif 1039a34a9854SMasami Hiramatsu 1040804b3606SMasami Hiramatsu off = 0; 1041*5a62257aSMasami Hiramatsu pf->lcache = intlist__new(NULL); 1042*5a62257aSMasami Hiramatsu if (!pf->lcache) 1043*5a62257aSMasami Hiramatsu return -ENOMEM; 1044cd25f8bcSLin Ming 1045cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1046cd25f8bcSLin Ming if (pp->function) { 1047cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1048cd25f8bcSLin Ming .function = pp->function, 1049cd25f8bcSLin Ming .file = pp->file, 1050cd25f8bcSLin Ming .cu_die = &pf->cu_die, 1051cd25f8bcSLin Ming .sp_die = &pf->sp_die, 10522b348a77SLin Ming .found = 0, 1053cd25f8bcSLin Ming }; 1054cd25f8bcSLin Ming struct dwarf_callback_param probe_param = { 1055cd25f8bcSLin Ming .data = pf, 1056cd25f8bcSLin Ming }; 1057cd25f8bcSLin Ming 1058316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1059ff741783SMasami Hiramatsu &pubname_param, 0); 1060cd25f8bcSLin Ming if (pubname_param.found) { 1061cd25f8bcSLin Ming ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1062cd25f8bcSLin Ming if (ret) 1063cd25f8bcSLin Ming goto found; 1064cd25f8bcSLin Ming } 1065cd25f8bcSLin Ming } 1066cd25f8bcSLin Ming 1067804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1068316c7136SArnaldo Carvalho de Melo while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 10694ea42b18SMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1070316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die); 1071804b3606SMasami Hiramatsu if (!diep) 1072804b3606SMasami Hiramatsu continue; 10734ea42b18SMasami Hiramatsu 10744ea42b18SMasami Hiramatsu /* Check if target file is included. */ 10754ea42b18SMasami Hiramatsu if (pp->file) 1076cf6eb489SMasami Hiramatsu pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1077804b3606SMasami Hiramatsu else 1078cf6eb489SMasami Hiramatsu pf->fname = NULL; 10794ea42b18SMasami Hiramatsu 1080cf6eb489SMasami Hiramatsu if (!pp->file || pf->fname) { 10814ea42b18SMasami Hiramatsu if (pp->function) 1082cf6eb489SMasami Hiramatsu ret = find_probe_point_by_func(pf); 10832a9c8c36SMasami Hiramatsu else if (pp->lazy_line) 1084cf6eb489SMasami Hiramatsu ret = find_probe_point_lazy(NULL, pf); 1085b0ef0732SMasami Hiramatsu else { 1086cf6eb489SMasami Hiramatsu pf->lno = pp->line; 1087cf6eb489SMasami Hiramatsu ret = find_probe_point_by_line(pf); 10884ea42b18SMasami Hiramatsu } 10898635bf6eSArnaldo Carvalho de Melo if (ret < 0) 1090fbee632dSArnaldo Carvalho de Melo break; 1091b0ef0732SMasami Hiramatsu } 1092804b3606SMasami Hiramatsu off = noff; 10934ea42b18SMasami Hiramatsu } 1094cd25f8bcSLin Ming 1095cd25f8bcSLin Ming found: 1096*5a62257aSMasami Hiramatsu intlist__delete(pf->lcache); 1097*5a62257aSMasami Hiramatsu pf->lcache = NULL; 10984ea42b18SMasami Hiramatsu 1099cf6eb489SMasami Hiramatsu return ret; 1100cf6eb489SMasami Hiramatsu } 1101cf6eb489SMasami Hiramatsu 11027969ec77SMasami Hiramatsu struct local_vars_finder { 11037969ec77SMasami Hiramatsu struct probe_finder *pf; 11047969ec77SMasami Hiramatsu struct perf_probe_arg *args; 11057969ec77SMasami Hiramatsu int max_args; 11067969ec77SMasami Hiramatsu int nargs; 11077969ec77SMasami Hiramatsu int ret; 11087969ec77SMasami Hiramatsu }; 11097969ec77SMasami Hiramatsu 11107969ec77SMasami Hiramatsu /* Collect available variables in this scope */ 11117969ec77SMasami Hiramatsu static int copy_variables_cb(Dwarf_Die *die_mem, void *data) 11127969ec77SMasami Hiramatsu { 11137969ec77SMasami Hiramatsu struct local_vars_finder *vf = data; 11143d918a12SMasami Hiramatsu struct probe_finder *pf = vf->pf; 11157969ec77SMasami Hiramatsu int tag; 11167969ec77SMasami Hiramatsu 11177969ec77SMasami Hiramatsu tag = dwarf_tag(die_mem); 11187969ec77SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 11197969ec77SMasami Hiramatsu tag == DW_TAG_variable) { 11207969ec77SMasami Hiramatsu if (convert_variable_location(die_mem, vf->pf->addr, 11213d918a12SMasami Hiramatsu vf->pf->fb_ops, &pf->sp_die, 11223d918a12SMasami Hiramatsu NULL) == 0) { 11237969ec77SMasami Hiramatsu vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); 11247969ec77SMasami Hiramatsu if (vf->args[vf->nargs].var == NULL) { 11257969ec77SMasami Hiramatsu vf->ret = -ENOMEM; 11267969ec77SMasami Hiramatsu return DIE_FIND_CB_END; 11277969ec77SMasami Hiramatsu } 11287969ec77SMasami Hiramatsu pr_debug(" %s", vf->args[vf->nargs].var); 11297969ec77SMasami Hiramatsu vf->nargs++; 11307969ec77SMasami Hiramatsu } 11317969ec77SMasami Hiramatsu } 11327969ec77SMasami Hiramatsu 11337969ec77SMasami Hiramatsu if (dwarf_haspc(die_mem, vf->pf->addr)) 11347969ec77SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 11357969ec77SMasami Hiramatsu else 11367969ec77SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 11377969ec77SMasami Hiramatsu } 11387969ec77SMasami Hiramatsu 11397969ec77SMasami Hiramatsu static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, 11407969ec77SMasami Hiramatsu struct perf_probe_arg *args) 11417969ec77SMasami Hiramatsu { 11427969ec77SMasami Hiramatsu Dwarf_Die die_mem; 11437969ec77SMasami Hiramatsu int i; 11447969ec77SMasami Hiramatsu int n = 0; 11457969ec77SMasami Hiramatsu struct local_vars_finder vf = {.pf = pf, .args = args, 11467969ec77SMasami Hiramatsu .max_args = MAX_PROBE_ARGS, .ret = 0}; 11477969ec77SMasami Hiramatsu 11487969ec77SMasami Hiramatsu for (i = 0; i < pf->pev->nargs; i++) { 11497969ec77SMasami Hiramatsu /* var never be NULL */ 11507969ec77SMasami Hiramatsu if (strcmp(pf->pev->args[i].var, "$vars") == 0) { 11517969ec77SMasami Hiramatsu pr_debug("Expanding $vars into:"); 11527969ec77SMasami Hiramatsu vf.nargs = n; 11537969ec77SMasami Hiramatsu /* Special local variables */ 11547969ec77SMasami Hiramatsu die_find_child(sc_die, copy_variables_cb, (void *)&vf, 11557969ec77SMasami Hiramatsu &die_mem); 11567969ec77SMasami Hiramatsu pr_debug(" (%d)\n", vf.nargs - n); 11577969ec77SMasami Hiramatsu if (vf.ret < 0) 11587969ec77SMasami Hiramatsu return vf.ret; 11597969ec77SMasami Hiramatsu n = vf.nargs; 11607969ec77SMasami Hiramatsu } else { 11617969ec77SMasami Hiramatsu /* Copy normal argument */ 11627969ec77SMasami Hiramatsu args[n] = pf->pev->args[i]; 11637969ec77SMasami Hiramatsu n++; 11647969ec77SMasami Hiramatsu } 11657969ec77SMasami Hiramatsu } 11667969ec77SMasami Hiramatsu return n; 11677969ec77SMasami Hiramatsu } 11687969ec77SMasami Hiramatsu 1169cf6eb489SMasami Hiramatsu /* Add a found probe point into trace event list */ 1170221d0611SMasami Hiramatsu static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1171cf6eb489SMasami Hiramatsu { 1172cf6eb489SMasami Hiramatsu struct trace_event_finder *tf = 1173cf6eb489SMasami Hiramatsu container_of(pf, struct trace_event_finder, pf); 1174cf6eb489SMasami Hiramatsu struct probe_trace_event *tev; 11757969ec77SMasami Hiramatsu struct perf_probe_arg *args; 1176cf6eb489SMasami Hiramatsu int ret, i; 1177cf6eb489SMasami Hiramatsu 1178cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1179cf6eb489SMasami Hiramatsu if (tf->ntevs == tf->max_tevs) { 1180cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", 1181cf6eb489SMasami Hiramatsu tf->max_tevs); 1182cf6eb489SMasami Hiramatsu return -ERANGE; 1183cf6eb489SMasami Hiramatsu } 1184cf6eb489SMasami Hiramatsu tev = &tf->tevs[tf->ntevs++]; 1185cf6eb489SMasami Hiramatsu 1186221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1187576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 1188221d0611SMasami Hiramatsu pf->pev->point.retprobe, &tev->point); 1189cf6eb489SMasami Hiramatsu if (ret < 0) 1190cf6eb489SMasami Hiramatsu return ret; 1191cf6eb489SMasami Hiramatsu 1192cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1193cf6eb489SMasami Hiramatsu tev->point.offset); 1194cf6eb489SMasami Hiramatsu 11957969ec77SMasami Hiramatsu /* Expand special probe argument if exist */ 11967969ec77SMasami Hiramatsu args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); 11977969ec77SMasami Hiramatsu if (args == NULL) 1198cf6eb489SMasami Hiramatsu return -ENOMEM; 11997969ec77SMasami Hiramatsu 12007969ec77SMasami Hiramatsu ret = expand_probe_args(sc_die, pf, args); 12017969ec77SMasami Hiramatsu if (ret < 0) 12027969ec77SMasami Hiramatsu goto end; 12037969ec77SMasami Hiramatsu 12047969ec77SMasami Hiramatsu tev->nargs = ret; 12057969ec77SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 12067969ec77SMasami Hiramatsu if (tev->args == NULL) { 12077969ec77SMasami Hiramatsu ret = -ENOMEM; 12087969ec77SMasami Hiramatsu goto end; 12097969ec77SMasami Hiramatsu } 12107969ec77SMasami Hiramatsu 12117969ec77SMasami Hiramatsu /* Find each argument */ 12127969ec77SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 12137969ec77SMasami Hiramatsu pf->pvar = &args[i]; 1214cf6eb489SMasami Hiramatsu pf->tvar = &tev->args[i]; 1215221d0611SMasami Hiramatsu /* Variable should be found from scope DIE */ 1216221d0611SMasami Hiramatsu ret = find_variable(sc_die, pf); 1217cf6eb489SMasami Hiramatsu if (ret != 0) 12187969ec77SMasami Hiramatsu break; 1219cf6eb489SMasami Hiramatsu } 1220cf6eb489SMasami Hiramatsu 12217969ec77SMasami Hiramatsu end: 12227969ec77SMasami Hiramatsu free(args); 12237969ec77SMasami Hiramatsu return ret; 1224cf6eb489SMasami Hiramatsu } 1225cf6eb489SMasami Hiramatsu 1226cf6eb489SMasami Hiramatsu /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1227316c7136SArnaldo Carvalho de Melo int debuginfo__find_trace_events(struct debuginfo *dbg, 1228ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1229cf6eb489SMasami Hiramatsu struct probe_trace_event **tevs, int max_tevs) 1230cf6eb489SMasami Hiramatsu { 1231cf6eb489SMasami Hiramatsu struct trace_event_finder tf = { 1232cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_probe_trace_event}, 1233316c7136SArnaldo Carvalho de Melo .mod = dbg->mod, .max_tevs = max_tevs}; 1234cf6eb489SMasami Hiramatsu int ret; 1235cf6eb489SMasami Hiramatsu 1236cf6eb489SMasami Hiramatsu /* Allocate result tevs array */ 1237cf6eb489SMasami Hiramatsu *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1238cf6eb489SMasami Hiramatsu if (*tevs == NULL) 1239cf6eb489SMasami Hiramatsu return -ENOMEM; 1240cf6eb489SMasami Hiramatsu 1241cf6eb489SMasami Hiramatsu tf.tevs = *tevs; 1242cf6eb489SMasami Hiramatsu tf.ntevs = 0; 1243cf6eb489SMasami Hiramatsu 1244316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &tf.pf); 1245cf6eb489SMasami Hiramatsu if (ret < 0) { 124604662523SArnaldo Carvalho de Melo zfree(tevs); 1247cf6eb489SMasami Hiramatsu return ret; 1248cf6eb489SMasami Hiramatsu } 1249cf6eb489SMasami Hiramatsu 1250cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : tf.ntevs; 1251cf6eb489SMasami Hiramatsu } 1252cf6eb489SMasami Hiramatsu 1253cf6eb489SMasami Hiramatsu #define MAX_VAR_LEN 64 1254cf6eb489SMasami Hiramatsu 1255cf6eb489SMasami Hiramatsu /* Collect available variables in this scope */ 1256cf6eb489SMasami Hiramatsu static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1257cf6eb489SMasami Hiramatsu { 1258cf6eb489SMasami Hiramatsu struct available_var_finder *af = data; 1259cf6eb489SMasami Hiramatsu struct variable_list *vl; 1260cf6eb489SMasami Hiramatsu char buf[MAX_VAR_LEN]; 1261cf6eb489SMasami Hiramatsu int tag, ret; 1262cf6eb489SMasami Hiramatsu 1263cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls - 1]; 1264cf6eb489SMasami Hiramatsu 1265cf6eb489SMasami Hiramatsu tag = dwarf_tag(die_mem); 1266cf6eb489SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1267cf6eb489SMasami Hiramatsu tag == DW_TAG_variable) { 1268cf6eb489SMasami Hiramatsu ret = convert_variable_location(die_mem, af->pf.addr, 12693d918a12SMasami Hiramatsu af->pf.fb_ops, &af->pf.sp_die, 12703d918a12SMasami Hiramatsu NULL); 1271cf6eb489SMasami Hiramatsu if (ret == 0) { 1272cf6eb489SMasami Hiramatsu ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1273fb8c5a56SMasami Hiramatsu pr_debug2("Add new var: %s\n", buf); 1274cf6eb489SMasami Hiramatsu if (ret > 0) 1275cf6eb489SMasami Hiramatsu strlist__add(vl->vars, buf); 1276cf6eb489SMasami Hiramatsu } 1277cf6eb489SMasami Hiramatsu } 1278cf6eb489SMasami Hiramatsu 1279fb8c5a56SMasami Hiramatsu if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1280cf6eb489SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 1281cf6eb489SMasami Hiramatsu else 1282cf6eb489SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 1283cf6eb489SMasami Hiramatsu } 1284cf6eb489SMasami Hiramatsu 1285cf6eb489SMasami Hiramatsu /* Add a found vars into available variables list */ 1286221d0611SMasami Hiramatsu static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1287cf6eb489SMasami Hiramatsu { 1288cf6eb489SMasami Hiramatsu struct available_var_finder *af = 1289cf6eb489SMasami Hiramatsu container_of(pf, struct available_var_finder, pf); 1290cf6eb489SMasami Hiramatsu struct variable_list *vl; 1291f182e3e1SMasami Hiramatsu Dwarf_Die die_mem; 1292f182e3e1SMasami Hiramatsu int ret; 1293cf6eb489SMasami Hiramatsu 1294cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1295cf6eb489SMasami Hiramatsu if (af->nvls == af->max_vls) { 1296cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1297cf6eb489SMasami Hiramatsu return -ERANGE; 1298cf6eb489SMasami Hiramatsu } 1299cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls++]; 1300cf6eb489SMasami Hiramatsu 1301221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1302576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, 1303221d0611SMasami Hiramatsu pf->pev->point.retprobe, &vl->point); 1304cf6eb489SMasami Hiramatsu if (ret < 0) 1305cf6eb489SMasami Hiramatsu return ret; 1306cf6eb489SMasami Hiramatsu 1307cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1308cf6eb489SMasami Hiramatsu vl->point.offset); 1309cf6eb489SMasami Hiramatsu 1310cf6eb489SMasami Hiramatsu /* Find local variables */ 1311cf6eb489SMasami Hiramatsu vl->vars = strlist__new(true, NULL); 1312cf6eb489SMasami Hiramatsu if (vl->vars == NULL) 1313cf6eb489SMasami Hiramatsu return -ENOMEM; 1314fb8c5a56SMasami Hiramatsu af->child = true; 1315221d0611SMasami Hiramatsu die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1316cf6eb489SMasami Hiramatsu 1317fb8c5a56SMasami Hiramatsu /* Find external variables */ 1318fb8c5a56SMasami Hiramatsu if (!af->externs) 1319fb8c5a56SMasami Hiramatsu goto out; 1320fb8c5a56SMasami Hiramatsu /* Don't need to search child DIE for externs. */ 1321fb8c5a56SMasami Hiramatsu af->child = false; 1322f182e3e1SMasami Hiramatsu die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1323fb8c5a56SMasami Hiramatsu 1324fb8c5a56SMasami Hiramatsu out: 1325cf6eb489SMasami Hiramatsu if (strlist__empty(vl->vars)) { 1326cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 1327cf6eb489SMasami Hiramatsu vl->vars = NULL; 1328cf6eb489SMasami Hiramatsu } 1329cf6eb489SMasami Hiramatsu 1330cf6eb489SMasami Hiramatsu return ret; 1331cf6eb489SMasami Hiramatsu } 1332cf6eb489SMasami Hiramatsu 1333cf6eb489SMasami Hiramatsu /* Find available variables at given probe point */ 1334316c7136SArnaldo Carvalho de Melo int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1335ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1336ff741783SMasami Hiramatsu struct variable_list **vls, 1337ff741783SMasami Hiramatsu int max_vls, bool externs) 1338cf6eb489SMasami Hiramatsu { 1339cf6eb489SMasami Hiramatsu struct available_var_finder af = { 1340cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_available_vars}, 1341316c7136SArnaldo Carvalho de Melo .mod = dbg->mod, 1342fb8c5a56SMasami Hiramatsu .max_vls = max_vls, .externs = externs}; 1343cf6eb489SMasami Hiramatsu int ret; 1344cf6eb489SMasami Hiramatsu 1345cf6eb489SMasami Hiramatsu /* Allocate result vls array */ 1346cf6eb489SMasami Hiramatsu *vls = zalloc(sizeof(struct variable_list) * max_vls); 1347cf6eb489SMasami Hiramatsu if (*vls == NULL) 1348cf6eb489SMasami Hiramatsu return -ENOMEM; 1349cf6eb489SMasami Hiramatsu 1350cf6eb489SMasami Hiramatsu af.vls = *vls; 1351cf6eb489SMasami Hiramatsu af.nvls = 0; 1352cf6eb489SMasami Hiramatsu 1353316c7136SArnaldo Carvalho de Melo ret = debuginfo__find_probes(dbg, &af.pf); 1354cf6eb489SMasami Hiramatsu if (ret < 0) { 1355cf6eb489SMasami Hiramatsu /* Free vlist for error */ 1356cf6eb489SMasami Hiramatsu while (af.nvls--) { 135774cf249dSArnaldo Carvalho de Melo zfree(&af.vls[af.nvls].point.symbol); 1358cf6eb489SMasami Hiramatsu strlist__delete(af.vls[af.nvls].vars); 1359cf6eb489SMasami Hiramatsu } 136004662523SArnaldo Carvalho de Melo zfree(vls); 1361cf6eb489SMasami Hiramatsu return ret; 1362cf6eb489SMasami Hiramatsu } 1363cf6eb489SMasami Hiramatsu 1364cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : af.nvls; 13654ea42b18SMasami Hiramatsu } 13664ea42b18SMasami Hiramatsu 1367fb1587d8SMasami Hiramatsu /* Reverse search */ 1368316c7136SArnaldo Carvalho de Melo int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, 1369ff741783SMasami Hiramatsu struct perf_probe_point *ppt) 1370fb1587d8SMasami Hiramatsu { 1371fb1587d8SMasami Hiramatsu Dwarf_Die cudie, spdie, indie; 1372e08cfd4bSMasami Hiramatsu Dwarf_Addr _addr = 0, baseaddr = 0; 1373e08cfd4bSMasami Hiramatsu const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; 13741d46ea2aSMasami Hiramatsu int baseline = 0, lineno = 0, ret = 0; 1375fb1587d8SMasami Hiramatsu 1376469b9b88SMasami Hiramatsu /* Adjust address with bias */ 1377316c7136SArnaldo Carvalho de Melo addr += dbg->bias; 1378ff741783SMasami Hiramatsu 1379fb1587d8SMasami Hiramatsu /* Find cu die */ 1380316c7136SArnaldo Carvalho de Melo if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr - dbg->bias, &cudie)) { 13810e43e5d2SMasami Hiramatsu pr_warning("Failed to find debug information for address %lx\n", 13820e43e5d2SMasami Hiramatsu addr); 138375ec5a24SMasami Hiramatsu ret = -EINVAL; 138475ec5a24SMasami Hiramatsu goto end; 138575ec5a24SMasami Hiramatsu } 1386fb1587d8SMasami Hiramatsu 13871d46ea2aSMasami Hiramatsu /* Find a corresponding line (filename and lineno) */ 13881d46ea2aSMasami Hiramatsu cu_find_lineinfo(&cudie, addr, &fname, &lineno); 13891d46ea2aSMasami Hiramatsu /* Don't care whether it failed or not */ 1390fb1587d8SMasami Hiramatsu 13911d46ea2aSMasami Hiramatsu /* Find a corresponding function (name, baseline and baseaddr) */ 1392e0d153c6SMasami Hiramatsu if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 13931d46ea2aSMasami Hiramatsu /* Get function entry information */ 1394e08cfd4bSMasami Hiramatsu func = basefunc = dwarf_diename(&spdie); 1395e08cfd4bSMasami Hiramatsu if (!func || 13961d46ea2aSMasami Hiramatsu dwarf_entrypc(&spdie, &baseaddr) != 0 || 1397e08cfd4bSMasami Hiramatsu dwarf_decl_line(&spdie, &baseline) != 0) { 1398e08cfd4bSMasami Hiramatsu lineno = 0; 13991d46ea2aSMasami Hiramatsu goto post; 1400e08cfd4bSMasami Hiramatsu } 1401fb1587d8SMasami Hiramatsu 14021b286bddSMasami Hiramatsu fname = dwarf_decl_file(&spdie); 1403e08cfd4bSMasami Hiramatsu if (addr == (unsigned long)baseaddr) { 14041d46ea2aSMasami Hiramatsu /* Function entry - Relative line number is 0 */ 14051d46ea2aSMasami Hiramatsu lineno = baseline; 1406e08cfd4bSMasami Hiramatsu goto post; 1407e08cfd4bSMasami Hiramatsu } 1408e08cfd4bSMasami Hiramatsu 1409e08cfd4bSMasami Hiramatsu /* Track down the inline functions step by step */ 1410e08cfd4bSMasami Hiramatsu while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, 1411b55a87adSMasami Hiramatsu &indie)) { 1412e08cfd4bSMasami Hiramatsu /* There is an inline function */ 14131d46ea2aSMasami Hiramatsu if (dwarf_entrypc(&indie, &_addr) == 0 && 1414e08cfd4bSMasami Hiramatsu _addr == addr) { 14151d46ea2aSMasami Hiramatsu /* 14161d46ea2aSMasami Hiramatsu * addr is at an inline function entry. 14171d46ea2aSMasami Hiramatsu * In this case, lineno should be the call-site 1418e08cfd4bSMasami Hiramatsu * line number. (overwrite lineinfo) 14191d46ea2aSMasami Hiramatsu */ 14201d46ea2aSMasami Hiramatsu lineno = die_get_call_lineno(&indie); 1421e08cfd4bSMasami Hiramatsu fname = die_get_call_file(&indie); 1422e08cfd4bSMasami Hiramatsu break; 1423e08cfd4bSMasami Hiramatsu } else { 14241d46ea2aSMasami Hiramatsu /* 14251d46ea2aSMasami Hiramatsu * addr is in an inline function body. 14261d46ea2aSMasami Hiramatsu * Since lineno points one of the lines 14271d46ea2aSMasami Hiramatsu * of the inline function, baseline should 14281d46ea2aSMasami Hiramatsu * be the entry line of the inline function. 14291d46ea2aSMasami Hiramatsu */ 1430fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&indie); 1431e08cfd4bSMasami Hiramatsu if (!tmp || 1432e08cfd4bSMasami Hiramatsu dwarf_decl_line(&indie, &baseline) != 0) 1433e08cfd4bSMasami Hiramatsu break; 14341d46ea2aSMasami Hiramatsu func = tmp; 1435e08cfd4bSMasami Hiramatsu spdie = indie; 1436b55a87adSMasami Hiramatsu } 1437b55a87adSMasami Hiramatsu } 1438e08cfd4bSMasami Hiramatsu /* Verify the lineno and baseline are in a same file */ 1439e08cfd4bSMasami Hiramatsu tmp = dwarf_decl_file(&spdie); 1440e08cfd4bSMasami Hiramatsu if (!tmp || strcmp(tmp, fname) != 0) 1441e08cfd4bSMasami Hiramatsu lineno = 0; 14421d46ea2aSMasami Hiramatsu } 14431d46ea2aSMasami Hiramatsu 14441d46ea2aSMasami Hiramatsu post: 14451d46ea2aSMasami Hiramatsu /* Make a relative line number or an offset */ 14461d46ea2aSMasami Hiramatsu if (lineno) 14471d46ea2aSMasami Hiramatsu ppt->line = lineno - baseline; 1448e08cfd4bSMasami Hiramatsu else if (basefunc) { 14491d46ea2aSMasami Hiramatsu ppt->offset = addr - (unsigned long)baseaddr; 1450e08cfd4bSMasami Hiramatsu func = basefunc; 1451e08cfd4bSMasami Hiramatsu } 14521d46ea2aSMasami Hiramatsu 14531d46ea2aSMasami Hiramatsu /* Duplicate strings */ 14541d46ea2aSMasami Hiramatsu if (func) { 14551d46ea2aSMasami Hiramatsu ppt->function = strdup(func); 145602b95dadSMasami Hiramatsu if (ppt->function == NULL) { 145702b95dadSMasami Hiramatsu ret = -ENOMEM; 145802b95dadSMasami Hiramatsu goto end; 145902b95dadSMasami Hiramatsu } 1460fb1587d8SMasami Hiramatsu } 14611d46ea2aSMasami Hiramatsu if (fname) { 14621d46ea2aSMasami Hiramatsu ppt->file = strdup(fname); 14631d46ea2aSMasami Hiramatsu if (ppt->file == NULL) { 146404662523SArnaldo Carvalho de Melo zfree(&ppt->function); 14651d46ea2aSMasami Hiramatsu ret = -ENOMEM; 14661d46ea2aSMasami Hiramatsu goto end; 14671d46ea2aSMasami Hiramatsu } 14681d46ea2aSMasami Hiramatsu } 1469fb1587d8SMasami Hiramatsu end: 14701d46ea2aSMasami Hiramatsu if (ret == 0 && (fname || func)) 14711d46ea2aSMasami Hiramatsu ret = 1; /* Found a point */ 1472fb1587d8SMasami Hiramatsu return ret; 1473fb1587d8SMasami Hiramatsu } 1474fb1587d8SMasami Hiramatsu 1475f6c903f5SMasami Hiramatsu /* Add a line and store the src path */ 1476f6c903f5SMasami Hiramatsu static int line_range_add_line(const char *src, unsigned int lineno, 1477f6c903f5SMasami Hiramatsu struct line_range *lr) 1478f6c903f5SMasami Hiramatsu { 14797cf0b79eSMasami Hiramatsu /* Copy source path */ 1480f6c903f5SMasami Hiramatsu if (!lr->path) { 14817cf0b79eSMasami Hiramatsu lr->path = strdup(src); 14827cf0b79eSMasami Hiramatsu if (lr->path == NULL) 14837cf0b79eSMasami Hiramatsu return -ENOMEM; 1484f6c903f5SMasami Hiramatsu } 1485*5a62257aSMasami Hiramatsu return intlist__add(lr->line_list, lineno); 1486f6c903f5SMasami Hiramatsu } 1487f6c903f5SMasami Hiramatsu 14884cc9cec6SMasami Hiramatsu static int line_range_walk_cb(const char *fname, int lineno, 14891d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused, 14904cc9cec6SMasami Hiramatsu void *data) 1491f6c903f5SMasami Hiramatsu { 14924cc9cec6SMasami Hiramatsu struct line_finder *lf = data; 1493f6c903f5SMasami Hiramatsu 14944cc9cec6SMasami Hiramatsu if ((strtailcmp(fname, lf->fname) != 0) || 1495f6c903f5SMasami Hiramatsu (lf->lno_s > lineno || lf->lno_e < lineno)) 14964cc9cec6SMasami Hiramatsu return 0; 1497f6c903f5SMasami Hiramatsu 14984cc9cec6SMasami Hiramatsu if (line_range_add_line(fname, lineno, lf->lr) < 0) 14994cc9cec6SMasami Hiramatsu return -EINVAL; 1500f6c903f5SMasami Hiramatsu 15014cc9cec6SMasami Hiramatsu return 0; 1502f6c903f5SMasami Hiramatsu } 1503fb1587d8SMasami Hiramatsu 1504631c9defSMasami Hiramatsu /* Find line range from its line number */ 1505b55a87adSMasami Hiramatsu static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1506631c9defSMasami Hiramatsu { 15074cc9cec6SMasami Hiramatsu int ret; 1508631c9defSMasami Hiramatsu 15094cc9cec6SMasami Hiramatsu ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1510f6c903f5SMasami Hiramatsu 1511804b3606SMasami Hiramatsu /* Update status */ 1512f6c903f5SMasami Hiramatsu if (ret >= 0) 1513*5a62257aSMasami Hiramatsu if (!intlist__empty(lf->lr->line_list)) 1514f6c903f5SMasami Hiramatsu ret = lf->found = 1; 1515f6c903f5SMasami Hiramatsu else 1516f6c903f5SMasami Hiramatsu ret = 0; /* Lines are not found */ 1517804b3606SMasami Hiramatsu else { 151804662523SArnaldo Carvalho de Melo zfree(&lf->lr->path); 1519804b3606SMasami Hiramatsu } 1520f6c903f5SMasami Hiramatsu return ret; 1521631c9defSMasami Hiramatsu } 1522631c9defSMasami Hiramatsu 1523161a26b0SMasami Hiramatsu static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1524161a26b0SMasami Hiramatsu { 1525db0d2c64SMasami Hiramatsu find_line_range_by_line(in_die, data); 152636c0c588SMasami Hiramatsu 152736c0c588SMasami Hiramatsu /* 152836c0c588SMasami Hiramatsu * We have to check all instances of inlined function, because 152936c0c588SMasami Hiramatsu * some execution paths can be optimized out depends on the 153036c0c588SMasami Hiramatsu * function argument of instances 153136c0c588SMasami Hiramatsu */ 1532db0d2c64SMasami Hiramatsu return 0; 1533161a26b0SMasami Hiramatsu } 1534161a26b0SMasami Hiramatsu 15350dbb1cacSMasami Hiramatsu /* Search function definition from function name */ 1536e92b85e1SMasami Hiramatsu static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1537631c9defSMasami Hiramatsu { 1538b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1539b55a87adSMasami Hiramatsu struct line_finder *lf = param->data; 1540631c9defSMasami Hiramatsu struct line_range *lr = lf->lr; 1541631c9defSMasami Hiramatsu 15427d21635aSMasami Hiramatsu /* Check declared file */ 15437d21635aSMasami Hiramatsu if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 15447d21635aSMasami Hiramatsu return DWARF_CB_OK; 15457d21635aSMasami Hiramatsu 15460dbb1cacSMasami Hiramatsu if (die_is_func_def(sp_die) && 154782175633SMasami Hiramatsu die_compare_name(sp_die, lr->function)) { 1548e92b85e1SMasami Hiramatsu lf->fname = dwarf_decl_file(sp_die); 1549e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &lr->offset); 1550804b3606SMasami Hiramatsu pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1551631c9defSMasami Hiramatsu lf->lno_s = lr->offset + lr->start; 1552d3b63d7aSMasami Hiramatsu if (lf->lno_s < 0) /* Overflow */ 1553d3b63d7aSMasami Hiramatsu lf->lno_s = INT_MAX; 1554631c9defSMasami Hiramatsu lf->lno_e = lr->offset + lr->end; 1555d3b63d7aSMasami Hiramatsu if (lf->lno_e < 0) /* Overflow */ 1556d3b63d7aSMasami Hiramatsu lf->lno_e = INT_MAX; 1557d3b63d7aSMasami Hiramatsu pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1558631c9defSMasami Hiramatsu lr->start = lf->lno_s; 1559631c9defSMasami Hiramatsu lr->end = lf->lno_e; 1560db0d2c64SMasami Hiramatsu if (dwarf_func_inline(sp_die)) 1561db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1562db0d2c64SMasami Hiramatsu line_range_inline_cb, lf); 1563db0d2c64SMasami Hiramatsu else 1564b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(sp_die, lf); 1565b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1566631c9defSMasami Hiramatsu } 1567b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1568631c9defSMasami Hiramatsu } 1569631c9defSMasami Hiramatsu 1570b55a87adSMasami Hiramatsu static int find_line_range_by_func(struct line_finder *lf) 1571631c9defSMasami Hiramatsu { 1572b55a87adSMasami Hiramatsu struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1573b55a87adSMasami Hiramatsu dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1574b55a87adSMasami Hiramatsu return param.retval; 1575631c9defSMasami Hiramatsu } 1576631c9defSMasami Hiramatsu 1577316c7136SArnaldo Carvalho de Melo int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr) 1578631c9defSMasami Hiramatsu { 1579804b3606SMasami Hiramatsu struct line_finder lf = {.lr = lr, .found = 0}; 1580b55a87adSMasami Hiramatsu int ret = 0; 1581804b3606SMasami Hiramatsu Dwarf_Off off = 0, noff; 1582804b3606SMasami Hiramatsu size_t cuhl; 1583804b3606SMasami Hiramatsu Dwarf_Die *diep; 15846a330a3cSMasami Hiramatsu const char *comp_dir; 1585631c9defSMasami Hiramatsu 1586cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1587cd25f8bcSLin Ming if (lr->function) { 1588cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1589cd25f8bcSLin Ming .function = lr->function, .file = lr->file, 1590cd25f8bcSLin Ming .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1591cd25f8bcSLin Ming struct dwarf_callback_param line_range_param = { 1592cd25f8bcSLin Ming .data = (void *)&lf, .retval = 0}; 1593cd25f8bcSLin Ming 1594316c7136SArnaldo Carvalho de Melo dwarf_getpubnames(dbg->dbg, pubname_search_cb, 1595ff741783SMasami Hiramatsu &pubname_param, 0); 1596cd25f8bcSLin Ming if (pubname_param.found) { 1597cd25f8bcSLin Ming line_range_search_cb(&lf.sp_die, &line_range_param); 1598cd25f8bcSLin Ming if (lf.found) 1599cd25f8bcSLin Ming goto found; 1600cd25f8bcSLin Ming } 1601cd25f8bcSLin Ming } 1602cd25f8bcSLin Ming 1603804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1604b55a87adSMasami Hiramatsu while (!lf.found && ret >= 0) { 1605316c7136SArnaldo Carvalho de Melo if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, 1606ff741783SMasami Hiramatsu NULL, NULL, NULL) != 0) 1607631c9defSMasami Hiramatsu break; 1608631c9defSMasami Hiramatsu 1609631c9defSMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1610316c7136SArnaldo Carvalho de Melo diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die); 1611804b3606SMasami Hiramatsu if (!diep) 1612804b3606SMasami Hiramatsu continue; 1613631c9defSMasami Hiramatsu 1614631c9defSMasami Hiramatsu /* Check if target file is included. */ 1615631c9defSMasami Hiramatsu if (lr->file) 16162a9c8c36SMasami Hiramatsu lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1617804b3606SMasami Hiramatsu else 16182a9c8c36SMasami Hiramatsu lf.fname = 0; 1619631c9defSMasami Hiramatsu 16202a9c8c36SMasami Hiramatsu if (!lr->file || lf.fname) { 1621631c9defSMasami Hiramatsu if (lr->function) 1622b55a87adSMasami Hiramatsu ret = find_line_range_by_func(&lf); 1623631c9defSMasami Hiramatsu else { 1624631c9defSMasami Hiramatsu lf.lno_s = lr->start; 1625631c9defSMasami Hiramatsu lf.lno_e = lr->end; 1626b55a87adSMasami Hiramatsu ret = find_line_range_by_line(NULL, &lf); 1627631c9defSMasami Hiramatsu } 1628631c9defSMasami Hiramatsu } 1629804b3606SMasami Hiramatsu off = noff; 1630631c9defSMasami Hiramatsu } 16316a330a3cSMasami Hiramatsu 1632cd25f8bcSLin Ming found: 16336a330a3cSMasami Hiramatsu /* Store comp_dir */ 16346a330a3cSMasami Hiramatsu if (lf.found) { 16356a330a3cSMasami Hiramatsu comp_dir = cu_get_comp_dir(&lf.cu_die); 16366a330a3cSMasami Hiramatsu if (comp_dir) { 16376a330a3cSMasami Hiramatsu lr->comp_dir = strdup(comp_dir); 16386a330a3cSMasami Hiramatsu if (!lr->comp_dir) 16396a330a3cSMasami Hiramatsu ret = -ENOMEM; 16406a330a3cSMasami Hiramatsu } 16416a330a3cSMasami Hiramatsu } 16426a330a3cSMasami Hiramatsu 16437cf0b79eSMasami Hiramatsu pr_debug("path: %s\n", lr->path); 1644b55a87adSMasami Hiramatsu return (ret < 0) ? ret : lf.found; 1645631c9defSMasami Hiramatsu } 1646631c9defSMasami Hiramatsu 1647