18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * probe-file.c : operate ftrace k/uprobe events files 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <errno.h> 88c2ecf20Sopenharmony_ci#include <fcntl.h> 98c2ecf20Sopenharmony_ci#include <sys/stat.h> 108c2ecf20Sopenharmony_ci#include <sys/types.h> 118c2ecf20Sopenharmony_ci#include <sys/uio.h> 128c2ecf20Sopenharmony_ci#include <unistd.h> 138c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 148c2ecf20Sopenharmony_ci#include "namespaces.h" 158c2ecf20Sopenharmony_ci#include "event.h" 168c2ecf20Sopenharmony_ci#include "strlist.h" 178c2ecf20Sopenharmony_ci#include "strfilter.h" 188c2ecf20Sopenharmony_ci#include "debug.h" 198c2ecf20Sopenharmony_ci#include "build-id.h" 208c2ecf20Sopenharmony_ci#include "dso.h" 218c2ecf20Sopenharmony_ci#include "color.h" 228c2ecf20Sopenharmony_ci#include "symbol.h" 238c2ecf20Sopenharmony_ci#include "strbuf.h" 248c2ecf20Sopenharmony_ci#include <api/fs/tracing_path.h> 258c2ecf20Sopenharmony_ci#include "probe-event.h" 268c2ecf20Sopenharmony_ci#include "probe-file.h" 278c2ecf20Sopenharmony_ci#include "session.h" 288c2ecf20Sopenharmony_ci#include "perf_regs.h" 298c2ecf20Sopenharmony_ci#include "string2.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 4096 - 2 ('\n' + '\0') */ 328c2ecf20Sopenharmony_ci#define MAX_CMDLEN 4094 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void print_open_warning(int err, bool uprobe) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (err == -ENOENT) { 398c2ecf20Sopenharmony_ci const char *config; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (uprobe) 428c2ecf20Sopenharmony_ci config = "CONFIG_UPROBE_EVENTS"; 438c2ecf20Sopenharmony_ci else 448c2ecf20Sopenharmony_ci config = "CONFIG_KPROBE_EVENTS"; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci pr_warning("%cprobe_events file does not exist" 478c2ecf20Sopenharmony_ci " - please rebuild kernel with %s.\n", 488c2ecf20Sopenharmony_ci uprobe ? 'u' : 'k', config); 498c2ecf20Sopenharmony_ci } else if (err == -ENOTSUP) 508c2ecf20Sopenharmony_ci pr_warning("Tracefs or debugfs is not mounted.\n"); 518c2ecf20Sopenharmony_ci else 528c2ecf20Sopenharmony_ci pr_warning("Failed to open %cprobe_events: %s\n", 538c2ecf20Sopenharmony_ci uprobe ? 'u' : 'k', 548c2ecf20Sopenharmony_ci str_error_r(-err, sbuf, sizeof(sbuf))); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void print_both_open_warning(int kerr, int uerr) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci /* Both kprobes and uprobes are disabled, warn it. */ 608c2ecf20Sopenharmony_ci if (kerr == -ENOTSUP && uerr == -ENOTSUP) 618c2ecf20Sopenharmony_ci pr_warning("Tracefs or debugfs is not mounted.\n"); 628c2ecf20Sopenharmony_ci else if (kerr == -ENOENT && uerr == -ENOENT) 638c2ecf20Sopenharmony_ci pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " 648c2ecf20Sopenharmony_ci "or/and CONFIG_UPROBE_EVENTS.\n"); 658c2ecf20Sopenharmony_ci else { 668c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 678c2ecf20Sopenharmony_ci pr_warning("Failed to open kprobe events: %s.\n", 688c2ecf20Sopenharmony_ci str_error_r(-kerr, sbuf, sizeof(sbuf))); 698c2ecf20Sopenharmony_ci pr_warning("Failed to open uprobe events: %s.\n", 708c2ecf20Sopenharmony_ci str_error_r(-uerr, sbuf, sizeof(sbuf))); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciint open_trace_file(const char *trace_file, bool readwrite) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci char buf[PATH_MAX]; 778c2ecf20Sopenharmony_ci int ret; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file); 808c2ecf20Sopenharmony_ci if (ret >= 0) { 818c2ecf20Sopenharmony_ci pr_debug("Opening %s write=%d\n", buf, readwrite); 828c2ecf20Sopenharmony_ci if (readwrite && !probe_event_dry_run) 838c2ecf20Sopenharmony_ci ret = open(buf, O_RDWR | O_APPEND, 0); 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci ret = open(buf, O_RDONLY, 0); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (ret < 0) 888c2ecf20Sopenharmony_ci ret = -errno; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci return ret; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int open_kprobe_events(bool readwrite) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return open_trace_file("kprobe_events", readwrite); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int open_uprobe_events(bool readwrite) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci return open_trace_file("uprobe_events", readwrite); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciint probe_file__open(int flag) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int fd; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (flag & PF_FL_UPROBE) 1088c2ecf20Sopenharmony_ci fd = open_uprobe_events(flag & PF_FL_RW); 1098c2ecf20Sopenharmony_ci else 1108c2ecf20Sopenharmony_ci fd = open_kprobe_events(flag & PF_FL_RW); 1118c2ecf20Sopenharmony_ci if (fd < 0) 1128c2ecf20Sopenharmony_ci print_open_warning(fd, flag & PF_FL_UPROBE); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return fd; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciint probe_file__open_both(int *kfd, int *ufd, int flag) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci if (!kfd || !ufd) 1208c2ecf20Sopenharmony_ci return -EINVAL; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci *kfd = open_kprobe_events(flag & PF_FL_RW); 1238c2ecf20Sopenharmony_ci *ufd = open_uprobe_events(flag & PF_FL_RW); 1248c2ecf20Sopenharmony_ci if (*kfd < 0 && *ufd < 0) { 1258c2ecf20Sopenharmony_ci print_both_open_warning(*kfd, *ufd); 1268c2ecf20Sopenharmony_ci return *kfd; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* Get raw string list of current kprobe_events or uprobe_events */ 1338c2ecf20Sopenharmony_cistruct strlist *probe_file__get_rawlist(int fd) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci int ret, idx, fddup; 1368c2ecf20Sopenharmony_ci FILE *fp; 1378c2ecf20Sopenharmony_ci char buf[MAX_CMDLEN]; 1388c2ecf20Sopenharmony_ci char *p; 1398c2ecf20Sopenharmony_ci struct strlist *sl; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (fd < 0) 1428c2ecf20Sopenharmony_ci return NULL; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci sl = strlist__new(NULL, NULL); 1458c2ecf20Sopenharmony_ci if (sl == NULL) 1468c2ecf20Sopenharmony_ci return NULL; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci fddup = dup(fd); 1498c2ecf20Sopenharmony_ci if (fddup < 0) 1508c2ecf20Sopenharmony_ci goto out_free_sl; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci fp = fdopen(fddup, "r"); 1538c2ecf20Sopenharmony_ci if (!fp) 1548c2ecf20Sopenharmony_ci goto out_close_fddup; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci while (!feof(fp)) { 1578c2ecf20Sopenharmony_ci p = fgets(buf, MAX_CMDLEN, fp); 1588c2ecf20Sopenharmony_ci if (!p) 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci idx = strlen(p) - 1; 1628c2ecf20Sopenharmony_ci if (p[idx] == '\n') 1638c2ecf20Sopenharmony_ci p[idx] = '\0'; 1648c2ecf20Sopenharmony_ci ret = strlist__add(sl, buf); 1658c2ecf20Sopenharmony_ci if (ret < 0) { 1668c2ecf20Sopenharmony_ci pr_debug("strlist__add failed (%d)\n", ret); 1678c2ecf20Sopenharmony_ci goto out_close_fp; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci fclose(fp); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return sl; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciout_close_fp: 1758c2ecf20Sopenharmony_ci fclose(fp); 1768c2ecf20Sopenharmony_ci goto out_free_sl; 1778c2ecf20Sopenharmony_ciout_close_fddup: 1788c2ecf20Sopenharmony_ci close(fddup); 1798c2ecf20Sopenharmony_ciout_free_sl: 1808c2ecf20Sopenharmony_ci strlist__delete(sl); 1818c2ecf20Sopenharmony_ci return NULL; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic struct strlist *__probe_file__get_namelist(int fd, bool include_group) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci char buf[128]; 1878c2ecf20Sopenharmony_ci struct strlist *sl, *rawlist; 1888c2ecf20Sopenharmony_ci struct str_node *ent; 1898c2ecf20Sopenharmony_ci struct probe_trace_event tev; 1908c2ecf20Sopenharmony_ci int ret = 0; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci memset(&tev, 0, sizeof(tev)); 1938c2ecf20Sopenharmony_ci rawlist = probe_file__get_rawlist(fd); 1948c2ecf20Sopenharmony_ci if (!rawlist) 1958c2ecf20Sopenharmony_ci return NULL; 1968c2ecf20Sopenharmony_ci sl = strlist__new(NULL, NULL); 1978c2ecf20Sopenharmony_ci strlist__for_each_entry(ent, rawlist) { 1988c2ecf20Sopenharmony_ci ret = parse_probe_trace_command(ent->s, &tev); 1998c2ecf20Sopenharmony_ci if (ret < 0) 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci if (include_group) { 2028c2ecf20Sopenharmony_ci ret = e_snprintf(buf, 128, "%s:%s", tev.group, 2038c2ecf20Sopenharmony_ci tev.event); 2048c2ecf20Sopenharmony_ci if (ret >= 0) 2058c2ecf20Sopenharmony_ci ret = strlist__add(sl, buf); 2068c2ecf20Sopenharmony_ci } else 2078c2ecf20Sopenharmony_ci ret = strlist__add(sl, tev.event); 2088c2ecf20Sopenharmony_ci clear_probe_trace_event(&tev); 2098c2ecf20Sopenharmony_ci /* Skip if there is same name multi-probe event in the list */ 2108c2ecf20Sopenharmony_ci if (ret == -EEXIST) 2118c2ecf20Sopenharmony_ci ret = 0; 2128c2ecf20Sopenharmony_ci if (ret < 0) 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci strlist__delete(rawlist); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (ret < 0) { 2188c2ecf20Sopenharmony_ci strlist__delete(sl); 2198c2ecf20Sopenharmony_ci return NULL; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci return sl; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* Get current perf-probe event names */ 2258c2ecf20Sopenharmony_cistruct strlist *probe_file__get_namelist(int fd) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci return __probe_file__get_namelist(fd, false); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciint probe_file__add_event(int fd, struct probe_trace_event *tev) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci int ret = 0; 2338c2ecf20Sopenharmony_ci char *buf = synthesize_probe_trace_command(tev); 2348c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (!buf) { 2378c2ecf20Sopenharmony_ci pr_debug("Failed to synthesize probe trace event.\n"); 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci pr_debug("Writing event: %s\n", buf); 2428c2ecf20Sopenharmony_ci if (!probe_event_dry_run) { 2438c2ecf20Sopenharmony_ci if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) { 2448c2ecf20Sopenharmony_ci ret = -errno; 2458c2ecf20Sopenharmony_ci pr_warning("Failed to write event: %s\n", 2468c2ecf20Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf))); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci free(buf); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int __del_trace_probe_event(int fd, struct str_node *ent) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci char *p; 2578c2ecf20Sopenharmony_ci char buf[128]; 2588c2ecf20Sopenharmony_ci int ret; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Convert from perf-probe event to trace-probe event */ 2618c2ecf20Sopenharmony_ci ret = e_snprintf(buf, 128, "-:%s", ent->s); 2628c2ecf20Sopenharmony_ci if (ret < 0) 2638c2ecf20Sopenharmony_ci goto error; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci p = strchr(buf + 2, ':'); 2668c2ecf20Sopenharmony_ci if (!p) { 2678c2ecf20Sopenharmony_ci pr_debug("Internal error: %s should have ':' but not.\n", 2688c2ecf20Sopenharmony_ci ent->s); 2698c2ecf20Sopenharmony_ci ret = -ENOTSUP; 2708c2ecf20Sopenharmony_ci goto error; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci *p = '/'; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci pr_debug("Writing event: %s\n", buf); 2758c2ecf20Sopenharmony_ci ret = write(fd, buf, strlen(buf)); 2768c2ecf20Sopenharmony_ci if (ret < 0) { 2778c2ecf20Sopenharmony_ci ret = -errno; 2788c2ecf20Sopenharmony_ci goto error; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_cierror: 2838c2ecf20Sopenharmony_ci pr_warning("Failed to delete event: %s\n", 2848c2ecf20Sopenharmony_ci str_error_r(-ret, buf, sizeof(buf))); 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ciint probe_file__get_events(int fd, struct strfilter *filter, 2898c2ecf20Sopenharmony_ci struct strlist *plist) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct strlist *namelist; 2928c2ecf20Sopenharmony_ci struct str_node *ent; 2938c2ecf20Sopenharmony_ci const char *p; 2948c2ecf20Sopenharmony_ci int ret = -ENOENT; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!plist) 2978c2ecf20Sopenharmony_ci return -EINVAL; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci namelist = __probe_file__get_namelist(fd, true); 3008c2ecf20Sopenharmony_ci if (!namelist) 3018c2ecf20Sopenharmony_ci return -ENOENT; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci strlist__for_each_entry(ent, namelist) { 3048c2ecf20Sopenharmony_ci p = strchr(ent->s, ':'); 3058c2ecf20Sopenharmony_ci if ((p && strfilter__compare(filter, p + 1)) || 3068c2ecf20Sopenharmony_ci strfilter__compare(filter, ent->s)) { 3078c2ecf20Sopenharmony_ci ret = strlist__add(plist, ent->s); 3088c2ecf20Sopenharmony_ci if (ret == -ENOMEM) { 3098c2ecf20Sopenharmony_ci pr_err("strlist__add failed with -ENOMEM\n"); 3108c2ecf20Sopenharmony_ci goto out; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci ret = 0; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ciout: 3168c2ecf20Sopenharmony_ci strlist__delete(namelist); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return ret; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ciint probe_file__del_strlist(int fd, struct strlist *namelist) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int ret = 0; 3248c2ecf20Sopenharmony_ci struct str_node *ent; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci strlist__for_each_entry(ent, namelist) { 3278c2ecf20Sopenharmony_ci ret = __del_trace_probe_event(fd, ent); 3288c2ecf20Sopenharmony_ci if (ret < 0) 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciint probe_file__del_events(int fd, struct strfilter *filter) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct strlist *namelist; 3378c2ecf20Sopenharmony_ci int ret; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci namelist = strlist__new(NULL, NULL); 3408c2ecf20Sopenharmony_ci if (!namelist) 3418c2ecf20Sopenharmony_ci return -ENOMEM; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ret = probe_file__get_events(fd, filter, namelist); 3448c2ecf20Sopenharmony_ci if (ret < 0) 3458c2ecf20Sopenharmony_ci goto out; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ret = probe_file__del_strlist(fd, namelist); 3488c2ecf20Sopenharmony_ciout: 3498c2ecf20Sopenharmony_ci strlist__delete(namelist); 3508c2ecf20Sopenharmony_ci return ret; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* Caller must ensure to remove this entry from list */ 3548c2ecf20Sopenharmony_cistatic void probe_cache_entry__delete(struct probe_cache_entry *entry) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci if (entry) { 3578c2ecf20Sopenharmony_ci BUG_ON(!list_empty(&entry->node)); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci strlist__delete(entry->tevlist); 3608c2ecf20Sopenharmony_ci clear_perf_probe_event(&entry->pev); 3618c2ecf20Sopenharmony_ci zfree(&entry->spev); 3628c2ecf20Sopenharmony_ci free(entry); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic struct probe_cache_entry * 3678c2ecf20Sopenharmony_ciprobe_cache_entry__new(struct perf_probe_event *pev) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct probe_cache_entry *entry = zalloc(sizeof(*entry)); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (entry) { 3728c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&entry->node); 3738c2ecf20Sopenharmony_ci entry->tevlist = strlist__new(NULL, NULL); 3748c2ecf20Sopenharmony_ci if (!entry->tevlist) 3758c2ecf20Sopenharmony_ci zfree(&entry); 3768c2ecf20Sopenharmony_ci else if (pev) { 3778c2ecf20Sopenharmony_ci entry->spev = synthesize_perf_probe_command(pev); 3788c2ecf20Sopenharmony_ci if (!entry->spev || 3798c2ecf20Sopenharmony_ci perf_probe_event__copy(&entry->pev, pev) < 0) { 3808c2ecf20Sopenharmony_ci probe_cache_entry__delete(entry); 3818c2ecf20Sopenharmony_ci return NULL; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return entry; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ciint probe_cache_entry__get_event(struct probe_cache_entry *entry, 3908c2ecf20Sopenharmony_ci struct probe_trace_event **tevs) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct probe_trace_event *tev; 3938c2ecf20Sopenharmony_ci struct str_node *node; 3948c2ecf20Sopenharmony_ci int ret, i; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ret = strlist__nr_entries(entry->tevlist); 3978c2ecf20Sopenharmony_ci if (ret > probe_conf.max_probes) 3988c2ecf20Sopenharmony_ci return -E2BIG; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci *tevs = zalloc(ret * sizeof(*tev)); 4018c2ecf20Sopenharmony_ci if (!*tevs) 4028c2ecf20Sopenharmony_ci return -ENOMEM; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci i = 0; 4058c2ecf20Sopenharmony_ci strlist__for_each_entry(node, entry->tevlist) { 4068c2ecf20Sopenharmony_ci tev = &(*tevs)[i++]; 4078c2ecf20Sopenharmony_ci ret = parse_probe_trace_command(node->s, tev); 4088c2ecf20Sopenharmony_ci if (ret < 0) 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci return i; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */ 4158c2ecf20Sopenharmony_cistatic int probe_cache__open(struct probe_cache *pcache, const char *target, 4168c2ecf20Sopenharmony_ci struct nsinfo *nsi) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci char cpath[PATH_MAX]; 4198c2ecf20Sopenharmony_ci char sbuildid[SBUILD_ID_SIZE]; 4208c2ecf20Sopenharmony_ci char *dir_name = NULL; 4218c2ecf20Sopenharmony_ci bool is_kallsyms = false; 4228c2ecf20Sopenharmony_ci int ret, fd; 4238c2ecf20Sopenharmony_ci struct nscookie nsc; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (target && build_id_cache__cached(target)) { 4268c2ecf20Sopenharmony_ci /* This is a cached buildid */ 4278c2ecf20Sopenharmony_ci strlcpy(sbuildid, target, SBUILD_ID_SIZE); 4288c2ecf20Sopenharmony_ci dir_name = build_id_cache__linkname(sbuildid, NULL, 0); 4298c2ecf20Sopenharmony_ci goto found; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) { 4338c2ecf20Sopenharmony_ci target = DSO__NAME_KALLSYMS; 4348c2ecf20Sopenharmony_ci is_kallsyms = true; 4358c2ecf20Sopenharmony_ci ret = sysfs__sprintf_build_id("/", sbuildid); 4368c2ecf20Sopenharmony_ci } else { 4378c2ecf20Sopenharmony_ci nsinfo__mountns_enter(nsi, &nsc); 4388c2ecf20Sopenharmony_ci ret = filename__sprintf_build_id(target, sbuildid); 4398c2ecf20Sopenharmony_ci nsinfo__mountns_exit(&nsc); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (ret < 0) { 4438c2ecf20Sopenharmony_ci pr_debug("Failed to get build-id from %s.\n", target); 4448c2ecf20Sopenharmony_ci return ret; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* If we have no buildid cache, make it */ 4488c2ecf20Sopenharmony_ci if (!build_id_cache__cached(sbuildid)) { 4498c2ecf20Sopenharmony_ci ret = build_id_cache__add_s(sbuildid, target, nsi, 4508c2ecf20Sopenharmony_ci is_kallsyms, NULL); 4518c2ecf20Sopenharmony_ci if (ret < 0) { 4528c2ecf20Sopenharmony_ci pr_debug("Failed to add build-id cache: %s\n", target); 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci dir_name = build_id_cache__cachedir(sbuildid, target, nsi, is_kallsyms, 4588c2ecf20Sopenharmony_ci false); 4598c2ecf20Sopenharmony_cifound: 4608c2ecf20Sopenharmony_ci if (!dir_name) { 4618c2ecf20Sopenharmony_ci pr_debug("Failed to get cache from %s\n", target); 4628c2ecf20Sopenharmony_ci return -ENOMEM; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci snprintf(cpath, PATH_MAX, "%s/probes", dir_name); 4668c2ecf20Sopenharmony_ci fd = open(cpath, O_CREAT | O_RDWR, 0644); 4678c2ecf20Sopenharmony_ci if (fd < 0) 4688c2ecf20Sopenharmony_ci pr_debug("Failed to open cache(%d): %s\n", fd, cpath); 4698c2ecf20Sopenharmony_ci free(dir_name); 4708c2ecf20Sopenharmony_ci pcache->fd = fd; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return fd; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int probe_cache__load(struct probe_cache *pcache) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct probe_cache_entry *entry = NULL; 4788c2ecf20Sopenharmony_ci char buf[MAX_CMDLEN], *p; 4798c2ecf20Sopenharmony_ci int ret = 0, fddup; 4808c2ecf20Sopenharmony_ci FILE *fp; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci fddup = dup(pcache->fd); 4838c2ecf20Sopenharmony_ci if (fddup < 0) 4848c2ecf20Sopenharmony_ci return -errno; 4858c2ecf20Sopenharmony_ci fp = fdopen(fddup, "r"); 4868c2ecf20Sopenharmony_ci if (!fp) { 4878c2ecf20Sopenharmony_ci close(fddup); 4888c2ecf20Sopenharmony_ci return -EINVAL; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci while (!feof(fp)) { 4928c2ecf20Sopenharmony_ci if (!fgets(buf, MAX_CMDLEN, fp)) 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci p = strchr(buf, '\n'); 4958c2ecf20Sopenharmony_ci if (p) 4968c2ecf20Sopenharmony_ci *p = '\0'; 4978c2ecf20Sopenharmony_ci /* #perf_probe_event or %sdt_event */ 4988c2ecf20Sopenharmony_ci if (buf[0] == '#' || buf[0] == '%') { 4998c2ecf20Sopenharmony_ci entry = probe_cache_entry__new(NULL); 5008c2ecf20Sopenharmony_ci if (!entry) { 5018c2ecf20Sopenharmony_ci ret = -ENOMEM; 5028c2ecf20Sopenharmony_ci goto out; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci if (buf[0] == '%') 5058c2ecf20Sopenharmony_ci entry->sdt = true; 5068c2ecf20Sopenharmony_ci entry->spev = strdup(buf + 1); 5078c2ecf20Sopenharmony_ci if (entry->spev) 5088c2ecf20Sopenharmony_ci ret = parse_perf_probe_command(buf + 1, 5098c2ecf20Sopenharmony_ci &entry->pev); 5108c2ecf20Sopenharmony_ci else 5118c2ecf20Sopenharmony_ci ret = -ENOMEM; 5128c2ecf20Sopenharmony_ci if (ret < 0) { 5138c2ecf20Sopenharmony_ci probe_cache_entry__delete(entry); 5148c2ecf20Sopenharmony_ci goto out; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci list_add_tail(&entry->node, &pcache->entries); 5178c2ecf20Sopenharmony_ci } else { /* trace_probe_event */ 5188c2ecf20Sopenharmony_ci if (!entry) { 5198c2ecf20Sopenharmony_ci ret = -EINVAL; 5208c2ecf20Sopenharmony_ci goto out; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci ret = strlist__add(entry->tevlist, buf); 5238c2ecf20Sopenharmony_ci if (ret == -ENOMEM) { 5248c2ecf20Sopenharmony_ci pr_err("strlist__add failed with -ENOMEM\n"); 5258c2ecf20Sopenharmony_ci goto out; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ciout: 5308c2ecf20Sopenharmony_ci fclose(fp); 5318c2ecf20Sopenharmony_ci return ret; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic struct probe_cache *probe_cache__alloc(void) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct probe_cache *pcache = zalloc(sizeof(*pcache)); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (pcache) { 5398c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pcache->entries); 5408c2ecf20Sopenharmony_ci pcache->fd = -EINVAL; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci return pcache; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_civoid probe_cache__purge(struct probe_cache *pcache) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct probe_cache_entry *entry, *n; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci list_for_each_entry_safe(entry, n, &pcache->entries, node) { 5508c2ecf20Sopenharmony_ci list_del_init(&entry->node); 5518c2ecf20Sopenharmony_ci probe_cache_entry__delete(entry); 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_civoid probe_cache__delete(struct probe_cache *pcache) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci if (!pcache) 5588c2ecf20Sopenharmony_ci return; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci probe_cache__purge(pcache); 5618c2ecf20Sopenharmony_ci if (pcache->fd > 0) 5628c2ecf20Sopenharmony_ci close(pcache->fd); 5638c2ecf20Sopenharmony_ci free(pcache); 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistruct probe_cache *probe_cache__new(const char *target, struct nsinfo *nsi) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct probe_cache *pcache = probe_cache__alloc(); 5698c2ecf20Sopenharmony_ci int ret; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (!pcache) 5728c2ecf20Sopenharmony_ci return NULL; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci ret = probe_cache__open(pcache, target, nsi); 5758c2ecf20Sopenharmony_ci if (ret < 0) { 5768c2ecf20Sopenharmony_ci pr_debug("Cache open error: %d\n", ret); 5778c2ecf20Sopenharmony_ci goto out_err; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci ret = probe_cache__load(pcache); 5818c2ecf20Sopenharmony_ci if (ret < 0) { 5828c2ecf20Sopenharmony_ci pr_debug("Cache read error: %d\n", ret); 5838c2ecf20Sopenharmony_ci goto out_err; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return pcache; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ciout_err: 5898c2ecf20Sopenharmony_ci probe_cache__delete(pcache); 5908c2ecf20Sopenharmony_ci return NULL; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic bool streql(const char *a, const char *b) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci if (a == b) 5968c2ecf20Sopenharmony_ci return true; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (!a || !b) 5998c2ecf20Sopenharmony_ci return false; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return !strcmp(a, b); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistruct probe_cache_entry * 6058c2ecf20Sopenharmony_ciprobe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct probe_cache_entry *entry = NULL; 6088c2ecf20Sopenharmony_ci char *cmd = synthesize_perf_probe_command(pev); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (!cmd) 6118c2ecf20Sopenharmony_ci return NULL; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci for_each_probe_cache_entry(entry, pcache) { 6148c2ecf20Sopenharmony_ci if (pev->sdt) { 6158c2ecf20Sopenharmony_ci if (entry->pev.event && 6168c2ecf20Sopenharmony_ci streql(entry->pev.event, pev->event) && 6178c2ecf20Sopenharmony_ci (!pev->group || 6188c2ecf20Sopenharmony_ci streql(entry->pev.group, pev->group))) 6198c2ecf20Sopenharmony_ci goto found; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci continue; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci /* Hit if same event name or same command-string */ 6248c2ecf20Sopenharmony_ci if ((pev->event && 6258c2ecf20Sopenharmony_ci (streql(entry->pev.group, pev->group) && 6268c2ecf20Sopenharmony_ci streql(entry->pev.event, pev->event))) || 6278c2ecf20Sopenharmony_ci (!strcmp(entry->spev, cmd))) 6288c2ecf20Sopenharmony_ci goto found; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci entry = NULL; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cifound: 6338c2ecf20Sopenharmony_ci free(cmd); 6348c2ecf20Sopenharmony_ci return entry; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistruct probe_cache_entry * 6388c2ecf20Sopenharmony_ciprobe_cache__find_by_name(struct probe_cache *pcache, 6398c2ecf20Sopenharmony_ci const char *group, const char *event) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct probe_cache_entry *entry = NULL; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci for_each_probe_cache_entry(entry, pcache) { 6448c2ecf20Sopenharmony_ci /* Hit if same event name or same command-string */ 6458c2ecf20Sopenharmony_ci if (streql(entry->pev.group, group) && 6468c2ecf20Sopenharmony_ci streql(entry->pev.event, event)) 6478c2ecf20Sopenharmony_ci goto found; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci entry = NULL; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cifound: 6528c2ecf20Sopenharmony_ci return entry; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ciint probe_cache__add_entry(struct probe_cache *pcache, 6568c2ecf20Sopenharmony_ci struct perf_probe_event *pev, 6578c2ecf20Sopenharmony_ci struct probe_trace_event *tevs, int ntevs) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct probe_cache_entry *entry = NULL; 6608c2ecf20Sopenharmony_ci char *command; 6618c2ecf20Sopenharmony_ci int i, ret = 0; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (!pcache || !pev || !tevs || ntevs <= 0) { 6648c2ecf20Sopenharmony_ci ret = -EINVAL; 6658c2ecf20Sopenharmony_ci goto out_err; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* Remove old cache entry */ 6698c2ecf20Sopenharmony_ci entry = probe_cache__find(pcache, pev); 6708c2ecf20Sopenharmony_ci if (entry) { 6718c2ecf20Sopenharmony_ci list_del_init(&entry->node); 6728c2ecf20Sopenharmony_ci probe_cache_entry__delete(entry); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci ret = -ENOMEM; 6768c2ecf20Sopenharmony_ci entry = probe_cache_entry__new(pev); 6778c2ecf20Sopenharmony_ci if (!entry) 6788c2ecf20Sopenharmony_ci goto out_err; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci for (i = 0; i < ntevs; i++) { 6818c2ecf20Sopenharmony_ci if (!tevs[i].point.symbol) 6828c2ecf20Sopenharmony_ci continue; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci command = synthesize_probe_trace_command(&tevs[i]); 6858c2ecf20Sopenharmony_ci if (!command) 6868c2ecf20Sopenharmony_ci goto out_err; 6878c2ecf20Sopenharmony_ci ret = strlist__add(entry->tevlist, command); 6888c2ecf20Sopenharmony_ci if (ret == -ENOMEM) { 6898c2ecf20Sopenharmony_ci pr_err("strlist__add failed with -ENOMEM\n"); 6908c2ecf20Sopenharmony_ci goto out_err; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci free(command); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci list_add_tail(&entry->node, &pcache->entries); 6968c2ecf20Sopenharmony_ci pr_debug("Added probe cache: %d\n", ntevs); 6978c2ecf20Sopenharmony_ci return 0; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ciout_err: 7008c2ecf20Sopenharmony_ci pr_debug("Failed to add probe caches\n"); 7018c2ecf20Sopenharmony_ci probe_cache_entry__delete(entry); 7028c2ecf20Sopenharmony_ci return ret; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci#ifdef HAVE_GELF_GETNOTE_SUPPORT 7068c2ecf20Sopenharmony_cistatic unsigned long long sdt_note__get_addr(struct sdt_note *note) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci return note->bit32 ? 7098c2ecf20Sopenharmony_ci (unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] : 7108c2ecf20Sopenharmony_ci (unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC]; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci return note->bit32 ? 7168c2ecf20Sopenharmony_ci (unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] : 7178c2ecf20Sopenharmony_ci (unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR]; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic const char * const type_to_suffix[] = { 7218c2ecf20Sopenharmony_ci ":s64", "", "", "", ":s32", "", ":s16", ":s8", 7228c2ecf20Sopenharmony_ci "", ":u8", ":u16", "", ":u32", "", "", "", ":u64" 7238c2ecf20Sopenharmony_ci}; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci/* 7268c2ecf20Sopenharmony_ci * Isolate the string number and convert it into a decimal value; 7278c2ecf20Sopenharmony_ci * this will be an index to get suffix of the uprobe name (defining 7288c2ecf20Sopenharmony_ci * the type) 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_cistatic int sdt_arg_parse_size(char *n_ptr, const char **suffix) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci long type_idx; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci type_idx = strtol(n_ptr, NULL, 10); 7358c2ecf20Sopenharmony_ci if (type_idx < -8 || type_idx > 8) { 7368c2ecf20Sopenharmony_ci pr_debug4("Failed to get a valid sdt type\n"); 7378c2ecf20Sopenharmony_ci return -1; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci *suffix = type_to_suffix[type_idx + 8]; 7418c2ecf20Sopenharmony_ci return 0; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci char *op, *desc = strdup(arg), *new_op = NULL; 7478c2ecf20Sopenharmony_ci const char *suffix = ""; 7488c2ecf20Sopenharmony_ci int ret = -1; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (desc == NULL) { 7518c2ecf20Sopenharmony_ci pr_debug4("Allocation error\n"); 7528c2ecf20Sopenharmony_ci return ret; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* 7568c2ecf20Sopenharmony_ci * Argument is in N@OP format. N is size of the argument and OP is 7578c2ecf20Sopenharmony_ci * the actual assembly operand. N can be omitted; in that case 7588c2ecf20Sopenharmony_ci * argument is just OP(without @). 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ci op = strchr(desc, '@'); 7618c2ecf20Sopenharmony_ci if (op) { 7628c2ecf20Sopenharmony_ci op[0] = '\0'; 7638c2ecf20Sopenharmony_ci op++; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (sdt_arg_parse_size(desc, &suffix)) 7668c2ecf20Sopenharmony_ci goto error; 7678c2ecf20Sopenharmony_ci } else { 7688c2ecf20Sopenharmony_ci op = desc; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci ret = arch_sdt_arg_parse_op(op, &new_op); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (ret < 0) 7748c2ecf20Sopenharmony_ci goto error; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (ret == SDT_ARG_VALID) { 7778c2ecf20Sopenharmony_ci ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix); 7788c2ecf20Sopenharmony_ci if (ret < 0) 7798c2ecf20Sopenharmony_ci goto error; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci ret = 0; 7838c2ecf20Sopenharmony_cierror: 7848c2ecf20Sopenharmony_ci free(desc); 7858c2ecf20Sopenharmony_ci free(new_op); 7868c2ecf20Sopenharmony_ci return ret; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic char *synthesize_sdt_probe_command(struct sdt_note *note, 7908c2ecf20Sopenharmony_ci const char *pathname, 7918c2ecf20Sopenharmony_ci const char *sdtgrp) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci struct strbuf buf; 7948c2ecf20Sopenharmony_ci char *ret = NULL; 7958c2ecf20Sopenharmony_ci int i, args_count, err; 7968c2ecf20Sopenharmony_ci unsigned long long ref_ctr_offset; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (strbuf_init(&buf, 32) < 0) 7998c2ecf20Sopenharmony_ci return NULL; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx", 8028c2ecf20Sopenharmony_ci sdtgrp, note->name, pathname, 8038c2ecf20Sopenharmony_ci sdt_note__get_addr(note)); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci ref_ctr_offset = sdt_note__get_ref_ctr_offset(note); 8068c2ecf20Sopenharmony_ci if (ref_ctr_offset && err >= 0) 8078c2ecf20Sopenharmony_ci err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (err < 0) 8108c2ecf20Sopenharmony_ci goto error; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (!note->args) 8138c2ecf20Sopenharmony_ci goto out; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (note->args) { 8168c2ecf20Sopenharmony_ci char **args = argv_split(note->args, &args_count); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (args == NULL) 8198c2ecf20Sopenharmony_ci goto error; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci for (i = 0; i < args_count; ++i) { 8228c2ecf20Sopenharmony_ci if (synthesize_sdt_probe_arg(&buf, i, args[i]) < 0) { 8238c2ecf20Sopenharmony_ci argv_free(args); 8248c2ecf20Sopenharmony_ci goto error; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci argv_free(args); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ciout: 8328c2ecf20Sopenharmony_ci ret = strbuf_detach(&buf, NULL); 8338c2ecf20Sopenharmony_cierror: 8348c2ecf20Sopenharmony_ci strbuf_release(&buf); 8358c2ecf20Sopenharmony_ci return ret; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ciint probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci struct probe_cache_entry *entry = NULL; 8418c2ecf20Sopenharmony_ci struct list_head sdtlist; 8428c2ecf20Sopenharmony_ci struct sdt_note *note; 8438c2ecf20Sopenharmony_ci char *buf; 8448c2ecf20Sopenharmony_ci char sdtgrp[64]; 8458c2ecf20Sopenharmony_ci int ret; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sdtlist); 8488c2ecf20Sopenharmony_ci ret = get_sdt_note_list(&sdtlist, pathname); 8498c2ecf20Sopenharmony_ci if (ret < 0) { 8508c2ecf20Sopenharmony_ci pr_debug4("Failed to get sdt note: %d\n", ret); 8518c2ecf20Sopenharmony_ci return ret; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci list_for_each_entry(note, &sdtlist, note_list) { 8548c2ecf20Sopenharmony_ci ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider); 8558c2ecf20Sopenharmony_ci if (ret < 0) 8568c2ecf20Sopenharmony_ci break; 8578c2ecf20Sopenharmony_ci /* Try to find same-name entry */ 8588c2ecf20Sopenharmony_ci entry = probe_cache__find_by_name(pcache, sdtgrp, note->name); 8598c2ecf20Sopenharmony_ci if (!entry) { 8608c2ecf20Sopenharmony_ci entry = probe_cache_entry__new(NULL); 8618c2ecf20Sopenharmony_ci if (!entry) { 8628c2ecf20Sopenharmony_ci ret = -ENOMEM; 8638c2ecf20Sopenharmony_ci break; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci entry->sdt = true; 8668c2ecf20Sopenharmony_ci ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp, 8678c2ecf20Sopenharmony_ci note->name, note->name); 8688c2ecf20Sopenharmony_ci if (ret < 0) 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci entry->pev.event = strdup(note->name); 8718c2ecf20Sopenharmony_ci entry->pev.group = strdup(sdtgrp); 8728c2ecf20Sopenharmony_ci list_add_tail(&entry->node, &pcache->entries); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci buf = synthesize_sdt_probe_command(note, pathname, sdtgrp); 8758c2ecf20Sopenharmony_ci if (!buf) { 8768c2ecf20Sopenharmony_ci ret = -ENOMEM; 8778c2ecf20Sopenharmony_ci break; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci ret = strlist__add(entry->tevlist, buf); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci free(buf); 8838c2ecf20Sopenharmony_ci entry = NULL; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (ret == -ENOMEM) { 8868c2ecf20Sopenharmony_ci pr_err("strlist__add failed with -ENOMEM\n"); 8878c2ecf20Sopenharmony_ci break; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci if (entry) { 8918c2ecf20Sopenharmony_ci list_del_init(&entry->node); 8928c2ecf20Sopenharmony_ci probe_cache_entry__delete(entry); 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci cleanup_sdt_note_list(&sdtlist); 8958c2ecf20Sopenharmony_ci return ret; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci#endif 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci struct str_node *snode; 9028c2ecf20Sopenharmony_ci struct stat st; 9038c2ecf20Sopenharmony_ci struct iovec iov[3]; 9048c2ecf20Sopenharmony_ci const char *prefix = entry->sdt ? "%" : "#"; 9058c2ecf20Sopenharmony_ci int ret; 9068c2ecf20Sopenharmony_ci /* Save stat for rollback */ 9078c2ecf20Sopenharmony_ci ret = fstat(fd, &st); 9088c2ecf20Sopenharmony_ci if (ret < 0) 9098c2ecf20Sopenharmony_ci return ret; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci pr_debug("Writing cache: %s%s\n", prefix, entry->spev); 9128c2ecf20Sopenharmony_ci iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1; 9138c2ecf20Sopenharmony_ci iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev); 9148c2ecf20Sopenharmony_ci iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1; 9158c2ecf20Sopenharmony_ci ret = writev(fd, iov, 3); 9168c2ecf20Sopenharmony_ci if (ret < (int)iov[1].iov_len + 2) 9178c2ecf20Sopenharmony_ci goto rollback; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci strlist__for_each_entry(snode, entry->tevlist) { 9208c2ecf20Sopenharmony_ci iov[0].iov_base = (void *)snode->s; 9218c2ecf20Sopenharmony_ci iov[0].iov_len = strlen(snode->s); 9228c2ecf20Sopenharmony_ci iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1; 9238c2ecf20Sopenharmony_ci ret = writev(fd, iov, 2); 9248c2ecf20Sopenharmony_ci if (ret < (int)iov[0].iov_len + 1) 9258c2ecf20Sopenharmony_ci goto rollback; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci return 0; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cirollback: 9308c2ecf20Sopenharmony_ci /* Rollback to avoid cache file corruption */ 9318c2ecf20Sopenharmony_ci if (ret > 0) 9328c2ecf20Sopenharmony_ci ret = -1; 9338c2ecf20Sopenharmony_ci if (ftruncate(fd, st.st_size) < 0) 9348c2ecf20Sopenharmony_ci ret = -2; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci return ret; 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ciint probe_cache__commit(struct probe_cache *pcache) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci struct probe_cache_entry *entry; 9428c2ecf20Sopenharmony_ci int ret = 0; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* TBD: if we do not update existing entries, skip it */ 9458c2ecf20Sopenharmony_ci ret = lseek(pcache->fd, 0, SEEK_SET); 9468c2ecf20Sopenharmony_ci if (ret < 0) 9478c2ecf20Sopenharmony_ci goto out; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci ret = ftruncate(pcache->fd, 0); 9508c2ecf20Sopenharmony_ci if (ret < 0) 9518c2ecf20Sopenharmony_ci goto out; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci for_each_probe_cache_entry(entry, pcache) { 9548c2ecf20Sopenharmony_ci ret = probe_cache_entry__write(entry, pcache->fd); 9558c2ecf20Sopenharmony_ci pr_debug("Cache committed: %d\n", ret); 9568c2ecf20Sopenharmony_ci if (ret < 0) 9578c2ecf20Sopenharmony_ci break; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ciout: 9608c2ecf20Sopenharmony_ci return ret; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic bool probe_cache_entry__compare(struct probe_cache_entry *entry, 9648c2ecf20Sopenharmony_ci struct strfilter *filter) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci char buf[128], *ptr = entry->spev; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (entry->pev.event) { 9698c2ecf20Sopenharmony_ci snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event); 9708c2ecf20Sopenharmony_ci ptr = buf; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci return strfilter__compare(filter, ptr); 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ciint probe_cache__filter_purge(struct probe_cache *pcache, 9768c2ecf20Sopenharmony_ci struct strfilter *filter) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci struct probe_cache_entry *entry, *tmp; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &pcache->entries, node) { 9818c2ecf20Sopenharmony_ci if (probe_cache_entry__compare(entry, filter)) { 9828c2ecf20Sopenharmony_ci pr_info("Removed cached event: %s\n", entry->spev); 9838c2ecf20Sopenharmony_ci list_del_init(&entry->node); 9848c2ecf20Sopenharmony_ci probe_cache_entry__delete(entry); 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci return 0; 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic int probe_cache__show_entries(struct probe_cache *pcache, 9918c2ecf20Sopenharmony_ci struct strfilter *filter) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci struct probe_cache_entry *entry; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci for_each_probe_cache_entry(entry, pcache) { 9968c2ecf20Sopenharmony_ci if (probe_cache_entry__compare(entry, filter)) 9978c2ecf20Sopenharmony_ci printf("%s\n", entry->spev); 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci return 0; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci/* Show all cached probes */ 10038c2ecf20Sopenharmony_ciint probe_cache__show_all_caches(struct strfilter *filter) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci struct probe_cache *pcache; 10068c2ecf20Sopenharmony_ci struct strlist *bidlist; 10078c2ecf20Sopenharmony_ci struct str_node *nd; 10088c2ecf20Sopenharmony_ci char *buf = strfilter__string(filter); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci pr_debug("list cache with filter: %s\n", buf); 10118c2ecf20Sopenharmony_ci free(buf); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci bidlist = build_id_cache__list_all(true); 10148c2ecf20Sopenharmony_ci if (!bidlist) { 10158c2ecf20Sopenharmony_ci pr_debug("Failed to get buildids: %d\n", errno); 10168c2ecf20Sopenharmony_ci return -EINVAL; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci strlist__for_each_entry(nd, bidlist) { 10198c2ecf20Sopenharmony_ci pcache = probe_cache__new(nd->s, NULL); 10208c2ecf20Sopenharmony_ci if (!pcache) 10218c2ecf20Sopenharmony_ci continue; 10228c2ecf20Sopenharmony_ci if (!list_empty(&pcache->entries)) { 10238c2ecf20Sopenharmony_ci buf = build_id_cache__origname(nd->s); 10248c2ecf20Sopenharmony_ci printf("%s (%s):\n", buf, nd->s); 10258c2ecf20Sopenharmony_ci free(buf); 10268c2ecf20Sopenharmony_ci probe_cache__show_entries(pcache, filter); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci probe_cache__delete(pcache); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci strlist__delete(bidlist); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cienum ftrace_readme { 10368c2ecf20Sopenharmony_ci FTRACE_README_PROBE_TYPE_X = 0, 10378c2ecf20Sopenharmony_ci FTRACE_README_KRETPROBE_OFFSET, 10388c2ecf20Sopenharmony_ci FTRACE_README_UPROBE_REF_CTR, 10398c2ecf20Sopenharmony_ci FTRACE_README_USER_ACCESS, 10408c2ecf20Sopenharmony_ci FTRACE_README_MULTIPROBE_EVENT, 10418c2ecf20Sopenharmony_ci FTRACE_README_IMMEDIATE_VALUE, 10428c2ecf20Sopenharmony_ci FTRACE_README_END, 10438c2ecf20Sopenharmony_ci}; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic struct { 10468c2ecf20Sopenharmony_ci const char *pattern; 10478c2ecf20Sopenharmony_ci bool avail; 10488c2ecf20Sopenharmony_ci} ftrace_readme_table[] = { 10498c2ecf20Sopenharmony_ci#define DEFINE_TYPE(idx, pat) \ 10508c2ecf20Sopenharmony_ci [idx] = {.pattern = pat, .avail = false} 10518c2ecf20Sopenharmony_ci DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"), 10528c2ecf20Sopenharmony_ci DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"), 10538c2ecf20Sopenharmony_ci DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"), 10548c2ecf20Sopenharmony_ci DEFINE_TYPE(FTRACE_README_USER_ACCESS, "*u]<offset>*"), 10558c2ecf20Sopenharmony_ci DEFINE_TYPE(FTRACE_README_MULTIPROBE_EVENT, "*Create/append/*"), 10568c2ecf20Sopenharmony_ci DEFINE_TYPE(FTRACE_README_IMMEDIATE_VALUE, "*\\imm-value,*"), 10578c2ecf20Sopenharmony_ci}; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic bool scan_ftrace_readme(enum ftrace_readme type) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci int fd; 10628c2ecf20Sopenharmony_ci FILE *fp; 10638c2ecf20Sopenharmony_ci char *buf = NULL; 10648c2ecf20Sopenharmony_ci size_t len = 0; 10658c2ecf20Sopenharmony_ci bool ret = false; 10668c2ecf20Sopenharmony_ci static bool scanned = false; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (scanned) 10698c2ecf20Sopenharmony_ci goto result; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci fd = open_trace_file("README", false); 10728c2ecf20Sopenharmony_ci if (fd < 0) 10738c2ecf20Sopenharmony_ci return ret; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci fp = fdopen(fd, "r"); 10768c2ecf20Sopenharmony_ci if (!fp) { 10778c2ecf20Sopenharmony_ci close(fd); 10788c2ecf20Sopenharmony_ci return ret; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci while (getline(&buf, &len, fp) > 0) 10828c2ecf20Sopenharmony_ci for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++) 10838c2ecf20Sopenharmony_ci if (!ftrace_readme_table[i].avail) 10848c2ecf20Sopenharmony_ci ftrace_readme_table[i].avail = 10858c2ecf20Sopenharmony_ci strglobmatch(buf, ftrace_readme_table[i].pattern); 10868c2ecf20Sopenharmony_ci scanned = true; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci fclose(fp); 10898c2ecf20Sopenharmony_ci free(buf); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ciresult: 10928c2ecf20Sopenharmony_ci if (type >= FTRACE_README_END) 10938c2ecf20Sopenharmony_ci return false; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return ftrace_readme_table[type].avail; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cibool probe_type_is_available(enum probe_type type) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci if (type >= PROBE_TYPE_END) 11018c2ecf20Sopenharmony_ci return false; 11028c2ecf20Sopenharmony_ci else if (type == PROBE_TYPE_X) 11038c2ecf20Sopenharmony_ci return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci return true; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cibool kretprobe_offset_is_supported(void) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET); 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cibool uprobe_ref_ctr_is_supported(void) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR); 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cibool user_access_is_supported(void) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci return scan_ftrace_readme(FTRACE_README_USER_ACCESS); 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cibool multiprobe_event_is_supported(void) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci return scan_ftrace_readme(FTRACE_README_MULTIPROBE_EVENT); 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cibool immediate_value_is_supported(void) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci return scan_ftrace_readme(FTRACE_README_IMMEDIATE_VALUE); 11318c2ecf20Sopenharmony_ci} 1132