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" 38074fc0e4SMasami Hiramatsu #include "util.h" 399ed7e1b8SChase Douglas #include "symbol.h" 404ea42b18SMasami Hiramatsu #include "probe-finder.h" 414ea42b18SMasami Hiramatsu 424984912eSMasami Hiramatsu /* Kprobe tracer basic type is up to u64 */ 434984912eSMasami Hiramatsu #define MAX_BASIC_TYPE_BITS 64 444984912eSMasami Hiramatsu 452a9c8c36SMasami Hiramatsu /* Line number list operations */ 462a9c8c36SMasami Hiramatsu 472a9c8c36SMasami Hiramatsu /* Add a line to line number list */ 48d3b63d7aSMasami Hiramatsu static int line_list__add_line(struct list_head *head, int line) 492a9c8c36SMasami Hiramatsu { 502a9c8c36SMasami Hiramatsu struct line_node *ln; 512a9c8c36SMasami Hiramatsu struct list_head *p; 522a9c8c36SMasami Hiramatsu 532a9c8c36SMasami Hiramatsu /* Reverse search, because new line will be the last one */ 542a9c8c36SMasami Hiramatsu list_for_each_entry_reverse(ln, head, list) { 552a9c8c36SMasami Hiramatsu if (ln->line < line) { 562a9c8c36SMasami Hiramatsu p = &ln->list; 572a9c8c36SMasami Hiramatsu goto found; 582a9c8c36SMasami Hiramatsu } else if (ln->line == line) /* Already exist */ 59e334016fSMasami Hiramatsu return 1; 602a9c8c36SMasami Hiramatsu } 612a9c8c36SMasami Hiramatsu /* List is empty, or the smallest entry */ 622a9c8c36SMasami Hiramatsu p = head; 632a9c8c36SMasami Hiramatsu found: 642a9c8c36SMasami Hiramatsu pr_debug("line list: add a line %u\n", line); 65e334016fSMasami Hiramatsu ln = zalloc(sizeof(struct line_node)); 66e334016fSMasami Hiramatsu if (ln == NULL) 67e334016fSMasami Hiramatsu return -ENOMEM; 682a9c8c36SMasami Hiramatsu ln->line = line; 692a9c8c36SMasami Hiramatsu INIT_LIST_HEAD(&ln->list); 702a9c8c36SMasami Hiramatsu list_add(&ln->list, p); 71e334016fSMasami Hiramatsu return 0; 722a9c8c36SMasami Hiramatsu } 732a9c8c36SMasami Hiramatsu 742a9c8c36SMasami Hiramatsu /* Check if the line in line number list */ 75d3b63d7aSMasami Hiramatsu static int line_list__has_line(struct list_head *head, int line) 762a9c8c36SMasami Hiramatsu { 772a9c8c36SMasami Hiramatsu struct line_node *ln; 782a9c8c36SMasami Hiramatsu 792a9c8c36SMasami Hiramatsu /* Reverse search, because new line will be the last one */ 802a9c8c36SMasami Hiramatsu list_for_each_entry(ln, head, list) 812a9c8c36SMasami Hiramatsu if (ln->line == line) 822a9c8c36SMasami Hiramatsu return 1; 832a9c8c36SMasami Hiramatsu 842a9c8c36SMasami Hiramatsu return 0; 852a9c8c36SMasami Hiramatsu } 862a9c8c36SMasami Hiramatsu 872a9c8c36SMasami Hiramatsu /* Init line number list */ 882a9c8c36SMasami Hiramatsu static void line_list__init(struct list_head *head) 892a9c8c36SMasami Hiramatsu { 902a9c8c36SMasami Hiramatsu INIT_LIST_HEAD(head); 912a9c8c36SMasami Hiramatsu } 922a9c8c36SMasami Hiramatsu 932a9c8c36SMasami Hiramatsu /* Free line number list */ 942a9c8c36SMasami Hiramatsu static void line_list__free(struct list_head *head) 952a9c8c36SMasami Hiramatsu { 962a9c8c36SMasami Hiramatsu struct line_node *ln; 972a9c8c36SMasami Hiramatsu while (!list_empty(head)) { 982a9c8c36SMasami Hiramatsu ln = list_first_entry(head, struct line_node, list); 992a9c8c36SMasami Hiramatsu list_del(&ln->list); 1002a9c8c36SMasami Hiramatsu free(ln); 1012a9c8c36SMasami Hiramatsu } 1022a9c8c36SMasami Hiramatsu } 1032a9c8c36SMasami Hiramatsu 104469b9b88SMasami Hiramatsu /* Dwarf FL wrappers */ 105469b9b88SMasami Hiramatsu static char *debuginfo_path; /* Currently dummy */ 106469b9b88SMasami Hiramatsu 107469b9b88SMasami Hiramatsu static const Dwfl_Callbacks offline_callbacks = { 108469b9b88SMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 109469b9b88SMasami Hiramatsu .debuginfo_path = &debuginfo_path, 110469b9b88SMasami Hiramatsu 111469b9b88SMasami Hiramatsu .section_address = dwfl_offline_section_address, 112469b9b88SMasami Hiramatsu 113469b9b88SMasami Hiramatsu /* We use this table for core files too. */ 114469b9b88SMasami Hiramatsu .find_elf = dwfl_build_id_find_elf, 115469b9b88SMasami Hiramatsu }; 116469b9b88SMasami Hiramatsu 117469b9b88SMasami Hiramatsu /* Get a Dwarf from offline image */ 118ff741783SMasami Hiramatsu static int debuginfo__init_offline_dwarf(struct debuginfo *self, 119ff741783SMasami Hiramatsu const char *path) 120469b9b88SMasami Hiramatsu { 121469b9b88SMasami Hiramatsu Dwfl_Module *mod; 122ff741783SMasami Hiramatsu int fd; 123469b9b88SMasami Hiramatsu 124ff741783SMasami Hiramatsu fd = open(path, O_RDONLY); 125ff741783SMasami Hiramatsu if (fd < 0) 126ff741783SMasami Hiramatsu return fd; 127469b9b88SMasami Hiramatsu 128ff741783SMasami Hiramatsu self->dwfl = dwfl_begin(&offline_callbacks); 129ff741783SMasami Hiramatsu if (!self->dwfl) 130ff741783SMasami Hiramatsu goto error; 131469b9b88SMasami Hiramatsu 132ff741783SMasami Hiramatsu mod = dwfl_report_offline(self->dwfl, "", "", fd); 133469b9b88SMasami Hiramatsu if (!mod) 134469b9b88SMasami Hiramatsu goto error; 135469b9b88SMasami Hiramatsu 136ff741783SMasami Hiramatsu self->dbg = dwfl_module_getdwarf(mod, &self->bias); 137ff741783SMasami Hiramatsu if (!self->dbg) 138ff741783SMasami Hiramatsu goto error; 139ff741783SMasami Hiramatsu 140ff741783SMasami Hiramatsu return 0; 141469b9b88SMasami Hiramatsu error: 142ff741783SMasami Hiramatsu if (self->dwfl) 143ff741783SMasami Hiramatsu dwfl_end(self->dwfl); 144ff741783SMasami Hiramatsu else 145ff741783SMasami Hiramatsu close(fd); 146ff741783SMasami Hiramatsu memset(self, 0, sizeof(*self)); 147ff741783SMasami Hiramatsu 148ff741783SMasami Hiramatsu return -ENOENT; 149469b9b88SMasami Hiramatsu } 150469b9b88SMasami Hiramatsu 1513b4694deSMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 148) 1523b4694deSMasami Hiramatsu /* This method is buggy if elfutils is older than 0.148 */ 1533b4694deSMasami Hiramatsu static int __linux_kernel_find_elf(Dwfl_Module *mod, 1543b4694deSMasami Hiramatsu void **userdata, 1553b4694deSMasami Hiramatsu const char *module_name, 1563b4694deSMasami Hiramatsu Dwarf_Addr base, 1573b4694deSMasami Hiramatsu char **file_name, Elf **elfp) 1583b4694deSMasami Hiramatsu { 1593b4694deSMasami Hiramatsu int fd; 1603b4694deSMasami Hiramatsu const char *path = kernel_get_module_path(module_name); 1613b4694deSMasami Hiramatsu 1623b4694deSMasami Hiramatsu pr_debug2("Use file %s for %s\n", path, module_name); 1633b4694deSMasami Hiramatsu if (path) { 1643b4694deSMasami Hiramatsu fd = open(path, O_RDONLY); 1653b4694deSMasami Hiramatsu if (fd >= 0) { 1663b4694deSMasami Hiramatsu *file_name = strdup(path); 1673b4694deSMasami Hiramatsu return fd; 1683b4694deSMasami Hiramatsu } 1693b4694deSMasami Hiramatsu } 1703b4694deSMasami Hiramatsu /* If failed, try to call standard method */ 1713b4694deSMasami Hiramatsu return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, 1723b4694deSMasami Hiramatsu file_name, elfp); 1733b4694deSMasami Hiramatsu } 1743b4694deSMasami Hiramatsu 1753b4694deSMasami Hiramatsu static const Dwfl_Callbacks kernel_callbacks = { 1763b4694deSMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 1773b4694deSMasami Hiramatsu .debuginfo_path = &debuginfo_path, 1783b4694deSMasami Hiramatsu 1793b4694deSMasami Hiramatsu .find_elf = __linux_kernel_find_elf, 1803b4694deSMasami Hiramatsu .section_address = dwfl_linux_kernel_module_section_address, 1813b4694deSMasami Hiramatsu }; 1823b4694deSMasami Hiramatsu 183469b9b88SMasami Hiramatsu /* Get a Dwarf from live kernel image */ 184ff741783SMasami Hiramatsu static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 185ff741783SMasami Hiramatsu Dwarf_Addr addr) 186469b9b88SMasami Hiramatsu { 187ff741783SMasami Hiramatsu self->dwfl = dwfl_begin(&kernel_callbacks); 188ff741783SMasami Hiramatsu if (!self->dwfl) 189ff741783SMasami Hiramatsu return -EINVAL; 190469b9b88SMasami Hiramatsu 191469b9b88SMasami Hiramatsu /* Load the kernel dwarves: Don't care the result here */ 192ff741783SMasami Hiramatsu dwfl_linux_kernel_report_kernel(self->dwfl); 193ff741783SMasami Hiramatsu dwfl_linux_kernel_report_modules(self->dwfl); 194469b9b88SMasami Hiramatsu 195ff741783SMasami Hiramatsu self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); 196469b9b88SMasami Hiramatsu /* Here, check whether we could get a real dwarf */ 197ff741783SMasami Hiramatsu if (!self->dbg) { 1983b4694deSMasami Hiramatsu pr_debug("Failed to find kernel dwarf at %lx\n", 1993b4694deSMasami Hiramatsu (unsigned long)addr); 200ff741783SMasami Hiramatsu dwfl_end(self->dwfl); 201ff741783SMasami Hiramatsu memset(self, 0, sizeof(*self)); 202ff741783SMasami Hiramatsu return -ENOENT; 203469b9b88SMasami Hiramatsu } 204ff741783SMasami Hiramatsu 205ff741783SMasami Hiramatsu return 0; 206469b9b88SMasami Hiramatsu } 2073b4694deSMasami Hiramatsu #else 2083b4694deSMasami Hiramatsu /* With older elfutils, this just support kernel module... */ 209ff741783SMasami Hiramatsu static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 2101d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused) 2113b4694deSMasami Hiramatsu { 2123b4694deSMasami Hiramatsu const char *path = kernel_get_module_path("kernel"); 2133b4694deSMasami Hiramatsu 2143b4694deSMasami Hiramatsu if (!path) { 2153b4694deSMasami Hiramatsu pr_err("Failed to find vmlinux path\n"); 216ff741783SMasami Hiramatsu return -ENOENT; 2173b4694deSMasami Hiramatsu } 2183b4694deSMasami Hiramatsu 2193b4694deSMasami Hiramatsu pr_debug2("Use file %s for debuginfo\n", path); 220ff741783SMasami Hiramatsu return debuginfo__init_offline_dwarf(self, path); 2213b4694deSMasami Hiramatsu } 2223b4694deSMasami Hiramatsu #endif 223469b9b88SMasami Hiramatsu 224ff741783SMasami Hiramatsu struct debuginfo *debuginfo__new(const char *path) 225ff741783SMasami Hiramatsu { 226ff741783SMasami Hiramatsu struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 227ff741783SMasami Hiramatsu if (!self) 228ff741783SMasami Hiramatsu return NULL; 229ff741783SMasami Hiramatsu 230ff741783SMasami Hiramatsu if (debuginfo__init_offline_dwarf(self, path) < 0) { 231ff741783SMasami Hiramatsu free(self); 232ff741783SMasami Hiramatsu self = NULL; 233ff741783SMasami Hiramatsu } 234ff741783SMasami Hiramatsu 235ff741783SMasami Hiramatsu return self; 236ff741783SMasami Hiramatsu } 237ff741783SMasami Hiramatsu 238ff741783SMasami Hiramatsu struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) 239ff741783SMasami Hiramatsu { 240ff741783SMasami Hiramatsu struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 241ff741783SMasami Hiramatsu if (!self) 242ff741783SMasami Hiramatsu return NULL; 243ff741783SMasami Hiramatsu 244ff741783SMasami Hiramatsu if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { 245ff741783SMasami Hiramatsu free(self); 246ff741783SMasami Hiramatsu self = NULL; 247ff741783SMasami Hiramatsu } 248ff741783SMasami Hiramatsu 249ff741783SMasami Hiramatsu return self; 250ff741783SMasami Hiramatsu } 251ff741783SMasami Hiramatsu 252ff741783SMasami Hiramatsu void debuginfo__delete(struct debuginfo *self) 253ff741783SMasami Hiramatsu { 254ff741783SMasami Hiramatsu if (self) { 255ff741783SMasami Hiramatsu if (self->dwfl) 256ff741783SMasami Hiramatsu dwfl_end(self->dwfl); 257ff741783SMasami Hiramatsu free(self); 258ff741783SMasami Hiramatsu } 259ff741783SMasami Hiramatsu } 260ff741783SMasami Hiramatsu 2614ea42b18SMasami Hiramatsu /* 2624ea42b18SMasami Hiramatsu * Probe finder related functions 2634ea42b18SMasami Hiramatsu */ 2644ea42b18SMasami Hiramatsu 2650e60836bSSrikar Dronamraju static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 2664ea42b18SMasami Hiramatsu { 2670e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref; 2680e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 269b7dcb857SMasami Hiramatsu if (ref != NULL) 270b7dcb857SMasami Hiramatsu ref->offset = offs; 271b7dcb857SMasami Hiramatsu return ref; 272b7dcb857SMasami Hiramatsu } 273b7dcb857SMasami Hiramatsu 274cf6eb489SMasami Hiramatsu /* 275cf6eb489SMasami Hiramatsu * Convert a location into trace_arg. 276cf6eb489SMasami Hiramatsu * If tvar == NULL, this just checks variable can be converted. 277cf6eb489SMasami Hiramatsu */ 278cf6eb489SMasami Hiramatsu static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 279cf6eb489SMasami Hiramatsu Dwarf_Op *fb_ops, 280cf6eb489SMasami Hiramatsu struct probe_trace_arg *tvar) 281b7dcb857SMasami Hiramatsu { 282b7dcb857SMasami Hiramatsu Dwarf_Attribute attr; 283b7dcb857SMasami Hiramatsu Dwarf_Op *op; 284b7dcb857SMasami Hiramatsu size_t nops; 285804b3606SMasami Hiramatsu unsigned int regn; 286804b3606SMasami Hiramatsu Dwarf_Word offs = 0; 2874235b045SMasami Hiramatsu bool ref = false; 2884ea42b18SMasami Hiramatsu const char *regs; 289b7dcb857SMasami Hiramatsu int ret; 290b7dcb857SMasami Hiramatsu 291632941c4SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 292632941c4SMasami Hiramatsu goto static_var; 293632941c4SMasami Hiramatsu 294b7dcb857SMasami Hiramatsu /* TODO: handle more than 1 exprs */ 295b7dcb857SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 296cf6eb489SMasami Hiramatsu dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || 297b7dcb857SMasami Hiramatsu nops == 0) { 298b7dcb857SMasami Hiramatsu /* TODO: Support const_value */ 299b7dcb857SMasami Hiramatsu return -ENOENT; 300b7dcb857SMasami Hiramatsu } 301b7dcb857SMasami Hiramatsu 302b7dcb857SMasami Hiramatsu if (op->atom == DW_OP_addr) { 303632941c4SMasami Hiramatsu static_var: 304cf6eb489SMasami Hiramatsu if (!tvar) 305cf6eb489SMasami Hiramatsu return 0; 306b7dcb857SMasami Hiramatsu /* Static variables on memory (not stack), make @varname */ 307b7dcb857SMasami Hiramatsu ret = strlen(dwarf_diename(vr_die)); 308b7dcb857SMasami Hiramatsu tvar->value = zalloc(ret + 2); 309b7dcb857SMasami Hiramatsu if (tvar->value == NULL) 310b7dcb857SMasami Hiramatsu return -ENOMEM; 311b7dcb857SMasami Hiramatsu snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 312b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 313b7dcb857SMasami Hiramatsu if (tvar->ref == NULL) 314b7dcb857SMasami Hiramatsu return -ENOMEM; 315b7dcb857SMasami Hiramatsu return 0; 316b7dcb857SMasami Hiramatsu } 3174ea42b18SMasami Hiramatsu 3184ea42b18SMasami Hiramatsu /* If this is based on frame buffer, set the offset */ 319804b3606SMasami Hiramatsu if (op->atom == DW_OP_fbreg) { 320cf6eb489SMasami Hiramatsu if (fb_ops == NULL) 321b55a87adSMasami Hiramatsu return -ENOTSUP; 3224235b045SMasami Hiramatsu ref = true; 323804b3606SMasami Hiramatsu offs = op->number; 324cf6eb489SMasami Hiramatsu op = &fb_ops[0]; 325804b3606SMasami Hiramatsu } 3264ea42b18SMasami Hiramatsu 327804b3606SMasami Hiramatsu if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 328804b3606SMasami Hiramatsu regn = op->atom - DW_OP_breg0; 329804b3606SMasami Hiramatsu offs += op->number; 3304235b045SMasami Hiramatsu ref = true; 331804b3606SMasami Hiramatsu } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 332804b3606SMasami Hiramatsu regn = op->atom - DW_OP_reg0; 333804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_bregx) { 334804b3606SMasami Hiramatsu regn = op->number; 335804b3606SMasami Hiramatsu offs += op->number2; 3364235b045SMasami Hiramatsu ref = true; 337804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_regx) { 338804b3606SMasami Hiramatsu regn = op->number; 339b55a87adSMasami Hiramatsu } else { 340cf6eb489SMasami Hiramatsu pr_debug("DW_OP %x is not supported.\n", op->atom); 341b55a87adSMasami Hiramatsu return -ENOTSUP; 342b55a87adSMasami Hiramatsu } 3434ea42b18SMasami Hiramatsu 344cf6eb489SMasami Hiramatsu if (!tvar) 345cf6eb489SMasami Hiramatsu return 0; 346cf6eb489SMasami Hiramatsu 3474ea42b18SMasami Hiramatsu regs = get_arch_regstr(regn); 348b55a87adSMasami Hiramatsu if (!regs) { 349cf6eb489SMasami Hiramatsu /* This should be a bug in DWARF or this tool */ 3500e43e5d2SMasami Hiramatsu pr_warning("Mapping for the register number %u " 3510e43e5d2SMasami Hiramatsu "missing on this architecture.\n", regn); 352b55a87adSMasami Hiramatsu return -ERANGE; 353b55a87adSMasami Hiramatsu } 3544ea42b18SMasami Hiramatsu 35502b95dadSMasami Hiramatsu tvar->value = strdup(regs); 35602b95dadSMasami Hiramatsu if (tvar->value == NULL) 35702b95dadSMasami Hiramatsu return -ENOMEM; 35802b95dadSMasami Hiramatsu 3594235b045SMasami Hiramatsu if (ref) { 360b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 361e334016fSMasami Hiramatsu if (tvar->ref == NULL) 362e334016fSMasami Hiramatsu return -ENOMEM; 3634235b045SMasami Hiramatsu } 364b55a87adSMasami Hiramatsu return 0; 3654ea42b18SMasami Hiramatsu } 3664ea42b18SMasami Hiramatsu 367124bb83cSMasami Hiramatsu #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 368124bb83cSMasami Hiramatsu 369b55a87adSMasami Hiramatsu static int convert_variable_type(Dwarf_Die *vr_die, 3700e60836bSSrikar Dronamraju struct probe_trace_arg *tvar, 37173317b95SMasami Hiramatsu const char *cast) 3724984912eSMasami Hiramatsu { 3730e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 3744984912eSMasami Hiramatsu Dwarf_Die type; 3754984912eSMasami Hiramatsu char buf[16]; 376bcfc0821SMasami Hiramatsu int bsize, boffs, total; 3774984912eSMasami Hiramatsu int ret; 3784984912eSMasami Hiramatsu 37973317b95SMasami Hiramatsu /* TODO: check all types */ 38073317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") != 0) { 38173317b95SMasami Hiramatsu /* Non string type is OK */ 38273317b95SMasami Hiramatsu tvar->type = strdup(cast); 38373317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 38473317b95SMasami Hiramatsu } 38573317b95SMasami Hiramatsu 386bcfc0821SMasami Hiramatsu bsize = dwarf_bitsize(vr_die); 387bcfc0821SMasami Hiramatsu if (bsize > 0) { 388124bb83cSMasami Hiramatsu /* This is a bitfield */ 389bcfc0821SMasami Hiramatsu boffs = dwarf_bitoffset(vr_die); 390bcfc0821SMasami Hiramatsu total = dwarf_bytesize(vr_die); 391bcfc0821SMasami Hiramatsu if (boffs < 0 || total < 0) 392bcfc0821SMasami Hiramatsu return -ENOENT; 393bcfc0821SMasami Hiramatsu ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 394bcfc0821SMasami Hiramatsu BYTES_TO_BITS(total)); 395124bb83cSMasami Hiramatsu goto formatted; 396124bb83cSMasami Hiramatsu } 397124bb83cSMasami Hiramatsu 398b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 399b55a87adSMasami Hiramatsu pr_warning("Failed to get a type information of %s.\n", 4004984912eSMasami Hiramatsu dwarf_diename(vr_die)); 401b55a87adSMasami Hiramatsu return -ENOENT; 402b55a87adSMasami Hiramatsu } 4034984912eSMasami Hiramatsu 404b2a3c12bSMasami Hiramatsu pr_debug("%s type is %s.\n", 405b2a3c12bSMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 406b2a3c12bSMasami Hiramatsu 40773317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") == 0) { /* String type */ 40873317b95SMasami Hiramatsu ret = dwarf_tag(&type); 40973317b95SMasami Hiramatsu if (ret != DW_TAG_pointer_type && 41073317b95SMasami Hiramatsu ret != DW_TAG_array_type) { 41173317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 4120e43e5d2SMasami Hiramatsu "%s(%s) is not a pointer nor array.\n", 41373317b95SMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 41473317b95SMasami Hiramatsu return -EINVAL; 41573317b95SMasami Hiramatsu } 41673317b95SMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 4170e43e5d2SMasami Hiramatsu pr_warning("Failed to get a type" 4180e43e5d2SMasami Hiramatsu " information.\n"); 41973317b95SMasami Hiramatsu return -ENOENT; 42073317b95SMasami Hiramatsu } 4217ce28b5bSHyeoncheol Lee if (ret == DW_TAG_pointer_type) { 42273317b95SMasami Hiramatsu while (*ref_ptr) 42373317b95SMasami Hiramatsu ref_ptr = &(*ref_ptr)->next; 42473317b95SMasami Hiramatsu /* Add new reference with offset +0 */ 4250e60836bSSrikar Dronamraju *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 42673317b95SMasami Hiramatsu if (*ref_ptr == NULL) { 42773317b95SMasami Hiramatsu pr_warning("Out of memory error\n"); 42873317b95SMasami Hiramatsu return -ENOMEM; 42973317b95SMasami Hiramatsu } 43073317b95SMasami Hiramatsu } 43182175633SMasami Hiramatsu if (!die_compare_name(&type, "char") && 43282175633SMasami Hiramatsu !die_compare_name(&type, "unsigned char")) { 43373317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 4340e43e5d2SMasami Hiramatsu "%s is not (unsigned) char *.\n", 43573317b95SMasami Hiramatsu dwarf_diename(vr_die)); 43673317b95SMasami Hiramatsu return -EINVAL; 43773317b95SMasami Hiramatsu } 43873317b95SMasami Hiramatsu tvar->type = strdup(cast); 43973317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 44073317b95SMasami Hiramatsu } 44173317b95SMasami Hiramatsu 442bcfc0821SMasami Hiramatsu ret = dwarf_bytesize(&type); 443bcfc0821SMasami Hiramatsu if (ret <= 0) 444124bb83cSMasami Hiramatsu /* No size ... try to use default type */ 445124bb83cSMasami Hiramatsu return 0; 446bcfc0821SMasami Hiramatsu ret = BYTES_TO_BITS(ret); 447124bb83cSMasami Hiramatsu 4484984912eSMasami Hiramatsu /* Check the bitwidth */ 4494984912eSMasami Hiramatsu if (ret > MAX_BASIC_TYPE_BITS) { 450124bb83cSMasami Hiramatsu pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 4514984912eSMasami Hiramatsu dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 4524984912eSMasami Hiramatsu ret = MAX_BASIC_TYPE_BITS; 4534984912eSMasami Hiramatsu } 4544984912eSMasami Hiramatsu ret = snprintf(buf, 16, "%c%d", 4554984912eSMasami Hiramatsu die_is_signed_type(&type) ? 's' : 'u', ret); 456124bb83cSMasami Hiramatsu 457124bb83cSMasami Hiramatsu formatted: 458b55a87adSMasami Hiramatsu if (ret < 0 || ret >= 16) { 459b55a87adSMasami Hiramatsu if (ret >= 16) 460b55a87adSMasami Hiramatsu ret = -E2BIG; 461b55a87adSMasami Hiramatsu pr_warning("Failed to convert variable type: %s\n", 462b55a87adSMasami Hiramatsu strerror(-ret)); 463b55a87adSMasami Hiramatsu return ret; 464b55a87adSMasami Hiramatsu } 46573317b95SMasami Hiramatsu tvar->type = strdup(buf); 46673317b95SMasami Hiramatsu if (tvar->type == NULL) 46702b95dadSMasami Hiramatsu return -ENOMEM; 468b55a87adSMasami Hiramatsu return 0; 4694984912eSMasami Hiramatsu } 4704984912eSMasami Hiramatsu 471b55a87adSMasami Hiramatsu static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 4727df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, 4730e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr, 4744984912eSMasami Hiramatsu Dwarf_Die *die_mem) 4757df2f329SMasami Hiramatsu { 4760e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = *ref_ptr; 4777df2f329SMasami Hiramatsu Dwarf_Die type; 4787df2f329SMasami Hiramatsu Dwarf_Word offs; 479b2a3c12bSMasami Hiramatsu int ret, tag; 4807df2f329SMasami Hiramatsu 4817df2f329SMasami Hiramatsu pr_debug("converting %s in %s\n", field->name, varname); 482b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 483b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 484b55a87adSMasami Hiramatsu return -ENOENT; 485b55a87adSMasami Hiramatsu } 486b2a3c12bSMasami Hiramatsu pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); 487b2a3c12bSMasami Hiramatsu tag = dwarf_tag(&type); 4887df2f329SMasami Hiramatsu 489b2a3c12bSMasami Hiramatsu if (field->name[0] == '[' && 490b2a3c12bSMasami Hiramatsu (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 491b2a3c12bSMasami Hiramatsu if (field->next) 492b2a3c12bSMasami Hiramatsu /* Save original type for next field */ 493b2a3c12bSMasami Hiramatsu memcpy(die_mem, &type, sizeof(*die_mem)); 494b2a3c12bSMasami Hiramatsu /* Get the type of this array */ 495b2a3c12bSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 496b2a3c12bSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 497b2a3c12bSMasami Hiramatsu return -ENOENT; 498b2a3c12bSMasami Hiramatsu } 499b2a3c12bSMasami Hiramatsu pr_debug2("Array real type: (%x)\n", 500b2a3c12bSMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 501b2a3c12bSMasami Hiramatsu if (tag == DW_TAG_pointer_type) { 5020e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 503b2a3c12bSMasami Hiramatsu if (ref == NULL) 504b2a3c12bSMasami Hiramatsu return -ENOMEM; 505b2a3c12bSMasami Hiramatsu if (*ref_ptr) 506b2a3c12bSMasami Hiramatsu (*ref_ptr)->next = ref; 507b2a3c12bSMasami Hiramatsu else 508b2a3c12bSMasami Hiramatsu *ref_ptr = ref; 509b2a3c12bSMasami Hiramatsu } 510bcfc0821SMasami Hiramatsu ref->offset += dwarf_bytesize(&type) * field->index; 511b2a3c12bSMasami Hiramatsu if (!field->next) 512b2a3c12bSMasami Hiramatsu /* Save vr_die for converting types */ 513b2a3c12bSMasami Hiramatsu memcpy(die_mem, vr_die, sizeof(*die_mem)); 514b2a3c12bSMasami Hiramatsu goto next; 515b2a3c12bSMasami Hiramatsu } else if (tag == DW_TAG_pointer_type) { 5167df2f329SMasami Hiramatsu /* Check the pointer and dereference */ 517b55a87adSMasami Hiramatsu if (!field->ref) { 518b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '->'\n", 5197df2f329SMasami Hiramatsu field->name); 520b55a87adSMasami Hiramatsu return -EINVAL; 521b55a87adSMasami Hiramatsu } 5227df2f329SMasami Hiramatsu /* Get the type pointed by this pointer */ 523b55a87adSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 524b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 525b55a87adSMasami Hiramatsu return -ENOENT; 526b55a87adSMasami Hiramatsu } 52712e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 5287b0295b3SHyeoncheol Lee tag = dwarf_tag(&type); 5297b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 5307b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 5317b0295b3SHyeoncheol Lee varname); 532b55a87adSMasami Hiramatsu return -EINVAL; 533b55a87adSMasami Hiramatsu } 53412e5a7aeSMasami Hiramatsu 5350e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 536e334016fSMasami Hiramatsu if (ref == NULL) 537e334016fSMasami Hiramatsu return -ENOMEM; 5387df2f329SMasami Hiramatsu if (*ref_ptr) 5397df2f329SMasami Hiramatsu (*ref_ptr)->next = ref; 5407df2f329SMasami Hiramatsu else 5417df2f329SMasami Hiramatsu *ref_ptr = ref; 5427df2f329SMasami Hiramatsu } else { 54312e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 5447b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 5457b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 5467b0295b3SHyeoncheol Lee varname); 547b55a87adSMasami Hiramatsu return -EINVAL; 548b55a87adSMasami Hiramatsu } 549b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') { 5500e43e5d2SMasami Hiramatsu pr_err("Semantic error: %s is not a pointor" 5510e43e5d2SMasami Hiramatsu " nor array.\n", varname); 552b2a3c12bSMasami Hiramatsu return -EINVAL; 553b2a3c12bSMasami Hiramatsu } 554b55a87adSMasami Hiramatsu if (field->ref) { 555b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '.'\n", 5567df2f329SMasami Hiramatsu field->name); 557b55a87adSMasami Hiramatsu return -EINVAL; 558b55a87adSMasami Hiramatsu } 559b55a87adSMasami Hiramatsu if (!ref) { 560b55a87adSMasami Hiramatsu pr_warning("Structure on a register is not " 561b55a87adSMasami Hiramatsu "supported yet.\n"); 562b55a87adSMasami Hiramatsu return -ENOTSUP; 563b55a87adSMasami Hiramatsu } 5647df2f329SMasami Hiramatsu } 5657df2f329SMasami Hiramatsu 566b55a87adSMasami Hiramatsu if (die_find_member(&type, field->name, die_mem) == NULL) { 567b55a87adSMasami Hiramatsu pr_warning("%s(tyep:%s) has no member %s.\n", varname, 5687df2f329SMasami Hiramatsu dwarf_diename(&type), field->name); 569b55a87adSMasami Hiramatsu return -EINVAL; 570b55a87adSMasami Hiramatsu } 5717df2f329SMasami Hiramatsu 5727df2f329SMasami Hiramatsu /* Get the offset of the field */ 5737b0295b3SHyeoncheol Lee if (tag == DW_TAG_union_type) { 5747b0295b3SHyeoncheol Lee offs = 0; 5757b0295b3SHyeoncheol Lee } else { 576de1439d8SMasami Hiramatsu ret = die_get_data_member_location(die_mem, &offs); 577de1439d8SMasami Hiramatsu if (ret < 0) { 5787b0295b3SHyeoncheol Lee pr_warning("Failed to get the offset of %s.\n", 5797b0295b3SHyeoncheol Lee field->name); 580de1439d8SMasami Hiramatsu return ret; 581b55a87adSMasami Hiramatsu } 5827b0295b3SHyeoncheol Lee } 5837df2f329SMasami Hiramatsu ref->offset += (long)offs; 5847df2f329SMasami Hiramatsu 585b2a3c12bSMasami Hiramatsu next: 5867df2f329SMasami Hiramatsu /* Converting next field */ 5877df2f329SMasami Hiramatsu if (field->next) 588b55a87adSMasami Hiramatsu return convert_variable_fields(die_mem, field->name, 589b55a87adSMasami Hiramatsu field->next, &ref, die_mem); 590b55a87adSMasami Hiramatsu else 591b55a87adSMasami Hiramatsu return 0; 5927df2f329SMasami Hiramatsu } 5937df2f329SMasami Hiramatsu 5944ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */ 595b55a87adSMasami Hiramatsu static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 5964ea42b18SMasami Hiramatsu { 5974984912eSMasami Hiramatsu Dwarf_Die die_mem; 5984ea42b18SMasami Hiramatsu int ret; 5994ea42b18SMasami Hiramatsu 600b7dcb857SMasami Hiramatsu pr_debug("Converting variable %s into trace event.\n", 601b7dcb857SMasami Hiramatsu dwarf_diename(vr_die)); 602804b3606SMasami Hiramatsu 603cf6eb489SMasami Hiramatsu ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 604cf6eb489SMasami Hiramatsu pf->tvar); 605cf6eb489SMasami Hiramatsu if (ret == -ENOENT) 606cf6eb489SMasami Hiramatsu pr_err("Failed to find the location of %s at this address.\n" 607cf6eb489SMasami Hiramatsu " Perhaps, it has been optimized out.\n", pf->pvar->var); 608cf6eb489SMasami Hiramatsu else if (ret == -ENOTSUP) 609cf6eb489SMasami Hiramatsu pr_err("Sorry, we don't support this variable location yet.\n"); 610cf6eb489SMasami Hiramatsu else if (pf->pvar->field) { 611b55a87adSMasami Hiramatsu ret = convert_variable_fields(vr_die, pf->pvar->var, 6124984912eSMasami Hiramatsu pf->pvar->field, &pf->tvar->ref, 6134984912eSMasami Hiramatsu &die_mem); 6144984912eSMasami Hiramatsu vr_die = &die_mem; 6154984912eSMasami Hiramatsu } 61673317b95SMasami Hiramatsu if (ret == 0) 61773317b95SMasami Hiramatsu ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); 618804b3606SMasami Hiramatsu /* *expr will be cached in libdw. Don't free it. */ 619b55a87adSMasami Hiramatsu return ret; 6204ea42b18SMasami Hiramatsu } 6214ea42b18SMasami Hiramatsu 622221d0611SMasami Hiramatsu /* Find a variable in a scope DIE */ 623221d0611SMasami Hiramatsu static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 6244ea42b18SMasami Hiramatsu { 625f182e3e1SMasami Hiramatsu Dwarf_Die vr_die; 62611a1ca35SMasami Hiramatsu char buf[32], *ptr; 627f182e3e1SMasami Hiramatsu int ret = 0; 6284ea42b18SMasami Hiramatsu 629367e94c1SMasami Hiramatsu if (!is_c_varname(pf->pvar->var)) { 630367e94c1SMasami Hiramatsu /* Copy raw parameters */ 631367e94c1SMasami Hiramatsu pf->tvar->value = strdup(pf->pvar->var); 632367e94c1SMasami Hiramatsu if (pf->tvar->value == NULL) 633367e94c1SMasami Hiramatsu return -ENOMEM; 634367e94c1SMasami Hiramatsu if (pf->pvar->type) { 635367e94c1SMasami Hiramatsu pf->tvar->type = strdup(pf->pvar->type); 636367e94c1SMasami Hiramatsu if (pf->tvar->type == NULL) 637367e94c1SMasami Hiramatsu return -ENOMEM; 638367e94c1SMasami Hiramatsu } 639367e94c1SMasami Hiramatsu if (pf->pvar->name) { 640367e94c1SMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 641367e94c1SMasami Hiramatsu if (pf->tvar->name == NULL) 642367e94c1SMasami Hiramatsu return -ENOMEM; 643367e94c1SMasami Hiramatsu } else 644367e94c1SMasami Hiramatsu pf->tvar->name = NULL; 645367e94c1SMasami Hiramatsu return 0; 646367e94c1SMasami Hiramatsu } 647367e94c1SMasami Hiramatsu 64848481938SMasami Hiramatsu if (pf->pvar->name) 64902b95dadSMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 65048481938SMasami Hiramatsu else { 65102b95dadSMasami Hiramatsu ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); 65202b95dadSMasami Hiramatsu if (ret < 0) 65302b95dadSMasami Hiramatsu return ret; 65411a1ca35SMasami Hiramatsu ptr = strchr(buf, ':'); /* Change type separator to _ */ 65511a1ca35SMasami Hiramatsu if (ptr) 65611a1ca35SMasami Hiramatsu *ptr = '_'; 65702b95dadSMasami Hiramatsu pf->tvar->name = strdup(buf); 65848481938SMasami Hiramatsu } 65902b95dadSMasami Hiramatsu if (pf->tvar->name == NULL) 66002b95dadSMasami Hiramatsu return -ENOMEM; 66148481938SMasami Hiramatsu 662f182e3e1SMasami Hiramatsu pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 6634ea42b18SMasami Hiramatsu /* Search child die for local variables and parameters. */ 664f182e3e1SMasami Hiramatsu if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 665f182e3e1SMasami Hiramatsu /* Search again in global variables */ 666f182e3e1SMasami Hiramatsu if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 6678afa2a70SMasami Hiramatsu ret = -ENOENT; 668f182e3e1SMasami Hiramatsu } 669f66fedcbSMasami Hiramatsu if (ret >= 0) 670b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 671f182e3e1SMasami Hiramatsu 672b7dcb857SMasami Hiramatsu if (ret < 0) 673b55a87adSMasami Hiramatsu pr_warning("Failed to find '%s' in this function.\n", 67448481938SMasami Hiramatsu pf->pvar->var); 675b7dcb857SMasami Hiramatsu return ret; 6764ea42b18SMasami Hiramatsu } 6774ea42b18SMasami Hiramatsu 678cf6eb489SMasami Hiramatsu /* Convert subprogram DIE to trace point */ 679cf6eb489SMasami Hiramatsu static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 680cf6eb489SMasami Hiramatsu bool retprobe, struct probe_trace_point *tp) 6814ea42b18SMasami Hiramatsu { 68226b79524SPrashanth Nageshappa Dwarf_Addr eaddr, highaddr; 683804b3606SMasami Hiramatsu const char *name; 684cf6eb489SMasami Hiramatsu 685cf6eb489SMasami Hiramatsu /* Copy the name of probe point */ 686cf6eb489SMasami Hiramatsu name = dwarf_diename(sp_die); 687cf6eb489SMasami Hiramatsu if (name) { 688cf6eb489SMasami Hiramatsu if (dwarf_entrypc(sp_die, &eaddr) != 0) { 6890e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s\n", 690cf6eb489SMasami Hiramatsu dwarf_diename(sp_die)); 691cf6eb489SMasami Hiramatsu return -ENOENT; 692cf6eb489SMasami Hiramatsu } 69326b79524SPrashanth Nageshappa if (dwarf_highpc(sp_die, &highaddr) != 0) { 69426b79524SPrashanth Nageshappa pr_warning("Failed to get end address of %s\n", 69526b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 69626b79524SPrashanth Nageshappa return -ENOENT; 69726b79524SPrashanth Nageshappa } 69826b79524SPrashanth Nageshappa if (paddr > highaddr) { 69926b79524SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 70026b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 70126b79524SPrashanth Nageshappa return -EINVAL; 70226b79524SPrashanth Nageshappa } 703cf6eb489SMasami Hiramatsu tp->symbol = strdup(name); 704cf6eb489SMasami Hiramatsu if (tp->symbol == NULL) 705cf6eb489SMasami Hiramatsu return -ENOMEM; 706cf6eb489SMasami Hiramatsu tp->offset = (unsigned long)(paddr - eaddr); 707cf6eb489SMasami Hiramatsu } else 708cf6eb489SMasami Hiramatsu /* This function has no name. */ 709cf6eb489SMasami Hiramatsu tp->offset = (unsigned long)paddr; 710cf6eb489SMasami Hiramatsu 711cf6eb489SMasami Hiramatsu /* Return probe must be on the head of a subprogram */ 712cf6eb489SMasami Hiramatsu if (retprobe) { 713cf6eb489SMasami Hiramatsu if (eaddr != paddr) { 714cf6eb489SMasami Hiramatsu pr_warning("Return probe must be on the head of" 7150e43e5d2SMasami Hiramatsu " a real function.\n"); 716cf6eb489SMasami Hiramatsu return -EINVAL; 717cf6eb489SMasami Hiramatsu } 718cf6eb489SMasami Hiramatsu tp->retprobe = true; 719cf6eb489SMasami Hiramatsu } 720cf6eb489SMasami Hiramatsu 721cf6eb489SMasami Hiramatsu return 0; 722cf6eb489SMasami Hiramatsu } 723cf6eb489SMasami Hiramatsu 724221d0611SMasami Hiramatsu /* Call probe_finder callback with scope DIE */ 725221d0611SMasami Hiramatsu static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 726cf6eb489SMasami Hiramatsu { 727804b3606SMasami Hiramatsu Dwarf_Attribute fb_attr; 728804b3606SMasami Hiramatsu size_t nops; 729cf6eb489SMasami Hiramatsu int ret; 7304235b045SMasami Hiramatsu 731221d0611SMasami Hiramatsu if (!sc_die) { 732221d0611SMasami Hiramatsu pr_err("Caller must pass a scope DIE. Program error.\n"); 733221d0611SMasami Hiramatsu return -EINVAL; 734221d0611SMasami Hiramatsu } 735221d0611SMasami Hiramatsu 736221d0611SMasami Hiramatsu /* If not a real subprogram, find a real one */ 737*0dbb1cacSMasami Hiramatsu if (!die_is_func_def(sc_die)) { 738221d0611SMasami Hiramatsu if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 739b55a87adSMasami Hiramatsu pr_warning("Failed to find probe point in any " 740b55a87adSMasami Hiramatsu "functions.\n"); 741b55a87adSMasami Hiramatsu return -ENOENT; 742b55a87adSMasami Hiramatsu } 743221d0611SMasami Hiramatsu } else 744221d0611SMasami Hiramatsu memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 745e92b85e1SMasami Hiramatsu 746221d0611SMasami Hiramatsu /* Get the frame base attribute/ops from subprogram */ 747221d0611SMasami Hiramatsu dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 748d0cb4260SMasami Hiramatsu ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 749a34a9854SMasami Hiramatsu if (ret <= 0 || nops == 0) { 750804b3606SMasami Hiramatsu pf->fb_ops = NULL; 7517752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 752a34a9854SMasami Hiramatsu } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 753a34a9854SMasami Hiramatsu pf->cfi != NULL) { 754a34a9854SMasami Hiramatsu Dwarf_Frame *frame; 755b55a87adSMasami Hiramatsu if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 756b55a87adSMasami Hiramatsu dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 7570e43e5d2SMasami Hiramatsu pr_warning("Failed to get call frame on 0x%jx\n", 758b55a87adSMasami Hiramatsu (uintmax_t)pf->addr); 759b55a87adSMasami Hiramatsu return -ENOENT; 760b55a87adSMasami Hiramatsu } 7617752f1b0SMasami Hiramatsu #endif 762a34a9854SMasami Hiramatsu } 763804b3606SMasami Hiramatsu 764cf6eb489SMasami Hiramatsu /* Call finder's callback handler */ 765221d0611SMasami Hiramatsu ret = pf->callback(sc_die, pf); 766804b3606SMasami Hiramatsu 767804b3606SMasami Hiramatsu /* *pf->fb_ops will be cached in libdw. Don't free it. */ 768804b3606SMasami Hiramatsu pf->fb_ops = NULL; 769cf6eb489SMasami Hiramatsu 770cf6eb489SMasami Hiramatsu return ret; 7714ea42b18SMasami Hiramatsu } 7724ea42b18SMasami Hiramatsu 773221d0611SMasami Hiramatsu struct find_scope_param { 774221d0611SMasami Hiramatsu const char *function; 775221d0611SMasami Hiramatsu const char *file; 776221d0611SMasami Hiramatsu int line; 777221d0611SMasami Hiramatsu int diff; 778221d0611SMasami Hiramatsu Dwarf_Die *die_mem; 779221d0611SMasami Hiramatsu bool found; 780221d0611SMasami Hiramatsu }; 781221d0611SMasami Hiramatsu 782221d0611SMasami Hiramatsu static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 783221d0611SMasami Hiramatsu { 784221d0611SMasami Hiramatsu struct find_scope_param *fsp = data; 785221d0611SMasami Hiramatsu const char *file; 786221d0611SMasami Hiramatsu int lno; 787221d0611SMasami Hiramatsu 788221d0611SMasami Hiramatsu /* Skip if declared file name does not match */ 789221d0611SMasami Hiramatsu if (fsp->file) { 790221d0611SMasami Hiramatsu file = dwarf_decl_file(fn_die); 791221d0611SMasami Hiramatsu if (!file || strcmp(fsp->file, file) != 0) 792221d0611SMasami Hiramatsu return 0; 793221d0611SMasami Hiramatsu } 794221d0611SMasami Hiramatsu /* If the function name is given, that's what user expects */ 795221d0611SMasami Hiramatsu if (fsp->function) { 796221d0611SMasami Hiramatsu if (die_compare_name(fn_die, fsp->function)) { 797221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 798221d0611SMasami Hiramatsu fsp->found = true; 799221d0611SMasami Hiramatsu return 1; 800221d0611SMasami Hiramatsu } 801221d0611SMasami Hiramatsu } else { 802221d0611SMasami Hiramatsu /* With the line number, find the nearest declared DIE */ 803221d0611SMasami Hiramatsu dwarf_decl_line(fn_die, &lno); 804221d0611SMasami Hiramatsu if (lno < fsp->line && fsp->diff > fsp->line - lno) { 805221d0611SMasami Hiramatsu /* Keep a candidate and continue */ 806221d0611SMasami Hiramatsu fsp->diff = fsp->line - lno; 807221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 808221d0611SMasami Hiramatsu fsp->found = true; 809221d0611SMasami Hiramatsu } 810221d0611SMasami Hiramatsu } 811221d0611SMasami Hiramatsu return 0; 812221d0611SMasami Hiramatsu } 813221d0611SMasami Hiramatsu 814221d0611SMasami Hiramatsu /* Find an appropriate scope fits to given conditions */ 815221d0611SMasami Hiramatsu static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 816221d0611SMasami Hiramatsu { 817221d0611SMasami Hiramatsu struct find_scope_param fsp = { 818221d0611SMasami Hiramatsu .function = pf->pev->point.function, 819221d0611SMasami Hiramatsu .file = pf->fname, 820221d0611SMasami Hiramatsu .line = pf->lno, 821221d0611SMasami Hiramatsu .diff = INT_MAX, 822221d0611SMasami Hiramatsu .die_mem = die_mem, 823221d0611SMasami Hiramatsu .found = false, 824221d0611SMasami Hiramatsu }; 825221d0611SMasami Hiramatsu 826221d0611SMasami Hiramatsu cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 827221d0611SMasami Hiramatsu 828221d0611SMasami Hiramatsu return fsp.found ? die_mem : NULL; 829221d0611SMasami Hiramatsu } 830221d0611SMasami Hiramatsu 8314cc9cec6SMasami Hiramatsu static int probe_point_line_walker(const char *fname, int lineno, 8324cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 8334cc9cec6SMasami Hiramatsu { 8344cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 835221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 8364cc9cec6SMasami Hiramatsu int ret; 8374cc9cec6SMasami Hiramatsu 8384cc9cec6SMasami Hiramatsu if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 8394cc9cec6SMasami Hiramatsu return 0; 8404cc9cec6SMasami Hiramatsu 8414cc9cec6SMasami Hiramatsu pf->addr = addr; 842221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 843221d0611SMasami Hiramatsu if (!sc_die) { 844221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 845221d0611SMasami Hiramatsu return -ENOENT; 846221d0611SMasami Hiramatsu } 847221d0611SMasami Hiramatsu 848221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8494cc9cec6SMasami Hiramatsu 8504cc9cec6SMasami Hiramatsu /* Continue if no error, because the line will be in inline function */ 851fbee632dSArnaldo Carvalho de Melo return ret < 0 ? ret : 0; 8524cc9cec6SMasami Hiramatsu } 8534cc9cec6SMasami Hiramatsu 8544ea42b18SMasami Hiramatsu /* Find probe point from its line number */ 855b55a87adSMasami Hiramatsu static int find_probe_point_by_line(struct probe_finder *pf) 8564ea42b18SMasami Hiramatsu { 8574cc9cec6SMasami Hiramatsu return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 8584ea42b18SMasami Hiramatsu } 8594ea42b18SMasami Hiramatsu 8602a9c8c36SMasami Hiramatsu /* Find lines which match lazy pattern */ 8612a9c8c36SMasami Hiramatsu static int find_lazy_match_lines(struct list_head *head, 8622a9c8c36SMasami Hiramatsu const char *fname, const char *pat) 8632a9c8c36SMasami Hiramatsu { 864f50c2169SFranck Bui-Huu FILE *fp; 865f50c2169SFranck Bui-Huu char *line = NULL; 866f50c2169SFranck Bui-Huu size_t line_len; 867f50c2169SFranck Bui-Huu ssize_t len; 868f50c2169SFranck Bui-Huu int count = 0, linenum = 1; 8692a9c8c36SMasami Hiramatsu 870f50c2169SFranck Bui-Huu fp = fopen(fname, "r"); 871f50c2169SFranck Bui-Huu if (!fp) { 872f50c2169SFranck Bui-Huu pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); 873b448c4b6SArnaldo Carvalho de Melo return -errno; 874b55a87adSMasami Hiramatsu } 875b55a87adSMasami Hiramatsu 876f50c2169SFranck Bui-Huu while ((len = getline(&line, &line_len, fp)) > 0) { 877f50c2169SFranck Bui-Huu 878f50c2169SFranck Bui-Huu if (line[len - 1] == '\n') 879f50c2169SFranck Bui-Huu line[len - 1] = '\0'; 880f50c2169SFranck Bui-Huu 881f50c2169SFranck Bui-Huu if (strlazymatch(line, pat)) { 882f50c2169SFranck Bui-Huu line_list__add_line(head, linenum); 883f50c2169SFranck Bui-Huu count++; 884f50c2169SFranck Bui-Huu } 885f50c2169SFranck Bui-Huu linenum++; 886b55a87adSMasami Hiramatsu } 887b448c4b6SArnaldo Carvalho de Melo 888f50c2169SFranck Bui-Huu if (ferror(fp)) 889f50c2169SFranck Bui-Huu count = -errno; 890f50c2169SFranck Bui-Huu free(line); 891f50c2169SFranck Bui-Huu fclose(fp); 892f50c2169SFranck Bui-Huu 893f50c2169SFranck Bui-Huu if (count == 0) 894f50c2169SFranck Bui-Huu pr_debug("No matched lines found in %s.\n", fname); 895f50c2169SFranck Bui-Huu return count; 8962a9c8c36SMasami Hiramatsu } 8972a9c8c36SMasami Hiramatsu 8984cc9cec6SMasami Hiramatsu static int probe_point_lazy_walker(const char *fname, int lineno, 8994cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 9004cc9cec6SMasami Hiramatsu { 9014cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 902221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 9034cc9cec6SMasami Hiramatsu int ret; 9044cc9cec6SMasami Hiramatsu 9054cc9cec6SMasami Hiramatsu if (!line_list__has_line(&pf->lcache, lineno) || 9064cc9cec6SMasami Hiramatsu strtailcmp(fname, pf->fname) != 0) 9074cc9cec6SMasami Hiramatsu return 0; 9084cc9cec6SMasami Hiramatsu 9094cc9cec6SMasami Hiramatsu pr_debug("Probe line found: line:%d addr:0x%llx\n", 9104cc9cec6SMasami Hiramatsu lineno, (unsigned long long)addr); 9114cc9cec6SMasami Hiramatsu pf->addr = addr; 912221d0611SMasami Hiramatsu pf->lno = lineno; 913221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 914221d0611SMasami Hiramatsu if (!sc_die) { 915221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 916221d0611SMasami Hiramatsu return -ENOENT; 917221d0611SMasami Hiramatsu } 918221d0611SMasami Hiramatsu 919221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 9204cc9cec6SMasami Hiramatsu 9214cc9cec6SMasami Hiramatsu /* 9224cc9cec6SMasami Hiramatsu * Continue if no error, because the lazy pattern will match 9234cc9cec6SMasami Hiramatsu * to other lines 9244cc9cec6SMasami Hiramatsu */ 9255e814dd5SIngo Molnar return ret < 0 ? ret : 0; 9264cc9cec6SMasami Hiramatsu } 9274cc9cec6SMasami Hiramatsu 9282a9c8c36SMasami Hiramatsu /* Find probe points from lazy pattern */ 929b55a87adSMasami Hiramatsu static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 9302a9c8c36SMasami Hiramatsu { 931b55a87adSMasami Hiramatsu int ret = 0; 9322a9c8c36SMasami Hiramatsu 9332a9c8c36SMasami Hiramatsu if (list_empty(&pf->lcache)) { 9342a9c8c36SMasami Hiramatsu /* Matching lazy line pattern */ 9352a9c8c36SMasami Hiramatsu ret = find_lazy_match_lines(&pf->lcache, pf->fname, 9364235b045SMasami Hiramatsu pf->pev->point.lazy_line); 937f50c2169SFranck Bui-Huu if (ret <= 0) 938b55a87adSMasami Hiramatsu return ret; 9392a9c8c36SMasami Hiramatsu } 9402a9c8c36SMasami Hiramatsu 9414cc9cec6SMasami Hiramatsu return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 9422a9c8c36SMasami Hiramatsu } 9432a9c8c36SMasami Hiramatsu 944e92b85e1SMasami Hiramatsu static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 9454ea42b18SMasami Hiramatsu { 946db0d2c64SMasami Hiramatsu struct probe_finder *pf = data; 9474235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 948b55a87adSMasami Hiramatsu Dwarf_Addr addr; 949db0d2c64SMasami Hiramatsu int ret; 9504ea42b18SMasami Hiramatsu 9512a9c8c36SMasami Hiramatsu if (pp->lazy_line) 952db0d2c64SMasami Hiramatsu ret = find_probe_point_lazy(in_die, pf); 9532a9c8c36SMasami Hiramatsu else { 954e92b85e1SMasami Hiramatsu /* Get probe address */ 955b55a87adSMasami Hiramatsu if (dwarf_entrypc(in_die, &addr) != 0) { 9560e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s.\n", 957b55a87adSMasami Hiramatsu dwarf_diename(in_die)); 958db0d2c64SMasami Hiramatsu return -ENOENT; 959b55a87adSMasami Hiramatsu } 960b55a87adSMasami Hiramatsu pf->addr = addr; 961e92b85e1SMasami Hiramatsu pf->addr += pp->offset; 9622a9c8c36SMasami Hiramatsu pr_debug("found inline addr: 0x%jx\n", 9632a9c8c36SMasami Hiramatsu (uintmax_t)pf->addr); 964e92b85e1SMasami Hiramatsu 965db0d2c64SMasami Hiramatsu ret = call_probe_finder(in_die, pf); 9662a9c8c36SMasami Hiramatsu } 9672a9c8c36SMasami Hiramatsu 968db0d2c64SMasami Hiramatsu return ret; 969e92b85e1SMasami Hiramatsu } 970e92b85e1SMasami Hiramatsu 971db0d2c64SMasami Hiramatsu /* Callback parameter with return value for libdw */ 972db0d2c64SMasami Hiramatsu struct dwarf_callback_param { 973db0d2c64SMasami Hiramatsu void *data; 974db0d2c64SMasami Hiramatsu int retval; 975db0d2c64SMasami Hiramatsu }; 976db0d2c64SMasami Hiramatsu 977e92b85e1SMasami Hiramatsu /* Search function from function name */ 978e92b85e1SMasami Hiramatsu static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 979e92b85e1SMasami Hiramatsu { 980b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 981b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 9824235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 983e92b85e1SMasami Hiramatsu 984e92b85e1SMasami Hiramatsu /* Check tag and diename */ 985*0dbb1cacSMasami Hiramatsu if (!die_is_func_def(sp_die) || 986*0dbb1cacSMasami Hiramatsu !die_compare_name(sp_die, pp->function)) 987b55a87adSMasami Hiramatsu return DWARF_CB_OK; 988e92b85e1SMasami Hiramatsu 9897d21635aSMasami Hiramatsu /* Check declared file */ 9907d21635aSMasami Hiramatsu if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 9917d21635aSMasami Hiramatsu return DWARF_CB_OK; 9927d21635aSMasami Hiramatsu 993e92b85e1SMasami Hiramatsu pf->fname = dwarf_decl_file(sp_die); 9942a9c8c36SMasami Hiramatsu if (pp->line) { /* Function relative line */ 995e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &pf->lno); 996804b3606SMasami Hiramatsu pf->lno += pp->line; 997b55a87adSMasami Hiramatsu param->retval = find_probe_point_by_line(pf); 998e92b85e1SMasami Hiramatsu } else if (!dwarf_func_inline(sp_die)) { 999e92b85e1SMasami Hiramatsu /* Real function */ 10002a9c8c36SMasami Hiramatsu if (pp->lazy_line) 1001b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(sp_die, pf); 10022a9c8c36SMasami Hiramatsu else { 1003b55a87adSMasami Hiramatsu if (dwarf_entrypc(sp_die, &pf->addr) != 0) { 10040e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of " 10050e43e5d2SMasami Hiramatsu "%s.\n", dwarf_diename(sp_die)); 1006b55a87adSMasami Hiramatsu param->retval = -ENOENT; 1007b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1008b55a87adSMasami Hiramatsu } 10094ea42b18SMasami Hiramatsu pf->addr += pp->offset; 10104ea42b18SMasami Hiramatsu /* TODO: Check the address in this function */ 1011cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(sp_die, pf); 10122a9c8c36SMasami Hiramatsu } 1013db0d2c64SMasami Hiramatsu } else 1014e92b85e1SMasami Hiramatsu /* Inlined function: search instances */ 1015db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1016db0d2c64SMasami Hiramatsu probe_point_inline_cb, (void *)pf); 10174ea42b18SMasami Hiramatsu 1018b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1019b55a87adSMasami Hiramatsu } 1020b55a87adSMasami Hiramatsu 1021b55a87adSMasami Hiramatsu static int find_probe_point_by_func(struct probe_finder *pf) 10224ea42b18SMasami Hiramatsu { 1023b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 1024b55a87adSMasami Hiramatsu .retval = 0}; 1025b55a87adSMasami Hiramatsu dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 1026b55a87adSMasami Hiramatsu return _param.retval; 10274ea42b18SMasami Hiramatsu } 10284ea42b18SMasami Hiramatsu 1029cd25f8bcSLin Ming struct pubname_callback_param { 1030cd25f8bcSLin Ming char *function; 1031cd25f8bcSLin Ming char *file; 1032cd25f8bcSLin Ming Dwarf_Die *cu_die; 1033cd25f8bcSLin Ming Dwarf_Die *sp_die; 1034cd25f8bcSLin Ming int found; 1035cd25f8bcSLin Ming }; 1036cd25f8bcSLin Ming 1037cd25f8bcSLin Ming static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 1038cd25f8bcSLin Ming { 1039cd25f8bcSLin Ming struct pubname_callback_param *param = data; 1040cd25f8bcSLin Ming 1041cd25f8bcSLin Ming if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1042cd25f8bcSLin Ming if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1043cd25f8bcSLin Ming return DWARF_CB_OK; 1044cd25f8bcSLin Ming 1045cd25f8bcSLin Ming if (die_compare_name(param->sp_die, param->function)) { 1046cd25f8bcSLin Ming if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1047cd25f8bcSLin Ming return DWARF_CB_OK; 1048cd25f8bcSLin Ming 1049cd25f8bcSLin Ming if (param->file && 1050cd25f8bcSLin Ming strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1051cd25f8bcSLin Ming return DWARF_CB_OK; 1052cd25f8bcSLin Ming 1053cd25f8bcSLin Ming param->found = 1; 1054cd25f8bcSLin Ming return DWARF_CB_ABORT; 1055cd25f8bcSLin Ming } 1056cd25f8bcSLin Ming } 1057cd25f8bcSLin Ming 1058cd25f8bcSLin Ming return DWARF_CB_OK; 1059cd25f8bcSLin Ming } 1060cd25f8bcSLin Ming 1061cf6eb489SMasami Hiramatsu /* Find probe points from debuginfo */ 1062ff741783SMasami Hiramatsu static int debuginfo__find_probes(struct debuginfo *self, 1063ff741783SMasami Hiramatsu struct probe_finder *pf) 10644ea42b18SMasami Hiramatsu { 1065cf6eb489SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1066804b3606SMasami Hiramatsu Dwarf_Off off, noff; 1067804b3606SMasami Hiramatsu size_t cuhl; 1068804b3606SMasami Hiramatsu Dwarf_Die *diep; 1069b55a87adSMasami Hiramatsu int ret = 0; 10704ea42b18SMasami Hiramatsu 10717752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 1072a34a9854SMasami Hiramatsu /* Get the call frame information from this dwarf */ 1073ff741783SMasami Hiramatsu pf->cfi = dwarf_getcfi(self->dbg); 10747752f1b0SMasami Hiramatsu #endif 1075a34a9854SMasami Hiramatsu 1076804b3606SMasami Hiramatsu off = 0; 1077cf6eb489SMasami Hiramatsu line_list__init(&pf->lcache); 1078cd25f8bcSLin Ming 1079cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1080cd25f8bcSLin Ming if (pp->function) { 1081cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1082cd25f8bcSLin Ming .function = pp->function, 1083cd25f8bcSLin Ming .file = pp->file, 1084cd25f8bcSLin Ming .cu_die = &pf->cu_die, 1085cd25f8bcSLin Ming .sp_die = &pf->sp_die, 10862b348a77SLin Ming .found = 0, 1087cd25f8bcSLin Ming }; 1088cd25f8bcSLin Ming struct dwarf_callback_param probe_param = { 1089cd25f8bcSLin Ming .data = pf, 1090cd25f8bcSLin Ming }; 1091cd25f8bcSLin Ming 1092ff741783SMasami Hiramatsu dwarf_getpubnames(self->dbg, pubname_search_cb, 1093ff741783SMasami Hiramatsu &pubname_param, 0); 1094cd25f8bcSLin Ming if (pubname_param.found) { 1095cd25f8bcSLin Ming ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1096cd25f8bcSLin Ming if (ret) 1097cd25f8bcSLin Ming goto found; 1098cd25f8bcSLin Ming } 1099cd25f8bcSLin Ming } 1100cd25f8bcSLin Ming 1101804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1102ff741783SMasami Hiramatsu while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 11034ea42b18SMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1104ff741783SMasami Hiramatsu diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); 1105804b3606SMasami Hiramatsu if (!diep) 1106804b3606SMasami Hiramatsu continue; 11074ea42b18SMasami Hiramatsu 11084ea42b18SMasami Hiramatsu /* Check if target file is included. */ 11094ea42b18SMasami Hiramatsu if (pp->file) 1110cf6eb489SMasami Hiramatsu pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1111804b3606SMasami Hiramatsu else 1112cf6eb489SMasami Hiramatsu pf->fname = NULL; 11134ea42b18SMasami Hiramatsu 1114cf6eb489SMasami Hiramatsu if (!pp->file || pf->fname) { 11154ea42b18SMasami Hiramatsu if (pp->function) 1116cf6eb489SMasami Hiramatsu ret = find_probe_point_by_func(pf); 11172a9c8c36SMasami Hiramatsu else if (pp->lazy_line) 1118cf6eb489SMasami Hiramatsu ret = find_probe_point_lazy(NULL, pf); 1119b0ef0732SMasami Hiramatsu else { 1120cf6eb489SMasami Hiramatsu pf->lno = pp->line; 1121cf6eb489SMasami Hiramatsu ret = find_probe_point_by_line(pf); 11224ea42b18SMasami Hiramatsu } 11238635bf6eSArnaldo Carvalho de Melo if (ret < 0) 1124fbee632dSArnaldo Carvalho de Melo break; 1125b0ef0732SMasami Hiramatsu } 1126804b3606SMasami Hiramatsu off = noff; 11274ea42b18SMasami Hiramatsu } 1128cd25f8bcSLin Ming 1129cd25f8bcSLin Ming found: 1130cf6eb489SMasami Hiramatsu line_list__free(&pf->lcache); 11314ea42b18SMasami Hiramatsu 1132cf6eb489SMasami Hiramatsu return ret; 1133cf6eb489SMasami Hiramatsu } 1134cf6eb489SMasami Hiramatsu 1135cf6eb489SMasami Hiramatsu /* Add a found probe point into trace event list */ 1136221d0611SMasami Hiramatsu static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1137cf6eb489SMasami Hiramatsu { 1138cf6eb489SMasami Hiramatsu struct trace_event_finder *tf = 1139cf6eb489SMasami Hiramatsu container_of(pf, struct trace_event_finder, pf); 1140cf6eb489SMasami Hiramatsu struct probe_trace_event *tev; 1141cf6eb489SMasami Hiramatsu int ret, i; 1142cf6eb489SMasami Hiramatsu 1143cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1144cf6eb489SMasami Hiramatsu if (tf->ntevs == tf->max_tevs) { 1145cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", 1146cf6eb489SMasami Hiramatsu tf->max_tevs); 1147cf6eb489SMasami Hiramatsu return -ERANGE; 1148cf6eb489SMasami Hiramatsu } 1149cf6eb489SMasami Hiramatsu tev = &tf->tevs[tf->ntevs++]; 1150cf6eb489SMasami Hiramatsu 1151221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1152221d0611SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1153221d0611SMasami Hiramatsu pf->pev->point.retprobe, &tev->point); 1154cf6eb489SMasami Hiramatsu if (ret < 0) 1155cf6eb489SMasami Hiramatsu return ret; 1156cf6eb489SMasami Hiramatsu 1157cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1158cf6eb489SMasami Hiramatsu tev->point.offset); 1159cf6eb489SMasami Hiramatsu 1160cf6eb489SMasami Hiramatsu /* Find each argument */ 1161cf6eb489SMasami Hiramatsu tev->nargs = pf->pev->nargs; 1162cf6eb489SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1163cf6eb489SMasami Hiramatsu if (tev->args == NULL) 1164cf6eb489SMasami Hiramatsu return -ENOMEM; 1165cf6eb489SMasami Hiramatsu for (i = 0; i < pf->pev->nargs; i++) { 1166cf6eb489SMasami Hiramatsu pf->pvar = &pf->pev->args[i]; 1167cf6eb489SMasami Hiramatsu pf->tvar = &tev->args[i]; 1168221d0611SMasami Hiramatsu /* Variable should be found from scope DIE */ 1169221d0611SMasami Hiramatsu ret = find_variable(sc_die, pf); 1170cf6eb489SMasami Hiramatsu if (ret != 0) 1171cf6eb489SMasami Hiramatsu return ret; 1172cf6eb489SMasami Hiramatsu } 1173cf6eb489SMasami Hiramatsu 1174cf6eb489SMasami Hiramatsu return 0; 1175cf6eb489SMasami Hiramatsu } 1176cf6eb489SMasami Hiramatsu 1177cf6eb489SMasami Hiramatsu /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1178ff741783SMasami Hiramatsu int debuginfo__find_trace_events(struct debuginfo *self, 1179ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1180cf6eb489SMasami Hiramatsu struct probe_trace_event **tevs, int max_tevs) 1181cf6eb489SMasami Hiramatsu { 1182cf6eb489SMasami Hiramatsu struct trace_event_finder tf = { 1183cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_probe_trace_event}, 1184cf6eb489SMasami Hiramatsu .max_tevs = max_tevs}; 1185cf6eb489SMasami Hiramatsu int ret; 1186cf6eb489SMasami Hiramatsu 1187cf6eb489SMasami Hiramatsu /* Allocate result tevs array */ 1188cf6eb489SMasami Hiramatsu *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1189cf6eb489SMasami Hiramatsu if (*tevs == NULL) 1190cf6eb489SMasami Hiramatsu return -ENOMEM; 1191cf6eb489SMasami Hiramatsu 1192cf6eb489SMasami Hiramatsu tf.tevs = *tevs; 1193cf6eb489SMasami Hiramatsu tf.ntevs = 0; 1194cf6eb489SMasami Hiramatsu 1195ff741783SMasami Hiramatsu ret = debuginfo__find_probes(self, &tf.pf); 1196cf6eb489SMasami Hiramatsu if (ret < 0) { 1197cf6eb489SMasami Hiramatsu free(*tevs); 1198cf6eb489SMasami Hiramatsu *tevs = NULL; 1199cf6eb489SMasami Hiramatsu return ret; 1200cf6eb489SMasami Hiramatsu } 1201cf6eb489SMasami Hiramatsu 1202cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : tf.ntevs; 1203cf6eb489SMasami Hiramatsu } 1204cf6eb489SMasami Hiramatsu 1205cf6eb489SMasami Hiramatsu #define MAX_VAR_LEN 64 1206cf6eb489SMasami Hiramatsu 1207cf6eb489SMasami Hiramatsu /* Collect available variables in this scope */ 1208cf6eb489SMasami Hiramatsu static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1209cf6eb489SMasami Hiramatsu { 1210cf6eb489SMasami Hiramatsu struct available_var_finder *af = data; 1211cf6eb489SMasami Hiramatsu struct variable_list *vl; 1212cf6eb489SMasami Hiramatsu char buf[MAX_VAR_LEN]; 1213cf6eb489SMasami Hiramatsu int tag, ret; 1214cf6eb489SMasami Hiramatsu 1215cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls - 1]; 1216cf6eb489SMasami Hiramatsu 1217cf6eb489SMasami Hiramatsu tag = dwarf_tag(die_mem); 1218cf6eb489SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1219cf6eb489SMasami Hiramatsu tag == DW_TAG_variable) { 1220cf6eb489SMasami Hiramatsu ret = convert_variable_location(die_mem, af->pf.addr, 1221cf6eb489SMasami Hiramatsu af->pf.fb_ops, NULL); 1222cf6eb489SMasami Hiramatsu if (ret == 0) { 1223cf6eb489SMasami Hiramatsu ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1224fb8c5a56SMasami Hiramatsu pr_debug2("Add new var: %s\n", buf); 1225cf6eb489SMasami Hiramatsu if (ret > 0) 1226cf6eb489SMasami Hiramatsu strlist__add(vl->vars, buf); 1227cf6eb489SMasami Hiramatsu } 1228cf6eb489SMasami Hiramatsu } 1229cf6eb489SMasami Hiramatsu 1230fb8c5a56SMasami Hiramatsu if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1231cf6eb489SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 1232cf6eb489SMasami Hiramatsu else 1233cf6eb489SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 1234cf6eb489SMasami Hiramatsu } 1235cf6eb489SMasami Hiramatsu 1236cf6eb489SMasami Hiramatsu /* Add a found vars into available variables list */ 1237221d0611SMasami Hiramatsu static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1238cf6eb489SMasami Hiramatsu { 1239cf6eb489SMasami Hiramatsu struct available_var_finder *af = 1240cf6eb489SMasami Hiramatsu container_of(pf, struct available_var_finder, pf); 1241cf6eb489SMasami Hiramatsu struct variable_list *vl; 1242f182e3e1SMasami Hiramatsu Dwarf_Die die_mem; 1243f182e3e1SMasami Hiramatsu int ret; 1244cf6eb489SMasami Hiramatsu 1245cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1246cf6eb489SMasami Hiramatsu if (af->nvls == af->max_vls) { 1247cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1248cf6eb489SMasami Hiramatsu return -ERANGE; 1249cf6eb489SMasami Hiramatsu } 1250cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls++]; 1251cf6eb489SMasami Hiramatsu 1252221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1253221d0611SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1254221d0611SMasami Hiramatsu pf->pev->point.retprobe, &vl->point); 1255cf6eb489SMasami Hiramatsu if (ret < 0) 1256cf6eb489SMasami Hiramatsu return ret; 1257cf6eb489SMasami Hiramatsu 1258cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1259cf6eb489SMasami Hiramatsu vl->point.offset); 1260cf6eb489SMasami Hiramatsu 1261cf6eb489SMasami Hiramatsu /* Find local variables */ 1262cf6eb489SMasami Hiramatsu vl->vars = strlist__new(true, NULL); 1263cf6eb489SMasami Hiramatsu if (vl->vars == NULL) 1264cf6eb489SMasami Hiramatsu return -ENOMEM; 1265fb8c5a56SMasami Hiramatsu af->child = true; 1266221d0611SMasami Hiramatsu die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1267cf6eb489SMasami Hiramatsu 1268fb8c5a56SMasami Hiramatsu /* Find external variables */ 1269fb8c5a56SMasami Hiramatsu if (!af->externs) 1270fb8c5a56SMasami Hiramatsu goto out; 1271fb8c5a56SMasami Hiramatsu /* Don't need to search child DIE for externs. */ 1272fb8c5a56SMasami Hiramatsu af->child = false; 1273f182e3e1SMasami Hiramatsu die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1274fb8c5a56SMasami Hiramatsu 1275fb8c5a56SMasami Hiramatsu out: 1276cf6eb489SMasami Hiramatsu if (strlist__empty(vl->vars)) { 1277cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 1278cf6eb489SMasami Hiramatsu vl->vars = NULL; 1279cf6eb489SMasami Hiramatsu } 1280cf6eb489SMasami Hiramatsu 1281cf6eb489SMasami Hiramatsu return ret; 1282cf6eb489SMasami Hiramatsu } 1283cf6eb489SMasami Hiramatsu 1284cf6eb489SMasami Hiramatsu /* Find available variables at given probe point */ 1285ff741783SMasami Hiramatsu int debuginfo__find_available_vars_at(struct debuginfo *self, 1286ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1287ff741783SMasami Hiramatsu struct variable_list **vls, 1288ff741783SMasami Hiramatsu int max_vls, bool externs) 1289cf6eb489SMasami Hiramatsu { 1290cf6eb489SMasami Hiramatsu struct available_var_finder af = { 1291cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_available_vars}, 1292fb8c5a56SMasami Hiramatsu .max_vls = max_vls, .externs = externs}; 1293cf6eb489SMasami Hiramatsu int ret; 1294cf6eb489SMasami Hiramatsu 1295cf6eb489SMasami Hiramatsu /* Allocate result vls array */ 1296cf6eb489SMasami Hiramatsu *vls = zalloc(sizeof(struct variable_list) * max_vls); 1297cf6eb489SMasami Hiramatsu if (*vls == NULL) 1298cf6eb489SMasami Hiramatsu return -ENOMEM; 1299cf6eb489SMasami Hiramatsu 1300cf6eb489SMasami Hiramatsu af.vls = *vls; 1301cf6eb489SMasami Hiramatsu af.nvls = 0; 1302cf6eb489SMasami Hiramatsu 1303ff741783SMasami Hiramatsu ret = debuginfo__find_probes(self, &af.pf); 1304cf6eb489SMasami Hiramatsu if (ret < 0) { 1305cf6eb489SMasami Hiramatsu /* Free vlist for error */ 1306cf6eb489SMasami Hiramatsu while (af.nvls--) { 1307cf6eb489SMasami Hiramatsu if (af.vls[af.nvls].point.symbol) 1308cf6eb489SMasami Hiramatsu free(af.vls[af.nvls].point.symbol); 1309cf6eb489SMasami Hiramatsu if (af.vls[af.nvls].vars) 1310cf6eb489SMasami Hiramatsu strlist__delete(af.vls[af.nvls].vars); 1311cf6eb489SMasami Hiramatsu } 1312cf6eb489SMasami Hiramatsu free(af.vls); 1313cf6eb489SMasami Hiramatsu *vls = NULL; 1314cf6eb489SMasami Hiramatsu return ret; 1315cf6eb489SMasami Hiramatsu } 1316cf6eb489SMasami Hiramatsu 1317cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : af.nvls; 13184ea42b18SMasami Hiramatsu } 13194ea42b18SMasami Hiramatsu 1320fb1587d8SMasami Hiramatsu /* Reverse search */ 1321ff741783SMasami Hiramatsu int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, 1322ff741783SMasami Hiramatsu struct perf_probe_point *ppt) 1323fb1587d8SMasami Hiramatsu { 1324fb1587d8SMasami Hiramatsu Dwarf_Die cudie, spdie, indie; 1325ff741783SMasami Hiramatsu Dwarf_Addr _addr, baseaddr; 13261d46ea2aSMasami Hiramatsu const char *fname = NULL, *func = NULL, *tmp; 13271d46ea2aSMasami Hiramatsu int baseline = 0, lineno = 0, ret = 0; 1328fb1587d8SMasami Hiramatsu 1329469b9b88SMasami Hiramatsu /* Adjust address with bias */ 1330ff741783SMasami Hiramatsu addr += self->bias; 1331ff741783SMasami Hiramatsu 1332fb1587d8SMasami Hiramatsu /* Find cu die */ 1333ff741783SMasami Hiramatsu if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { 13340e43e5d2SMasami Hiramatsu pr_warning("Failed to find debug information for address %lx\n", 13350e43e5d2SMasami Hiramatsu addr); 133675ec5a24SMasami Hiramatsu ret = -EINVAL; 133775ec5a24SMasami Hiramatsu goto end; 133875ec5a24SMasami Hiramatsu } 1339fb1587d8SMasami Hiramatsu 13401d46ea2aSMasami Hiramatsu /* Find a corresponding line (filename and lineno) */ 13411d46ea2aSMasami Hiramatsu cu_find_lineinfo(&cudie, addr, &fname, &lineno); 13421d46ea2aSMasami Hiramatsu /* Don't care whether it failed or not */ 1343fb1587d8SMasami Hiramatsu 13441d46ea2aSMasami Hiramatsu /* Find a corresponding function (name, baseline and baseaddr) */ 1345e0d153c6SMasami Hiramatsu if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 13461d46ea2aSMasami Hiramatsu /* Get function entry information */ 1347fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&spdie); 13481d46ea2aSMasami Hiramatsu if (!tmp || 13491d46ea2aSMasami Hiramatsu dwarf_entrypc(&spdie, &baseaddr) != 0 || 13501d46ea2aSMasami Hiramatsu dwarf_decl_line(&spdie, &baseline) != 0) 13511d46ea2aSMasami Hiramatsu goto post; 13521d46ea2aSMasami Hiramatsu func = tmp; 1353fb1587d8SMasami Hiramatsu 13541d46ea2aSMasami Hiramatsu if (addr == (unsigned long)baseaddr) 13551d46ea2aSMasami Hiramatsu /* Function entry - Relative line number is 0 */ 13561d46ea2aSMasami Hiramatsu lineno = baseline; 13571d46ea2aSMasami Hiramatsu else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1358b55a87adSMasami Hiramatsu &indie)) { 13591d46ea2aSMasami Hiramatsu if (dwarf_entrypc(&indie, &_addr) == 0 && 13601d46ea2aSMasami Hiramatsu _addr == addr) 13611d46ea2aSMasami Hiramatsu /* 13621d46ea2aSMasami Hiramatsu * addr is at an inline function entry. 13631d46ea2aSMasami Hiramatsu * In this case, lineno should be the call-site 13641d46ea2aSMasami Hiramatsu * line number. 13651d46ea2aSMasami Hiramatsu */ 13661d46ea2aSMasami Hiramatsu lineno = die_get_call_lineno(&indie); 13671d46ea2aSMasami Hiramatsu else { 13681d46ea2aSMasami Hiramatsu /* 13691d46ea2aSMasami Hiramatsu * addr is in an inline function body. 13701d46ea2aSMasami Hiramatsu * Since lineno points one of the lines 13711d46ea2aSMasami Hiramatsu * of the inline function, baseline should 13721d46ea2aSMasami Hiramatsu * be the entry line of the inline function. 13731d46ea2aSMasami Hiramatsu */ 1374fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&indie); 13751d46ea2aSMasami Hiramatsu if (tmp && 13761d46ea2aSMasami Hiramatsu dwarf_decl_line(&spdie, &baseline) == 0) 13771d46ea2aSMasami Hiramatsu func = tmp; 1378b55a87adSMasami Hiramatsu } 1379b55a87adSMasami Hiramatsu } 13801d46ea2aSMasami Hiramatsu } 13811d46ea2aSMasami Hiramatsu 13821d46ea2aSMasami Hiramatsu post: 13831d46ea2aSMasami Hiramatsu /* Make a relative line number or an offset */ 13841d46ea2aSMasami Hiramatsu if (lineno) 13851d46ea2aSMasami Hiramatsu ppt->line = lineno - baseline; 13861d46ea2aSMasami Hiramatsu else if (func) 13871d46ea2aSMasami Hiramatsu ppt->offset = addr - (unsigned long)baseaddr; 13881d46ea2aSMasami Hiramatsu 13891d46ea2aSMasami Hiramatsu /* Duplicate strings */ 13901d46ea2aSMasami Hiramatsu if (func) { 13911d46ea2aSMasami Hiramatsu ppt->function = strdup(func); 139202b95dadSMasami Hiramatsu if (ppt->function == NULL) { 139302b95dadSMasami Hiramatsu ret = -ENOMEM; 139402b95dadSMasami Hiramatsu goto end; 139502b95dadSMasami Hiramatsu } 1396fb1587d8SMasami Hiramatsu } 13971d46ea2aSMasami Hiramatsu if (fname) { 13981d46ea2aSMasami Hiramatsu ppt->file = strdup(fname); 13991d46ea2aSMasami Hiramatsu if (ppt->file == NULL) { 14001d46ea2aSMasami Hiramatsu if (ppt->function) { 14011d46ea2aSMasami Hiramatsu free(ppt->function); 14021d46ea2aSMasami Hiramatsu ppt->function = NULL; 14031d46ea2aSMasami Hiramatsu } 14041d46ea2aSMasami Hiramatsu ret = -ENOMEM; 14051d46ea2aSMasami Hiramatsu goto end; 14061d46ea2aSMasami Hiramatsu } 14071d46ea2aSMasami Hiramatsu } 1408fb1587d8SMasami Hiramatsu end: 14091d46ea2aSMasami Hiramatsu if (ret == 0 && (fname || func)) 14101d46ea2aSMasami Hiramatsu ret = 1; /* Found a point */ 1411fb1587d8SMasami Hiramatsu return ret; 1412fb1587d8SMasami Hiramatsu } 1413fb1587d8SMasami Hiramatsu 1414f6c903f5SMasami Hiramatsu /* Add a line and store the src path */ 1415f6c903f5SMasami Hiramatsu static int line_range_add_line(const char *src, unsigned int lineno, 1416f6c903f5SMasami Hiramatsu struct line_range *lr) 1417f6c903f5SMasami Hiramatsu { 14187cf0b79eSMasami Hiramatsu /* Copy source path */ 1419f6c903f5SMasami Hiramatsu if (!lr->path) { 14207cf0b79eSMasami Hiramatsu lr->path = strdup(src); 14217cf0b79eSMasami Hiramatsu if (lr->path == NULL) 14227cf0b79eSMasami Hiramatsu return -ENOMEM; 1423f6c903f5SMasami Hiramatsu } 1424f6c903f5SMasami Hiramatsu return line_list__add_line(&lr->line_list, lineno); 1425f6c903f5SMasami Hiramatsu } 1426f6c903f5SMasami Hiramatsu 14274cc9cec6SMasami Hiramatsu static int line_range_walk_cb(const char *fname, int lineno, 14281d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused, 14294cc9cec6SMasami Hiramatsu void *data) 1430f6c903f5SMasami Hiramatsu { 14314cc9cec6SMasami Hiramatsu struct line_finder *lf = data; 1432f6c903f5SMasami Hiramatsu 14334cc9cec6SMasami Hiramatsu if ((strtailcmp(fname, lf->fname) != 0) || 1434f6c903f5SMasami Hiramatsu (lf->lno_s > lineno || lf->lno_e < lineno)) 14354cc9cec6SMasami Hiramatsu return 0; 1436f6c903f5SMasami Hiramatsu 14374cc9cec6SMasami Hiramatsu if (line_range_add_line(fname, lineno, lf->lr) < 0) 14384cc9cec6SMasami Hiramatsu return -EINVAL; 1439f6c903f5SMasami Hiramatsu 14404cc9cec6SMasami Hiramatsu return 0; 1441f6c903f5SMasami Hiramatsu } 1442fb1587d8SMasami Hiramatsu 1443631c9defSMasami Hiramatsu /* Find line range from its line number */ 1444b55a87adSMasami Hiramatsu static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1445631c9defSMasami Hiramatsu { 14464cc9cec6SMasami Hiramatsu int ret; 1447631c9defSMasami Hiramatsu 14484cc9cec6SMasami Hiramatsu ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1449f6c903f5SMasami Hiramatsu 1450804b3606SMasami Hiramatsu /* Update status */ 1451f6c903f5SMasami Hiramatsu if (ret >= 0) 1452631c9defSMasami Hiramatsu if (!list_empty(&lf->lr->line_list)) 1453f6c903f5SMasami Hiramatsu ret = lf->found = 1; 1454f6c903f5SMasami Hiramatsu else 1455f6c903f5SMasami Hiramatsu ret = 0; /* Lines are not found */ 1456804b3606SMasami Hiramatsu else { 1457804b3606SMasami Hiramatsu free(lf->lr->path); 1458804b3606SMasami Hiramatsu lf->lr->path = NULL; 1459804b3606SMasami Hiramatsu } 1460f6c903f5SMasami Hiramatsu return ret; 1461631c9defSMasami Hiramatsu } 1462631c9defSMasami Hiramatsu 1463161a26b0SMasami Hiramatsu static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1464161a26b0SMasami Hiramatsu { 1465db0d2c64SMasami Hiramatsu find_line_range_by_line(in_die, data); 146636c0c588SMasami Hiramatsu 146736c0c588SMasami Hiramatsu /* 146836c0c588SMasami Hiramatsu * We have to check all instances of inlined function, because 146936c0c588SMasami Hiramatsu * some execution paths can be optimized out depends on the 147036c0c588SMasami Hiramatsu * function argument of instances 147136c0c588SMasami Hiramatsu */ 1472db0d2c64SMasami Hiramatsu return 0; 1473161a26b0SMasami Hiramatsu } 1474161a26b0SMasami Hiramatsu 1475*0dbb1cacSMasami Hiramatsu /* Search function definition from function name */ 1476e92b85e1SMasami Hiramatsu static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1477631c9defSMasami Hiramatsu { 1478b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1479b55a87adSMasami Hiramatsu struct line_finder *lf = param->data; 1480631c9defSMasami Hiramatsu struct line_range *lr = lf->lr; 1481631c9defSMasami Hiramatsu 14827d21635aSMasami Hiramatsu /* Check declared file */ 14837d21635aSMasami Hiramatsu if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 14847d21635aSMasami Hiramatsu return DWARF_CB_OK; 14857d21635aSMasami Hiramatsu 1486*0dbb1cacSMasami Hiramatsu if (die_is_func_def(sp_die) && 148782175633SMasami Hiramatsu die_compare_name(sp_die, lr->function)) { 1488e92b85e1SMasami Hiramatsu lf->fname = dwarf_decl_file(sp_die); 1489e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &lr->offset); 1490804b3606SMasami Hiramatsu pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1491631c9defSMasami Hiramatsu lf->lno_s = lr->offset + lr->start; 1492d3b63d7aSMasami Hiramatsu if (lf->lno_s < 0) /* Overflow */ 1493d3b63d7aSMasami Hiramatsu lf->lno_s = INT_MAX; 1494631c9defSMasami Hiramatsu lf->lno_e = lr->offset + lr->end; 1495d3b63d7aSMasami Hiramatsu if (lf->lno_e < 0) /* Overflow */ 1496d3b63d7aSMasami Hiramatsu lf->lno_e = INT_MAX; 1497d3b63d7aSMasami Hiramatsu pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1498631c9defSMasami Hiramatsu lr->start = lf->lno_s; 1499631c9defSMasami Hiramatsu lr->end = lf->lno_e; 1500db0d2c64SMasami Hiramatsu if (dwarf_func_inline(sp_die)) 1501db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1502db0d2c64SMasami Hiramatsu line_range_inline_cb, lf); 1503db0d2c64SMasami Hiramatsu else 1504b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(sp_die, lf); 1505b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1506631c9defSMasami Hiramatsu } 1507b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1508631c9defSMasami Hiramatsu } 1509631c9defSMasami Hiramatsu 1510b55a87adSMasami Hiramatsu static int find_line_range_by_func(struct line_finder *lf) 1511631c9defSMasami Hiramatsu { 1512b55a87adSMasami Hiramatsu struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1513b55a87adSMasami Hiramatsu dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1514b55a87adSMasami Hiramatsu return param.retval; 1515631c9defSMasami Hiramatsu } 1516631c9defSMasami Hiramatsu 1517ff741783SMasami Hiramatsu int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) 1518631c9defSMasami Hiramatsu { 1519804b3606SMasami Hiramatsu struct line_finder lf = {.lr = lr, .found = 0}; 1520b55a87adSMasami Hiramatsu int ret = 0; 1521804b3606SMasami Hiramatsu Dwarf_Off off = 0, noff; 1522804b3606SMasami Hiramatsu size_t cuhl; 1523804b3606SMasami Hiramatsu Dwarf_Die *diep; 15246a330a3cSMasami Hiramatsu const char *comp_dir; 1525631c9defSMasami Hiramatsu 1526cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1527cd25f8bcSLin Ming if (lr->function) { 1528cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1529cd25f8bcSLin Ming .function = lr->function, .file = lr->file, 1530cd25f8bcSLin Ming .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1531cd25f8bcSLin Ming struct dwarf_callback_param line_range_param = { 1532cd25f8bcSLin Ming .data = (void *)&lf, .retval = 0}; 1533cd25f8bcSLin Ming 1534ff741783SMasami Hiramatsu dwarf_getpubnames(self->dbg, pubname_search_cb, 1535ff741783SMasami Hiramatsu &pubname_param, 0); 1536cd25f8bcSLin Ming if (pubname_param.found) { 1537cd25f8bcSLin Ming line_range_search_cb(&lf.sp_die, &line_range_param); 1538cd25f8bcSLin Ming if (lf.found) 1539cd25f8bcSLin Ming goto found; 1540cd25f8bcSLin Ming } 1541cd25f8bcSLin Ming } 1542cd25f8bcSLin Ming 1543804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1544b55a87adSMasami Hiramatsu while (!lf.found && ret >= 0) { 1545ff741783SMasami Hiramatsu if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, 1546ff741783SMasami Hiramatsu NULL, NULL, NULL) != 0) 1547631c9defSMasami Hiramatsu break; 1548631c9defSMasami Hiramatsu 1549631c9defSMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1550ff741783SMasami Hiramatsu diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); 1551804b3606SMasami Hiramatsu if (!diep) 1552804b3606SMasami Hiramatsu continue; 1553631c9defSMasami Hiramatsu 1554631c9defSMasami Hiramatsu /* Check if target file is included. */ 1555631c9defSMasami Hiramatsu if (lr->file) 15562a9c8c36SMasami Hiramatsu lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1557804b3606SMasami Hiramatsu else 15582a9c8c36SMasami Hiramatsu lf.fname = 0; 1559631c9defSMasami Hiramatsu 15602a9c8c36SMasami Hiramatsu if (!lr->file || lf.fname) { 1561631c9defSMasami Hiramatsu if (lr->function) 1562b55a87adSMasami Hiramatsu ret = find_line_range_by_func(&lf); 1563631c9defSMasami Hiramatsu else { 1564631c9defSMasami Hiramatsu lf.lno_s = lr->start; 1565631c9defSMasami Hiramatsu lf.lno_e = lr->end; 1566b55a87adSMasami Hiramatsu ret = find_line_range_by_line(NULL, &lf); 1567631c9defSMasami Hiramatsu } 1568631c9defSMasami Hiramatsu } 1569804b3606SMasami Hiramatsu off = noff; 1570631c9defSMasami Hiramatsu } 15716a330a3cSMasami Hiramatsu 1572cd25f8bcSLin Ming found: 15736a330a3cSMasami Hiramatsu /* Store comp_dir */ 15746a330a3cSMasami Hiramatsu if (lf.found) { 15756a330a3cSMasami Hiramatsu comp_dir = cu_get_comp_dir(&lf.cu_die); 15766a330a3cSMasami Hiramatsu if (comp_dir) { 15776a330a3cSMasami Hiramatsu lr->comp_dir = strdup(comp_dir); 15786a330a3cSMasami Hiramatsu if (!lr->comp_dir) 15796a330a3cSMasami Hiramatsu ret = -ENOMEM; 15806a330a3cSMasami Hiramatsu } 15816a330a3cSMasami Hiramatsu } 15826a330a3cSMasami Hiramatsu 15837cf0b79eSMasami Hiramatsu pr_debug("path: %s\n", lr->path); 1584b55a87adSMasami Hiramatsu return (ret < 0) ? ret : lf.found; 1585631c9defSMasami Hiramatsu } 1586631c9defSMasami Hiramatsu 1587