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 { 121ff741783SMasami Hiramatsu int fd; 122469b9b88SMasami Hiramatsu 123ff741783SMasami Hiramatsu fd = open(path, O_RDONLY); 124ff741783SMasami Hiramatsu if (fd < 0) 125ff741783SMasami Hiramatsu return fd; 126469b9b88SMasami Hiramatsu 127ff741783SMasami Hiramatsu self->dwfl = dwfl_begin(&offline_callbacks); 128ff741783SMasami Hiramatsu if (!self->dwfl) 129ff741783SMasami Hiramatsu goto error; 130469b9b88SMasami Hiramatsu 131576b5237SMasami Hiramatsu self->mod = dwfl_report_offline(self->dwfl, "", "", fd); 132576b5237SMasami Hiramatsu if (!self->mod) 133469b9b88SMasami Hiramatsu goto error; 134469b9b88SMasami Hiramatsu 135576b5237SMasami Hiramatsu self->dbg = dwfl_module_getdwarf(self->mod, &self->bias); 136ff741783SMasami Hiramatsu if (!self->dbg) 137ff741783SMasami Hiramatsu goto error; 138ff741783SMasami Hiramatsu 139ff741783SMasami Hiramatsu return 0; 140469b9b88SMasami Hiramatsu error: 141ff741783SMasami Hiramatsu if (self->dwfl) 142ff741783SMasami Hiramatsu dwfl_end(self->dwfl); 143ff741783SMasami Hiramatsu else 144ff741783SMasami Hiramatsu close(fd); 145ff741783SMasami Hiramatsu memset(self, 0, sizeof(*self)); 146ff741783SMasami Hiramatsu 147ff741783SMasami Hiramatsu return -ENOENT; 148469b9b88SMasami Hiramatsu } 149469b9b88SMasami Hiramatsu 1503b4694deSMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 148) 1513b4694deSMasami Hiramatsu /* This method is buggy if elfutils is older than 0.148 */ 1523b4694deSMasami Hiramatsu static int __linux_kernel_find_elf(Dwfl_Module *mod, 1533b4694deSMasami Hiramatsu void **userdata, 1543b4694deSMasami Hiramatsu const char *module_name, 1553b4694deSMasami Hiramatsu Dwarf_Addr base, 1563b4694deSMasami Hiramatsu char **file_name, Elf **elfp) 1573b4694deSMasami Hiramatsu { 1583b4694deSMasami Hiramatsu int fd; 1593b4694deSMasami Hiramatsu const char *path = kernel_get_module_path(module_name); 1603b4694deSMasami Hiramatsu 1613b4694deSMasami Hiramatsu pr_debug2("Use file %s for %s\n", path, module_name); 1623b4694deSMasami Hiramatsu if (path) { 1633b4694deSMasami Hiramatsu fd = open(path, O_RDONLY); 1643b4694deSMasami Hiramatsu if (fd >= 0) { 1653b4694deSMasami Hiramatsu *file_name = strdup(path); 1663b4694deSMasami Hiramatsu return fd; 1673b4694deSMasami Hiramatsu } 1683b4694deSMasami Hiramatsu } 1693b4694deSMasami Hiramatsu /* If failed, try to call standard method */ 1703b4694deSMasami Hiramatsu return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, 1713b4694deSMasami Hiramatsu file_name, elfp); 1723b4694deSMasami Hiramatsu } 1733b4694deSMasami Hiramatsu 1743b4694deSMasami Hiramatsu static const Dwfl_Callbacks kernel_callbacks = { 1753b4694deSMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 1763b4694deSMasami Hiramatsu .debuginfo_path = &debuginfo_path, 1773b4694deSMasami Hiramatsu 1783b4694deSMasami Hiramatsu .find_elf = __linux_kernel_find_elf, 1793b4694deSMasami Hiramatsu .section_address = dwfl_linux_kernel_module_section_address, 1803b4694deSMasami Hiramatsu }; 1813b4694deSMasami Hiramatsu 182469b9b88SMasami Hiramatsu /* Get a Dwarf from live kernel image */ 183ff741783SMasami Hiramatsu static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 184ff741783SMasami Hiramatsu Dwarf_Addr addr) 185469b9b88SMasami Hiramatsu { 186ff741783SMasami Hiramatsu self->dwfl = dwfl_begin(&kernel_callbacks); 187ff741783SMasami Hiramatsu if (!self->dwfl) 188ff741783SMasami Hiramatsu return -EINVAL; 189469b9b88SMasami Hiramatsu 190469b9b88SMasami Hiramatsu /* Load the kernel dwarves: Don't care the result here */ 191ff741783SMasami Hiramatsu dwfl_linux_kernel_report_kernel(self->dwfl); 192ff741783SMasami Hiramatsu dwfl_linux_kernel_report_modules(self->dwfl); 193469b9b88SMasami Hiramatsu 194ff741783SMasami Hiramatsu self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); 195469b9b88SMasami Hiramatsu /* Here, check whether we could get a real dwarf */ 196ff741783SMasami Hiramatsu if (!self->dbg) { 1973b4694deSMasami Hiramatsu pr_debug("Failed to find kernel dwarf at %lx\n", 1983b4694deSMasami Hiramatsu (unsigned long)addr); 199ff741783SMasami Hiramatsu dwfl_end(self->dwfl); 200ff741783SMasami Hiramatsu memset(self, 0, sizeof(*self)); 201ff741783SMasami Hiramatsu return -ENOENT; 202469b9b88SMasami Hiramatsu } 203ff741783SMasami Hiramatsu 204ff741783SMasami Hiramatsu return 0; 205469b9b88SMasami Hiramatsu } 2063b4694deSMasami Hiramatsu #else 2073b4694deSMasami Hiramatsu /* With older elfutils, this just support kernel module... */ 208ff741783SMasami Hiramatsu static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 2091d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused) 2103b4694deSMasami Hiramatsu { 2113b4694deSMasami Hiramatsu const char *path = kernel_get_module_path("kernel"); 2123b4694deSMasami Hiramatsu 2133b4694deSMasami Hiramatsu if (!path) { 2143b4694deSMasami Hiramatsu pr_err("Failed to find vmlinux path\n"); 215ff741783SMasami Hiramatsu return -ENOENT; 2163b4694deSMasami Hiramatsu } 2173b4694deSMasami Hiramatsu 2183b4694deSMasami Hiramatsu pr_debug2("Use file %s for debuginfo\n", path); 219ff741783SMasami Hiramatsu return debuginfo__init_offline_dwarf(self, path); 2203b4694deSMasami Hiramatsu } 2213b4694deSMasami Hiramatsu #endif 222469b9b88SMasami Hiramatsu 223ff741783SMasami Hiramatsu struct debuginfo *debuginfo__new(const char *path) 224ff741783SMasami Hiramatsu { 225ff741783SMasami Hiramatsu struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 226ff741783SMasami Hiramatsu if (!self) 227ff741783SMasami Hiramatsu return NULL; 228ff741783SMasami Hiramatsu 229ff741783SMasami Hiramatsu if (debuginfo__init_offline_dwarf(self, path) < 0) { 230ff741783SMasami Hiramatsu free(self); 231ff741783SMasami Hiramatsu self = NULL; 232ff741783SMasami Hiramatsu } 233ff741783SMasami Hiramatsu 234ff741783SMasami Hiramatsu return self; 235ff741783SMasami Hiramatsu } 236ff741783SMasami Hiramatsu 237ff741783SMasami Hiramatsu struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) 238ff741783SMasami Hiramatsu { 239ff741783SMasami Hiramatsu struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 240ff741783SMasami Hiramatsu if (!self) 241ff741783SMasami Hiramatsu return NULL; 242ff741783SMasami Hiramatsu 243ff741783SMasami Hiramatsu if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { 244ff741783SMasami Hiramatsu free(self); 245ff741783SMasami Hiramatsu self = NULL; 246ff741783SMasami Hiramatsu } 247ff741783SMasami Hiramatsu 248ff741783SMasami Hiramatsu return self; 249ff741783SMasami Hiramatsu } 250ff741783SMasami Hiramatsu 251ff741783SMasami Hiramatsu void debuginfo__delete(struct debuginfo *self) 252ff741783SMasami Hiramatsu { 253ff741783SMasami Hiramatsu if (self) { 254ff741783SMasami Hiramatsu if (self->dwfl) 255ff741783SMasami Hiramatsu dwfl_end(self->dwfl); 256ff741783SMasami Hiramatsu free(self); 257ff741783SMasami Hiramatsu } 258ff741783SMasami Hiramatsu } 259ff741783SMasami Hiramatsu 2604ea42b18SMasami Hiramatsu /* 2614ea42b18SMasami Hiramatsu * Probe finder related functions 2624ea42b18SMasami Hiramatsu */ 2634ea42b18SMasami Hiramatsu 2640e60836bSSrikar Dronamraju static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 2654ea42b18SMasami Hiramatsu { 2660e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref; 2670e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 268b7dcb857SMasami Hiramatsu if (ref != NULL) 269b7dcb857SMasami Hiramatsu ref->offset = offs; 270b7dcb857SMasami Hiramatsu return ref; 271b7dcb857SMasami Hiramatsu } 272b7dcb857SMasami Hiramatsu 273cf6eb489SMasami Hiramatsu /* 274cf6eb489SMasami Hiramatsu * Convert a location into trace_arg. 275cf6eb489SMasami Hiramatsu * If tvar == NULL, this just checks variable can be converted. 276cf6eb489SMasami Hiramatsu */ 277cf6eb489SMasami Hiramatsu static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 278cf6eb489SMasami Hiramatsu Dwarf_Op *fb_ops, 279cf6eb489SMasami Hiramatsu struct probe_trace_arg *tvar) 280b7dcb857SMasami Hiramatsu { 281b7dcb857SMasami Hiramatsu Dwarf_Attribute attr; 282b7dcb857SMasami Hiramatsu Dwarf_Op *op; 283b7dcb857SMasami Hiramatsu size_t nops; 284804b3606SMasami Hiramatsu unsigned int regn; 285804b3606SMasami Hiramatsu Dwarf_Word offs = 0; 2864235b045SMasami Hiramatsu bool ref = false; 2874ea42b18SMasami Hiramatsu const char *regs; 288b7dcb857SMasami Hiramatsu int ret; 289b7dcb857SMasami Hiramatsu 290632941c4SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 291632941c4SMasami Hiramatsu goto static_var; 292632941c4SMasami Hiramatsu 293b7dcb857SMasami Hiramatsu /* TODO: handle more than 1 exprs */ 294b7dcb857SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 295cf6eb489SMasami Hiramatsu dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || 296b7dcb857SMasami Hiramatsu nops == 0) { 297b7dcb857SMasami Hiramatsu /* TODO: Support const_value */ 298b7dcb857SMasami Hiramatsu return -ENOENT; 299b7dcb857SMasami Hiramatsu } 300b7dcb857SMasami Hiramatsu 301b7dcb857SMasami Hiramatsu if (op->atom == DW_OP_addr) { 302632941c4SMasami Hiramatsu static_var: 303cf6eb489SMasami Hiramatsu if (!tvar) 304cf6eb489SMasami Hiramatsu return 0; 305b7dcb857SMasami Hiramatsu /* Static variables on memory (not stack), make @varname */ 306b7dcb857SMasami Hiramatsu ret = strlen(dwarf_diename(vr_die)); 307b7dcb857SMasami Hiramatsu tvar->value = zalloc(ret + 2); 308b7dcb857SMasami Hiramatsu if (tvar->value == NULL) 309b7dcb857SMasami Hiramatsu return -ENOMEM; 310b7dcb857SMasami Hiramatsu snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 311b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 312b7dcb857SMasami Hiramatsu if (tvar->ref == NULL) 313b7dcb857SMasami Hiramatsu return -ENOMEM; 314b7dcb857SMasami Hiramatsu return 0; 315b7dcb857SMasami Hiramatsu } 3164ea42b18SMasami Hiramatsu 3174ea42b18SMasami Hiramatsu /* If this is based on frame buffer, set the offset */ 318804b3606SMasami Hiramatsu if (op->atom == DW_OP_fbreg) { 319cf6eb489SMasami Hiramatsu if (fb_ops == NULL) 320b55a87adSMasami Hiramatsu return -ENOTSUP; 3214235b045SMasami Hiramatsu ref = true; 322804b3606SMasami Hiramatsu offs = op->number; 323cf6eb489SMasami Hiramatsu op = &fb_ops[0]; 324804b3606SMasami Hiramatsu } 3254ea42b18SMasami Hiramatsu 326804b3606SMasami Hiramatsu if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 327804b3606SMasami Hiramatsu regn = op->atom - DW_OP_breg0; 328804b3606SMasami Hiramatsu offs += op->number; 3294235b045SMasami Hiramatsu ref = true; 330804b3606SMasami Hiramatsu } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 331804b3606SMasami Hiramatsu regn = op->atom - DW_OP_reg0; 332804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_bregx) { 333804b3606SMasami Hiramatsu regn = op->number; 334804b3606SMasami Hiramatsu offs += op->number2; 3354235b045SMasami Hiramatsu ref = true; 336804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_regx) { 337804b3606SMasami Hiramatsu regn = op->number; 338b55a87adSMasami Hiramatsu } else { 339cf6eb489SMasami Hiramatsu pr_debug("DW_OP %x is not supported.\n", op->atom); 340b55a87adSMasami Hiramatsu return -ENOTSUP; 341b55a87adSMasami Hiramatsu } 3424ea42b18SMasami Hiramatsu 343cf6eb489SMasami Hiramatsu if (!tvar) 344cf6eb489SMasami Hiramatsu return 0; 345cf6eb489SMasami Hiramatsu 3464ea42b18SMasami Hiramatsu regs = get_arch_regstr(regn); 347b55a87adSMasami Hiramatsu if (!regs) { 348cf6eb489SMasami Hiramatsu /* This should be a bug in DWARF or this tool */ 3490e43e5d2SMasami Hiramatsu pr_warning("Mapping for the register number %u " 3500e43e5d2SMasami Hiramatsu "missing on this architecture.\n", regn); 351b55a87adSMasami Hiramatsu return -ERANGE; 352b55a87adSMasami Hiramatsu } 3534ea42b18SMasami Hiramatsu 35402b95dadSMasami Hiramatsu tvar->value = strdup(regs); 35502b95dadSMasami Hiramatsu if (tvar->value == NULL) 35602b95dadSMasami Hiramatsu return -ENOMEM; 35702b95dadSMasami Hiramatsu 3584235b045SMasami Hiramatsu if (ref) { 359b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 360e334016fSMasami Hiramatsu if (tvar->ref == NULL) 361e334016fSMasami Hiramatsu return -ENOMEM; 3624235b045SMasami Hiramatsu } 363b55a87adSMasami Hiramatsu return 0; 3644ea42b18SMasami Hiramatsu } 3654ea42b18SMasami Hiramatsu 366124bb83cSMasami Hiramatsu #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 367124bb83cSMasami Hiramatsu 368b55a87adSMasami Hiramatsu static int convert_variable_type(Dwarf_Die *vr_die, 3690e60836bSSrikar Dronamraju struct probe_trace_arg *tvar, 37073317b95SMasami Hiramatsu const char *cast) 3714984912eSMasami Hiramatsu { 3720e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 3734984912eSMasami Hiramatsu Dwarf_Die type; 3744984912eSMasami Hiramatsu char buf[16]; 375bcfc0821SMasami Hiramatsu int bsize, boffs, total; 3764984912eSMasami Hiramatsu int ret; 3774984912eSMasami Hiramatsu 37873317b95SMasami Hiramatsu /* TODO: check all types */ 37973317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") != 0) { 38073317b95SMasami Hiramatsu /* Non string type is OK */ 38173317b95SMasami Hiramatsu tvar->type = strdup(cast); 38273317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 38373317b95SMasami Hiramatsu } 38473317b95SMasami Hiramatsu 385bcfc0821SMasami Hiramatsu bsize = dwarf_bitsize(vr_die); 386bcfc0821SMasami Hiramatsu if (bsize > 0) { 387124bb83cSMasami Hiramatsu /* This is a bitfield */ 388bcfc0821SMasami Hiramatsu boffs = dwarf_bitoffset(vr_die); 389bcfc0821SMasami Hiramatsu total = dwarf_bytesize(vr_die); 390bcfc0821SMasami Hiramatsu if (boffs < 0 || total < 0) 391bcfc0821SMasami Hiramatsu return -ENOENT; 392bcfc0821SMasami Hiramatsu ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 393bcfc0821SMasami Hiramatsu BYTES_TO_BITS(total)); 394124bb83cSMasami Hiramatsu goto formatted; 395124bb83cSMasami Hiramatsu } 396124bb83cSMasami Hiramatsu 397b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 398b55a87adSMasami Hiramatsu pr_warning("Failed to get a type information of %s.\n", 3994984912eSMasami Hiramatsu dwarf_diename(vr_die)); 400b55a87adSMasami Hiramatsu return -ENOENT; 401b55a87adSMasami Hiramatsu } 4024984912eSMasami Hiramatsu 403b2a3c12bSMasami Hiramatsu pr_debug("%s type is %s.\n", 404b2a3c12bSMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 405b2a3c12bSMasami Hiramatsu 40673317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") == 0) { /* String type */ 40773317b95SMasami Hiramatsu ret = dwarf_tag(&type); 40873317b95SMasami Hiramatsu if (ret != DW_TAG_pointer_type && 40973317b95SMasami Hiramatsu ret != DW_TAG_array_type) { 41073317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 4110e43e5d2SMasami Hiramatsu "%s(%s) is not a pointer nor array.\n", 41273317b95SMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 41373317b95SMasami Hiramatsu return -EINVAL; 41473317b95SMasami Hiramatsu } 41573317b95SMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 4160e43e5d2SMasami Hiramatsu pr_warning("Failed to get a type" 4170e43e5d2SMasami Hiramatsu " information.\n"); 41873317b95SMasami Hiramatsu return -ENOENT; 41973317b95SMasami Hiramatsu } 4207ce28b5bSHyeoncheol Lee if (ret == DW_TAG_pointer_type) { 42173317b95SMasami Hiramatsu while (*ref_ptr) 42273317b95SMasami Hiramatsu ref_ptr = &(*ref_ptr)->next; 42373317b95SMasami Hiramatsu /* Add new reference with offset +0 */ 4240e60836bSSrikar Dronamraju *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 42573317b95SMasami Hiramatsu if (*ref_ptr == NULL) { 42673317b95SMasami Hiramatsu pr_warning("Out of memory error\n"); 42773317b95SMasami Hiramatsu return -ENOMEM; 42873317b95SMasami Hiramatsu } 42973317b95SMasami Hiramatsu } 43082175633SMasami Hiramatsu if (!die_compare_name(&type, "char") && 43182175633SMasami Hiramatsu !die_compare_name(&type, "unsigned char")) { 43273317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 4330e43e5d2SMasami Hiramatsu "%s is not (unsigned) char *.\n", 43473317b95SMasami Hiramatsu dwarf_diename(vr_die)); 43573317b95SMasami Hiramatsu return -EINVAL; 43673317b95SMasami Hiramatsu } 43773317b95SMasami Hiramatsu tvar->type = strdup(cast); 43873317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 43973317b95SMasami Hiramatsu } 44073317b95SMasami Hiramatsu 441bcfc0821SMasami Hiramatsu ret = dwarf_bytesize(&type); 442bcfc0821SMasami Hiramatsu if (ret <= 0) 443124bb83cSMasami Hiramatsu /* No size ... try to use default type */ 444124bb83cSMasami Hiramatsu return 0; 445bcfc0821SMasami Hiramatsu ret = BYTES_TO_BITS(ret); 446124bb83cSMasami Hiramatsu 4474984912eSMasami Hiramatsu /* Check the bitwidth */ 4484984912eSMasami Hiramatsu if (ret > MAX_BASIC_TYPE_BITS) { 449124bb83cSMasami Hiramatsu pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 4504984912eSMasami Hiramatsu dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 4514984912eSMasami Hiramatsu ret = MAX_BASIC_TYPE_BITS; 4524984912eSMasami Hiramatsu } 4534984912eSMasami Hiramatsu ret = snprintf(buf, 16, "%c%d", 4544984912eSMasami Hiramatsu die_is_signed_type(&type) ? 's' : 'u', ret); 455124bb83cSMasami Hiramatsu 456124bb83cSMasami Hiramatsu formatted: 457b55a87adSMasami Hiramatsu if (ret < 0 || ret >= 16) { 458b55a87adSMasami Hiramatsu if (ret >= 16) 459b55a87adSMasami Hiramatsu ret = -E2BIG; 460b55a87adSMasami Hiramatsu pr_warning("Failed to convert variable type: %s\n", 461b55a87adSMasami Hiramatsu strerror(-ret)); 462b55a87adSMasami Hiramatsu return ret; 463b55a87adSMasami Hiramatsu } 46473317b95SMasami Hiramatsu tvar->type = strdup(buf); 46573317b95SMasami Hiramatsu if (tvar->type == NULL) 46602b95dadSMasami Hiramatsu return -ENOMEM; 467b55a87adSMasami Hiramatsu return 0; 4684984912eSMasami Hiramatsu } 4694984912eSMasami Hiramatsu 470b55a87adSMasami Hiramatsu static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 4717df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, 4720e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr, 4734984912eSMasami Hiramatsu Dwarf_Die *die_mem) 4747df2f329SMasami Hiramatsu { 4750e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = *ref_ptr; 4767df2f329SMasami Hiramatsu Dwarf_Die type; 4777df2f329SMasami Hiramatsu Dwarf_Word offs; 478b2a3c12bSMasami Hiramatsu int ret, tag; 4797df2f329SMasami Hiramatsu 4807df2f329SMasami Hiramatsu pr_debug("converting %s in %s\n", field->name, varname); 481b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 482b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 483b55a87adSMasami Hiramatsu return -ENOENT; 484b55a87adSMasami Hiramatsu } 485b2a3c12bSMasami Hiramatsu pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); 486b2a3c12bSMasami Hiramatsu tag = dwarf_tag(&type); 4877df2f329SMasami Hiramatsu 488b2a3c12bSMasami Hiramatsu if (field->name[0] == '[' && 489b2a3c12bSMasami Hiramatsu (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 490b2a3c12bSMasami Hiramatsu if (field->next) 491b2a3c12bSMasami Hiramatsu /* Save original type for next field */ 492b2a3c12bSMasami Hiramatsu memcpy(die_mem, &type, sizeof(*die_mem)); 493b2a3c12bSMasami Hiramatsu /* Get the type of this array */ 494b2a3c12bSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 495b2a3c12bSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 496b2a3c12bSMasami Hiramatsu return -ENOENT; 497b2a3c12bSMasami Hiramatsu } 498b2a3c12bSMasami Hiramatsu pr_debug2("Array real type: (%x)\n", 499b2a3c12bSMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 500b2a3c12bSMasami Hiramatsu if (tag == DW_TAG_pointer_type) { 5010e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 502b2a3c12bSMasami Hiramatsu if (ref == NULL) 503b2a3c12bSMasami Hiramatsu return -ENOMEM; 504b2a3c12bSMasami Hiramatsu if (*ref_ptr) 505b2a3c12bSMasami Hiramatsu (*ref_ptr)->next = ref; 506b2a3c12bSMasami Hiramatsu else 507b2a3c12bSMasami Hiramatsu *ref_ptr = ref; 508b2a3c12bSMasami Hiramatsu } 509bcfc0821SMasami Hiramatsu ref->offset += dwarf_bytesize(&type) * field->index; 510b2a3c12bSMasami Hiramatsu if (!field->next) 511b2a3c12bSMasami Hiramatsu /* Save vr_die for converting types */ 512b2a3c12bSMasami Hiramatsu memcpy(die_mem, vr_die, sizeof(*die_mem)); 513b2a3c12bSMasami Hiramatsu goto next; 514b2a3c12bSMasami Hiramatsu } else if (tag == DW_TAG_pointer_type) { 5157df2f329SMasami Hiramatsu /* Check the pointer and dereference */ 516b55a87adSMasami Hiramatsu if (!field->ref) { 517b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '->'\n", 5187df2f329SMasami Hiramatsu field->name); 519b55a87adSMasami Hiramatsu return -EINVAL; 520b55a87adSMasami Hiramatsu } 5217df2f329SMasami Hiramatsu /* Get the type pointed by this pointer */ 522b55a87adSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 523b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 524b55a87adSMasami Hiramatsu return -ENOENT; 525b55a87adSMasami Hiramatsu } 52612e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 5277b0295b3SHyeoncheol Lee tag = dwarf_tag(&type); 5287b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 5297b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 5307b0295b3SHyeoncheol Lee varname); 531b55a87adSMasami Hiramatsu return -EINVAL; 532b55a87adSMasami Hiramatsu } 53312e5a7aeSMasami Hiramatsu 5340e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 535e334016fSMasami Hiramatsu if (ref == NULL) 536e334016fSMasami Hiramatsu return -ENOMEM; 5377df2f329SMasami Hiramatsu if (*ref_ptr) 5387df2f329SMasami Hiramatsu (*ref_ptr)->next = ref; 5397df2f329SMasami Hiramatsu else 5407df2f329SMasami Hiramatsu *ref_ptr = ref; 5417df2f329SMasami Hiramatsu } else { 54212e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 5437b0295b3SHyeoncheol Lee if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 5447b0295b3SHyeoncheol Lee pr_warning("%s is not a data structure nor an union.\n", 5457b0295b3SHyeoncheol Lee varname); 546b55a87adSMasami Hiramatsu return -EINVAL; 547b55a87adSMasami Hiramatsu } 548b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') { 5490e43e5d2SMasami Hiramatsu pr_err("Semantic error: %s is not a pointor" 5500e43e5d2SMasami Hiramatsu " nor array.\n", varname); 551b2a3c12bSMasami Hiramatsu return -EINVAL; 552b2a3c12bSMasami Hiramatsu } 553b55a87adSMasami Hiramatsu if (field->ref) { 554b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '.'\n", 5557df2f329SMasami Hiramatsu field->name); 556b55a87adSMasami Hiramatsu return -EINVAL; 557b55a87adSMasami Hiramatsu } 558b55a87adSMasami Hiramatsu if (!ref) { 559b55a87adSMasami Hiramatsu pr_warning("Structure on a register is not " 560b55a87adSMasami Hiramatsu "supported yet.\n"); 561b55a87adSMasami Hiramatsu return -ENOTSUP; 562b55a87adSMasami Hiramatsu } 5637df2f329SMasami Hiramatsu } 5647df2f329SMasami Hiramatsu 565b55a87adSMasami Hiramatsu if (die_find_member(&type, field->name, die_mem) == NULL) { 566b55a87adSMasami Hiramatsu pr_warning("%s(tyep:%s) has no member %s.\n", varname, 5677df2f329SMasami Hiramatsu dwarf_diename(&type), field->name); 568b55a87adSMasami Hiramatsu return -EINVAL; 569b55a87adSMasami Hiramatsu } 5707df2f329SMasami Hiramatsu 5717df2f329SMasami Hiramatsu /* Get the offset of the field */ 5727b0295b3SHyeoncheol Lee if (tag == DW_TAG_union_type) { 5737b0295b3SHyeoncheol Lee offs = 0; 5747b0295b3SHyeoncheol Lee } else { 575de1439d8SMasami Hiramatsu ret = die_get_data_member_location(die_mem, &offs); 576de1439d8SMasami Hiramatsu if (ret < 0) { 5777b0295b3SHyeoncheol Lee pr_warning("Failed to get the offset of %s.\n", 5787b0295b3SHyeoncheol Lee field->name); 579de1439d8SMasami Hiramatsu return ret; 580b55a87adSMasami Hiramatsu } 5817b0295b3SHyeoncheol Lee } 5827df2f329SMasami Hiramatsu ref->offset += (long)offs; 5837df2f329SMasami Hiramatsu 584b2a3c12bSMasami Hiramatsu next: 5857df2f329SMasami Hiramatsu /* Converting next field */ 5867df2f329SMasami Hiramatsu if (field->next) 587b55a87adSMasami Hiramatsu return convert_variable_fields(die_mem, field->name, 588b55a87adSMasami Hiramatsu field->next, &ref, die_mem); 589b55a87adSMasami Hiramatsu else 590b55a87adSMasami Hiramatsu return 0; 5917df2f329SMasami Hiramatsu } 5927df2f329SMasami Hiramatsu 5934ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */ 594b55a87adSMasami Hiramatsu static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 5954ea42b18SMasami Hiramatsu { 5964984912eSMasami Hiramatsu Dwarf_Die die_mem; 5974ea42b18SMasami Hiramatsu int ret; 5984ea42b18SMasami Hiramatsu 599b7dcb857SMasami Hiramatsu pr_debug("Converting variable %s into trace event.\n", 600b7dcb857SMasami Hiramatsu dwarf_diename(vr_die)); 601804b3606SMasami Hiramatsu 602cf6eb489SMasami Hiramatsu ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 603cf6eb489SMasami Hiramatsu pf->tvar); 604cf6eb489SMasami Hiramatsu if (ret == -ENOENT) 605cf6eb489SMasami Hiramatsu pr_err("Failed to find the location of %s at this address.\n" 606cf6eb489SMasami Hiramatsu " Perhaps, it has been optimized out.\n", pf->pvar->var); 607cf6eb489SMasami Hiramatsu else if (ret == -ENOTSUP) 608cf6eb489SMasami Hiramatsu pr_err("Sorry, we don't support this variable location yet.\n"); 609cf6eb489SMasami Hiramatsu else if (pf->pvar->field) { 610b55a87adSMasami Hiramatsu ret = convert_variable_fields(vr_die, pf->pvar->var, 6114984912eSMasami Hiramatsu pf->pvar->field, &pf->tvar->ref, 6124984912eSMasami Hiramatsu &die_mem); 6134984912eSMasami Hiramatsu vr_die = &die_mem; 6144984912eSMasami Hiramatsu } 61573317b95SMasami Hiramatsu if (ret == 0) 61673317b95SMasami Hiramatsu ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); 617804b3606SMasami Hiramatsu /* *expr will be cached in libdw. Don't free it. */ 618b55a87adSMasami Hiramatsu return ret; 6194ea42b18SMasami Hiramatsu } 6204ea42b18SMasami Hiramatsu 621221d0611SMasami Hiramatsu /* Find a variable in a scope DIE */ 622221d0611SMasami Hiramatsu static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 6234ea42b18SMasami Hiramatsu { 624f182e3e1SMasami Hiramatsu Dwarf_Die vr_die; 62511a1ca35SMasami Hiramatsu char buf[32], *ptr; 626f182e3e1SMasami Hiramatsu int ret = 0; 6274ea42b18SMasami Hiramatsu 628367e94c1SMasami Hiramatsu if (!is_c_varname(pf->pvar->var)) { 629367e94c1SMasami Hiramatsu /* Copy raw parameters */ 630367e94c1SMasami Hiramatsu pf->tvar->value = strdup(pf->pvar->var); 631367e94c1SMasami Hiramatsu if (pf->tvar->value == NULL) 632367e94c1SMasami Hiramatsu return -ENOMEM; 633367e94c1SMasami Hiramatsu if (pf->pvar->type) { 634367e94c1SMasami Hiramatsu pf->tvar->type = strdup(pf->pvar->type); 635367e94c1SMasami Hiramatsu if (pf->tvar->type == NULL) 636367e94c1SMasami Hiramatsu return -ENOMEM; 637367e94c1SMasami Hiramatsu } 638367e94c1SMasami Hiramatsu if (pf->pvar->name) { 639367e94c1SMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 640367e94c1SMasami Hiramatsu if (pf->tvar->name == NULL) 641367e94c1SMasami Hiramatsu return -ENOMEM; 642367e94c1SMasami Hiramatsu } else 643367e94c1SMasami Hiramatsu pf->tvar->name = NULL; 644367e94c1SMasami Hiramatsu return 0; 645367e94c1SMasami Hiramatsu } 646367e94c1SMasami Hiramatsu 64748481938SMasami Hiramatsu if (pf->pvar->name) 64802b95dadSMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 64948481938SMasami Hiramatsu else { 65002b95dadSMasami Hiramatsu ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); 65102b95dadSMasami Hiramatsu if (ret < 0) 65202b95dadSMasami Hiramatsu return ret; 65311a1ca35SMasami Hiramatsu ptr = strchr(buf, ':'); /* Change type separator to _ */ 65411a1ca35SMasami Hiramatsu if (ptr) 65511a1ca35SMasami Hiramatsu *ptr = '_'; 65602b95dadSMasami Hiramatsu pf->tvar->name = strdup(buf); 65748481938SMasami Hiramatsu } 65802b95dadSMasami Hiramatsu if (pf->tvar->name == NULL) 65902b95dadSMasami Hiramatsu return -ENOMEM; 66048481938SMasami Hiramatsu 661f182e3e1SMasami Hiramatsu pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 6624ea42b18SMasami Hiramatsu /* Search child die for local variables and parameters. */ 663f182e3e1SMasami Hiramatsu if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 664f182e3e1SMasami Hiramatsu /* Search again in global variables */ 665f182e3e1SMasami Hiramatsu if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 6668afa2a70SMasami Hiramatsu ret = -ENOENT; 667f182e3e1SMasami Hiramatsu } 668f66fedcbSMasami Hiramatsu if (ret >= 0) 669b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 670f182e3e1SMasami Hiramatsu 671b7dcb857SMasami Hiramatsu if (ret < 0) 672b55a87adSMasami Hiramatsu pr_warning("Failed to find '%s' in this function.\n", 67348481938SMasami Hiramatsu pf->pvar->var); 674b7dcb857SMasami Hiramatsu return ret; 6754ea42b18SMasami Hiramatsu } 6764ea42b18SMasami Hiramatsu 677cf6eb489SMasami Hiramatsu /* Convert subprogram DIE to trace point */ 678576b5237SMasami Hiramatsu static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, 679576b5237SMasami Hiramatsu Dwarf_Addr paddr, bool retprobe, 680576b5237SMasami Hiramatsu struct probe_trace_point *tp) 6814ea42b18SMasami Hiramatsu { 68226b79524SPrashanth Nageshappa Dwarf_Addr eaddr, highaddr; 683576b5237SMasami Hiramatsu GElf_Sym sym; 684576b5237SMasami Hiramatsu const char *symbol; 685cf6eb489SMasami Hiramatsu 686576b5237SMasami Hiramatsu /* Verify the address is correct */ 687cf6eb489SMasami Hiramatsu if (dwarf_entrypc(sp_die, &eaddr) != 0) { 6880e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s\n", 689cf6eb489SMasami Hiramatsu dwarf_diename(sp_die)); 690cf6eb489SMasami Hiramatsu return -ENOENT; 691cf6eb489SMasami Hiramatsu } 69226b79524SPrashanth Nageshappa if (dwarf_highpc(sp_die, &highaddr) != 0) { 69326b79524SPrashanth Nageshappa pr_warning("Failed to get end address of %s\n", 69426b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 69526b79524SPrashanth Nageshappa return -ENOENT; 69626b79524SPrashanth Nageshappa } 69726b79524SPrashanth Nageshappa if (paddr > highaddr) { 69826b79524SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 69926b79524SPrashanth Nageshappa dwarf_diename(sp_die)); 70026b79524SPrashanth Nageshappa return -EINVAL; 70126b79524SPrashanth Nageshappa } 702576b5237SMasami Hiramatsu 703576b5237SMasami Hiramatsu /* Get an appropriate symbol from symtab */ 704576b5237SMasami Hiramatsu symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); 705576b5237SMasami Hiramatsu if (!symbol) { 706576b5237SMasami Hiramatsu pr_warning("Failed to find symbol at 0x%lx\n", 707576b5237SMasami Hiramatsu (unsigned long)paddr); 708576b5237SMasami Hiramatsu return -ENOENT; 709576b5237SMasami Hiramatsu } 710576b5237SMasami Hiramatsu tp->offset = (unsigned long)(paddr - sym.st_value); 711576b5237SMasami Hiramatsu tp->symbol = strdup(symbol); 712576b5237SMasami Hiramatsu if (!tp->symbol) 713cf6eb489SMasami Hiramatsu return -ENOMEM; 714cf6eb489SMasami Hiramatsu 715cf6eb489SMasami Hiramatsu /* Return probe must be on the head of a subprogram */ 716cf6eb489SMasami Hiramatsu if (retprobe) { 717cf6eb489SMasami Hiramatsu if (eaddr != paddr) { 718cf6eb489SMasami Hiramatsu pr_warning("Return probe must be on the head of" 7190e43e5d2SMasami Hiramatsu " a real function.\n"); 720cf6eb489SMasami Hiramatsu return -EINVAL; 721cf6eb489SMasami Hiramatsu } 722cf6eb489SMasami Hiramatsu tp->retprobe = true; 723cf6eb489SMasami Hiramatsu } 724cf6eb489SMasami Hiramatsu 725cf6eb489SMasami Hiramatsu return 0; 726cf6eb489SMasami Hiramatsu } 727cf6eb489SMasami Hiramatsu 728221d0611SMasami Hiramatsu /* Call probe_finder callback with scope DIE */ 729221d0611SMasami Hiramatsu static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 730cf6eb489SMasami Hiramatsu { 731804b3606SMasami Hiramatsu Dwarf_Attribute fb_attr; 732804b3606SMasami Hiramatsu size_t nops; 733cf6eb489SMasami Hiramatsu int ret; 7344235b045SMasami Hiramatsu 735221d0611SMasami Hiramatsu if (!sc_die) { 736221d0611SMasami Hiramatsu pr_err("Caller must pass a scope DIE. Program error.\n"); 737221d0611SMasami Hiramatsu return -EINVAL; 738221d0611SMasami Hiramatsu } 739221d0611SMasami Hiramatsu 740221d0611SMasami Hiramatsu /* If not a real subprogram, find a real one */ 7410dbb1cacSMasami Hiramatsu if (!die_is_func_def(sc_die)) { 742221d0611SMasami Hiramatsu if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 743b55a87adSMasami Hiramatsu pr_warning("Failed to find probe point in any " 744b55a87adSMasami Hiramatsu "functions.\n"); 745b55a87adSMasami Hiramatsu return -ENOENT; 746b55a87adSMasami Hiramatsu } 747221d0611SMasami Hiramatsu } else 748221d0611SMasami Hiramatsu memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 749e92b85e1SMasami Hiramatsu 750221d0611SMasami Hiramatsu /* Get the frame base attribute/ops from subprogram */ 751221d0611SMasami Hiramatsu dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 752d0cb4260SMasami Hiramatsu ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 753a34a9854SMasami Hiramatsu if (ret <= 0 || nops == 0) { 754804b3606SMasami Hiramatsu pf->fb_ops = NULL; 7557752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 756a34a9854SMasami Hiramatsu } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 757a34a9854SMasami Hiramatsu pf->cfi != NULL) { 758a34a9854SMasami Hiramatsu Dwarf_Frame *frame; 759b55a87adSMasami Hiramatsu if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 760b55a87adSMasami Hiramatsu dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 7610e43e5d2SMasami Hiramatsu pr_warning("Failed to get call frame on 0x%jx\n", 762b55a87adSMasami Hiramatsu (uintmax_t)pf->addr); 763b55a87adSMasami Hiramatsu return -ENOENT; 764b55a87adSMasami Hiramatsu } 7657752f1b0SMasami Hiramatsu #endif 766a34a9854SMasami Hiramatsu } 767804b3606SMasami Hiramatsu 768cf6eb489SMasami Hiramatsu /* Call finder's callback handler */ 769221d0611SMasami Hiramatsu ret = pf->callback(sc_die, pf); 770804b3606SMasami Hiramatsu 771804b3606SMasami Hiramatsu /* *pf->fb_ops will be cached in libdw. Don't free it. */ 772804b3606SMasami Hiramatsu pf->fb_ops = NULL; 773cf6eb489SMasami Hiramatsu 774cf6eb489SMasami Hiramatsu return ret; 7754ea42b18SMasami Hiramatsu } 7764ea42b18SMasami Hiramatsu 777221d0611SMasami Hiramatsu struct find_scope_param { 778221d0611SMasami Hiramatsu const char *function; 779221d0611SMasami Hiramatsu const char *file; 780221d0611SMasami Hiramatsu int line; 781221d0611SMasami Hiramatsu int diff; 782221d0611SMasami Hiramatsu Dwarf_Die *die_mem; 783221d0611SMasami Hiramatsu bool found; 784221d0611SMasami Hiramatsu }; 785221d0611SMasami Hiramatsu 786221d0611SMasami Hiramatsu static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 787221d0611SMasami Hiramatsu { 788221d0611SMasami Hiramatsu struct find_scope_param *fsp = data; 789221d0611SMasami Hiramatsu const char *file; 790221d0611SMasami Hiramatsu int lno; 791221d0611SMasami Hiramatsu 792221d0611SMasami Hiramatsu /* Skip if declared file name does not match */ 793221d0611SMasami Hiramatsu if (fsp->file) { 794221d0611SMasami Hiramatsu file = dwarf_decl_file(fn_die); 795221d0611SMasami Hiramatsu if (!file || strcmp(fsp->file, file) != 0) 796221d0611SMasami Hiramatsu return 0; 797221d0611SMasami Hiramatsu } 798221d0611SMasami Hiramatsu /* If the function name is given, that's what user expects */ 799221d0611SMasami Hiramatsu if (fsp->function) { 800221d0611SMasami Hiramatsu if (die_compare_name(fn_die, fsp->function)) { 801221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 802221d0611SMasami Hiramatsu fsp->found = true; 803221d0611SMasami Hiramatsu return 1; 804221d0611SMasami Hiramatsu } 805221d0611SMasami Hiramatsu } else { 806221d0611SMasami Hiramatsu /* With the line number, find the nearest declared DIE */ 807221d0611SMasami Hiramatsu dwarf_decl_line(fn_die, &lno); 808221d0611SMasami Hiramatsu if (lno < fsp->line && fsp->diff > fsp->line - lno) { 809221d0611SMasami Hiramatsu /* Keep a candidate and continue */ 810221d0611SMasami Hiramatsu fsp->diff = fsp->line - lno; 811221d0611SMasami Hiramatsu memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 812221d0611SMasami Hiramatsu fsp->found = true; 813221d0611SMasami Hiramatsu } 814221d0611SMasami Hiramatsu } 815221d0611SMasami Hiramatsu return 0; 816221d0611SMasami Hiramatsu } 817221d0611SMasami Hiramatsu 818221d0611SMasami Hiramatsu /* Find an appropriate scope fits to given conditions */ 819221d0611SMasami Hiramatsu static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 820221d0611SMasami Hiramatsu { 821221d0611SMasami Hiramatsu struct find_scope_param fsp = { 822221d0611SMasami Hiramatsu .function = pf->pev->point.function, 823221d0611SMasami Hiramatsu .file = pf->fname, 824221d0611SMasami Hiramatsu .line = pf->lno, 825221d0611SMasami Hiramatsu .diff = INT_MAX, 826221d0611SMasami Hiramatsu .die_mem = die_mem, 827221d0611SMasami Hiramatsu .found = false, 828221d0611SMasami Hiramatsu }; 829221d0611SMasami Hiramatsu 830221d0611SMasami Hiramatsu cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 831221d0611SMasami Hiramatsu 832221d0611SMasami Hiramatsu return fsp.found ? die_mem : NULL; 833221d0611SMasami Hiramatsu } 834221d0611SMasami Hiramatsu 8354cc9cec6SMasami Hiramatsu static int probe_point_line_walker(const char *fname, int lineno, 8364cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 8374cc9cec6SMasami Hiramatsu { 8384cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 839221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 8404cc9cec6SMasami Hiramatsu int ret; 8414cc9cec6SMasami Hiramatsu 8424cc9cec6SMasami Hiramatsu if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 8434cc9cec6SMasami Hiramatsu return 0; 8444cc9cec6SMasami Hiramatsu 8454cc9cec6SMasami Hiramatsu pf->addr = addr; 846221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 847221d0611SMasami Hiramatsu if (!sc_die) { 848221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 849221d0611SMasami Hiramatsu return -ENOENT; 850221d0611SMasami Hiramatsu } 851221d0611SMasami Hiramatsu 852221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 8534cc9cec6SMasami Hiramatsu 8544cc9cec6SMasami Hiramatsu /* Continue if no error, because the line will be in inline function */ 855fbee632dSArnaldo Carvalho de Melo return ret < 0 ? ret : 0; 8564cc9cec6SMasami Hiramatsu } 8574cc9cec6SMasami Hiramatsu 8584ea42b18SMasami Hiramatsu /* Find probe point from its line number */ 859b55a87adSMasami Hiramatsu static int find_probe_point_by_line(struct probe_finder *pf) 8604ea42b18SMasami Hiramatsu { 8614cc9cec6SMasami Hiramatsu return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 8624ea42b18SMasami Hiramatsu } 8634ea42b18SMasami Hiramatsu 8642a9c8c36SMasami Hiramatsu /* Find lines which match lazy pattern */ 8652a9c8c36SMasami Hiramatsu static int find_lazy_match_lines(struct list_head *head, 8662a9c8c36SMasami Hiramatsu const char *fname, const char *pat) 8672a9c8c36SMasami Hiramatsu { 868f50c2169SFranck Bui-Huu FILE *fp; 869f50c2169SFranck Bui-Huu char *line = NULL; 870f50c2169SFranck Bui-Huu size_t line_len; 871f50c2169SFranck Bui-Huu ssize_t len; 872f50c2169SFranck Bui-Huu int count = 0, linenum = 1; 8732a9c8c36SMasami Hiramatsu 874f50c2169SFranck Bui-Huu fp = fopen(fname, "r"); 875f50c2169SFranck Bui-Huu if (!fp) { 876f50c2169SFranck Bui-Huu pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); 877b448c4b6SArnaldo Carvalho de Melo return -errno; 878b55a87adSMasami Hiramatsu } 879b55a87adSMasami Hiramatsu 880f50c2169SFranck Bui-Huu while ((len = getline(&line, &line_len, fp)) > 0) { 881f50c2169SFranck Bui-Huu 882f50c2169SFranck Bui-Huu if (line[len - 1] == '\n') 883f50c2169SFranck Bui-Huu line[len - 1] = '\0'; 884f50c2169SFranck Bui-Huu 885f50c2169SFranck Bui-Huu if (strlazymatch(line, pat)) { 886f50c2169SFranck Bui-Huu line_list__add_line(head, linenum); 887f50c2169SFranck Bui-Huu count++; 888f50c2169SFranck Bui-Huu } 889f50c2169SFranck Bui-Huu linenum++; 890b55a87adSMasami Hiramatsu } 891b448c4b6SArnaldo Carvalho de Melo 892f50c2169SFranck Bui-Huu if (ferror(fp)) 893f50c2169SFranck Bui-Huu count = -errno; 894f50c2169SFranck Bui-Huu free(line); 895f50c2169SFranck Bui-Huu fclose(fp); 896f50c2169SFranck Bui-Huu 897f50c2169SFranck Bui-Huu if (count == 0) 898f50c2169SFranck Bui-Huu pr_debug("No matched lines found in %s.\n", fname); 899f50c2169SFranck Bui-Huu return count; 9002a9c8c36SMasami Hiramatsu } 9012a9c8c36SMasami Hiramatsu 9024cc9cec6SMasami Hiramatsu static int probe_point_lazy_walker(const char *fname, int lineno, 9034cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 9044cc9cec6SMasami Hiramatsu { 9054cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 906221d0611SMasami Hiramatsu Dwarf_Die *sc_die, die_mem; 9074cc9cec6SMasami Hiramatsu int ret; 9084cc9cec6SMasami Hiramatsu 9094cc9cec6SMasami Hiramatsu if (!line_list__has_line(&pf->lcache, lineno) || 9104cc9cec6SMasami Hiramatsu strtailcmp(fname, pf->fname) != 0) 9114cc9cec6SMasami Hiramatsu return 0; 9124cc9cec6SMasami Hiramatsu 9134cc9cec6SMasami Hiramatsu pr_debug("Probe line found: line:%d addr:0x%llx\n", 9144cc9cec6SMasami Hiramatsu lineno, (unsigned long long)addr); 9154cc9cec6SMasami Hiramatsu pf->addr = addr; 916221d0611SMasami Hiramatsu pf->lno = lineno; 917221d0611SMasami Hiramatsu sc_die = find_best_scope(pf, &die_mem); 918221d0611SMasami Hiramatsu if (!sc_die) { 919221d0611SMasami Hiramatsu pr_warning("Failed to find scope of probe point.\n"); 920221d0611SMasami Hiramatsu return -ENOENT; 921221d0611SMasami Hiramatsu } 922221d0611SMasami Hiramatsu 923221d0611SMasami Hiramatsu ret = call_probe_finder(sc_die, pf); 9244cc9cec6SMasami Hiramatsu 9254cc9cec6SMasami Hiramatsu /* 9264cc9cec6SMasami Hiramatsu * Continue if no error, because the lazy pattern will match 9274cc9cec6SMasami Hiramatsu * to other lines 9284cc9cec6SMasami Hiramatsu */ 9295e814dd5SIngo Molnar return ret < 0 ? ret : 0; 9304cc9cec6SMasami Hiramatsu } 9314cc9cec6SMasami Hiramatsu 9322a9c8c36SMasami Hiramatsu /* Find probe points from lazy pattern */ 933b55a87adSMasami Hiramatsu static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 9342a9c8c36SMasami Hiramatsu { 935b55a87adSMasami Hiramatsu int ret = 0; 9362a9c8c36SMasami Hiramatsu 9372a9c8c36SMasami Hiramatsu if (list_empty(&pf->lcache)) { 9382a9c8c36SMasami Hiramatsu /* Matching lazy line pattern */ 9392a9c8c36SMasami Hiramatsu ret = find_lazy_match_lines(&pf->lcache, pf->fname, 9404235b045SMasami Hiramatsu pf->pev->point.lazy_line); 941f50c2169SFranck Bui-Huu if (ret <= 0) 942b55a87adSMasami Hiramatsu return ret; 9432a9c8c36SMasami Hiramatsu } 9442a9c8c36SMasami Hiramatsu 9454cc9cec6SMasami Hiramatsu return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 9462a9c8c36SMasami Hiramatsu } 9472a9c8c36SMasami Hiramatsu 948e92b85e1SMasami Hiramatsu static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 9494ea42b18SMasami Hiramatsu { 950db0d2c64SMasami Hiramatsu struct probe_finder *pf = data; 9514235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 952b55a87adSMasami Hiramatsu Dwarf_Addr addr; 953db0d2c64SMasami Hiramatsu int ret; 9544ea42b18SMasami Hiramatsu 9552a9c8c36SMasami Hiramatsu if (pp->lazy_line) 956db0d2c64SMasami Hiramatsu ret = find_probe_point_lazy(in_die, pf); 9572a9c8c36SMasami Hiramatsu else { 958e92b85e1SMasami Hiramatsu /* Get probe address */ 959b55a87adSMasami Hiramatsu if (dwarf_entrypc(in_die, &addr) != 0) { 9600e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s.\n", 961b55a87adSMasami Hiramatsu dwarf_diename(in_die)); 962db0d2c64SMasami Hiramatsu return -ENOENT; 963b55a87adSMasami Hiramatsu } 964b55a87adSMasami Hiramatsu pf->addr = addr; 965e92b85e1SMasami Hiramatsu pf->addr += pp->offset; 9662a9c8c36SMasami Hiramatsu pr_debug("found inline addr: 0x%jx\n", 9672a9c8c36SMasami Hiramatsu (uintmax_t)pf->addr); 968e92b85e1SMasami Hiramatsu 969db0d2c64SMasami Hiramatsu ret = call_probe_finder(in_die, pf); 9702a9c8c36SMasami Hiramatsu } 9712a9c8c36SMasami Hiramatsu 972db0d2c64SMasami Hiramatsu return ret; 973e92b85e1SMasami Hiramatsu } 974e92b85e1SMasami Hiramatsu 975db0d2c64SMasami Hiramatsu /* Callback parameter with return value for libdw */ 976db0d2c64SMasami Hiramatsu struct dwarf_callback_param { 977db0d2c64SMasami Hiramatsu void *data; 978db0d2c64SMasami Hiramatsu int retval; 979db0d2c64SMasami Hiramatsu }; 980db0d2c64SMasami Hiramatsu 981e92b85e1SMasami Hiramatsu /* Search function from function name */ 982e92b85e1SMasami Hiramatsu static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 983e92b85e1SMasami Hiramatsu { 984b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 985b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 9864235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 987e92b85e1SMasami Hiramatsu 988e92b85e1SMasami Hiramatsu /* Check tag and diename */ 9890dbb1cacSMasami Hiramatsu if (!die_is_func_def(sp_die) || 9900dbb1cacSMasami Hiramatsu !die_compare_name(sp_die, pp->function)) 991b55a87adSMasami Hiramatsu return DWARF_CB_OK; 992e92b85e1SMasami Hiramatsu 9937d21635aSMasami Hiramatsu /* Check declared file */ 9947d21635aSMasami Hiramatsu if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 9957d21635aSMasami Hiramatsu return DWARF_CB_OK; 9967d21635aSMasami Hiramatsu 997e92b85e1SMasami Hiramatsu pf->fname = dwarf_decl_file(sp_die); 9982a9c8c36SMasami Hiramatsu if (pp->line) { /* Function relative line */ 999e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &pf->lno); 1000804b3606SMasami Hiramatsu pf->lno += pp->line; 1001b55a87adSMasami Hiramatsu param->retval = find_probe_point_by_line(pf); 1002e92b85e1SMasami Hiramatsu } else if (!dwarf_func_inline(sp_die)) { 1003e92b85e1SMasami Hiramatsu /* Real function */ 10042a9c8c36SMasami Hiramatsu if (pp->lazy_line) 1005b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(sp_die, pf); 10062a9c8c36SMasami Hiramatsu else { 1007b55a87adSMasami Hiramatsu if (dwarf_entrypc(sp_die, &pf->addr) != 0) { 10080e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of " 10090e43e5d2SMasami Hiramatsu "%s.\n", dwarf_diename(sp_die)); 1010b55a87adSMasami Hiramatsu param->retval = -ENOENT; 1011b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1012b55a87adSMasami Hiramatsu } 10134ea42b18SMasami Hiramatsu pf->addr += pp->offset; 10144ea42b18SMasami Hiramatsu /* TODO: Check the address in this function */ 1015cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(sp_die, pf); 10162a9c8c36SMasami Hiramatsu } 1017db0d2c64SMasami Hiramatsu } else 1018e92b85e1SMasami Hiramatsu /* Inlined function: search instances */ 1019db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1020db0d2c64SMasami Hiramatsu probe_point_inline_cb, (void *)pf); 10214ea42b18SMasami Hiramatsu 1022b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1023b55a87adSMasami Hiramatsu } 1024b55a87adSMasami Hiramatsu 1025b55a87adSMasami Hiramatsu static int find_probe_point_by_func(struct probe_finder *pf) 10264ea42b18SMasami Hiramatsu { 1027b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 1028b55a87adSMasami Hiramatsu .retval = 0}; 1029b55a87adSMasami Hiramatsu dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 1030b55a87adSMasami Hiramatsu return _param.retval; 10314ea42b18SMasami Hiramatsu } 10324ea42b18SMasami Hiramatsu 1033cd25f8bcSLin Ming struct pubname_callback_param { 1034cd25f8bcSLin Ming char *function; 1035cd25f8bcSLin Ming char *file; 1036cd25f8bcSLin Ming Dwarf_Die *cu_die; 1037cd25f8bcSLin Ming Dwarf_Die *sp_die; 1038cd25f8bcSLin Ming int found; 1039cd25f8bcSLin Ming }; 1040cd25f8bcSLin Ming 1041cd25f8bcSLin Ming static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 1042cd25f8bcSLin Ming { 1043cd25f8bcSLin Ming struct pubname_callback_param *param = data; 1044cd25f8bcSLin Ming 1045cd25f8bcSLin Ming if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1046cd25f8bcSLin Ming if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1047cd25f8bcSLin Ming return DWARF_CB_OK; 1048cd25f8bcSLin Ming 1049cd25f8bcSLin Ming if (die_compare_name(param->sp_die, param->function)) { 1050cd25f8bcSLin Ming if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1051cd25f8bcSLin Ming return DWARF_CB_OK; 1052cd25f8bcSLin Ming 1053cd25f8bcSLin Ming if (param->file && 1054cd25f8bcSLin Ming strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1055cd25f8bcSLin Ming return DWARF_CB_OK; 1056cd25f8bcSLin Ming 1057cd25f8bcSLin Ming param->found = 1; 1058cd25f8bcSLin Ming return DWARF_CB_ABORT; 1059cd25f8bcSLin Ming } 1060cd25f8bcSLin Ming } 1061cd25f8bcSLin Ming 1062cd25f8bcSLin Ming return DWARF_CB_OK; 1063cd25f8bcSLin Ming } 1064cd25f8bcSLin Ming 1065cf6eb489SMasami Hiramatsu /* Find probe points from debuginfo */ 1066ff741783SMasami Hiramatsu static int debuginfo__find_probes(struct debuginfo *self, 1067ff741783SMasami Hiramatsu struct probe_finder *pf) 10684ea42b18SMasami Hiramatsu { 1069cf6eb489SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1070804b3606SMasami Hiramatsu Dwarf_Off off, noff; 1071804b3606SMasami Hiramatsu size_t cuhl; 1072804b3606SMasami Hiramatsu Dwarf_Die *diep; 1073b55a87adSMasami Hiramatsu int ret = 0; 10744ea42b18SMasami Hiramatsu 10757752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 1076a34a9854SMasami Hiramatsu /* Get the call frame information from this dwarf */ 1077ff741783SMasami Hiramatsu pf->cfi = dwarf_getcfi(self->dbg); 10787752f1b0SMasami Hiramatsu #endif 1079a34a9854SMasami Hiramatsu 1080804b3606SMasami Hiramatsu off = 0; 1081cf6eb489SMasami Hiramatsu line_list__init(&pf->lcache); 1082cd25f8bcSLin Ming 1083cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1084cd25f8bcSLin Ming if (pp->function) { 1085cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1086cd25f8bcSLin Ming .function = pp->function, 1087cd25f8bcSLin Ming .file = pp->file, 1088cd25f8bcSLin Ming .cu_die = &pf->cu_die, 1089cd25f8bcSLin Ming .sp_die = &pf->sp_die, 10902b348a77SLin Ming .found = 0, 1091cd25f8bcSLin Ming }; 1092cd25f8bcSLin Ming struct dwarf_callback_param probe_param = { 1093cd25f8bcSLin Ming .data = pf, 1094cd25f8bcSLin Ming }; 1095cd25f8bcSLin Ming 1096ff741783SMasami Hiramatsu dwarf_getpubnames(self->dbg, pubname_search_cb, 1097ff741783SMasami Hiramatsu &pubname_param, 0); 1098cd25f8bcSLin Ming if (pubname_param.found) { 1099cd25f8bcSLin Ming ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1100cd25f8bcSLin Ming if (ret) 1101cd25f8bcSLin Ming goto found; 1102cd25f8bcSLin Ming } 1103cd25f8bcSLin Ming } 1104cd25f8bcSLin Ming 1105804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1106ff741783SMasami Hiramatsu while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 11074ea42b18SMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1108ff741783SMasami Hiramatsu diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); 1109804b3606SMasami Hiramatsu if (!diep) 1110804b3606SMasami Hiramatsu continue; 11114ea42b18SMasami Hiramatsu 11124ea42b18SMasami Hiramatsu /* Check if target file is included. */ 11134ea42b18SMasami Hiramatsu if (pp->file) 1114cf6eb489SMasami Hiramatsu pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1115804b3606SMasami Hiramatsu else 1116cf6eb489SMasami Hiramatsu pf->fname = NULL; 11174ea42b18SMasami Hiramatsu 1118cf6eb489SMasami Hiramatsu if (!pp->file || pf->fname) { 11194ea42b18SMasami Hiramatsu if (pp->function) 1120cf6eb489SMasami Hiramatsu ret = find_probe_point_by_func(pf); 11212a9c8c36SMasami Hiramatsu else if (pp->lazy_line) 1122cf6eb489SMasami Hiramatsu ret = find_probe_point_lazy(NULL, pf); 1123b0ef0732SMasami Hiramatsu else { 1124cf6eb489SMasami Hiramatsu pf->lno = pp->line; 1125cf6eb489SMasami Hiramatsu ret = find_probe_point_by_line(pf); 11264ea42b18SMasami Hiramatsu } 11278635bf6eSArnaldo Carvalho de Melo if (ret < 0) 1128fbee632dSArnaldo Carvalho de Melo break; 1129b0ef0732SMasami Hiramatsu } 1130804b3606SMasami Hiramatsu off = noff; 11314ea42b18SMasami Hiramatsu } 1132cd25f8bcSLin Ming 1133cd25f8bcSLin Ming found: 1134cf6eb489SMasami Hiramatsu line_list__free(&pf->lcache); 11354ea42b18SMasami Hiramatsu 1136cf6eb489SMasami Hiramatsu return ret; 1137cf6eb489SMasami Hiramatsu } 1138cf6eb489SMasami Hiramatsu 1139cf6eb489SMasami Hiramatsu /* Add a found probe point into trace event list */ 1140221d0611SMasami Hiramatsu static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1141cf6eb489SMasami Hiramatsu { 1142cf6eb489SMasami Hiramatsu struct trace_event_finder *tf = 1143cf6eb489SMasami Hiramatsu container_of(pf, struct trace_event_finder, pf); 1144cf6eb489SMasami Hiramatsu struct probe_trace_event *tev; 1145cf6eb489SMasami Hiramatsu int ret, i; 1146cf6eb489SMasami Hiramatsu 1147cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1148cf6eb489SMasami Hiramatsu if (tf->ntevs == tf->max_tevs) { 1149cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", 1150cf6eb489SMasami Hiramatsu tf->max_tevs); 1151cf6eb489SMasami Hiramatsu return -ERANGE; 1152cf6eb489SMasami Hiramatsu } 1153cf6eb489SMasami Hiramatsu tev = &tf->tevs[tf->ntevs++]; 1154cf6eb489SMasami Hiramatsu 1155221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1156576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 1157221d0611SMasami Hiramatsu pf->pev->point.retprobe, &tev->point); 1158cf6eb489SMasami Hiramatsu if (ret < 0) 1159cf6eb489SMasami Hiramatsu return ret; 1160cf6eb489SMasami Hiramatsu 1161cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1162cf6eb489SMasami Hiramatsu tev->point.offset); 1163cf6eb489SMasami Hiramatsu 1164cf6eb489SMasami Hiramatsu /* Find each argument */ 1165cf6eb489SMasami Hiramatsu tev->nargs = pf->pev->nargs; 1166cf6eb489SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1167cf6eb489SMasami Hiramatsu if (tev->args == NULL) 1168cf6eb489SMasami Hiramatsu return -ENOMEM; 1169cf6eb489SMasami Hiramatsu for (i = 0; i < pf->pev->nargs; i++) { 1170cf6eb489SMasami Hiramatsu pf->pvar = &pf->pev->args[i]; 1171cf6eb489SMasami Hiramatsu pf->tvar = &tev->args[i]; 1172221d0611SMasami Hiramatsu /* Variable should be found from scope DIE */ 1173221d0611SMasami Hiramatsu ret = find_variable(sc_die, pf); 1174cf6eb489SMasami Hiramatsu if (ret != 0) 1175cf6eb489SMasami Hiramatsu return ret; 1176cf6eb489SMasami Hiramatsu } 1177cf6eb489SMasami Hiramatsu 1178cf6eb489SMasami Hiramatsu return 0; 1179cf6eb489SMasami Hiramatsu } 1180cf6eb489SMasami Hiramatsu 1181cf6eb489SMasami Hiramatsu /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1182ff741783SMasami Hiramatsu int debuginfo__find_trace_events(struct debuginfo *self, 1183ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1184cf6eb489SMasami Hiramatsu struct probe_trace_event **tevs, int max_tevs) 1185cf6eb489SMasami Hiramatsu { 1186cf6eb489SMasami Hiramatsu struct trace_event_finder tf = { 1187cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_probe_trace_event}, 1188576b5237SMasami Hiramatsu .mod = self->mod, .max_tevs = max_tevs}; 1189cf6eb489SMasami Hiramatsu int ret; 1190cf6eb489SMasami Hiramatsu 1191cf6eb489SMasami Hiramatsu /* Allocate result tevs array */ 1192cf6eb489SMasami Hiramatsu *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1193cf6eb489SMasami Hiramatsu if (*tevs == NULL) 1194cf6eb489SMasami Hiramatsu return -ENOMEM; 1195cf6eb489SMasami Hiramatsu 1196cf6eb489SMasami Hiramatsu tf.tevs = *tevs; 1197cf6eb489SMasami Hiramatsu tf.ntevs = 0; 1198cf6eb489SMasami Hiramatsu 1199ff741783SMasami Hiramatsu ret = debuginfo__find_probes(self, &tf.pf); 1200cf6eb489SMasami Hiramatsu if (ret < 0) { 1201cf6eb489SMasami Hiramatsu free(*tevs); 1202cf6eb489SMasami Hiramatsu *tevs = NULL; 1203cf6eb489SMasami Hiramatsu return ret; 1204cf6eb489SMasami Hiramatsu } 1205cf6eb489SMasami Hiramatsu 1206cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : tf.ntevs; 1207cf6eb489SMasami Hiramatsu } 1208cf6eb489SMasami Hiramatsu 1209cf6eb489SMasami Hiramatsu #define MAX_VAR_LEN 64 1210cf6eb489SMasami Hiramatsu 1211cf6eb489SMasami Hiramatsu /* Collect available variables in this scope */ 1212cf6eb489SMasami Hiramatsu static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1213cf6eb489SMasami Hiramatsu { 1214cf6eb489SMasami Hiramatsu struct available_var_finder *af = data; 1215cf6eb489SMasami Hiramatsu struct variable_list *vl; 1216cf6eb489SMasami Hiramatsu char buf[MAX_VAR_LEN]; 1217cf6eb489SMasami Hiramatsu int tag, ret; 1218cf6eb489SMasami Hiramatsu 1219cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls - 1]; 1220cf6eb489SMasami Hiramatsu 1221cf6eb489SMasami Hiramatsu tag = dwarf_tag(die_mem); 1222cf6eb489SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1223cf6eb489SMasami Hiramatsu tag == DW_TAG_variable) { 1224cf6eb489SMasami Hiramatsu ret = convert_variable_location(die_mem, af->pf.addr, 1225cf6eb489SMasami Hiramatsu af->pf.fb_ops, NULL); 1226cf6eb489SMasami Hiramatsu if (ret == 0) { 1227cf6eb489SMasami Hiramatsu ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1228fb8c5a56SMasami Hiramatsu pr_debug2("Add new var: %s\n", buf); 1229cf6eb489SMasami Hiramatsu if (ret > 0) 1230cf6eb489SMasami Hiramatsu strlist__add(vl->vars, buf); 1231cf6eb489SMasami Hiramatsu } 1232cf6eb489SMasami Hiramatsu } 1233cf6eb489SMasami Hiramatsu 1234fb8c5a56SMasami Hiramatsu if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1235cf6eb489SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 1236cf6eb489SMasami Hiramatsu else 1237cf6eb489SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 1238cf6eb489SMasami Hiramatsu } 1239cf6eb489SMasami Hiramatsu 1240cf6eb489SMasami Hiramatsu /* Add a found vars into available variables list */ 1241221d0611SMasami Hiramatsu static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1242cf6eb489SMasami Hiramatsu { 1243cf6eb489SMasami Hiramatsu struct available_var_finder *af = 1244cf6eb489SMasami Hiramatsu container_of(pf, struct available_var_finder, pf); 1245cf6eb489SMasami Hiramatsu struct variable_list *vl; 1246f182e3e1SMasami Hiramatsu Dwarf_Die die_mem; 1247f182e3e1SMasami Hiramatsu int ret; 1248cf6eb489SMasami Hiramatsu 1249cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1250cf6eb489SMasami Hiramatsu if (af->nvls == af->max_vls) { 1251cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1252cf6eb489SMasami Hiramatsu return -ERANGE; 1253cf6eb489SMasami Hiramatsu } 1254cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls++]; 1255cf6eb489SMasami Hiramatsu 1256221d0611SMasami Hiramatsu /* Trace point should be converted from subprogram DIE */ 1257576b5237SMasami Hiramatsu ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, 1258221d0611SMasami Hiramatsu pf->pev->point.retprobe, &vl->point); 1259cf6eb489SMasami Hiramatsu if (ret < 0) 1260cf6eb489SMasami Hiramatsu return ret; 1261cf6eb489SMasami Hiramatsu 1262cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1263cf6eb489SMasami Hiramatsu vl->point.offset); 1264cf6eb489SMasami Hiramatsu 1265cf6eb489SMasami Hiramatsu /* Find local variables */ 1266cf6eb489SMasami Hiramatsu vl->vars = strlist__new(true, NULL); 1267cf6eb489SMasami Hiramatsu if (vl->vars == NULL) 1268cf6eb489SMasami Hiramatsu return -ENOMEM; 1269fb8c5a56SMasami Hiramatsu af->child = true; 1270221d0611SMasami Hiramatsu die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1271cf6eb489SMasami Hiramatsu 1272fb8c5a56SMasami Hiramatsu /* Find external variables */ 1273fb8c5a56SMasami Hiramatsu if (!af->externs) 1274fb8c5a56SMasami Hiramatsu goto out; 1275fb8c5a56SMasami Hiramatsu /* Don't need to search child DIE for externs. */ 1276fb8c5a56SMasami Hiramatsu af->child = false; 1277f182e3e1SMasami Hiramatsu die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1278fb8c5a56SMasami Hiramatsu 1279fb8c5a56SMasami Hiramatsu out: 1280cf6eb489SMasami Hiramatsu if (strlist__empty(vl->vars)) { 1281cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 1282cf6eb489SMasami Hiramatsu vl->vars = NULL; 1283cf6eb489SMasami Hiramatsu } 1284cf6eb489SMasami Hiramatsu 1285cf6eb489SMasami Hiramatsu return ret; 1286cf6eb489SMasami Hiramatsu } 1287cf6eb489SMasami Hiramatsu 1288cf6eb489SMasami Hiramatsu /* Find available variables at given probe point */ 1289ff741783SMasami Hiramatsu int debuginfo__find_available_vars_at(struct debuginfo *self, 1290ff741783SMasami Hiramatsu struct perf_probe_event *pev, 1291ff741783SMasami Hiramatsu struct variable_list **vls, 1292ff741783SMasami Hiramatsu int max_vls, bool externs) 1293cf6eb489SMasami Hiramatsu { 1294cf6eb489SMasami Hiramatsu struct available_var_finder af = { 1295cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_available_vars}, 1296576b5237SMasami Hiramatsu .mod = self->mod, 1297fb8c5a56SMasami Hiramatsu .max_vls = max_vls, .externs = externs}; 1298cf6eb489SMasami Hiramatsu int ret; 1299cf6eb489SMasami Hiramatsu 1300cf6eb489SMasami Hiramatsu /* Allocate result vls array */ 1301cf6eb489SMasami Hiramatsu *vls = zalloc(sizeof(struct variable_list) * max_vls); 1302cf6eb489SMasami Hiramatsu if (*vls == NULL) 1303cf6eb489SMasami Hiramatsu return -ENOMEM; 1304cf6eb489SMasami Hiramatsu 1305cf6eb489SMasami Hiramatsu af.vls = *vls; 1306cf6eb489SMasami Hiramatsu af.nvls = 0; 1307cf6eb489SMasami Hiramatsu 1308ff741783SMasami Hiramatsu ret = debuginfo__find_probes(self, &af.pf); 1309cf6eb489SMasami Hiramatsu if (ret < 0) { 1310cf6eb489SMasami Hiramatsu /* Free vlist for error */ 1311cf6eb489SMasami Hiramatsu while (af.nvls--) { 1312cf6eb489SMasami Hiramatsu if (af.vls[af.nvls].point.symbol) 1313cf6eb489SMasami Hiramatsu free(af.vls[af.nvls].point.symbol); 1314cf6eb489SMasami Hiramatsu if (af.vls[af.nvls].vars) 1315cf6eb489SMasami Hiramatsu strlist__delete(af.vls[af.nvls].vars); 1316cf6eb489SMasami Hiramatsu } 1317cf6eb489SMasami Hiramatsu free(af.vls); 1318cf6eb489SMasami Hiramatsu *vls = NULL; 1319cf6eb489SMasami Hiramatsu return ret; 1320cf6eb489SMasami Hiramatsu } 1321cf6eb489SMasami Hiramatsu 1322cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : af.nvls; 13234ea42b18SMasami Hiramatsu } 13244ea42b18SMasami Hiramatsu 1325fb1587d8SMasami Hiramatsu /* Reverse search */ 1326ff741783SMasami Hiramatsu int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, 1327ff741783SMasami Hiramatsu struct perf_probe_point *ppt) 1328fb1587d8SMasami Hiramatsu { 1329fb1587d8SMasami Hiramatsu Dwarf_Die cudie, spdie, indie; 1330*e08cfd4bSMasami Hiramatsu Dwarf_Addr _addr = 0, baseaddr = 0; 1331*e08cfd4bSMasami Hiramatsu const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; 13321d46ea2aSMasami Hiramatsu int baseline = 0, lineno = 0, ret = 0; 1333fb1587d8SMasami Hiramatsu 1334469b9b88SMasami Hiramatsu /* Adjust address with bias */ 1335ff741783SMasami Hiramatsu addr += self->bias; 1336ff741783SMasami Hiramatsu 1337fb1587d8SMasami Hiramatsu /* Find cu die */ 1338ff741783SMasami Hiramatsu if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { 13390e43e5d2SMasami Hiramatsu pr_warning("Failed to find debug information for address %lx\n", 13400e43e5d2SMasami Hiramatsu addr); 134175ec5a24SMasami Hiramatsu ret = -EINVAL; 134275ec5a24SMasami Hiramatsu goto end; 134375ec5a24SMasami Hiramatsu } 1344fb1587d8SMasami Hiramatsu 13451d46ea2aSMasami Hiramatsu /* Find a corresponding line (filename and lineno) */ 13461d46ea2aSMasami Hiramatsu cu_find_lineinfo(&cudie, addr, &fname, &lineno); 13471d46ea2aSMasami Hiramatsu /* Don't care whether it failed or not */ 1348fb1587d8SMasami Hiramatsu 13491d46ea2aSMasami Hiramatsu /* Find a corresponding function (name, baseline and baseaddr) */ 1350e0d153c6SMasami Hiramatsu if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 13511d46ea2aSMasami Hiramatsu /* Get function entry information */ 1352*e08cfd4bSMasami Hiramatsu func = basefunc = dwarf_diename(&spdie); 1353*e08cfd4bSMasami Hiramatsu if (!func || 13541d46ea2aSMasami Hiramatsu dwarf_entrypc(&spdie, &baseaddr) != 0 || 1355*e08cfd4bSMasami Hiramatsu dwarf_decl_line(&spdie, &baseline) != 0) { 1356*e08cfd4bSMasami Hiramatsu lineno = 0; 13571d46ea2aSMasami Hiramatsu goto post; 1358*e08cfd4bSMasami Hiramatsu } 1359fb1587d8SMasami Hiramatsu 1360*e08cfd4bSMasami Hiramatsu if (addr == (unsigned long)baseaddr) { 13611d46ea2aSMasami Hiramatsu /* Function entry - Relative line number is 0 */ 13621d46ea2aSMasami Hiramatsu lineno = baseline; 1363*e08cfd4bSMasami Hiramatsu fname = dwarf_decl_file(&spdie); 1364*e08cfd4bSMasami Hiramatsu goto post; 1365*e08cfd4bSMasami Hiramatsu } 1366*e08cfd4bSMasami Hiramatsu 1367*e08cfd4bSMasami Hiramatsu /* Track down the inline functions step by step */ 1368*e08cfd4bSMasami Hiramatsu while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, 1369b55a87adSMasami Hiramatsu &indie)) { 1370*e08cfd4bSMasami Hiramatsu /* There is an inline function */ 13711d46ea2aSMasami Hiramatsu if (dwarf_entrypc(&indie, &_addr) == 0 && 1372*e08cfd4bSMasami Hiramatsu _addr == addr) { 13731d46ea2aSMasami Hiramatsu /* 13741d46ea2aSMasami Hiramatsu * addr is at an inline function entry. 13751d46ea2aSMasami Hiramatsu * In this case, lineno should be the call-site 1376*e08cfd4bSMasami Hiramatsu * line number. (overwrite lineinfo) 13771d46ea2aSMasami Hiramatsu */ 13781d46ea2aSMasami Hiramatsu lineno = die_get_call_lineno(&indie); 1379*e08cfd4bSMasami Hiramatsu fname = die_get_call_file(&indie); 1380*e08cfd4bSMasami Hiramatsu break; 1381*e08cfd4bSMasami Hiramatsu } else { 13821d46ea2aSMasami Hiramatsu /* 13831d46ea2aSMasami Hiramatsu * addr is in an inline function body. 13841d46ea2aSMasami Hiramatsu * Since lineno points one of the lines 13851d46ea2aSMasami Hiramatsu * of the inline function, baseline should 13861d46ea2aSMasami Hiramatsu * be the entry line of the inline function. 13871d46ea2aSMasami Hiramatsu */ 1388fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&indie); 1389*e08cfd4bSMasami Hiramatsu if (!tmp || 1390*e08cfd4bSMasami Hiramatsu dwarf_decl_line(&indie, &baseline) != 0) 1391*e08cfd4bSMasami Hiramatsu break; 13921d46ea2aSMasami Hiramatsu func = tmp; 1393*e08cfd4bSMasami Hiramatsu spdie = indie; 1394b55a87adSMasami Hiramatsu } 1395b55a87adSMasami Hiramatsu } 1396*e08cfd4bSMasami Hiramatsu /* Verify the lineno and baseline are in a same file */ 1397*e08cfd4bSMasami Hiramatsu tmp = dwarf_decl_file(&spdie); 1398*e08cfd4bSMasami Hiramatsu if (!tmp || strcmp(tmp, fname) != 0) 1399*e08cfd4bSMasami Hiramatsu lineno = 0; 14001d46ea2aSMasami Hiramatsu } 14011d46ea2aSMasami Hiramatsu 14021d46ea2aSMasami Hiramatsu post: 14031d46ea2aSMasami Hiramatsu /* Make a relative line number or an offset */ 14041d46ea2aSMasami Hiramatsu if (lineno) 14051d46ea2aSMasami Hiramatsu ppt->line = lineno - baseline; 1406*e08cfd4bSMasami Hiramatsu else if (basefunc) { 14071d46ea2aSMasami Hiramatsu ppt->offset = addr - (unsigned long)baseaddr; 1408*e08cfd4bSMasami Hiramatsu func = basefunc; 1409*e08cfd4bSMasami Hiramatsu } 14101d46ea2aSMasami Hiramatsu 14111d46ea2aSMasami Hiramatsu /* Duplicate strings */ 14121d46ea2aSMasami Hiramatsu if (func) { 14131d46ea2aSMasami Hiramatsu ppt->function = strdup(func); 141402b95dadSMasami Hiramatsu if (ppt->function == NULL) { 141502b95dadSMasami Hiramatsu ret = -ENOMEM; 141602b95dadSMasami Hiramatsu goto end; 141702b95dadSMasami Hiramatsu } 1418fb1587d8SMasami Hiramatsu } 14191d46ea2aSMasami Hiramatsu if (fname) { 14201d46ea2aSMasami Hiramatsu ppt->file = strdup(fname); 14211d46ea2aSMasami Hiramatsu if (ppt->file == NULL) { 14221d46ea2aSMasami Hiramatsu if (ppt->function) { 14231d46ea2aSMasami Hiramatsu free(ppt->function); 14241d46ea2aSMasami Hiramatsu ppt->function = NULL; 14251d46ea2aSMasami Hiramatsu } 14261d46ea2aSMasami Hiramatsu ret = -ENOMEM; 14271d46ea2aSMasami Hiramatsu goto end; 14281d46ea2aSMasami Hiramatsu } 14291d46ea2aSMasami Hiramatsu } 1430fb1587d8SMasami Hiramatsu end: 14311d46ea2aSMasami Hiramatsu if (ret == 0 && (fname || func)) 14321d46ea2aSMasami Hiramatsu ret = 1; /* Found a point */ 1433fb1587d8SMasami Hiramatsu return ret; 1434fb1587d8SMasami Hiramatsu } 1435fb1587d8SMasami Hiramatsu 1436f6c903f5SMasami Hiramatsu /* Add a line and store the src path */ 1437f6c903f5SMasami Hiramatsu static int line_range_add_line(const char *src, unsigned int lineno, 1438f6c903f5SMasami Hiramatsu struct line_range *lr) 1439f6c903f5SMasami Hiramatsu { 14407cf0b79eSMasami Hiramatsu /* Copy source path */ 1441f6c903f5SMasami Hiramatsu if (!lr->path) { 14427cf0b79eSMasami Hiramatsu lr->path = strdup(src); 14437cf0b79eSMasami Hiramatsu if (lr->path == NULL) 14447cf0b79eSMasami Hiramatsu return -ENOMEM; 1445f6c903f5SMasami Hiramatsu } 1446f6c903f5SMasami Hiramatsu return line_list__add_line(&lr->line_list, lineno); 1447f6c903f5SMasami Hiramatsu } 1448f6c903f5SMasami Hiramatsu 14494cc9cec6SMasami Hiramatsu static int line_range_walk_cb(const char *fname, int lineno, 14501d037ca1SIrina Tirdea Dwarf_Addr addr __maybe_unused, 14514cc9cec6SMasami Hiramatsu void *data) 1452f6c903f5SMasami Hiramatsu { 14534cc9cec6SMasami Hiramatsu struct line_finder *lf = data; 1454f6c903f5SMasami Hiramatsu 14554cc9cec6SMasami Hiramatsu if ((strtailcmp(fname, lf->fname) != 0) || 1456f6c903f5SMasami Hiramatsu (lf->lno_s > lineno || lf->lno_e < lineno)) 14574cc9cec6SMasami Hiramatsu return 0; 1458f6c903f5SMasami Hiramatsu 14594cc9cec6SMasami Hiramatsu if (line_range_add_line(fname, lineno, lf->lr) < 0) 14604cc9cec6SMasami Hiramatsu return -EINVAL; 1461f6c903f5SMasami Hiramatsu 14624cc9cec6SMasami Hiramatsu return 0; 1463f6c903f5SMasami Hiramatsu } 1464fb1587d8SMasami Hiramatsu 1465631c9defSMasami Hiramatsu /* Find line range from its line number */ 1466b55a87adSMasami Hiramatsu static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1467631c9defSMasami Hiramatsu { 14684cc9cec6SMasami Hiramatsu int ret; 1469631c9defSMasami Hiramatsu 14704cc9cec6SMasami Hiramatsu ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1471f6c903f5SMasami Hiramatsu 1472804b3606SMasami Hiramatsu /* Update status */ 1473f6c903f5SMasami Hiramatsu if (ret >= 0) 1474631c9defSMasami Hiramatsu if (!list_empty(&lf->lr->line_list)) 1475f6c903f5SMasami Hiramatsu ret = lf->found = 1; 1476f6c903f5SMasami Hiramatsu else 1477f6c903f5SMasami Hiramatsu ret = 0; /* Lines are not found */ 1478804b3606SMasami Hiramatsu else { 1479804b3606SMasami Hiramatsu free(lf->lr->path); 1480804b3606SMasami Hiramatsu lf->lr->path = NULL; 1481804b3606SMasami Hiramatsu } 1482f6c903f5SMasami Hiramatsu return ret; 1483631c9defSMasami Hiramatsu } 1484631c9defSMasami Hiramatsu 1485161a26b0SMasami Hiramatsu static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1486161a26b0SMasami Hiramatsu { 1487db0d2c64SMasami Hiramatsu find_line_range_by_line(in_die, data); 148836c0c588SMasami Hiramatsu 148936c0c588SMasami Hiramatsu /* 149036c0c588SMasami Hiramatsu * We have to check all instances of inlined function, because 149136c0c588SMasami Hiramatsu * some execution paths can be optimized out depends on the 149236c0c588SMasami Hiramatsu * function argument of instances 149336c0c588SMasami Hiramatsu */ 1494db0d2c64SMasami Hiramatsu return 0; 1495161a26b0SMasami Hiramatsu } 1496161a26b0SMasami Hiramatsu 14970dbb1cacSMasami Hiramatsu /* Search function definition from function name */ 1498e92b85e1SMasami Hiramatsu static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1499631c9defSMasami Hiramatsu { 1500b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1501b55a87adSMasami Hiramatsu struct line_finder *lf = param->data; 1502631c9defSMasami Hiramatsu struct line_range *lr = lf->lr; 1503631c9defSMasami Hiramatsu 15047d21635aSMasami Hiramatsu /* Check declared file */ 15057d21635aSMasami Hiramatsu if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 15067d21635aSMasami Hiramatsu return DWARF_CB_OK; 15077d21635aSMasami Hiramatsu 15080dbb1cacSMasami Hiramatsu if (die_is_func_def(sp_die) && 150982175633SMasami Hiramatsu die_compare_name(sp_die, lr->function)) { 1510e92b85e1SMasami Hiramatsu lf->fname = dwarf_decl_file(sp_die); 1511e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &lr->offset); 1512804b3606SMasami Hiramatsu pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1513631c9defSMasami Hiramatsu lf->lno_s = lr->offset + lr->start; 1514d3b63d7aSMasami Hiramatsu if (lf->lno_s < 0) /* Overflow */ 1515d3b63d7aSMasami Hiramatsu lf->lno_s = INT_MAX; 1516631c9defSMasami Hiramatsu lf->lno_e = lr->offset + lr->end; 1517d3b63d7aSMasami Hiramatsu if (lf->lno_e < 0) /* Overflow */ 1518d3b63d7aSMasami Hiramatsu lf->lno_e = INT_MAX; 1519d3b63d7aSMasami Hiramatsu pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1520631c9defSMasami Hiramatsu lr->start = lf->lno_s; 1521631c9defSMasami Hiramatsu lr->end = lf->lno_e; 1522db0d2c64SMasami Hiramatsu if (dwarf_func_inline(sp_die)) 1523db0d2c64SMasami Hiramatsu param->retval = die_walk_instances(sp_die, 1524db0d2c64SMasami Hiramatsu line_range_inline_cb, lf); 1525db0d2c64SMasami Hiramatsu else 1526b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(sp_die, lf); 1527b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1528631c9defSMasami Hiramatsu } 1529b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1530631c9defSMasami Hiramatsu } 1531631c9defSMasami Hiramatsu 1532b55a87adSMasami Hiramatsu static int find_line_range_by_func(struct line_finder *lf) 1533631c9defSMasami Hiramatsu { 1534b55a87adSMasami Hiramatsu struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1535b55a87adSMasami Hiramatsu dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1536b55a87adSMasami Hiramatsu return param.retval; 1537631c9defSMasami Hiramatsu } 1538631c9defSMasami Hiramatsu 1539ff741783SMasami Hiramatsu int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) 1540631c9defSMasami Hiramatsu { 1541804b3606SMasami Hiramatsu struct line_finder lf = {.lr = lr, .found = 0}; 1542b55a87adSMasami Hiramatsu int ret = 0; 1543804b3606SMasami Hiramatsu Dwarf_Off off = 0, noff; 1544804b3606SMasami Hiramatsu size_t cuhl; 1545804b3606SMasami Hiramatsu Dwarf_Die *diep; 15466a330a3cSMasami Hiramatsu const char *comp_dir; 1547631c9defSMasami Hiramatsu 1548cd25f8bcSLin Ming /* Fastpath: lookup by function name from .debug_pubnames section */ 1549cd25f8bcSLin Ming if (lr->function) { 1550cd25f8bcSLin Ming struct pubname_callback_param pubname_param = { 1551cd25f8bcSLin Ming .function = lr->function, .file = lr->file, 1552cd25f8bcSLin Ming .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1553cd25f8bcSLin Ming struct dwarf_callback_param line_range_param = { 1554cd25f8bcSLin Ming .data = (void *)&lf, .retval = 0}; 1555cd25f8bcSLin Ming 1556ff741783SMasami Hiramatsu dwarf_getpubnames(self->dbg, pubname_search_cb, 1557ff741783SMasami Hiramatsu &pubname_param, 0); 1558cd25f8bcSLin Ming if (pubname_param.found) { 1559cd25f8bcSLin Ming line_range_search_cb(&lf.sp_die, &line_range_param); 1560cd25f8bcSLin Ming if (lf.found) 1561cd25f8bcSLin Ming goto found; 1562cd25f8bcSLin Ming } 1563cd25f8bcSLin Ming } 1564cd25f8bcSLin Ming 1565804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1566b55a87adSMasami Hiramatsu while (!lf.found && ret >= 0) { 1567ff741783SMasami Hiramatsu if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, 1568ff741783SMasami Hiramatsu NULL, NULL, NULL) != 0) 1569631c9defSMasami Hiramatsu break; 1570631c9defSMasami Hiramatsu 1571631c9defSMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1572ff741783SMasami Hiramatsu diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); 1573804b3606SMasami Hiramatsu if (!diep) 1574804b3606SMasami Hiramatsu continue; 1575631c9defSMasami Hiramatsu 1576631c9defSMasami Hiramatsu /* Check if target file is included. */ 1577631c9defSMasami Hiramatsu if (lr->file) 15782a9c8c36SMasami Hiramatsu lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1579804b3606SMasami Hiramatsu else 15802a9c8c36SMasami Hiramatsu lf.fname = 0; 1581631c9defSMasami Hiramatsu 15822a9c8c36SMasami Hiramatsu if (!lr->file || lf.fname) { 1583631c9defSMasami Hiramatsu if (lr->function) 1584b55a87adSMasami Hiramatsu ret = find_line_range_by_func(&lf); 1585631c9defSMasami Hiramatsu else { 1586631c9defSMasami Hiramatsu lf.lno_s = lr->start; 1587631c9defSMasami Hiramatsu lf.lno_e = lr->end; 1588b55a87adSMasami Hiramatsu ret = find_line_range_by_line(NULL, &lf); 1589631c9defSMasami Hiramatsu } 1590631c9defSMasami Hiramatsu } 1591804b3606SMasami Hiramatsu off = noff; 1592631c9defSMasami Hiramatsu } 15936a330a3cSMasami Hiramatsu 1594cd25f8bcSLin Ming found: 15956a330a3cSMasami Hiramatsu /* Store comp_dir */ 15966a330a3cSMasami Hiramatsu if (lf.found) { 15976a330a3cSMasami Hiramatsu comp_dir = cu_get_comp_dir(&lf.cu_die); 15986a330a3cSMasami Hiramatsu if (comp_dir) { 15996a330a3cSMasami Hiramatsu lr->comp_dir = strdup(comp_dir); 16006a330a3cSMasami Hiramatsu if (!lr->comp_dir) 16016a330a3cSMasami Hiramatsu ret = -ENOMEM; 16026a330a3cSMasami Hiramatsu } 16036a330a3cSMasami Hiramatsu } 16046a330a3cSMasami Hiramatsu 16057cf0b79eSMasami Hiramatsu pr_debug("path: %s\n", lr->path); 1606b55a87adSMasami Hiramatsu return (ret < 0) ? ret : lf.found; 1607631c9defSMasami Hiramatsu } 1608631c9defSMasami Hiramatsu 1609