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> 334ea42b18SMasami Hiramatsu #include <ctype.h> 34cd932c59SIan Munsie #include <dwarf-regs.h> 35074fc0e4SMasami Hiramatsu 36*124bb83cSMasami Hiramatsu #include <linux/bitops.h> 3789c69c0eSMasami Hiramatsu #include "event.h" 3889c69c0eSMasami Hiramatsu #include "debug.h" 39074fc0e4SMasami Hiramatsu #include "util.h" 409ed7e1b8SChase Douglas #include "symbol.h" 414ea42b18SMasami Hiramatsu #include "probe-finder.h" 424ea42b18SMasami Hiramatsu 434984912eSMasami Hiramatsu /* Kprobe tracer basic type is up to u64 */ 444984912eSMasami Hiramatsu #define MAX_BASIC_TYPE_BITS 64 454984912eSMasami Hiramatsu 464ea42b18SMasami Hiramatsu /* 474ea42b18SMasami Hiramatsu * Compare the tail of two strings. 484ea42b18SMasami Hiramatsu * Return 0 if whole of either string is same as another's tail part. 494ea42b18SMasami Hiramatsu */ 504ea42b18SMasami Hiramatsu static int strtailcmp(const char *s1, const char *s2) 514ea42b18SMasami Hiramatsu { 524ea42b18SMasami Hiramatsu int i1 = strlen(s1); 534ea42b18SMasami Hiramatsu int i2 = strlen(s2); 54d56728b8SJuha Leppanen while (--i1 >= 0 && --i2 >= 0) { 554ea42b18SMasami Hiramatsu if (s1[i1] != s2[i2]) 564ea42b18SMasami Hiramatsu return s1[i1] - s2[i2]; 574ea42b18SMasami Hiramatsu } 584ea42b18SMasami Hiramatsu return 0; 594ea42b18SMasami Hiramatsu } 604ea42b18SMasami Hiramatsu 612a9c8c36SMasami Hiramatsu /* Line number list operations */ 622a9c8c36SMasami Hiramatsu 632a9c8c36SMasami Hiramatsu /* Add a line to line number list */ 64d3b63d7aSMasami Hiramatsu static int line_list__add_line(struct list_head *head, int line) 652a9c8c36SMasami Hiramatsu { 662a9c8c36SMasami Hiramatsu struct line_node *ln; 672a9c8c36SMasami Hiramatsu struct list_head *p; 682a9c8c36SMasami Hiramatsu 692a9c8c36SMasami Hiramatsu /* Reverse search, because new line will be the last one */ 702a9c8c36SMasami Hiramatsu list_for_each_entry_reverse(ln, head, list) { 712a9c8c36SMasami Hiramatsu if (ln->line < line) { 722a9c8c36SMasami Hiramatsu p = &ln->list; 732a9c8c36SMasami Hiramatsu goto found; 742a9c8c36SMasami Hiramatsu } else if (ln->line == line) /* Already exist */ 75e334016fSMasami Hiramatsu return 1; 762a9c8c36SMasami Hiramatsu } 772a9c8c36SMasami Hiramatsu /* List is empty, or the smallest entry */ 782a9c8c36SMasami Hiramatsu p = head; 792a9c8c36SMasami Hiramatsu found: 802a9c8c36SMasami Hiramatsu pr_debug("line list: add a line %u\n", line); 81e334016fSMasami Hiramatsu ln = zalloc(sizeof(struct line_node)); 82e334016fSMasami Hiramatsu if (ln == NULL) 83e334016fSMasami Hiramatsu return -ENOMEM; 842a9c8c36SMasami Hiramatsu ln->line = line; 852a9c8c36SMasami Hiramatsu INIT_LIST_HEAD(&ln->list); 862a9c8c36SMasami Hiramatsu list_add(&ln->list, p); 87e334016fSMasami Hiramatsu return 0; 882a9c8c36SMasami Hiramatsu } 892a9c8c36SMasami Hiramatsu 902a9c8c36SMasami Hiramatsu /* Check if the line in line number list */ 91d3b63d7aSMasami Hiramatsu static int line_list__has_line(struct list_head *head, int line) 922a9c8c36SMasami Hiramatsu { 932a9c8c36SMasami Hiramatsu struct line_node *ln; 942a9c8c36SMasami Hiramatsu 952a9c8c36SMasami Hiramatsu /* Reverse search, because new line will be the last one */ 962a9c8c36SMasami Hiramatsu list_for_each_entry(ln, head, list) 972a9c8c36SMasami Hiramatsu if (ln->line == line) 982a9c8c36SMasami Hiramatsu return 1; 992a9c8c36SMasami Hiramatsu 1002a9c8c36SMasami Hiramatsu return 0; 1012a9c8c36SMasami Hiramatsu } 1022a9c8c36SMasami Hiramatsu 1032a9c8c36SMasami Hiramatsu /* Init line number list */ 1042a9c8c36SMasami Hiramatsu static void line_list__init(struct list_head *head) 1052a9c8c36SMasami Hiramatsu { 1062a9c8c36SMasami Hiramatsu INIT_LIST_HEAD(head); 1072a9c8c36SMasami Hiramatsu } 1082a9c8c36SMasami Hiramatsu 1092a9c8c36SMasami Hiramatsu /* Free line number list */ 1102a9c8c36SMasami Hiramatsu static void line_list__free(struct list_head *head) 1112a9c8c36SMasami Hiramatsu { 1122a9c8c36SMasami Hiramatsu struct line_node *ln; 1132a9c8c36SMasami Hiramatsu while (!list_empty(head)) { 1142a9c8c36SMasami Hiramatsu ln = list_first_entry(head, struct line_node, list); 1152a9c8c36SMasami Hiramatsu list_del(&ln->list); 1162a9c8c36SMasami Hiramatsu free(ln); 1172a9c8c36SMasami Hiramatsu } 1182a9c8c36SMasami Hiramatsu } 1192a9c8c36SMasami Hiramatsu 120469b9b88SMasami Hiramatsu /* Dwarf FL wrappers */ 121469b9b88SMasami Hiramatsu static char *debuginfo_path; /* Currently dummy */ 122469b9b88SMasami Hiramatsu 123469b9b88SMasami Hiramatsu static const Dwfl_Callbacks offline_callbacks = { 124469b9b88SMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 125469b9b88SMasami Hiramatsu .debuginfo_path = &debuginfo_path, 126469b9b88SMasami Hiramatsu 127469b9b88SMasami Hiramatsu .section_address = dwfl_offline_section_address, 128469b9b88SMasami Hiramatsu 129469b9b88SMasami Hiramatsu /* We use this table for core files too. */ 130469b9b88SMasami Hiramatsu .find_elf = dwfl_build_id_find_elf, 131469b9b88SMasami Hiramatsu }; 132469b9b88SMasami Hiramatsu 133469b9b88SMasami Hiramatsu /* Get a Dwarf from offline image */ 134469b9b88SMasami Hiramatsu static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) 135469b9b88SMasami Hiramatsu { 136469b9b88SMasami Hiramatsu Dwfl_Module *mod; 137469b9b88SMasami Hiramatsu Dwarf *dbg = NULL; 138469b9b88SMasami Hiramatsu 139469b9b88SMasami Hiramatsu if (!dwflp) 140469b9b88SMasami Hiramatsu return NULL; 141469b9b88SMasami Hiramatsu 142469b9b88SMasami Hiramatsu *dwflp = dwfl_begin(&offline_callbacks); 143469b9b88SMasami Hiramatsu if (!*dwflp) 144469b9b88SMasami Hiramatsu return NULL; 145469b9b88SMasami Hiramatsu 146469b9b88SMasami Hiramatsu mod = dwfl_report_offline(*dwflp, "", "", fd); 147469b9b88SMasami Hiramatsu if (!mod) 148469b9b88SMasami Hiramatsu goto error; 149469b9b88SMasami Hiramatsu 150469b9b88SMasami Hiramatsu dbg = dwfl_module_getdwarf(mod, bias); 151469b9b88SMasami Hiramatsu if (!dbg) { 152469b9b88SMasami Hiramatsu error: 153469b9b88SMasami Hiramatsu dwfl_end(*dwflp); 154469b9b88SMasami Hiramatsu *dwflp = NULL; 155469b9b88SMasami Hiramatsu } 156469b9b88SMasami Hiramatsu return dbg; 157469b9b88SMasami Hiramatsu } 158469b9b88SMasami Hiramatsu 1593b4694deSMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 148) 1603b4694deSMasami Hiramatsu /* This method is buggy if elfutils is older than 0.148 */ 1613b4694deSMasami Hiramatsu static int __linux_kernel_find_elf(Dwfl_Module *mod, 1623b4694deSMasami Hiramatsu void **userdata, 1633b4694deSMasami Hiramatsu const char *module_name, 1643b4694deSMasami Hiramatsu Dwarf_Addr base, 1653b4694deSMasami Hiramatsu char **file_name, Elf **elfp) 1663b4694deSMasami Hiramatsu { 1673b4694deSMasami Hiramatsu int fd; 1683b4694deSMasami Hiramatsu const char *path = kernel_get_module_path(module_name); 1693b4694deSMasami Hiramatsu 1703b4694deSMasami Hiramatsu pr_debug2("Use file %s for %s\n", path, module_name); 1713b4694deSMasami Hiramatsu if (path) { 1723b4694deSMasami Hiramatsu fd = open(path, O_RDONLY); 1733b4694deSMasami Hiramatsu if (fd >= 0) { 1743b4694deSMasami Hiramatsu *file_name = strdup(path); 1753b4694deSMasami Hiramatsu return fd; 1763b4694deSMasami Hiramatsu } 1773b4694deSMasami Hiramatsu } 1783b4694deSMasami Hiramatsu /* If failed, try to call standard method */ 1793b4694deSMasami Hiramatsu return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, 1803b4694deSMasami Hiramatsu file_name, elfp); 1813b4694deSMasami Hiramatsu } 1823b4694deSMasami Hiramatsu 1833b4694deSMasami Hiramatsu static const Dwfl_Callbacks kernel_callbacks = { 1843b4694deSMasami Hiramatsu .find_debuginfo = dwfl_standard_find_debuginfo, 1853b4694deSMasami Hiramatsu .debuginfo_path = &debuginfo_path, 1863b4694deSMasami Hiramatsu 1873b4694deSMasami Hiramatsu .find_elf = __linux_kernel_find_elf, 1883b4694deSMasami Hiramatsu .section_address = dwfl_linux_kernel_module_section_address, 1893b4694deSMasami Hiramatsu }; 1903b4694deSMasami Hiramatsu 191469b9b88SMasami Hiramatsu /* Get a Dwarf from live kernel image */ 192469b9b88SMasami Hiramatsu static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, 193469b9b88SMasami Hiramatsu Dwarf_Addr *bias) 194469b9b88SMasami Hiramatsu { 195469b9b88SMasami Hiramatsu Dwarf *dbg; 196469b9b88SMasami Hiramatsu 197469b9b88SMasami Hiramatsu if (!dwflp) 198469b9b88SMasami Hiramatsu return NULL; 199469b9b88SMasami Hiramatsu 200469b9b88SMasami Hiramatsu *dwflp = dwfl_begin(&kernel_callbacks); 201469b9b88SMasami Hiramatsu if (!*dwflp) 202469b9b88SMasami Hiramatsu return NULL; 203469b9b88SMasami Hiramatsu 204469b9b88SMasami Hiramatsu /* Load the kernel dwarves: Don't care the result here */ 205469b9b88SMasami Hiramatsu dwfl_linux_kernel_report_kernel(*dwflp); 206469b9b88SMasami Hiramatsu dwfl_linux_kernel_report_modules(*dwflp); 207469b9b88SMasami Hiramatsu 208469b9b88SMasami Hiramatsu dbg = dwfl_addrdwarf(*dwflp, addr, bias); 209469b9b88SMasami Hiramatsu /* Here, check whether we could get a real dwarf */ 210469b9b88SMasami Hiramatsu if (!dbg) { 2113b4694deSMasami Hiramatsu pr_debug("Failed to find kernel dwarf at %lx\n", 2123b4694deSMasami Hiramatsu (unsigned long)addr); 213469b9b88SMasami Hiramatsu dwfl_end(*dwflp); 214469b9b88SMasami Hiramatsu *dwflp = NULL; 215469b9b88SMasami Hiramatsu } 216469b9b88SMasami Hiramatsu return dbg; 217469b9b88SMasami Hiramatsu } 2183b4694deSMasami Hiramatsu #else 2193b4694deSMasami Hiramatsu /* With older elfutils, this just support kernel module... */ 2203b4694deSMasami Hiramatsu static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp, 2213b4694deSMasami Hiramatsu Dwarf_Addr *bias) 2223b4694deSMasami Hiramatsu { 2233b4694deSMasami Hiramatsu int fd; 2243b4694deSMasami Hiramatsu const char *path = kernel_get_module_path("kernel"); 2253b4694deSMasami Hiramatsu 2263b4694deSMasami Hiramatsu if (!path) { 2273b4694deSMasami Hiramatsu pr_err("Failed to find vmlinux path\n"); 2283b4694deSMasami Hiramatsu return NULL; 2293b4694deSMasami Hiramatsu } 2303b4694deSMasami Hiramatsu 2313b4694deSMasami Hiramatsu pr_debug2("Use file %s for debuginfo\n", path); 2323b4694deSMasami Hiramatsu fd = open(path, O_RDONLY); 2333b4694deSMasami Hiramatsu if (fd < 0) 2343b4694deSMasami Hiramatsu return NULL; 2353b4694deSMasami Hiramatsu 2363b4694deSMasami Hiramatsu return dwfl_init_offline_dwarf(fd, dwflp, bias); 2373b4694deSMasami Hiramatsu } 2383b4694deSMasami Hiramatsu #endif 239469b9b88SMasami Hiramatsu 2402a9c8c36SMasami Hiramatsu /* Dwarf wrappers */ 2412a9c8c36SMasami Hiramatsu 2422a9c8c36SMasami Hiramatsu /* Find the realpath of the target file. */ 2432a9c8c36SMasami Hiramatsu static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) 2444ea42b18SMasami Hiramatsu { 245804b3606SMasami Hiramatsu Dwarf_Files *files; 246804b3606SMasami Hiramatsu size_t nfiles, i; 247accd3cc4SArnaldo Carvalho de Melo const char *src = NULL; 2484ea42b18SMasami Hiramatsu int ret; 2494ea42b18SMasami Hiramatsu 2504ea42b18SMasami Hiramatsu if (!fname) 2512a9c8c36SMasami Hiramatsu return NULL; 252631c9defSMasami Hiramatsu 253804b3606SMasami Hiramatsu ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); 2542a9c8c36SMasami Hiramatsu if (ret != 0) 2552a9c8c36SMasami Hiramatsu return NULL; 2562a9c8c36SMasami Hiramatsu 257804b3606SMasami Hiramatsu for (i = 0; i < nfiles; i++) { 258804b3606SMasami Hiramatsu src = dwarf_filesrc(files, i, NULL, NULL); 2592a9c8c36SMasami Hiramatsu if (strtailcmp(src, fname) == 0) 260804b3606SMasami Hiramatsu break; 261804b3606SMasami Hiramatsu } 262c9e38582SMasami Hiramatsu if (i == nfiles) 263c9e38582SMasami Hiramatsu return NULL; 2642a9c8c36SMasami Hiramatsu return src; 265631c9defSMasami Hiramatsu } 266631c9defSMasami Hiramatsu 2676a330a3cSMasami Hiramatsu /* Get DW_AT_comp_dir (should be NULL with older gcc) */ 2686a330a3cSMasami Hiramatsu static const char *cu_get_comp_dir(Dwarf_Die *cu_die) 2696a330a3cSMasami Hiramatsu { 2706a330a3cSMasami Hiramatsu Dwarf_Attribute attr; 2716a330a3cSMasami Hiramatsu if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) 2726a330a3cSMasami Hiramatsu return NULL; 2736a330a3cSMasami Hiramatsu return dwarf_formstring(&attr); 2746a330a3cSMasami Hiramatsu } 2756a330a3cSMasami Hiramatsu 276016f262eSMasami Hiramatsu /* Compare diename and tname */ 277016f262eSMasami Hiramatsu static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 278016f262eSMasami Hiramatsu { 279016f262eSMasami Hiramatsu const char *name; 280016f262eSMasami Hiramatsu name = dwarf_diename(dw_die); 28182175633SMasami Hiramatsu return name ? (strcmp(tname, name) == 0) : false; 282016f262eSMasami Hiramatsu } 283016f262eSMasami Hiramatsu 2845069ed86SMasami Hiramatsu /* Get callsite line number of inline-function instance */ 2855069ed86SMasami Hiramatsu static int die_get_call_lineno(Dwarf_Die *in_die) 2865069ed86SMasami Hiramatsu { 2875069ed86SMasami Hiramatsu Dwarf_Attribute attr; 2885069ed86SMasami Hiramatsu Dwarf_Word ret; 2895069ed86SMasami Hiramatsu 2905069ed86SMasami Hiramatsu if (!dwarf_attr(in_die, DW_AT_call_line, &attr)) 2915069ed86SMasami Hiramatsu return -ENOENT; 2925069ed86SMasami Hiramatsu 2935069ed86SMasami Hiramatsu dwarf_formudata(&attr, &ret); 2945069ed86SMasami Hiramatsu return (int)ret; 2955069ed86SMasami Hiramatsu } 2965069ed86SMasami Hiramatsu 2974046b8bbSMasami Hiramatsu /* Get type die */ 2984046b8bbSMasami Hiramatsu static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 2994046b8bbSMasami Hiramatsu { 3004046b8bbSMasami Hiramatsu Dwarf_Attribute attr; 3014046b8bbSMasami Hiramatsu 3024046b8bbSMasami Hiramatsu if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && 3034046b8bbSMasami Hiramatsu dwarf_formref_die(&attr, die_mem)) 3044046b8bbSMasami Hiramatsu return die_mem; 3054046b8bbSMasami Hiramatsu else 3064046b8bbSMasami Hiramatsu return NULL; 3074046b8bbSMasami Hiramatsu } 3084046b8bbSMasami Hiramatsu 309cf6eb489SMasami Hiramatsu /* Get a type die, but skip qualifiers */ 310cf6eb489SMasami Hiramatsu static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 3117df2f329SMasami Hiramatsu { 3127df2f329SMasami Hiramatsu int tag; 3137df2f329SMasami Hiramatsu 3147df2f329SMasami Hiramatsu do { 3154046b8bbSMasami Hiramatsu vr_die = die_get_type(vr_die, die_mem); 3164046b8bbSMasami Hiramatsu if (!vr_die) 3174046b8bbSMasami Hiramatsu break; 3184046b8bbSMasami Hiramatsu tag = dwarf_tag(vr_die); 3197df2f329SMasami Hiramatsu } while (tag == DW_TAG_const_type || 3207df2f329SMasami Hiramatsu tag == DW_TAG_restrict_type || 3217df2f329SMasami Hiramatsu tag == DW_TAG_volatile_type || 322cf6eb489SMasami Hiramatsu tag == DW_TAG_shared_type); 323cf6eb489SMasami Hiramatsu 324cf6eb489SMasami Hiramatsu return vr_die; 325cf6eb489SMasami Hiramatsu } 326cf6eb489SMasami Hiramatsu 327cf6eb489SMasami Hiramatsu /* Get a type die, but skip qualifiers and typedef */ 328cf6eb489SMasami Hiramatsu static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 329cf6eb489SMasami Hiramatsu { 330cf6eb489SMasami Hiramatsu do { 331cf6eb489SMasami Hiramatsu vr_die = __die_get_real_type(vr_die, die_mem); 332cf6eb489SMasami Hiramatsu } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef); 3337df2f329SMasami Hiramatsu 3344046b8bbSMasami Hiramatsu return vr_die; 3357df2f329SMasami Hiramatsu } 3367df2f329SMasami Hiramatsu 337*124bb83cSMasami Hiramatsu static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, 338*124bb83cSMasami Hiramatsu Dwarf_Word *result) 3394984912eSMasami Hiramatsu { 3404984912eSMasami Hiramatsu Dwarf_Attribute attr; 341*124bb83cSMasami Hiramatsu 342*124bb83cSMasami Hiramatsu if (dwarf_attr(tp_die, attr_name, &attr) == NULL || 343*124bb83cSMasami Hiramatsu dwarf_formudata(&attr, result) != 0) 344*124bb83cSMasami Hiramatsu return -ENOENT; 345*124bb83cSMasami Hiramatsu 346*124bb83cSMasami Hiramatsu return 0; 347*124bb83cSMasami Hiramatsu } 348*124bb83cSMasami Hiramatsu 349*124bb83cSMasami Hiramatsu static bool die_is_signed_type(Dwarf_Die *tp_die) 350*124bb83cSMasami Hiramatsu { 3514984912eSMasami Hiramatsu Dwarf_Word ret; 3524984912eSMasami Hiramatsu 353*124bb83cSMasami Hiramatsu if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret)) 3544984912eSMasami Hiramatsu return false; 3554984912eSMasami Hiramatsu 3564984912eSMasami Hiramatsu return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || 3574984912eSMasami Hiramatsu ret == DW_ATE_signed_fixed); 3584984912eSMasami Hiramatsu } 3594984912eSMasami Hiramatsu 3604984912eSMasami Hiramatsu static int die_get_byte_size(Dwarf_Die *tp_die) 3614984912eSMasami Hiramatsu { 3624984912eSMasami Hiramatsu Dwarf_Word ret; 3634984912eSMasami Hiramatsu 364*124bb83cSMasami Hiramatsu if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret)) 365*124bb83cSMasami Hiramatsu return 0; 366*124bb83cSMasami Hiramatsu 367*124bb83cSMasami Hiramatsu return (int)ret; 368*124bb83cSMasami Hiramatsu } 369*124bb83cSMasami Hiramatsu 370*124bb83cSMasami Hiramatsu static int die_get_bit_size(Dwarf_Die *tp_die) 371*124bb83cSMasami Hiramatsu { 372*124bb83cSMasami Hiramatsu Dwarf_Word ret; 373*124bb83cSMasami Hiramatsu 374*124bb83cSMasami Hiramatsu if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret)) 375*124bb83cSMasami Hiramatsu return 0; 376*124bb83cSMasami Hiramatsu 377*124bb83cSMasami Hiramatsu return (int)ret; 378*124bb83cSMasami Hiramatsu } 379*124bb83cSMasami Hiramatsu 380*124bb83cSMasami Hiramatsu static int die_get_bit_offset(Dwarf_Die *tp_die) 381*124bb83cSMasami Hiramatsu { 382*124bb83cSMasami Hiramatsu Dwarf_Word ret; 383*124bb83cSMasami Hiramatsu 384*124bb83cSMasami Hiramatsu if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret)) 3854984912eSMasami Hiramatsu return 0; 3864984912eSMasami Hiramatsu 3874984912eSMasami Hiramatsu return (int)ret; 3884984912eSMasami Hiramatsu } 3894984912eSMasami Hiramatsu 390de1439d8SMasami Hiramatsu /* Get data_member_location offset */ 391de1439d8SMasami Hiramatsu static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) 392de1439d8SMasami Hiramatsu { 393de1439d8SMasami Hiramatsu Dwarf_Attribute attr; 394de1439d8SMasami Hiramatsu Dwarf_Op *expr; 395de1439d8SMasami Hiramatsu size_t nexpr; 396de1439d8SMasami Hiramatsu int ret; 397de1439d8SMasami Hiramatsu 398de1439d8SMasami Hiramatsu if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) 399de1439d8SMasami Hiramatsu return -ENOENT; 400de1439d8SMasami Hiramatsu 401de1439d8SMasami Hiramatsu if (dwarf_formudata(&attr, offs) != 0) { 402de1439d8SMasami Hiramatsu /* DW_AT_data_member_location should be DW_OP_plus_uconst */ 403de1439d8SMasami Hiramatsu ret = dwarf_getlocation(&attr, &expr, &nexpr); 404de1439d8SMasami Hiramatsu if (ret < 0 || nexpr == 0) 405de1439d8SMasami Hiramatsu return -ENOENT; 406de1439d8SMasami Hiramatsu 407de1439d8SMasami Hiramatsu if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { 408de1439d8SMasami Hiramatsu pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", 409de1439d8SMasami Hiramatsu expr[0].atom, nexpr); 410de1439d8SMasami Hiramatsu return -ENOTSUP; 411de1439d8SMasami Hiramatsu } 412de1439d8SMasami Hiramatsu *offs = (Dwarf_Word)expr[0].number; 413de1439d8SMasami Hiramatsu } 414de1439d8SMasami Hiramatsu return 0; 415de1439d8SMasami Hiramatsu } 416de1439d8SMasami Hiramatsu 417016f262eSMasami Hiramatsu /* Return values for die_find callbacks */ 418016f262eSMasami Hiramatsu enum { 419016f262eSMasami Hiramatsu DIE_FIND_CB_FOUND = 0, /* End of Search */ 420016f262eSMasami Hiramatsu DIE_FIND_CB_CHILD = 1, /* Search only children */ 421016f262eSMasami Hiramatsu DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ 422016f262eSMasami Hiramatsu DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ 423016f262eSMasami Hiramatsu }; 424016f262eSMasami Hiramatsu 425016f262eSMasami Hiramatsu /* Search a child die */ 426016f262eSMasami Hiramatsu static Dwarf_Die *die_find_child(Dwarf_Die *rt_die, 427016f262eSMasami Hiramatsu int (*callback)(Dwarf_Die *, void *), 428016f262eSMasami Hiramatsu void *data, Dwarf_Die *die_mem) 429016f262eSMasami Hiramatsu { 430016f262eSMasami Hiramatsu Dwarf_Die child_die; 431016f262eSMasami Hiramatsu int ret; 432016f262eSMasami Hiramatsu 433016f262eSMasami Hiramatsu ret = dwarf_child(rt_die, die_mem); 434016f262eSMasami Hiramatsu if (ret != 0) 435016f262eSMasami Hiramatsu return NULL; 436016f262eSMasami Hiramatsu 437016f262eSMasami Hiramatsu do { 438016f262eSMasami Hiramatsu ret = callback(die_mem, data); 439016f262eSMasami Hiramatsu if (ret == DIE_FIND_CB_FOUND) 440016f262eSMasami Hiramatsu return die_mem; 441016f262eSMasami Hiramatsu 442016f262eSMasami Hiramatsu if ((ret & DIE_FIND_CB_CHILD) && 443016f262eSMasami Hiramatsu die_find_child(die_mem, callback, data, &child_die)) { 444016f262eSMasami Hiramatsu memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); 445016f262eSMasami Hiramatsu return die_mem; 446016f262eSMasami Hiramatsu } 447016f262eSMasami Hiramatsu } while ((ret & DIE_FIND_CB_SIBLING) && 448016f262eSMasami Hiramatsu dwarf_siblingof(die_mem, die_mem) == 0); 449016f262eSMasami Hiramatsu 450016f262eSMasami Hiramatsu return NULL; 451016f262eSMasami Hiramatsu } 452016f262eSMasami Hiramatsu 453804b3606SMasami Hiramatsu struct __addr_die_search_param { 454804b3606SMasami Hiramatsu Dwarf_Addr addr; 455804b3606SMasami Hiramatsu Dwarf_Die *die_mem; 456804b3606SMasami Hiramatsu }; 457804b3606SMasami Hiramatsu 458804b3606SMasami Hiramatsu static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) 459804b3606SMasami Hiramatsu { 460804b3606SMasami Hiramatsu struct __addr_die_search_param *ad = data; 461804b3606SMasami Hiramatsu 462804b3606SMasami Hiramatsu if (dwarf_tag(fn_die) == DW_TAG_subprogram && 463804b3606SMasami Hiramatsu dwarf_haspc(fn_die, ad->addr)) { 464804b3606SMasami Hiramatsu memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); 465804b3606SMasami Hiramatsu return DWARF_CB_ABORT; 466804b3606SMasami Hiramatsu } 467804b3606SMasami Hiramatsu return DWARF_CB_OK; 468804b3606SMasami Hiramatsu } 469804b3606SMasami Hiramatsu 470804b3606SMasami Hiramatsu /* Search a real subprogram including this line, */ 47195a3e4c4SMasami Hiramatsu static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, 472804b3606SMasami Hiramatsu Dwarf_Die *die_mem) 473804b3606SMasami Hiramatsu { 474804b3606SMasami Hiramatsu struct __addr_die_search_param ad; 475804b3606SMasami Hiramatsu ad.addr = addr; 476804b3606SMasami Hiramatsu ad.die_mem = die_mem; 477804b3606SMasami Hiramatsu /* dwarf_getscopes can't find subprogram. */ 478804b3606SMasami Hiramatsu if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) 479804b3606SMasami Hiramatsu return NULL; 480804b3606SMasami Hiramatsu else 481804b3606SMasami Hiramatsu return die_mem; 482804b3606SMasami Hiramatsu } 483804b3606SMasami Hiramatsu 484016f262eSMasami Hiramatsu /* die_find callback for inline function search */ 485016f262eSMasami Hiramatsu static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) 486016f262eSMasami Hiramatsu { 487016f262eSMasami Hiramatsu Dwarf_Addr *addr = data; 488016f262eSMasami Hiramatsu 489016f262eSMasami Hiramatsu if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && 490016f262eSMasami Hiramatsu dwarf_haspc(die_mem, *addr)) 491016f262eSMasami Hiramatsu return DIE_FIND_CB_FOUND; 492016f262eSMasami Hiramatsu 493016f262eSMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 494016f262eSMasami Hiramatsu } 495016f262eSMasami Hiramatsu 496161a26b0SMasami Hiramatsu /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ 49795a3e4c4SMasami Hiramatsu static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 498161a26b0SMasami Hiramatsu Dwarf_Die *die_mem) 499161a26b0SMasami Hiramatsu { 500016f262eSMasami Hiramatsu return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); 501161a26b0SMasami Hiramatsu } 502161a26b0SMasami Hiramatsu 5034cc9cec6SMasami Hiramatsu /* Walker on lines (Note: line number will not be sorted) */ 5044cc9cec6SMasami Hiramatsu typedef int (* line_walk_handler_t) (const char *fname, int lineno, 5054cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data); 5064cc9cec6SMasami Hiramatsu 5074cc9cec6SMasami Hiramatsu struct __line_walk_param { 5085069ed86SMasami Hiramatsu const char *fname; 5094cc9cec6SMasami Hiramatsu line_walk_handler_t handler; 5104cc9cec6SMasami Hiramatsu void *data; 5114cc9cec6SMasami Hiramatsu int retval; 5124cc9cec6SMasami Hiramatsu }; 5134cc9cec6SMasami Hiramatsu 5145069ed86SMasami Hiramatsu static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) 5155069ed86SMasami Hiramatsu { 5165069ed86SMasami Hiramatsu struct __line_walk_param *lw = data; 5175069ed86SMasami Hiramatsu Dwarf_Addr addr; 5185069ed86SMasami Hiramatsu int lineno; 5195069ed86SMasami Hiramatsu 5205069ed86SMasami Hiramatsu if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { 5215069ed86SMasami Hiramatsu lineno = die_get_call_lineno(in_die); 5225069ed86SMasami Hiramatsu if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { 5235069ed86SMasami Hiramatsu lw->retval = lw->handler(lw->fname, lineno, addr, 5245069ed86SMasami Hiramatsu lw->data); 5255069ed86SMasami Hiramatsu if (lw->retval != 0) 5265069ed86SMasami Hiramatsu return DIE_FIND_CB_FOUND; 5275069ed86SMasami Hiramatsu } 5285069ed86SMasami Hiramatsu } 5295069ed86SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 5305069ed86SMasami Hiramatsu } 5315069ed86SMasami Hiramatsu 5325069ed86SMasami Hiramatsu /* Walk on lines of blocks included in given DIE */ 5334cc9cec6SMasami Hiramatsu static int __die_walk_funclines(Dwarf_Die *sp_die, 5344cc9cec6SMasami Hiramatsu line_walk_handler_t handler, void *data) 5354cc9cec6SMasami Hiramatsu { 5365069ed86SMasami Hiramatsu struct __line_walk_param lw = { 5375069ed86SMasami Hiramatsu .handler = handler, 5385069ed86SMasami Hiramatsu .data = data, 5395069ed86SMasami Hiramatsu .retval = 0, 5405069ed86SMasami Hiramatsu }; 5415069ed86SMasami Hiramatsu Dwarf_Die die_mem; 5424cc9cec6SMasami Hiramatsu Dwarf_Addr addr; 5435069ed86SMasami Hiramatsu int lineno; 5444cc9cec6SMasami Hiramatsu 5454cc9cec6SMasami Hiramatsu /* Handle function declaration line */ 5465069ed86SMasami Hiramatsu lw.fname = dwarf_decl_file(sp_die); 5475069ed86SMasami Hiramatsu if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && 5484cc9cec6SMasami Hiramatsu dwarf_entrypc(sp_die, &addr) == 0) { 5495069ed86SMasami Hiramatsu lw.retval = handler(lw.fname, lineno, addr, data); 5505069ed86SMasami Hiramatsu if (lw.retval != 0) 5515069ed86SMasami Hiramatsu goto done; 5524cc9cec6SMasami Hiramatsu } 5535069ed86SMasami Hiramatsu die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem); 5545069ed86SMasami Hiramatsu done: 5555069ed86SMasami Hiramatsu return lw.retval; 5564cc9cec6SMasami Hiramatsu } 5574cc9cec6SMasami Hiramatsu 5584cc9cec6SMasami Hiramatsu static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) 5594cc9cec6SMasami Hiramatsu { 5604cc9cec6SMasami Hiramatsu struct __line_walk_param *lw = data; 5614cc9cec6SMasami Hiramatsu 5624cc9cec6SMasami Hiramatsu lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data); 5634cc9cec6SMasami Hiramatsu if (lw->retval != 0) 5644cc9cec6SMasami Hiramatsu return DWARF_CB_ABORT; 5654cc9cec6SMasami Hiramatsu 5664cc9cec6SMasami Hiramatsu return DWARF_CB_OK; 5674cc9cec6SMasami Hiramatsu } 5684cc9cec6SMasami Hiramatsu 5694cc9cec6SMasami Hiramatsu /* 5704cc9cec6SMasami Hiramatsu * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on 5714cc9cec6SMasami Hiramatsu * the lines inside the subprogram, otherwise PDIE must be a CU DIE. 5724cc9cec6SMasami Hiramatsu */ 5734cc9cec6SMasami Hiramatsu static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler, 5744cc9cec6SMasami Hiramatsu void *data) 5754cc9cec6SMasami Hiramatsu { 5764cc9cec6SMasami Hiramatsu Dwarf_Lines *lines; 5774cc9cec6SMasami Hiramatsu Dwarf_Line *line; 5784cc9cec6SMasami Hiramatsu Dwarf_Addr addr; 5794cc9cec6SMasami Hiramatsu const char *fname; 5804cc9cec6SMasami Hiramatsu int lineno, ret = 0; 5814cc9cec6SMasami Hiramatsu Dwarf_Die die_mem, *cu_die; 5824cc9cec6SMasami Hiramatsu size_t nlines, i; 5834cc9cec6SMasami Hiramatsu 5844cc9cec6SMasami Hiramatsu /* Get the CU die */ 5854cc9cec6SMasami Hiramatsu if (dwarf_tag(pdie) == DW_TAG_subprogram) 5864cc9cec6SMasami Hiramatsu cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL); 5874cc9cec6SMasami Hiramatsu else 5884cc9cec6SMasami Hiramatsu cu_die = pdie; 5894cc9cec6SMasami Hiramatsu if (!cu_die) { 5904cc9cec6SMasami Hiramatsu pr_debug2("Failed to get CU from subprogram\n"); 5914cc9cec6SMasami Hiramatsu return -EINVAL; 5924cc9cec6SMasami Hiramatsu } 5934cc9cec6SMasami Hiramatsu 5944cc9cec6SMasami Hiramatsu /* Get lines list in the CU */ 5954cc9cec6SMasami Hiramatsu if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) { 5964cc9cec6SMasami Hiramatsu pr_debug2("Failed to get source lines on this CU.\n"); 5974cc9cec6SMasami Hiramatsu return -ENOENT; 5984cc9cec6SMasami Hiramatsu } 5994cc9cec6SMasami Hiramatsu pr_debug2("Get %zd lines from this CU\n", nlines); 6004cc9cec6SMasami Hiramatsu 6014cc9cec6SMasami Hiramatsu /* Walk on the lines on lines list */ 6024cc9cec6SMasami Hiramatsu for (i = 0; i < nlines; i++) { 6034cc9cec6SMasami Hiramatsu line = dwarf_onesrcline(lines, i); 6044cc9cec6SMasami Hiramatsu if (line == NULL || 6054cc9cec6SMasami Hiramatsu dwarf_lineno(line, &lineno) != 0 || 6064cc9cec6SMasami Hiramatsu dwarf_lineaddr(line, &addr) != 0) { 6074cc9cec6SMasami Hiramatsu pr_debug2("Failed to get line info. " 6084cc9cec6SMasami Hiramatsu "Possible error in debuginfo.\n"); 6094cc9cec6SMasami Hiramatsu continue; 6104cc9cec6SMasami Hiramatsu } 6114cc9cec6SMasami Hiramatsu /* Filter lines based on address */ 6124cc9cec6SMasami Hiramatsu if (pdie != cu_die) 6134cc9cec6SMasami Hiramatsu /* 6144cc9cec6SMasami Hiramatsu * Address filtering 6154cc9cec6SMasami Hiramatsu * The line is included in given function, and 6164cc9cec6SMasami Hiramatsu * no inline block includes it. 6174cc9cec6SMasami Hiramatsu */ 6184cc9cec6SMasami Hiramatsu if (!dwarf_haspc(pdie, addr) || 6194cc9cec6SMasami Hiramatsu die_find_inlinefunc(pdie, addr, &die_mem)) 6204cc9cec6SMasami Hiramatsu continue; 6214cc9cec6SMasami Hiramatsu /* Get source line */ 6224cc9cec6SMasami Hiramatsu fname = dwarf_linesrc(line, NULL, NULL); 6234cc9cec6SMasami Hiramatsu 6244cc9cec6SMasami Hiramatsu ret = handler(fname, lineno, addr, data); 6254cc9cec6SMasami Hiramatsu if (ret != 0) 6264cc9cec6SMasami Hiramatsu return ret; 6274cc9cec6SMasami Hiramatsu } 6284cc9cec6SMasami Hiramatsu 6294cc9cec6SMasami Hiramatsu /* 6304cc9cec6SMasami Hiramatsu * Dwarf lines doesn't include function declarations and inlined 6314cc9cec6SMasami Hiramatsu * subroutines. We have to check functions list or given function. 6324cc9cec6SMasami Hiramatsu */ 6334cc9cec6SMasami Hiramatsu if (pdie != cu_die) 6344cc9cec6SMasami Hiramatsu ret = __die_walk_funclines(pdie, handler, data); 6354cc9cec6SMasami Hiramatsu else { 6364cc9cec6SMasami Hiramatsu struct __line_walk_param param = { 6374cc9cec6SMasami Hiramatsu .handler = handler, 6384cc9cec6SMasami Hiramatsu .data = data, 6394cc9cec6SMasami Hiramatsu .retval = 0, 6404cc9cec6SMasami Hiramatsu }; 6414cc9cec6SMasami Hiramatsu dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0); 6424cc9cec6SMasami Hiramatsu ret = param.retval; 6434cc9cec6SMasami Hiramatsu } 6444cc9cec6SMasami Hiramatsu 6454cc9cec6SMasami Hiramatsu return ret; 6464cc9cec6SMasami Hiramatsu } 6474cc9cec6SMasami Hiramatsu 648378eeaadSMasami Hiramatsu struct __find_variable_param { 649378eeaadSMasami Hiramatsu const char *name; 650378eeaadSMasami Hiramatsu Dwarf_Addr addr; 651378eeaadSMasami Hiramatsu }; 652378eeaadSMasami Hiramatsu 653016f262eSMasami Hiramatsu static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 6544ea42b18SMasami Hiramatsu { 655378eeaadSMasami Hiramatsu struct __find_variable_param *fvp = data; 656e92b85e1SMasami Hiramatsu int tag; 6574ea42b18SMasami Hiramatsu 658e92b85e1SMasami Hiramatsu tag = dwarf_tag(die_mem); 659e92b85e1SMasami Hiramatsu if ((tag == DW_TAG_formal_parameter || 660e92b85e1SMasami Hiramatsu tag == DW_TAG_variable) && 661378eeaadSMasami Hiramatsu die_compare_name(die_mem, fvp->name)) 662016f262eSMasami Hiramatsu return DIE_FIND_CB_FOUND; 6634ea42b18SMasami Hiramatsu 664378eeaadSMasami Hiramatsu if (dwarf_haspc(die_mem, fvp->addr)) 665016f262eSMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 666378eeaadSMasami Hiramatsu else 667378eeaadSMasami Hiramatsu return DIE_FIND_CB_SIBLING; 6684ea42b18SMasami Hiramatsu } 6694ea42b18SMasami Hiramatsu 670378eeaadSMasami Hiramatsu /* Find a variable called 'name' at given address */ 671378eeaadSMasami Hiramatsu static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, 672378eeaadSMasami Hiramatsu Dwarf_Addr addr, Dwarf_Die *die_mem) 673016f262eSMasami Hiramatsu { 674378eeaadSMasami Hiramatsu struct __find_variable_param fvp = { .name = name, .addr = addr}; 675378eeaadSMasami Hiramatsu 676378eeaadSMasami Hiramatsu return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp, 677016f262eSMasami Hiramatsu die_mem); 678e92b85e1SMasami Hiramatsu } 679b0ef0732SMasami Hiramatsu 6807df2f329SMasami Hiramatsu static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) 6817df2f329SMasami Hiramatsu { 6827df2f329SMasami Hiramatsu const char *name = data; 6837df2f329SMasami Hiramatsu 6847df2f329SMasami Hiramatsu if ((dwarf_tag(die_mem) == DW_TAG_member) && 68582175633SMasami Hiramatsu die_compare_name(die_mem, name)) 6867df2f329SMasami Hiramatsu return DIE_FIND_CB_FOUND; 6877df2f329SMasami Hiramatsu 6887df2f329SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 6897df2f329SMasami Hiramatsu } 6907df2f329SMasami Hiramatsu 6917df2f329SMasami Hiramatsu /* Find a member called 'name' */ 6927df2f329SMasami Hiramatsu static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, 6937df2f329SMasami Hiramatsu Dwarf_Die *die_mem) 6947df2f329SMasami Hiramatsu { 6957df2f329SMasami Hiramatsu return die_find_child(st_die, __die_find_member_cb, (void *)name, 6967df2f329SMasami Hiramatsu die_mem); 6977df2f329SMasami Hiramatsu } 6987df2f329SMasami Hiramatsu 699cf6eb489SMasami Hiramatsu /* Get the name of given variable DIE */ 700cf6eb489SMasami Hiramatsu static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) 701cf6eb489SMasami Hiramatsu { 702cf6eb489SMasami Hiramatsu Dwarf_Die type; 703cf6eb489SMasami Hiramatsu int tag, ret, ret2; 704cf6eb489SMasami Hiramatsu const char *tmp = ""; 705cf6eb489SMasami Hiramatsu 706cf6eb489SMasami Hiramatsu if (__die_get_real_type(vr_die, &type) == NULL) 707cf6eb489SMasami Hiramatsu return -ENOENT; 708cf6eb489SMasami Hiramatsu 709cf6eb489SMasami Hiramatsu tag = dwarf_tag(&type); 710cf6eb489SMasami Hiramatsu if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) 711cf6eb489SMasami Hiramatsu tmp = "*"; 712cf6eb489SMasami Hiramatsu else if (tag == DW_TAG_subroutine_type) { 713cf6eb489SMasami Hiramatsu /* Function pointer */ 714cf6eb489SMasami Hiramatsu ret = snprintf(buf, len, "(function_type)"); 715cf6eb489SMasami Hiramatsu return (ret >= len) ? -E2BIG : ret; 716cf6eb489SMasami Hiramatsu } else { 717cf6eb489SMasami Hiramatsu if (!dwarf_diename(&type)) 718cf6eb489SMasami Hiramatsu return -ENOENT; 719cf6eb489SMasami Hiramatsu if (tag == DW_TAG_union_type) 720cf6eb489SMasami Hiramatsu tmp = "union "; 721cf6eb489SMasami Hiramatsu else if (tag == DW_TAG_structure_type) 722cf6eb489SMasami Hiramatsu tmp = "struct "; 723cf6eb489SMasami Hiramatsu /* Write a base name */ 724cf6eb489SMasami Hiramatsu ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); 725cf6eb489SMasami Hiramatsu return (ret >= len) ? -E2BIG : ret; 726cf6eb489SMasami Hiramatsu } 727cf6eb489SMasami Hiramatsu ret = die_get_typename(&type, buf, len); 728cf6eb489SMasami Hiramatsu if (ret > 0) { 729cf6eb489SMasami Hiramatsu ret2 = snprintf(buf + ret, len - ret, "%s", tmp); 730cf6eb489SMasami Hiramatsu ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; 731cf6eb489SMasami Hiramatsu } 732cf6eb489SMasami Hiramatsu return ret; 733cf6eb489SMasami Hiramatsu } 734cf6eb489SMasami Hiramatsu 735cf6eb489SMasami Hiramatsu /* Get the name and type of given variable DIE, stored as "type\tname" */ 736cf6eb489SMasami Hiramatsu static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len) 737cf6eb489SMasami Hiramatsu { 738cf6eb489SMasami Hiramatsu int ret, ret2; 739cf6eb489SMasami Hiramatsu 740cf6eb489SMasami Hiramatsu ret = die_get_typename(vr_die, buf, len); 741cf6eb489SMasami Hiramatsu if (ret < 0) { 742cf6eb489SMasami Hiramatsu pr_debug("Failed to get type, make it unknown.\n"); 743cf6eb489SMasami Hiramatsu ret = snprintf(buf, len, "(unknown_type)"); 744cf6eb489SMasami Hiramatsu } 745cf6eb489SMasami Hiramatsu if (ret > 0) { 746cf6eb489SMasami Hiramatsu ret2 = snprintf(buf + ret, len - ret, "\t%s", 747cf6eb489SMasami Hiramatsu dwarf_diename(vr_die)); 748cf6eb489SMasami Hiramatsu ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; 749cf6eb489SMasami Hiramatsu } 750cf6eb489SMasami Hiramatsu return ret; 751cf6eb489SMasami Hiramatsu } 752cf6eb489SMasami Hiramatsu 7534ea42b18SMasami Hiramatsu /* 7544ea42b18SMasami Hiramatsu * Probe finder related functions 7554ea42b18SMasami Hiramatsu */ 7564ea42b18SMasami Hiramatsu 7570e60836bSSrikar Dronamraju static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 7584ea42b18SMasami Hiramatsu { 7590e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref; 7600e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 761b7dcb857SMasami Hiramatsu if (ref != NULL) 762b7dcb857SMasami Hiramatsu ref->offset = offs; 763b7dcb857SMasami Hiramatsu return ref; 764b7dcb857SMasami Hiramatsu } 765b7dcb857SMasami Hiramatsu 766cf6eb489SMasami Hiramatsu /* 767cf6eb489SMasami Hiramatsu * Convert a location into trace_arg. 768cf6eb489SMasami Hiramatsu * If tvar == NULL, this just checks variable can be converted. 769cf6eb489SMasami Hiramatsu */ 770cf6eb489SMasami Hiramatsu static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 771cf6eb489SMasami Hiramatsu Dwarf_Op *fb_ops, 772cf6eb489SMasami Hiramatsu struct probe_trace_arg *tvar) 773b7dcb857SMasami Hiramatsu { 774b7dcb857SMasami Hiramatsu Dwarf_Attribute attr; 775b7dcb857SMasami Hiramatsu Dwarf_Op *op; 776b7dcb857SMasami Hiramatsu size_t nops; 777804b3606SMasami Hiramatsu unsigned int regn; 778804b3606SMasami Hiramatsu Dwarf_Word offs = 0; 7794235b045SMasami Hiramatsu bool ref = false; 7804ea42b18SMasami Hiramatsu const char *regs; 781b7dcb857SMasami Hiramatsu int ret; 782b7dcb857SMasami Hiramatsu 783632941c4SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 784632941c4SMasami Hiramatsu goto static_var; 785632941c4SMasami Hiramatsu 786b7dcb857SMasami Hiramatsu /* TODO: handle more than 1 exprs */ 787b7dcb857SMasami Hiramatsu if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 788cf6eb489SMasami Hiramatsu dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || 789b7dcb857SMasami Hiramatsu nops == 0) { 790b7dcb857SMasami Hiramatsu /* TODO: Support const_value */ 791b7dcb857SMasami Hiramatsu return -ENOENT; 792b7dcb857SMasami Hiramatsu } 793b7dcb857SMasami Hiramatsu 794b7dcb857SMasami Hiramatsu if (op->atom == DW_OP_addr) { 795632941c4SMasami Hiramatsu static_var: 796cf6eb489SMasami Hiramatsu if (!tvar) 797cf6eb489SMasami Hiramatsu return 0; 798b7dcb857SMasami Hiramatsu /* Static variables on memory (not stack), make @varname */ 799b7dcb857SMasami Hiramatsu ret = strlen(dwarf_diename(vr_die)); 800b7dcb857SMasami Hiramatsu tvar->value = zalloc(ret + 2); 801b7dcb857SMasami Hiramatsu if (tvar->value == NULL) 802b7dcb857SMasami Hiramatsu return -ENOMEM; 803b7dcb857SMasami Hiramatsu snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 804b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 805b7dcb857SMasami Hiramatsu if (tvar->ref == NULL) 806b7dcb857SMasami Hiramatsu return -ENOMEM; 807b7dcb857SMasami Hiramatsu return 0; 808b7dcb857SMasami Hiramatsu } 8094ea42b18SMasami Hiramatsu 8104ea42b18SMasami Hiramatsu /* If this is based on frame buffer, set the offset */ 811804b3606SMasami Hiramatsu if (op->atom == DW_OP_fbreg) { 812cf6eb489SMasami Hiramatsu if (fb_ops == NULL) 813b55a87adSMasami Hiramatsu return -ENOTSUP; 8144235b045SMasami Hiramatsu ref = true; 815804b3606SMasami Hiramatsu offs = op->number; 816cf6eb489SMasami Hiramatsu op = &fb_ops[0]; 817804b3606SMasami Hiramatsu } 8184ea42b18SMasami Hiramatsu 819804b3606SMasami Hiramatsu if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 820804b3606SMasami Hiramatsu regn = op->atom - DW_OP_breg0; 821804b3606SMasami Hiramatsu offs += op->number; 8224235b045SMasami Hiramatsu ref = true; 823804b3606SMasami Hiramatsu } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 824804b3606SMasami Hiramatsu regn = op->atom - DW_OP_reg0; 825804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_bregx) { 826804b3606SMasami Hiramatsu regn = op->number; 827804b3606SMasami Hiramatsu offs += op->number2; 8284235b045SMasami Hiramatsu ref = true; 829804b3606SMasami Hiramatsu } else if (op->atom == DW_OP_regx) { 830804b3606SMasami Hiramatsu regn = op->number; 831b55a87adSMasami Hiramatsu } else { 832cf6eb489SMasami Hiramatsu pr_debug("DW_OP %x is not supported.\n", op->atom); 833b55a87adSMasami Hiramatsu return -ENOTSUP; 834b55a87adSMasami Hiramatsu } 8354ea42b18SMasami Hiramatsu 836cf6eb489SMasami Hiramatsu if (!tvar) 837cf6eb489SMasami Hiramatsu return 0; 838cf6eb489SMasami Hiramatsu 8394ea42b18SMasami Hiramatsu regs = get_arch_regstr(regn); 840b55a87adSMasami Hiramatsu if (!regs) { 841cf6eb489SMasami Hiramatsu /* This should be a bug in DWARF or this tool */ 8420e43e5d2SMasami Hiramatsu pr_warning("Mapping for the register number %u " 8430e43e5d2SMasami Hiramatsu "missing on this architecture.\n", regn); 844b55a87adSMasami Hiramatsu return -ERANGE; 845b55a87adSMasami Hiramatsu } 8464ea42b18SMasami Hiramatsu 84702b95dadSMasami Hiramatsu tvar->value = strdup(regs); 84802b95dadSMasami Hiramatsu if (tvar->value == NULL) 84902b95dadSMasami Hiramatsu return -ENOMEM; 85002b95dadSMasami Hiramatsu 8514235b045SMasami Hiramatsu if (ref) { 852b7dcb857SMasami Hiramatsu tvar->ref = alloc_trace_arg_ref((long)offs); 853e334016fSMasami Hiramatsu if (tvar->ref == NULL) 854e334016fSMasami Hiramatsu return -ENOMEM; 8554235b045SMasami Hiramatsu } 856b55a87adSMasami Hiramatsu return 0; 8574ea42b18SMasami Hiramatsu } 8584ea42b18SMasami Hiramatsu 859*124bb83cSMasami Hiramatsu #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 860*124bb83cSMasami Hiramatsu 861b55a87adSMasami Hiramatsu static int convert_variable_type(Dwarf_Die *vr_die, 8620e60836bSSrikar Dronamraju struct probe_trace_arg *tvar, 86373317b95SMasami Hiramatsu const char *cast) 8644984912eSMasami Hiramatsu { 8650e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 8664984912eSMasami Hiramatsu Dwarf_Die type; 8674984912eSMasami Hiramatsu char buf[16]; 8684984912eSMasami Hiramatsu int ret; 8694984912eSMasami Hiramatsu 87073317b95SMasami Hiramatsu /* TODO: check all types */ 87173317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") != 0) { 87273317b95SMasami Hiramatsu /* Non string type is OK */ 87373317b95SMasami Hiramatsu tvar->type = strdup(cast); 87473317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 87573317b95SMasami Hiramatsu } 87673317b95SMasami Hiramatsu 877*124bb83cSMasami Hiramatsu if (die_get_bit_size(vr_die) != 0) { 878*124bb83cSMasami Hiramatsu /* This is a bitfield */ 879*124bb83cSMasami Hiramatsu ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die), 880*124bb83cSMasami Hiramatsu die_get_bit_offset(vr_die), 881*124bb83cSMasami Hiramatsu BYTES_TO_BITS(die_get_byte_size(vr_die))); 882*124bb83cSMasami Hiramatsu goto formatted; 883*124bb83cSMasami Hiramatsu } 884*124bb83cSMasami Hiramatsu 885b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 886b55a87adSMasami Hiramatsu pr_warning("Failed to get a type information of %s.\n", 8874984912eSMasami Hiramatsu dwarf_diename(vr_die)); 888b55a87adSMasami Hiramatsu return -ENOENT; 889b55a87adSMasami Hiramatsu } 8904984912eSMasami Hiramatsu 891b2a3c12bSMasami Hiramatsu pr_debug("%s type is %s.\n", 892b2a3c12bSMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 893b2a3c12bSMasami Hiramatsu 89473317b95SMasami Hiramatsu if (cast && strcmp(cast, "string") == 0) { /* String type */ 89573317b95SMasami Hiramatsu ret = dwarf_tag(&type); 89673317b95SMasami Hiramatsu if (ret != DW_TAG_pointer_type && 89773317b95SMasami Hiramatsu ret != DW_TAG_array_type) { 89873317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 8990e43e5d2SMasami Hiramatsu "%s(%s) is not a pointer nor array.\n", 90073317b95SMasami Hiramatsu dwarf_diename(vr_die), dwarf_diename(&type)); 90173317b95SMasami Hiramatsu return -EINVAL; 90273317b95SMasami Hiramatsu } 90373317b95SMasami Hiramatsu if (ret == DW_TAG_pointer_type) { 90473317b95SMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 9050e43e5d2SMasami Hiramatsu pr_warning("Failed to get a type" 9060e43e5d2SMasami Hiramatsu " information.\n"); 90773317b95SMasami Hiramatsu return -ENOENT; 90873317b95SMasami Hiramatsu } 90973317b95SMasami Hiramatsu while (*ref_ptr) 91073317b95SMasami Hiramatsu ref_ptr = &(*ref_ptr)->next; 91173317b95SMasami Hiramatsu /* Add new reference with offset +0 */ 9120e60836bSSrikar Dronamraju *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 91373317b95SMasami Hiramatsu if (*ref_ptr == NULL) { 91473317b95SMasami Hiramatsu pr_warning("Out of memory error\n"); 91573317b95SMasami Hiramatsu return -ENOMEM; 91673317b95SMasami Hiramatsu } 91773317b95SMasami Hiramatsu } 91882175633SMasami Hiramatsu if (!die_compare_name(&type, "char") && 91982175633SMasami Hiramatsu !die_compare_name(&type, "unsigned char")) { 92073317b95SMasami Hiramatsu pr_warning("Failed to cast into string: " 9210e43e5d2SMasami Hiramatsu "%s is not (unsigned) char *.\n", 92273317b95SMasami Hiramatsu dwarf_diename(vr_die)); 92373317b95SMasami Hiramatsu return -EINVAL; 92473317b95SMasami Hiramatsu } 92573317b95SMasami Hiramatsu tvar->type = strdup(cast); 92673317b95SMasami Hiramatsu return (tvar->type == NULL) ? -ENOMEM : 0; 92773317b95SMasami Hiramatsu } 92873317b95SMasami Hiramatsu 929*124bb83cSMasami Hiramatsu ret = BYTES_TO_BITS(die_get_byte_size(&type)); 930*124bb83cSMasami Hiramatsu if (!ret) 931*124bb83cSMasami Hiramatsu /* No size ... try to use default type */ 932*124bb83cSMasami Hiramatsu return 0; 933*124bb83cSMasami Hiramatsu 9344984912eSMasami Hiramatsu /* Check the bitwidth */ 9354984912eSMasami Hiramatsu if (ret > MAX_BASIC_TYPE_BITS) { 936*124bb83cSMasami Hiramatsu pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 9374984912eSMasami Hiramatsu dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 9384984912eSMasami Hiramatsu ret = MAX_BASIC_TYPE_BITS; 9394984912eSMasami Hiramatsu } 9404984912eSMasami Hiramatsu ret = snprintf(buf, 16, "%c%d", 9414984912eSMasami Hiramatsu die_is_signed_type(&type) ? 's' : 'u', ret); 942*124bb83cSMasami Hiramatsu 943*124bb83cSMasami Hiramatsu formatted: 944b55a87adSMasami Hiramatsu if (ret < 0 || ret >= 16) { 945b55a87adSMasami Hiramatsu if (ret >= 16) 946b55a87adSMasami Hiramatsu ret = -E2BIG; 947b55a87adSMasami Hiramatsu pr_warning("Failed to convert variable type: %s\n", 948b55a87adSMasami Hiramatsu strerror(-ret)); 949b55a87adSMasami Hiramatsu return ret; 950b55a87adSMasami Hiramatsu } 95173317b95SMasami Hiramatsu tvar->type = strdup(buf); 95273317b95SMasami Hiramatsu if (tvar->type == NULL) 95302b95dadSMasami Hiramatsu return -ENOMEM; 954b55a87adSMasami Hiramatsu return 0; 9554984912eSMasami Hiramatsu } 9564984912eSMasami Hiramatsu 957b55a87adSMasami Hiramatsu static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 9587df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, 9590e60836bSSrikar Dronamraju struct probe_trace_arg_ref **ref_ptr, 9604984912eSMasami Hiramatsu Dwarf_Die *die_mem) 9617df2f329SMasami Hiramatsu { 9620e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = *ref_ptr; 9637df2f329SMasami Hiramatsu Dwarf_Die type; 9647df2f329SMasami Hiramatsu Dwarf_Word offs; 965b2a3c12bSMasami Hiramatsu int ret, tag; 9667df2f329SMasami Hiramatsu 9677df2f329SMasami Hiramatsu pr_debug("converting %s in %s\n", field->name, varname); 968b55a87adSMasami Hiramatsu if (die_get_real_type(vr_die, &type) == NULL) { 969b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 970b55a87adSMasami Hiramatsu return -ENOENT; 971b55a87adSMasami Hiramatsu } 972b2a3c12bSMasami Hiramatsu pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); 973b2a3c12bSMasami Hiramatsu tag = dwarf_tag(&type); 9747df2f329SMasami Hiramatsu 975b2a3c12bSMasami Hiramatsu if (field->name[0] == '[' && 976b2a3c12bSMasami Hiramatsu (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 977b2a3c12bSMasami Hiramatsu if (field->next) 978b2a3c12bSMasami Hiramatsu /* Save original type for next field */ 979b2a3c12bSMasami Hiramatsu memcpy(die_mem, &type, sizeof(*die_mem)); 980b2a3c12bSMasami Hiramatsu /* Get the type of this array */ 981b2a3c12bSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 982b2a3c12bSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 983b2a3c12bSMasami Hiramatsu return -ENOENT; 984b2a3c12bSMasami Hiramatsu } 985b2a3c12bSMasami Hiramatsu pr_debug2("Array real type: (%x)\n", 986b2a3c12bSMasami Hiramatsu (unsigned)dwarf_dieoffset(&type)); 987b2a3c12bSMasami Hiramatsu if (tag == DW_TAG_pointer_type) { 9880e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 989b2a3c12bSMasami Hiramatsu if (ref == NULL) 990b2a3c12bSMasami Hiramatsu return -ENOMEM; 991b2a3c12bSMasami Hiramatsu if (*ref_ptr) 992b2a3c12bSMasami Hiramatsu (*ref_ptr)->next = ref; 993b2a3c12bSMasami Hiramatsu else 994b2a3c12bSMasami Hiramatsu *ref_ptr = ref; 995b2a3c12bSMasami Hiramatsu } 996b2a3c12bSMasami Hiramatsu ref->offset += die_get_byte_size(&type) * field->index; 997b2a3c12bSMasami Hiramatsu if (!field->next) 998b2a3c12bSMasami Hiramatsu /* Save vr_die for converting types */ 999b2a3c12bSMasami Hiramatsu memcpy(die_mem, vr_die, sizeof(*die_mem)); 1000b2a3c12bSMasami Hiramatsu goto next; 1001b2a3c12bSMasami Hiramatsu } else if (tag == DW_TAG_pointer_type) { 10027df2f329SMasami Hiramatsu /* Check the pointer and dereference */ 1003b55a87adSMasami Hiramatsu if (!field->ref) { 1004b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '->'\n", 10057df2f329SMasami Hiramatsu field->name); 1006b55a87adSMasami Hiramatsu return -EINVAL; 1007b55a87adSMasami Hiramatsu } 10087df2f329SMasami Hiramatsu /* Get the type pointed by this pointer */ 1009b55a87adSMasami Hiramatsu if (die_get_real_type(&type, &type) == NULL) { 1010b55a87adSMasami Hiramatsu pr_warning("Failed to get the type of %s.\n", varname); 1011b55a87adSMasami Hiramatsu return -ENOENT; 1012b55a87adSMasami Hiramatsu } 101312e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 1014b55a87adSMasami Hiramatsu if (dwarf_tag(&type) != DW_TAG_structure_type) { 1015b55a87adSMasami Hiramatsu pr_warning("%s is not a data structure.\n", varname); 1016b55a87adSMasami Hiramatsu return -EINVAL; 1017b55a87adSMasami Hiramatsu } 101812e5a7aeSMasami Hiramatsu 10190e60836bSSrikar Dronamraju ref = zalloc(sizeof(struct probe_trace_arg_ref)); 1020e334016fSMasami Hiramatsu if (ref == NULL) 1021e334016fSMasami Hiramatsu return -ENOMEM; 10227df2f329SMasami Hiramatsu if (*ref_ptr) 10237df2f329SMasami Hiramatsu (*ref_ptr)->next = ref; 10247df2f329SMasami Hiramatsu else 10257df2f329SMasami Hiramatsu *ref_ptr = ref; 10267df2f329SMasami Hiramatsu } else { 102712e5a7aeSMasami Hiramatsu /* Verify it is a data structure */ 1028b2a3c12bSMasami Hiramatsu if (tag != DW_TAG_structure_type) { 1029b55a87adSMasami Hiramatsu pr_warning("%s is not a data structure.\n", varname); 1030b55a87adSMasami Hiramatsu return -EINVAL; 1031b55a87adSMasami Hiramatsu } 1032b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') { 10330e43e5d2SMasami Hiramatsu pr_err("Semantic error: %s is not a pointor" 10340e43e5d2SMasami Hiramatsu " nor array.\n", varname); 1035b2a3c12bSMasami Hiramatsu return -EINVAL; 1036b2a3c12bSMasami Hiramatsu } 1037b55a87adSMasami Hiramatsu if (field->ref) { 1038b55a87adSMasami Hiramatsu pr_err("Semantic error: %s must be referred by '.'\n", 10397df2f329SMasami Hiramatsu field->name); 1040b55a87adSMasami Hiramatsu return -EINVAL; 1041b55a87adSMasami Hiramatsu } 1042b55a87adSMasami Hiramatsu if (!ref) { 1043b55a87adSMasami Hiramatsu pr_warning("Structure on a register is not " 1044b55a87adSMasami Hiramatsu "supported yet.\n"); 1045b55a87adSMasami Hiramatsu return -ENOTSUP; 1046b55a87adSMasami Hiramatsu } 10477df2f329SMasami Hiramatsu } 10487df2f329SMasami Hiramatsu 1049b55a87adSMasami Hiramatsu if (die_find_member(&type, field->name, die_mem) == NULL) { 1050b55a87adSMasami Hiramatsu pr_warning("%s(tyep:%s) has no member %s.\n", varname, 10517df2f329SMasami Hiramatsu dwarf_diename(&type), field->name); 1052b55a87adSMasami Hiramatsu return -EINVAL; 1053b55a87adSMasami Hiramatsu } 10547df2f329SMasami Hiramatsu 10557df2f329SMasami Hiramatsu /* Get the offset of the field */ 1056de1439d8SMasami Hiramatsu ret = die_get_data_member_location(die_mem, &offs); 1057de1439d8SMasami Hiramatsu if (ret < 0) { 1058b55a87adSMasami Hiramatsu pr_warning("Failed to get the offset of %s.\n", field->name); 1059de1439d8SMasami Hiramatsu return ret; 1060b55a87adSMasami Hiramatsu } 10617df2f329SMasami Hiramatsu ref->offset += (long)offs; 10627df2f329SMasami Hiramatsu 1063b2a3c12bSMasami Hiramatsu next: 10647df2f329SMasami Hiramatsu /* Converting next field */ 10657df2f329SMasami Hiramatsu if (field->next) 1066b55a87adSMasami Hiramatsu return convert_variable_fields(die_mem, field->name, 1067b55a87adSMasami Hiramatsu field->next, &ref, die_mem); 1068b55a87adSMasami Hiramatsu else 1069b55a87adSMasami Hiramatsu return 0; 10707df2f329SMasami Hiramatsu } 10717df2f329SMasami Hiramatsu 10724ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */ 1073b55a87adSMasami Hiramatsu static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 10744ea42b18SMasami Hiramatsu { 10754984912eSMasami Hiramatsu Dwarf_Die die_mem; 10764ea42b18SMasami Hiramatsu int ret; 10774ea42b18SMasami Hiramatsu 1078b7dcb857SMasami Hiramatsu pr_debug("Converting variable %s into trace event.\n", 1079b7dcb857SMasami Hiramatsu dwarf_diename(vr_die)); 1080804b3606SMasami Hiramatsu 1081cf6eb489SMasami Hiramatsu ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 1082cf6eb489SMasami Hiramatsu pf->tvar); 1083cf6eb489SMasami Hiramatsu if (ret == -ENOENT) 1084cf6eb489SMasami Hiramatsu pr_err("Failed to find the location of %s at this address.\n" 1085cf6eb489SMasami Hiramatsu " Perhaps, it has been optimized out.\n", pf->pvar->var); 1086cf6eb489SMasami Hiramatsu else if (ret == -ENOTSUP) 1087cf6eb489SMasami Hiramatsu pr_err("Sorry, we don't support this variable location yet.\n"); 1088cf6eb489SMasami Hiramatsu else if (pf->pvar->field) { 1089b55a87adSMasami Hiramatsu ret = convert_variable_fields(vr_die, pf->pvar->var, 10904984912eSMasami Hiramatsu pf->pvar->field, &pf->tvar->ref, 10914984912eSMasami Hiramatsu &die_mem); 10924984912eSMasami Hiramatsu vr_die = &die_mem; 10934984912eSMasami Hiramatsu } 109473317b95SMasami Hiramatsu if (ret == 0) 109573317b95SMasami Hiramatsu ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); 1096804b3606SMasami Hiramatsu /* *expr will be cached in libdw. Don't free it. */ 1097b55a87adSMasami Hiramatsu return ret; 10984ea42b18SMasami Hiramatsu } 10994ea42b18SMasami Hiramatsu 11004ea42b18SMasami Hiramatsu /* Find a variable in a subprogram die */ 1101b55a87adSMasami Hiramatsu static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 11024ea42b18SMasami Hiramatsu { 1103b7dcb857SMasami Hiramatsu Dwarf_Die vr_die, *scopes; 110411a1ca35SMasami Hiramatsu char buf[32], *ptr; 1105b7dcb857SMasami Hiramatsu int ret, nscopes; 11064ea42b18SMasami Hiramatsu 1107367e94c1SMasami Hiramatsu if (!is_c_varname(pf->pvar->var)) { 1108367e94c1SMasami Hiramatsu /* Copy raw parameters */ 1109367e94c1SMasami Hiramatsu pf->tvar->value = strdup(pf->pvar->var); 1110367e94c1SMasami Hiramatsu if (pf->tvar->value == NULL) 1111367e94c1SMasami Hiramatsu return -ENOMEM; 1112367e94c1SMasami Hiramatsu if (pf->pvar->type) { 1113367e94c1SMasami Hiramatsu pf->tvar->type = strdup(pf->pvar->type); 1114367e94c1SMasami Hiramatsu if (pf->tvar->type == NULL) 1115367e94c1SMasami Hiramatsu return -ENOMEM; 1116367e94c1SMasami Hiramatsu } 1117367e94c1SMasami Hiramatsu if (pf->pvar->name) { 1118367e94c1SMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 1119367e94c1SMasami Hiramatsu if (pf->tvar->name == NULL) 1120367e94c1SMasami Hiramatsu return -ENOMEM; 1121367e94c1SMasami Hiramatsu } else 1122367e94c1SMasami Hiramatsu pf->tvar->name = NULL; 1123367e94c1SMasami Hiramatsu return 0; 1124367e94c1SMasami Hiramatsu } 1125367e94c1SMasami Hiramatsu 112648481938SMasami Hiramatsu if (pf->pvar->name) 112702b95dadSMasami Hiramatsu pf->tvar->name = strdup(pf->pvar->name); 112848481938SMasami Hiramatsu else { 112902b95dadSMasami Hiramatsu ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); 113002b95dadSMasami Hiramatsu if (ret < 0) 113102b95dadSMasami Hiramatsu return ret; 113211a1ca35SMasami Hiramatsu ptr = strchr(buf, ':'); /* Change type separator to _ */ 113311a1ca35SMasami Hiramatsu if (ptr) 113411a1ca35SMasami Hiramatsu *ptr = '_'; 113502b95dadSMasami Hiramatsu pf->tvar->name = strdup(buf); 113648481938SMasami Hiramatsu } 113702b95dadSMasami Hiramatsu if (pf->tvar->name == NULL) 113802b95dadSMasami Hiramatsu return -ENOMEM; 113948481938SMasami Hiramatsu 11404235b045SMasami Hiramatsu pr_debug("Searching '%s' variable in context.\n", 114148481938SMasami Hiramatsu pf->pvar->var); 11424ea42b18SMasami Hiramatsu /* Search child die for local variables and parameters. */ 1143378eeaadSMasami Hiramatsu if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) 1144b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 1145b7dcb857SMasami Hiramatsu else { 1146b7dcb857SMasami Hiramatsu /* Search upper class */ 1147b7dcb857SMasami Hiramatsu nscopes = dwarf_getscopes_die(sp_die, &scopes); 1148632941c4SMasami Hiramatsu while (nscopes-- > 1) { 1149632941c4SMasami Hiramatsu pr_debug("Searching variables in %s\n", 1150632941c4SMasami Hiramatsu dwarf_diename(&scopes[nscopes])); 1151632941c4SMasami Hiramatsu /* We should check this scope, so give dummy address */ 1152632941c4SMasami Hiramatsu if (die_find_variable_at(&scopes[nscopes], 1153632941c4SMasami Hiramatsu pf->pvar->var, 0, 1154632941c4SMasami Hiramatsu &vr_die)) { 1155b7dcb857SMasami Hiramatsu ret = convert_variable(&vr_die, pf); 1156632941c4SMasami Hiramatsu goto found; 1157632941c4SMasami Hiramatsu } 1158632941c4SMasami Hiramatsu } 1159632941c4SMasami Hiramatsu if (scopes) 1160b7dcb857SMasami Hiramatsu free(scopes); 1161b7dcb857SMasami Hiramatsu ret = -ENOENT; 1162b7dcb857SMasami Hiramatsu } 1163632941c4SMasami Hiramatsu found: 1164b7dcb857SMasami Hiramatsu if (ret < 0) 1165b55a87adSMasami Hiramatsu pr_warning("Failed to find '%s' in this function.\n", 116648481938SMasami Hiramatsu pf->pvar->var); 1167b7dcb857SMasami Hiramatsu return ret; 11684ea42b18SMasami Hiramatsu } 11694ea42b18SMasami Hiramatsu 1170cf6eb489SMasami Hiramatsu /* Convert subprogram DIE to trace point */ 1171cf6eb489SMasami Hiramatsu static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 1172cf6eb489SMasami Hiramatsu bool retprobe, struct probe_trace_point *tp) 11734ea42b18SMasami Hiramatsu { 1174e92b85e1SMasami Hiramatsu Dwarf_Addr eaddr; 1175804b3606SMasami Hiramatsu const char *name; 1176cf6eb489SMasami Hiramatsu 1177cf6eb489SMasami Hiramatsu /* Copy the name of probe point */ 1178cf6eb489SMasami Hiramatsu name = dwarf_diename(sp_die); 1179cf6eb489SMasami Hiramatsu if (name) { 1180cf6eb489SMasami Hiramatsu if (dwarf_entrypc(sp_die, &eaddr) != 0) { 11810e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s\n", 1182cf6eb489SMasami Hiramatsu dwarf_diename(sp_die)); 1183cf6eb489SMasami Hiramatsu return -ENOENT; 1184cf6eb489SMasami Hiramatsu } 1185cf6eb489SMasami Hiramatsu tp->symbol = strdup(name); 1186cf6eb489SMasami Hiramatsu if (tp->symbol == NULL) 1187cf6eb489SMasami Hiramatsu return -ENOMEM; 1188cf6eb489SMasami Hiramatsu tp->offset = (unsigned long)(paddr - eaddr); 1189cf6eb489SMasami Hiramatsu } else 1190cf6eb489SMasami Hiramatsu /* This function has no name. */ 1191cf6eb489SMasami Hiramatsu tp->offset = (unsigned long)paddr; 1192cf6eb489SMasami Hiramatsu 1193cf6eb489SMasami Hiramatsu /* Return probe must be on the head of a subprogram */ 1194cf6eb489SMasami Hiramatsu if (retprobe) { 1195cf6eb489SMasami Hiramatsu if (eaddr != paddr) { 1196cf6eb489SMasami Hiramatsu pr_warning("Return probe must be on the head of" 11970e43e5d2SMasami Hiramatsu " a real function.\n"); 1198cf6eb489SMasami Hiramatsu return -EINVAL; 1199cf6eb489SMasami Hiramatsu } 1200cf6eb489SMasami Hiramatsu tp->retprobe = true; 1201cf6eb489SMasami Hiramatsu } 1202cf6eb489SMasami Hiramatsu 1203cf6eb489SMasami Hiramatsu return 0; 1204cf6eb489SMasami Hiramatsu } 1205cf6eb489SMasami Hiramatsu 1206cf6eb489SMasami Hiramatsu /* Call probe_finder callback with real subprogram DIE */ 1207cf6eb489SMasami Hiramatsu static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) 1208cf6eb489SMasami Hiramatsu { 1209cf6eb489SMasami Hiramatsu Dwarf_Die die_mem; 1210804b3606SMasami Hiramatsu Dwarf_Attribute fb_attr; 1211804b3606SMasami Hiramatsu size_t nops; 1212cf6eb489SMasami Hiramatsu int ret; 12134235b045SMasami Hiramatsu 1214e92b85e1SMasami Hiramatsu /* If no real subprogram, find a real one */ 1215e92b85e1SMasami Hiramatsu if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 121695a3e4c4SMasami Hiramatsu sp_die = die_find_real_subprogram(&pf->cu_die, 1217e92b85e1SMasami Hiramatsu pf->addr, &die_mem); 1218b55a87adSMasami Hiramatsu if (!sp_die) { 1219b55a87adSMasami Hiramatsu pr_warning("Failed to find probe point in any " 1220b55a87adSMasami Hiramatsu "functions.\n"); 1221b55a87adSMasami Hiramatsu return -ENOENT; 1222b55a87adSMasami Hiramatsu } 1223e92b85e1SMasami Hiramatsu } 1224e92b85e1SMasami Hiramatsu 1225804b3606SMasami Hiramatsu /* Get the frame base attribute/ops */ 1226804b3606SMasami Hiramatsu dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 1227d0cb4260SMasami Hiramatsu ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 1228a34a9854SMasami Hiramatsu if (ret <= 0 || nops == 0) { 1229804b3606SMasami Hiramatsu pf->fb_ops = NULL; 12307752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 1231a34a9854SMasami Hiramatsu } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 1232a34a9854SMasami Hiramatsu pf->cfi != NULL) { 1233a34a9854SMasami Hiramatsu Dwarf_Frame *frame; 1234b55a87adSMasami Hiramatsu if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 1235b55a87adSMasami Hiramatsu dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 12360e43e5d2SMasami Hiramatsu pr_warning("Failed to get call frame on 0x%jx\n", 1237b55a87adSMasami Hiramatsu (uintmax_t)pf->addr); 1238b55a87adSMasami Hiramatsu return -ENOENT; 1239b55a87adSMasami Hiramatsu } 12407752f1b0SMasami Hiramatsu #endif 1241a34a9854SMasami Hiramatsu } 1242804b3606SMasami Hiramatsu 1243cf6eb489SMasami Hiramatsu /* Call finder's callback handler */ 1244cf6eb489SMasami Hiramatsu ret = pf->callback(sp_die, pf); 1245804b3606SMasami Hiramatsu 1246804b3606SMasami Hiramatsu /* *pf->fb_ops will be cached in libdw. Don't free it. */ 1247804b3606SMasami Hiramatsu pf->fb_ops = NULL; 1248cf6eb489SMasami Hiramatsu 1249cf6eb489SMasami Hiramatsu return ret; 12504ea42b18SMasami Hiramatsu } 12514ea42b18SMasami Hiramatsu 12524cc9cec6SMasami Hiramatsu static int probe_point_line_walker(const char *fname, int lineno, 12534cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 12544cc9cec6SMasami Hiramatsu { 12554cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 12564cc9cec6SMasami Hiramatsu int ret; 12574cc9cec6SMasami Hiramatsu 12584cc9cec6SMasami Hiramatsu if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 12594cc9cec6SMasami Hiramatsu return 0; 12604cc9cec6SMasami Hiramatsu 12614cc9cec6SMasami Hiramatsu pf->addr = addr; 12624cc9cec6SMasami Hiramatsu ret = call_probe_finder(NULL, pf); 12634cc9cec6SMasami Hiramatsu 12644cc9cec6SMasami Hiramatsu /* Continue if no error, because the line will be in inline function */ 12654cc9cec6SMasami Hiramatsu return ret < 0 ?: 0; 12664cc9cec6SMasami Hiramatsu } 12674cc9cec6SMasami Hiramatsu 12684ea42b18SMasami Hiramatsu /* Find probe point from its line number */ 1269b55a87adSMasami Hiramatsu static int find_probe_point_by_line(struct probe_finder *pf) 12704ea42b18SMasami Hiramatsu { 12714cc9cec6SMasami Hiramatsu return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 12724ea42b18SMasami Hiramatsu } 12734ea42b18SMasami Hiramatsu 12742a9c8c36SMasami Hiramatsu /* Find lines which match lazy pattern */ 12752a9c8c36SMasami Hiramatsu static int find_lazy_match_lines(struct list_head *head, 12762a9c8c36SMasami Hiramatsu const char *fname, const char *pat) 12772a9c8c36SMasami Hiramatsu { 1278f50c2169SFranck Bui-Huu FILE *fp; 1279f50c2169SFranck Bui-Huu char *line = NULL; 1280f50c2169SFranck Bui-Huu size_t line_len; 1281f50c2169SFranck Bui-Huu ssize_t len; 1282f50c2169SFranck Bui-Huu int count = 0, linenum = 1; 12832a9c8c36SMasami Hiramatsu 1284f50c2169SFranck Bui-Huu fp = fopen(fname, "r"); 1285f50c2169SFranck Bui-Huu if (!fp) { 1286f50c2169SFranck Bui-Huu pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); 1287b448c4b6SArnaldo Carvalho de Melo return -errno; 1288b55a87adSMasami Hiramatsu } 1289b55a87adSMasami Hiramatsu 1290f50c2169SFranck Bui-Huu while ((len = getline(&line, &line_len, fp)) > 0) { 1291f50c2169SFranck Bui-Huu 1292f50c2169SFranck Bui-Huu if (line[len - 1] == '\n') 1293f50c2169SFranck Bui-Huu line[len - 1] = '\0'; 1294f50c2169SFranck Bui-Huu 1295f50c2169SFranck Bui-Huu if (strlazymatch(line, pat)) { 1296f50c2169SFranck Bui-Huu line_list__add_line(head, linenum); 1297f50c2169SFranck Bui-Huu count++; 1298f50c2169SFranck Bui-Huu } 1299f50c2169SFranck Bui-Huu linenum++; 1300b55a87adSMasami Hiramatsu } 1301b448c4b6SArnaldo Carvalho de Melo 1302f50c2169SFranck Bui-Huu if (ferror(fp)) 1303f50c2169SFranck Bui-Huu count = -errno; 1304f50c2169SFranck Bui-Huu free(line); 1305f50c2169SFranck Bui-Huu fclose(fp); 1306f50c2169SFranck Bui-Huu 1307f50c2169SFranck Bui-Huu if (count == 0) 1308f50c2169SFranck Bui-Huu pr_debug("No matched lines found in %s.\n", fname); 1309f50c2169SFranck Bui-Huu return count; 13102a9c8c36SMasami Hiramatsu } 13112a9c8c36SMasami Hiramatsu 13124cc9cec6SMasami Hiramatsu static int probe_point_lazy_walker(const char *fname, int lineno, 13134cc9cec6SMasami Hiramatsu Dwarf_Addr addr, void *data) 13144cc9cec6SMasami Hiramatsu { 13154cc9cec6SMasami Hiramatsu struct probe_finder *pf = data; 13164cc9cec6SMasami Hiramatsu int ret; 13174cc9cec6SMasami Hiramatsu 13184cc9cec6SMasami Hiramatsu if (!line_list__has_line(&pf->lcache, lineno) || 13194cc9cec6SMasami Hiramatsu strtailcmp(fname, pf->fname) != 0) 13204cc9cec6SMasami Hiramatsu return 0; 13214cc9cec6SMasami Hiramatsu 13224cc9cec6SMasami Hiramatsu pr_debug("Probe line found: line:%d addr:0x%llx\n", 13234cc9cec6SMasami Hiramatsu lineno, (unsigned long long)addr); 13244cc9cec6SMasami Hiramatsu pf->addr = addr; 13254cc9cec6SMasami Hiramatsu ret = call_probe_finder(NULL, pf); 13264cc9cec6SMasami Hiramatsu 13274cc9cec6SMasami Hiramatsu /* 13284cc9cec6SMasami Hiramatsu * Continue if no error, because the lazy pattern will match 13294cc9cec6SMasami Hiramatsu * to other lines 13304cc9cec6SMasami Hiramatsu */ 13314cc9cec6SMasami Hiramatsu return ret < 0 ?: 0; 13324cc9cec6SMasami Hiramatsu } 13334cc9cec6SMasami Hiramatsu 13342a9c8c36SMasami Hiramatsu /* Find probe points from lazy pattern */ 1335b55a87adSMasami Hiramatsu static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 13362a9c8c36SMasami Hiramatsu { 1337b55a87adSMasami Hiramatsu int ret = 0; 13382a9c8c36SMasami Hiramatsu 13392a9c8c36SMasami Hiramatsu if (list_empty(&pf->lcache)) { 13402a9c8c36SMasami Hiramatsu /* Matching lazy line pattern */ 13412a9c8c36SMasami Hiramatsu ret = find_lazy_match_lines(&pf->lcache, pf->fname, 13424235b045SMasami Hiramatsu pf->pev->point.lazy_line); 1343f50c2169SFranck Bui-Huu if (ret <= 0) 1344b55a87adSMasami Hiramatsu return ret; 13452a9c8c36SMasami Hiramatsu } 13462a9c8c36SMasami Hiramatsu 13474cc9cec6SMasami Hiramatsu return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 13482a9c8c36SMasami Hiramatsu } 13492a9c8c36SMasami Hiramatsu 1350b55a87adSMasami Hiramatsu /* Callback parameter with return value */ 1351b55a87adSMasami Hiramatsu struct dwarf_callback_param { 1352b55a87adSMasami Hiramatsu void *data; 1353b55a87adSMasami Hiramatsu int retval; 1354b55a87adSMasami Hiramatsu }; 1355b55a87adSMasami Hiramatsu 1356e92b85e1SMasami Hiramatsu static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 13574ea42b18SMasami Hiramatsu { 1358b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1359b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 13604235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1361b55a87adSMasami Hiramatsu Dwarf_Addr addr; 13624ea42b18SMasami Hiramatsu 13632a9c8c36SMasami Hiramatsu if (pp->lazy_line) 1364b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(in_die, pf); 13652a9c8c36SMasami Hiramatsu else { 1366e92b85e1SMasami Hiramatsu /* Get probe address */ 1367b55a87adSMasami Hiramatsu if (dwarf_entrypc(in_die, &addr) != 0) { 13680e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of %s.\n", 1369b55a87adSMasami Hiramatsu dwarf_diename(in_die)); 1370b55a87adSMasami Hiramatsu param->retval = -ENOENT; 1371b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1372b55a87adSMasami Hiramatsu } 1373b55a87adSMasami Hiramatsu pf->addr = addr; 1374e92b85e1SMasami Hiramatsu pf->addr += pp->offset; 13752a9c8c36SMasami Hiramatsu pr_debug("found inline addr: 0x%jx\n", 13762a9c8c36SMasami Hiramatsu (uintmax_t)pf->addr); 1377e92b85e1SMasami Hiramatsu 1378cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(in_die, pf); 13795d1ee041SMasami Hiramatsu if (param->retval < 0) 13805d1ee041SMasami Hiramatsu return DWARF_CB_ABORT; 13812a9c8c36SMasami Hiramatsu } 13822a9c8c36SMasami Hiramatsu 1383e92b85e1SMasami Hiramatsu return DWARF_CB_OK; 1384e92b85e1SMasami Hiramatsu } 1385e92b85e1SMasami Hiramatsu 1386e92b85e1SMasami Hiramatsu /* Search function from function name */ 1387e92b85e1SMasami Hiramatsu static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 1388e92b85e1SMasami Hiramatsu { 1389b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1390b55a87adSMasami Hiramatsu struct probe_finder *pf = param->data; 13914235b045SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1392e92b85e1SMasami Hiramatsu 1393e92b85e1SMasami Hiramatsu /* Check tag and diename */ 1394e92b85e1SMasami Hiramatsu if (dwarf_tag(sp_die) != DW_TAG_subprogram || 139582175633SMasami Hiramatsu !die_compare_name(sp_die, pp->function)) 1396b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1397e92b85e1SMasami Hiramatsu 1398e92b85e1SMasami Hiramatsu pf->fname = dwarf_decl_file(sp_die); 13992a9c8c36SMasami Hiramatsu if (pp->line) { /* Function relative line */ 1400e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &pf->lno); 1401804b3606SMasami Hiramatsu pf->lno += pp->line; 1402b55a87adSMasami Hiramatsu param->retval = find_probe_point_by_line(pf); 1403e92b85e1SMasami Hiramatsu } else if (!dwarf_func_inline(sp_die)) { 1404e92b85e1SMasami Hiramatsu /* Real function */ 14052a9c8c36SMasami Hiramatsu if (pp->lazy_line) 1406b55a87adSMasami Hiramatsu param->retval = find_probe_point_lazy(sp_die, pf); 14072a9c8c36SMasami Hiramatsu else { 1408b55a87adSMasami Hiramatsu if (dwarf_entrypc(sp_die, &pf->addr) != 0) { 14090e43e5d2SMasami Hiramatsu pr_warning("Failed to get entry address of " 14100e43e5d2SMasami Hiramatsu "%s.\n", dwarf_diename(sp_die)); 1411b55a87adSMasami Hiramatsu param->retval = -ENOENT; 1412b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1413b55a87adSMasami Hiramatsu } 14144ea42b18SMasami Hiramatsu pf->addr += pp->offset; 14154ea42b18SMasami Hiramatsu /* TODO: Check the address in this function */ 1416cf6eb489SMasami Hiramatsu param->retval = call_probe_finder(sp_die, pf); 14172a9c8c36SMasami Hiramatsu } 1418b55a87adSMasami Hiramatsu } else { 1419b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 1420b55a87adSMasami Hiramatsu .retval = 0}; 1421e92b85e1SMasami Hiramatsu /* Inlined function: search instances */ 1422b55a87adSMasami Hiramatsu dwarf_func_inline_instances(sp_die, probe_point_inline_cb, 1423b55a87adSMasami Hiramatsu &_param); 1424b55a87adSMasami Hiramatsu param->retval = _param.retval; 14254ea42b18SMasami Hiramatsu } 14264ea42b18SMasami Hiramatsu 1427b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1428b55a87adSMasami Hiramatsu } 1429b55a87adSMasami Hiramatsu 1430b55a87adSMasami Hiramatsu static int find_probe_point_by_func(struct probe_finder *pf) 14314ea42b18SMasami Hiramatsu { 1432b55a87adSMasami Hiramatsu struct dwarf_callback_param _param = {.data = (void *)pf, 1433b55a87adSMasami Hiramatsu .retval = 0}; 1434b55a87adSMasami Hiramatsu dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 1435b55a87adSMasami Hiramatsu return _param.retval; 14364ea42b18SMasami Hiramatsu } 14374ea42b18SMasami Hiramatsu 1438cf6eb489SMasami Hiramatsu /* Find probe points from debuginfo */ 1439cf6eb489SMasami Hiramatsu static int find_probes(int fd, struct probe_finder *pf) 14404ea42b18SMasami Hiramatsu { 1441cf6eb489SMasami Hiramatsu struct perf_probe_point *pp = &pf->pev->point; 1442804b3606SMasami Hiramatsu Dwarf_Off off, noff; 1443804b3606SMasami Hiramatsu size_t cuhl; 1444804b3606SMasami Hiramatsu Dwarf_Die *diep; 1445469b9b88SMasami Hiramatsu Dwarf *dbg = NULL; 1446469b9b88SMasami Hiramatsu Dwfl *dwfl; 1447469b9b88SMasami Hiramatsu Dwarf_Addr bias; /* Currently ignored */ 1448b55a87adSMasami Hiramatsu int ret = 0; 14494ea42b18SMasami Hiramatsu 1450469b9b88SMasami Hiramatsu dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); 1451b55a87adSMasami Hiramatsu if (!dbg) { 14520e43e5d2SMasami Hiramatsu pr_warning("No debug information found in the vmlinux - " 1453b55a87adSMasami Hiramatsu "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1454b55a87adSMasami Hiramatsu return -EBADF; 1455b55a87adSMasami Hiramatsu } 14564ea42b18SMasami Hiramatsu 14577752f1b0SMasami Hiramatsu #if _ELFUTILS_PREREQ(0, 142) 1458a34a9854SMasami Hiramatsu /* Get the call frame information from this dwarf */ 1459cf6eb489SMasami Hiramatsu pf->cfi = dwarf_getcfi(dbg); 14607752f1b0SMasami Hiramatsu #endif 1461a34a9854SMasami Hiramatsu 1462804b3606SMasami Hiramatsu off = 0; 1463cf6eb489SMasami Hiramatsu line_list__init(&pf->lcache); 1464804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1465b55a87adSMasami Hiramatsu while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1466b55a87adSMasami Hiramatsu ret >= 0) { 14674ea42b18SMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1468cf6eb489SMasami Hiramatsu diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); 1469804b3606SMasami Hiramatsu if (!diep) 1470804b3606SMasami Hiramatsu continue; 14714ea42b18SMasami Hiramatsu 14724ea42b18SMasami Hiramatsu /* Check if target file is included. */ 14734ea42b18SMasami Hiramatsu if (pp->file) 1474cf6eb489SMasami Hiramatsu pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1475804b3606SMasami Hiramatsu else 1476cf6eb489SMasami Hiramatsu pf->fname = NULL; 14774ea42b18SMasami Hiramatsu 1478cf6eb489SMasami Hiramatsu if (!pp->file || pf->fname) { 14794ea42b18SMasami Hiramatsu if (pp->function) 1480cf6eb489SMasami Hiramatsu ret = find_probe_point_by_func(pf); 14812a9c8c36SMasami Hiramatsu else if (pp->lazy_line) 1482cf6eb489SMasami Hiramatsu ret = find_probe_point_lazy(NULL, pf); 1483b0ef0732SMasami Hiramatsu else { 1484cf6eb489SMasami Hiramatsu pf->lno = pp->line; 1485cf6eb489SMasami Hiramatsu ret = find_probe_point_by_line(pf); 14864ea42b18SMasami Hiramatsu } 1487b0ef0732SMasami Hiramatsu } 1488804b3606SMasami Hiramatsu off = noff; 14894ea42b18SMasami Hiramatsu } 1490cf6eb489SMasami Hiramatsu line_list__free(&pf->lcache); 1491469b9b88SMasami Hiramatsu if (dwfl) 1492469b9b88SMasami Hiramatsu dwfl_end(dwfl); 14934ea42b18SMasami Hiramatsu 1494cf6eb489SMasami Hiramatsu return ret; 1495cf6eb489SMasami Hiramatsu } 1496cf6eb489SMasami Hiramatsu 1497cf6eb489SMasami Hiramatsu /* Add a found probe point into trace event list */ 1498cf6eb489SMasami Hiramatsu static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) 1499cf6eb489SMasami Hiramatsu { 1500cf6eb489SMasami Hiramatsu struct trace_event_finder *tf = 1501cf6eb489SMasami Hiramatsu container_of(pf, struct trace_event_finder, pf); 1502cf6eb489SMasami Hiramatsu struct probe_trace_event *tev; 1503cf6eb489SMasami Hiramatsu int ret, i; 1504cf6eb489SMasami Hiramatsu 1505cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1506cf6eb489SMasami Hiramatsu if (tf->ntevs == tf->max_tevs) { 1507cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", 1508cf6eb489SMasami Hiramatsu tf->max_tevs); 1509cf6eb489SMasami Hiramatsu return -ERANGE; 1510cf6eb489SMasami Hiramatsu } 1511cf6eb489SMasami Hiramatsu tev = &tf->tevs[tf->ntevs++]; 1512cf6eb489SMasami Hiramatsu 1513cf6eb489SMasami Hiramatsu ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1514cf6eb489SMasami Hiramatsu &tev->point); 1515cf6eb489SMasami Hiramatsu if (ret < 0) 1516cf6eb489SMasami Hiramatsu return ret; 1517cf6eb489SMasami Hiramatsu 1518cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1519cf6eb489SMasami Hiramatsu tev->point.offset); 1520cf6eb489SMasami Hiramatsu 1521cf6eb489SMasami Hiramatsu /* Find each argument */ 1522cf6eb489SMasami Hiramatsu tev->nargs = pf->pev->nargs; 1523cf6eb489SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1524cf6eb489SMasami Hiramatsu if (tev->args == NULL) 1525cf6eb489SMasami Hiramatsu return -ENOMEM; 1526cf6eb489SMasami Hiramatsu for (i = 0; i < pf->pev->nargs; i++) { 1527cf6eb489SMasami Hiramatsu pf->pvar = &pf->pev->args[i]; 1528cf6eb489SMasami Hiramatsu pf->tvar = &tev->args[i]; 1529cf6eb489SMasami Hiramatsu ret = find_variable(sp_die, pf); 1530cf6eb489SMasami Hiramatsu if (ret != 0) 1531cf6eb489SMasami Hiramatsu return ret; 1532cf6eb489SMasami Hiramatsu } 1533cf6eb489SMasami Hiramatsu 1534cf6eb489SMasami Hiramatsu return 0; 1535cf6eb489SMasami Hiramatsu } 1536cf6eb489SMasami Hiramatsu 1537cf6eb489SMasami Hiramatsu /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1538cf6eb489SMasami Hiramatsu int find_probe_trace_events(int fd, struct perf_probe_event *pev, 1539cf6eb489SMasami Hiramatsu struct probe_trace_event **tevs, int max_tevs) 1540cf6eb489SMasami Hiramatsu { 1541cf6eb489SMasami Hiramatsu struct trace_event_finder tf = { 1542cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_probe_trace_event}, 1543cf6eb489SMasami Hiramatsu .max_tevs = max_tevs}; 1544cf6eb489SMasami Hiramatsu int ret; 1545cf6eb489SMasami Hiramatsu 1546cf6eb489SMasami Hiramatsu /* Allocate result tevs array */ 1547cf6eb489SMasami Hiramatsu *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1548cf6eb489SMasami Hiramatsu if (*tevs == NULL) 1549cf6eb489SMasami Hiramatsu return -ENOMEM; 1550cf6eb489SMasami Hiramatsu 1551cf6eb489SMasami Hiramatsu tf.tevs = *tevs; 1552cf6eb489SMasami Hiramatsu tf.ntevs = 0; 1553cf6eb489SMasami Hiramatsu 1554cf6eb489SMasami Hiramatsu ret = find_probes(fd, &tf.pf); 1555cf6eb489SMasami Hiramatsu if (ret < 0) { 1556cf6eb489SMasami Hiramatsu free(*tevs); 1557cf6eb489SMasami Hiramatsu *tevs = NULL; 1558cf6eb489SMasami Hiramatsu return ret; 1559cf6eb489SMasami Hiramatsu } 1560cf6eb489SMasami Hiramatsu 1561cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : tf.ntevs; 1562cf6eb489SMasami Hiramatsu } 1563cf6eb489SMasami Hiramatsu 1564cf6eb489SMasami Hiramatsu #define MAX_VAR_LEN 64 1565cf6eb489SMasami Hiramatsu 1566cf6eb489SMasami Hiramatsu /* Collect available variables in this scope */ 1567cf6eb489SMasami Hiramatsu static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1568cf6eb489SMasami Hiramatsu { 1569cf6eb489SMasami Hiramatsu struct available_var_finder *af = data; 1570cf6eb489SMasami Hiramatsu struct variable_list *vl; 1571cf6eb489SMasami Hiramatsu char buf[MAX_VAR_LEN]; 1572cf6eb489SMasami Hiramatsu int tag, ret; 1573cf6eb489SMasami Hiramatsu 1574cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls - 1]; 1575cf6eb489SMasami Hiramatsu 1576cf6eb489SMasami Hiramatsu tag = dwarf_tag(die_mem); 1577cf6eb489SMasami Hiramatsu if (tag == DW_TAG_formal_parameter || 1578cf6eb489SMasami Hiramatsu tag == DW_TAG_variable) { 1579cf6eb489SMasami Hiramatsu ret = convert_variable_location(die_mem, af->pf.addr, 1580cf6eb489SMasami Hiramatsu af->pf.fb_ops, NULL); 1581cf6eb489SMasami Hiramatsu if (ret == 0) { 1582cf6eb489SMasami Hiramatsu ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1583fb8c5a56SMasami Hiramatsu pr_debug2("Add new var: %s\n", buf); 1584cf6eb489SMasami Hiramatsu if (ret > 0) 1585cf6eb489SMasami Hiramatsu strlist__add(vl->vars, buf); 1586cf6eb489SMasami Hiramatsu } 1587cf6eb489SMasami Hiramatsu } 1588cf6eb489SMasami Hiramatsu 1589fb8c5a56SMasami Hiramatsu if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1590cf6eb489SMasami Hiramatsu return DIE_FIND_CB_CONTINUE; 1591cf6eb489SMasami Hiramatsu else 1592cf6eb489SMasami Hiramatsu return DIE_FIND_CB_SIBLING; 1593cf6eb489SMasami Hiramatsu } 1594cf6eb489SMasami Hiramatsu 1595cf6eb489SMasami Hiramatsu /* Add a found vars into available variables list */ 1596cf6eb489SMasami Hiramatsu static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) 1597cf6eb489SMasami Hiramatsu { 1598cf6eb489SMasami Hiramatsu struct available_var_finder *af = 1599cf6eb489SMasami Hiramatsu container_of(pf, struct available_var_finder, pf); 1600cf6eb489SMasami Hiramatsu struct variable_list *vl; 1601fb8c5a56SMasami Hiramatsu Dwarf_Die die_mem, *scopes = NULL; 1602fb8c5a56SMasami Hiramatsu int ret, nscopes; 1603cf6eb489SMasami Hiramatsu 1604cf6eb489SMasami Hiramatsu /* Check number of tevs */ 1605cf6eb489SMasami Hiramatsu if (af->nvls == af->max_vls) { 1606cf6eb489SMasami Hiramatsu pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1607cf6eb489SMasami Hiramatsu return -ERANGE; 1608cf6eb489SMasami Hiramatsu } 1609cf6eb489SMasami Hiramatsu vl = &af->vls[af->nvls++]; 1610cf6eb489SMasami Hiramatsu 1611cf6eb489SMasami Hiramatsu ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1612cf6eb489SMasami Hiramatsu &vl->point); 1613cf6eb489SMasami Hiramatsu if (ret < 0) 1614cf6eb489SMasami Hiramatsu return ret; 1615cf6eb489SMasami Hiramatsu 1616cf6eb489SMasami Hiramatsu pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1617cf6eb489SMasami Hiramatsu vl->point.offset); 1618cf6eb489SMasami Hiramatsu 1619cf6eb489SMasami Hiramatsu /* Find local variables */ 1620cf6eb489SMasami Hiramatsu vl->vars = strlist__new(true, NULL); 1621cf6eb489SMasami Hiramatsu if (vl->vars == NULL) 1622cf6eb489SMasami Hiramatsu return -ENOMEM; 1623fb8c5a56SMasami Hiramatsu af->child = true; 1624cf6eb489SMasami Hiramatsu die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); 1625cf6eb489SMasami Hiramatsu 1626fb8c5a56SMasami Hiramatsu /* Find external variables */ 1627fb8c5a56SMasami Hiramatsu if (!af->externs) 1628fb8c5a56SMasami Hiramatsu goto out; 1629fb8c5a56SMasami Hiramatsu /* Don't need to search child DIE for externs. */ 1630fb8c5a56SMasami Hiramatsu af->child = false; 1631fb8c5a56SMasami Hiramatsu nscopes = dwarf_getscopes_die(sp_die, &scopes); 1632fb8c5a56SMasami Hiramatsu while (nscopes-- > 1) 1633fb8c5a56SMasami Hiramatsu die_find_child(&scopes[nscopes], collect_variables_cb, 1634fb8c5a56SMasami Hiramatsu (void *)af, &die_mem); 1635fb8c5a56SMasami Hiramatsu if (scopes) 1636fb8c5a56SMasami Hiramatsu free(scopes); 1637fb8c5a56SMasami Hiramatsu 1638fb8c5a56SMasami Hiramatsu out: 1639cf6eb489SMasami Hiramatsu if (strlist__empty(vl->vars)) { 1640cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 1641cf6eb489SMasami Hiramatsu vl->vars = NULL; 1642cf6eb489SMasami Hiramatsu } 1643cf6eb489SMasami Hiramatsu 1644cf6eb489SMasami Hiramatsu return ret; 1645cf6eb489SMasami Hiramatsu } 1646cf6eb489SMasami Hiramatsu 1647cf6eb489SMasami Hiramatsu /* Find available variables at given probe point */ 1648cf6eb489SMasami Hiramatsu int find_available_vars_at(int fd, struct perf_probe_event *pev, 1649fb8c5a56SMasami Hiramatsu struct variable_list **vls, int max_vls, 1650fb8c5a56SMasami Hiramatsu bool externs) 1651cf6eb489SMasami Hiramatsu { 1652cf6eb489SMasami Hiramatsu struct available_var_finder af = { 1653cf6eb489SMasami Hiramatsu .pf = {.pev = pev, .callback = add_available_vars}, 1654fb8c5a56SMasami Hiramatsu .max_vls = max_vls, .externs = externs}; 1655cf6eb489SMasami Hiramatsu int ret; 1656cf6eb489SMasami Hiramatsu 1657cf6eb489SMasami Hiramatsu /* Allocate result vls array */ 1658cf6eb489SMasami Hiramatsu *vls = zalloc(sizeof(struct variable_list) * max_vls); 1659cf6eb489SMasami Hiramatsu if (*vls == NULL) 1660cf6eb489SMasami Hiramatsu return -ENOMEM; 1661cf6eb489SMasami Hiramatsu 1662cf6eb489SMasami Hiramatsu af.vls = *vls; 1663cf6eb489SMasami Hiramatsu af.nvls = 0; 1664cf6eb489SMasami Hiramatsu 1665cf6eb489SMasami Hiramatsu ret = find_probes(fd, &af.pf); 1666cf6eb489SMasami Hiramatsu if (ret < 0) { 1667cf6eb489SMasami Hiramatsu /* Free vlist for error */ 1668cf6eb489SMasami Hiramatsu while (af.nvls--) { 1669cf6eb489SMasami Hiramatsu if (af.vls[af.nvls].point.symbol) 1670cf6eb489SMasami Hiramatsu free(af.vls[af.nvls].point.symbol); 1671cf6eb489SMasami Hiramatsu if (af.vls[af.nvls].vars) 1672cf6eb489SMasami Hiramatsu strlist__delete(af.vls[af.nvls].vars); 1673cf6eb489SMasami Hiramatsu } 1674cf6eb489SMasami Hiramatsu free(af.vls); 1675cf6eb489SMasami Hiramatsu *vls = NULL; 1676cf6eb489SMasami Hiramatsu return ret; 1677cf6eb489SMasami Hiramatsu } 1678cf6eb489SMasami Hiramatsu 1679cf6eb489SMasami Hiramatsu return (ret < 0) ? ret : af.nvls; 16804ea42b18SMasami Hiramatsu } 16814ea42b18SMasami Hiramatsu 1682fb1587d8SMasami Hiramatsu /* Reverse search */ 1683469b9b88SMasami Hiramatsu int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) 1684fb1587d8SMasami Hiramatsu { 1685fb1587d8SMasami Hiramatsu Dwarf_Die cudie, spdie, indie; 1686469b9b88SMasami Hiramatsu Dwarf *dbg = NULL; 1687469b9b88SMasami Hiramatsu Dwfl *dwfl = NULL; 1688fb1587d8SMasami Hiramatsu Dwarf_Line *line; 1689469b9b88SMasami Hiramatsu Dwarf_Addr laddr, eaddr, bias = 0; 1690fb1587d8SMasami Hiramatsu const char *tmp; 1691fb1587d8SMasami Hiramatsu int lineno, ret = 0; 1692b55a87adSMasami Hiramatsu bool found = false; 1693fb1587d8SMasami Hiramatsu 1694469b9b88SMasami Hiramatsu /* Open the live linux kernel */ 1695469b9b88SMasami Hiramatsu dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); 1696469b9b88SMasami Hiramatsu if (!dbg) { 16970e43e5d2SMasami Hiramatsu pr_warning("No debug information found in the vmlinux - " 1698469b9b88SMasami Hiramatsu "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1699469b9b88SMasami Hiramatsu ret = -EINVAL; 1700469b9b88SMasami Hiramatsu goto end; 1701469b9b88SMasami Hiramatsu } 1702fb1587d8SMasami Hiramatsu 1703469b9b88SMasami Hiramatsu /* Adjust address with bias */ 1704469b9b88SMasami Hiramatsu addr += bias; 1705fb1587d8SMasami Hiramatsu /* Find cu die */ 1706469b9b88SMasami Hiramatsu if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { 17070e43e5d2SMasami Hiramatsu pr_warning("Failed to find debug information for address %lx\n", 17080e43e5d2SMasami Hiramatsu addr); 170975ec5a24SMasami Hiramatsu ret = -EINVAL; 171075ec5a24SMasami Hiramatsu goto end; 171175ec5a24SMasami Hiramatsu } 1712fb1587d8SMasami Hiramatsu 1713fb1587d8SMasami Hiramatsu /* Find a corresponding line */ 1714fb1587d8SMasami Hiramatsu line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); 1715fb1587d8SMasami Hiramatsu if (line) { 1716b55a87adSMasami Hiramatsu if (dwarf_lineaddr(line, &laddr) == 0 && 1717b55a87adSMasami Hiramatsu (Dwarf_Addr)addr == laddr && 1718b55a87adSMasami Hiramatsu dwarf_lineno(line, &lineno) == 0) { 1719fb1587d8SMasami Hiramatsu tmp = dwarf_linesrc(line, NULL, NULL); 1720b55a87adSMasami Hiramatsu if (tmp) { 1721b55a87adSMasami Hiramatsu ppt->line = lineno; 172202b95dadSMasami Hiramatsu ppt->file = strdup(tmp); 172302b95dadSMasami Hiramatsu if (ppt->file == NULL) { 172402b95dadSMasami Hiramatsu ret = -ENOMEM; 172502b95dadSMasami Hiramatsu goto end; 172602b95dadSMasami Hiramatsu } 1727b55a87adSMasami Hiramatsu found = true; 1728b55a87adSMasami Hiramatsu } 1729fb1587d8SMasami Hiramatsu } 1730fb1587d8SMasami Hiramatsu } 1731fb1587d8SMasami Hiramatsu 1732fb1587d8SMasami Hiramatsu /* Find a corresponding function */ 1733fb1587d8SMasami Hiramatsu if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { 1734fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&spdie); 1735b55a87adSMasami Hiramatsu if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) 1736fb1587d8SMasami Hiramatsu goto end; 1737fb1587d8SMasami Hiramatsu 1738b55a87adSMasami Hiramatsu if (ppt->line) { 1739b55a87adSMasami Hiramatsu if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1740b55a87adSMasami Hiramatsu &indie)) { 1741fb1587d8SMasami Hiramatsu /* addr in an inline function */ 1742fb1587d8SMasami Hiramatsu tmp = dwarf_diename(&indie); 1743fb1587d8SMasami Hiramatsu if (!tmp) 1744fb1587d8SMasami Hiramatsu goto end; 1745b55a87adSMasami Hiramatsu ret = dwarf_decl_line(&indie, &lineno); 1746fb1587d8SMasami Hiramatsu } else { 1747b55a87adSMasami Hiramatsu if (eaddr == addr) { /* Function entry */ 1748fb1587d8SMasami Hiramatsu lineno = ppt->line; 1749b55a87adSMasami Hiramatsu ret = 0; 1750b55a87adSMasami Hiramatsu } else 1751b55a87adSMasami Hiramatsu ret = dwarf_decl_line(&spdie, &lineno); 1752fb1587d8SMasami Hiramatsu } 1753b55a87adSMasami Hiramatsu if (ret == 0) { 1754b55a87adSMasami Hiramatsu /* Make a relative line number */ 1755b55a87adSMasami Hiramatsu ppt->line -= lineno; 1756b55a87adSMasami Hiramatsu goto found; 1757b55a87adSMasami Hiramatsu } 1758b55a87adSMasami Hiramatsu } 1759b55a87adSMasami Hiramatsu /* We don't have a line number, let's use offset */ 1760b55a87adSMasami Hiramatsu ppt->offset = addr - (unsigned long)eaddr; 1761b55a87adSMasami Hiramatsu found: 176202b95dadSMasami Hiramatsu ppt->function = strdup(tmp); 176302b95dadSMasami Hiramatsu if (ppt->function == NULL) { 176402b95dadSMasami Hiramatsu ret = -ENOMEM; 176502b95dadSMasami Hiramatsu goto end; 176602b95dadSMasami Hiramatsu } 1767b55a87adSMasami Hiramatsu found = true; 1768fb1587d8SMasami Hiramatsu } 1769fb1587d8SMasami Hiramatsu 1770fb1587d8SMasami Hiramatsu end: 1771469b9b88SMasami Hiramatsu if (dwfl) 1772469b9b88SMasami Hiramatsu dwfl_end(dwfl); 1773b55a87adSMasami Hiramatsu if (ret >= 0) 1774b55a87adSMasami Hiramatsu ret = found ? 1 : 0; 1775fb1587d8SMasami Hiramatsu return ret; 1776fb1587d8SMasami Hiramatsu } 1777fb1587d8SMasami Hiramatsu 1778f6c903f5SMasami Hiramatsu /* Add a line and store the src path */ 1779f6c903f5SMasami Hiramatsu static int line_range_add_line(const char *src, unsigned int lineno, 1780f6c903f5SMasami Hiramatsu struct line_range *lr) 1781f6c903f5SMasami Hiramatsu { 17827cf0b79eSMasami Hiramatsu /* Copy source path */ 1783f6c903f5SMasami Hiramatsu if (!lr->path) { 17847cf0b79eSMasami Hiramatsu lr->path = strdup(src); 17857cf0b79eSMasami Hiramatsu if (lr->path == NULL) 17867cf0b79eSMasami Hiramatsu return -ENOMEM; 1787f6c903f5SMasami Hiramatsu } 1788f6c903f5SMasami Hiramatsu return line_list__add_line(&lr->line_list, lineno); 1789f6c903f5SMasami Hiramatsu } 1790f6c903f5SMasami Hiramatsu 17914cc9cec6SMasami Hiramatsu static int line_range_walk_cb(const char *fname, int lineno, 17924cc9cec6SMasami Hiramatsu Dwarf_Addr addr __used, 17934cc9cec6SMasami Hiramatsu void *data) 1794f6c903f5SMasami Hiramatsu { 17954cc9cec6SMasami Hiramatsu struct line_finder *lf = data; 1796f6c903f5SMasami Hiramatsu 17974cc9cec6SMasami Hiramatsu if ((strtailcmp(fname, lf->fname) != 0) || 1798f6c903f5SMasami Hiramatsu (lf->lno_s > lineno || lf->lno_e < lineno)) 17994cc9cec6SMasami Hiramatsu return 0; 1800f6c903f5SMasami Hiramatsu 18014cc9cec6SMasami Hiramatsu if (line_range_add_line(fname, lineno, lf->lr) < 0) 18024cc9cec6SMasami Hiramatsu return -EINVAL; 1803f6c903f5SMasami Hiramatsu 18044cc9cec6SMasami Hiramatsu return 0; 1805f6c903f5SMasami Hiramatsu } 1806fb1587d8SMasami Hiramatsu 1807631c9defSMasami Hiramatsu /* Find line range from its line number */ 1808b55a87adSMasami Hiramatsu static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1809631c9defSMasami Hiramatsu { 18104cc9cec6SMasami Hiramatsu int ret; 1811631c9defSMasami Hiramatsu 18124cc9cec6SMasami Hiramatsu ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1813f6c903f5SMasami Hiramatsu 1814804b3606SMasami Hiramatsu /* Update status */ 1815f6c903f5SMasami Hiramatsu if (ret >= 0) 1816631c9defSMasami Hiramatsu if (!list_empty(&lf->lr->line_list)) 1817f6c903f5SMasami Hiramatsu ret = lf->found = 1; 1818f6c903f5SMasami Hiramatsu else 1819f6c903f5SMasami Hiramatsu ret = 0; /* Lines are not found */ 1820804b3606SMasami Hiramatsu else { 1821804b3606SMasami Hiramatsu free(lf->lr->path); 1822804b3606SMasami Hiramatsu lf->lr->path = NULL; 1823804b3606SMasami Hiramatsu } 1824f6c903f5SMasami Hiramatsu return ret; 1825631c9defSMasami Hiramatsu } 1826631c9defSMasami Hiramatsu 1827161a26b0SMasami Hiramatsu static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1828161a26b0SMasami Hiramatsu { 1829b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1830b55a87adSMasami Hiramatsu 1831b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(in_die, param->data); 1832161a26b0SMasami Hiramatsu return DWARF_CB_ABORT; /* No need to find other instances */ 1833161a26b0SMasami Hiramatsu } 1834161a26b0SMasami Hiramatsu 1835631c9defSMasami Hiramatsu /* Search function from function name */ 1836e92b85e1SMasami Hiramatsu static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1837631c9defSMasami Hiramatsu { 1838b55a87adSMasami Hiramatsu struct dwarf_callback_param *param = data; 1839b55a87adSMasami Hiramatsu struct line_finder *lf = param->data; 1840631c9defSMasami Hiramatsu struct line_range *lr = lf->lr; 1841631c9defSMasami Hiramatsu 1842e92b85e1SMasami Hiramatsu if (dwarf_tag(sp_die) == DW_TAG_subprogram && 184382175633SMasami Hiramatsu die_compare_name(sp_die, lr->function)) { 1844e92b85e1SMasami Hiramatsu lf->fname = dwarf_decl_file(sp_die); 1845e92b85e1SMasami Hiramatsu dwarf_decl_line(sp_die, &lr->offset); 1846804b3606SMasami Hiramatsu pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1847631c9defSMasami Hiramatsu lf->lno_s = lr->offset + lr->start; 1848d3b63d7aSMasami Hiramatsu if (lf->lno_s < 0) /* Overflow */ 1849d3b63d7aSMasami Hiramatsu lf->lno_s = INT_MAX; 1850631c9defSMasami Hiramatsu lf->lno_e = lr->offset + lr->end; 1851d3b63d7aSMasami Hiramatsu if (lf->lno_e < 0) /* Overflow */ 1852d3b63d7aSMasami Hiramatsu lf->lno_e = INT_MAX; 1853d3b63d7aSMasami Hiramatsu pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1854631c9defSMasami Hiramatsu lr->start = lf->lno_s; 1855631c9defSMasami Hiramatsu lr->end = lf->lno_e; 1856b55a87adSMasami Hiramatsu if (dwarf_func_inline(sp_die)) { 1857b55a87adSMasami Hiramatsu struct dwarf_callback_param _param; 1858b55a87adSMasami Hiramatsu _param.data = (void *)lf; 1859b55a87adSMasami Hiramatsu _param.retval = 0; 1860161a26b0SMasami Hiramatsu dwarf_func_inline_instances(sp_die, 1861b55a87adSMasami Hiramatsu line_range_inline_cb, 1862b55a87adSMasami Hiramatsu &_param); 1863b55a87adSMasami Hiramatsu param->retval = _param.retval; 1864b55a87adSMasami Hiramatsu } else 1865b55a87adSMasami Hiramatsu param->retval = find_line_range_by_line(sp_die, lf); 1866b55a87adSMasami Hiramatsu return DWARF_CB_ABORT; 1867631c9defSMasami Hiramatsu } 1868b55a87adSMasami Hiramatsu return DWARF_CB_OK; 1869631c9defSMasami Hiramatsu } 1870631c9defSMasami Hiramatsu 1871b55a87adSMasami Hiramatsu static int find_line_range_by_func(struct line_finder *lf) 1872631c9defSMasami Hiramatsu { 1873b55a87adSMasami Hiramatsu struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1874b55a87adSMasami Hiramatsu dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1875b55a87adSMasami Hiramatsu return param.retval; 1876631c9defSMasami Hiramatsu } 1877631c9defSMasami Hiramatsu 1878631c9defSMasami Hiramatsu int find_line_range(int fd, struct line_range *lr) 1879631c9defSMasami Hiramatsu { 1880804b3606SMasami Hiramatsu struct line_finder lf = {.lr = lr, .found = 0}; 1881b55a87adSMasami Hiramatsu int ret = 0; 1882804b3606SMasami Hiramatsu Dwarf_Off off = 0, noff; 1883804b3606SMasami Hiramatsu size_t cuhl; 1884804b3606SMasami Hiramatsu Dwarf_Die *diep; 1885469b9b88SMasami Hiramatsu Dwarf *dbg = NULL; 1886469b9b88SMasami Hiramatsu Dwfl *dwfl; 1887469b9b88SMasami Hiramatsu Dwarf_Addr bias; /* Currently ignored */ 18886a330a3cSMasami Hiramatsu const char *comp_dir; 1889631c9defSMasami Hiramatsu 1890469b9b88SMasami Hiramatsu dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); 1891b55a87adSMasami Hiramatsu if (!dbg) { 18920e43e5d2SMasami Hiramatsu pr_warning("No debug information found in the vmlinux - " 1893b55a87adSMasami Hiramatsu "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1894b55a87adSMasami Hiramatsu return -EBADF; 1895b55a87adSMasami Hiramatsu } 1896631c9defSMasami Hiramatsu 1897804b3606SMasami Hiramatsu /* Loop on CUs (Compilation Unit) */ 1898b55a87adSMasami Hiramatsu while (!lf.found && ret >= 0) { 1899b55a87adSMasami Hiramatsu if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) 1900631c9defSMasami Hiramatsu break; 1901631c9defSMasami Hiramatsu 1902631c9defSMasami Hiramatsu /* Get the DIE(Debugging Information Entry) of this CU */ 1903804b3606SMasami Hiramatsu diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); 1904804b3606SMasami Hiramatsu if (!diep) 1905804b3606SMasami Hiramatsu continue; 1906631c9defSMasami Hiramatsu 1907631c9defSMasami Hiramatsu /* Check if target file is included. */ 1908631c9defSMasami Hiramatsu if (lr->file) 19092a9c8c36SMasami Hiramatsu lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1910804b3606SMasami Hiramatsu else 19112a9c8c36SMasami Hiramatsu lf.fname = 0; 1912631c9defSMasami Hiramatsu 19132a9c8c36SMasami Hiramatsu if (!lr->file || lf.fname) { 1914631c9defSMasami Hiramatsu if (lr->function) 1915b55a87adSMasami Hiramatsu ret = find_line_range_by_func(&lf); 1916631c9defSMasami Hiramatsu else { 1917631c9defSMasami Hiramatsu lf.lno_s = lr->start; 1918631c9defSMasami Hiramatsu lf.lno_e = lr->end; 1919b55a87adSMasami Hiramatsu ret = find_line_range_by_line(NULL, &lf); 1920631c9defSMasami Hiramatsu } 1921631c9defSMasami Hiramatsu } 1922804b3606SMasami Hiramatsu off = noff; 1923631c9defSMasami Hiramatsu } 19246a330a3cSMasami Hiramatsu 19256a330a3cSMasami Hiramatsu /* Store comp_dir */ 19266a330a3cSMasami Hiramatsu if (lf.found) { 19276a330a3cSMasami Hiramatsu comp_dir = cu_get_comp_dir(&lf.cu_die); 19286a330a3cSMasami Hiramatsu if (comp_dir) { 19296a330a3cSMasami Hiramatsu lr->comp_dir = strdup(comp_dir); 19306a330a3cSMasami Hiramatsu if (!lr->comp_dir) 19316a330a3cSMasami Hiramatsu ret = -ENOMEM; 19326a330a3cSMasami Hiramatsu } 19336a330a3cSMasami Hiramatsu } 19346a330a3cSMasami Hiramatsu 19357cf0b79eSMasami Hiramatsu pr_debug("path: %s\n", lr->path); 1936469b9b88SMasami Hiramatsu dwfl_end(dwfl); 1937b55a87adSMasami Hiramatsu return (ret < 0) ? ret : lf.found; 1938631c9defSMasami Hiramatsu } 1939631c9defSMasami Hiramatsu 1940