1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
292f6c72eSMasami Hiramatsu /*
392f6c72eSMasami Hiramatsu * probe-file.c : operate ftrace k/uprobe events files
492f6c72eSMasami Hiramatsu *
592f6c72eSMasami Hiramatsu * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
692f6c72eSMasami Hiramatsu */
7a43783aeSArnaldo Carvalho de Melo #include <errno.h>
8c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h>
97a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h>
107a8ef4c4SArnaldo Carvalho de Melo #include <sys/types.h>
11dd975497SMasami Hiramatsu #include <sys/uio.h>
127a8ef4c4SArnaldo Carvalho de Melo #include <unistd.h>
137f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
1440f3b2d2SArnaldo Carvalho de Melo #include "namespaces.h"
1592f6c72eSMasami Hiramatsu #include "event.h"
1692f6c72eSMasami Hiramatsu #include "strlist.h"
178ec20b17SArnaldo Carvalho de Melo #include "strfilter.h"
1892f6c72eSMasami Hiramatsu #include "debug.h"
1936f3f450SArnaldo Carvalho de Melo #include "build-id.h"
20fac583fdSArnaldo Carvalho de Melo #include "dso.h"
2192f6c72eSMasami Hiramatsu #include "color.h"
2292f6c72eSMasami Hiramatsu #include "symbol.h"
23fa0d9846SArnaldo Carvalho de Melo #include "strbuf.h"
24fbf99625SJiri Olsa #include <api/fs/tracing_path.h>
250808b3d5SMasami Hiramatsu #include <api/fs/fs.h>
2692f6c72eSMasami Hiramatsu #include "probe-event.h"
2792f6c72eSMasami Hiramatsu #include "probe-file.h"
2892f6c72eSMasami Hiramatsu #include "session.h"
293b1f8311SAlexis Berlemont #include "perf_regs.h"
30a067558eSArnaldo Carvalho de Melo #include "string2.h"
3192f6c72eSMasami Hiramatsu
322e1f8f78SRavi Bangoria /* 4096 - 2 ('\n' + '\0') */
332e1f8f78SRavi Bangoria #define MAX_CMDLEN 4094
3492f6c72eSMasami Hiramatsu
print_common_warning(int err,bool readwrite)350808b3d5SMasami Hiramatsu static bool print_common_warning(int err, bool readwrite)
360808b3d5SMasami Hiramatsu {
370808b3d5SMasami Hiramatsu if (err == -EACCES)
380808b3d5SMasami Hiramatsu pr_warning("No permission to %s tracefs.\nPlease %s\n",
390808b3d5SMasami Hiramatsu readwrite ? "write" : "read",
400808b3d5SMasami Hiramatsu readwrite ? "run this command again with sudo." :
410808b3d5SMasami Hiramatsu "try 'sudo mount -o remount,mode=755 /sys/kernel/tracing/'");
420808b3d5SMasami Hiramatsu else
430808b3d5SMasami Hiramatsu return false;
440808b3d5SMasami Hiramatsu
450808b3d5SMasami Hiramatsu return true;
460808b3d5SMasami Hiramatsu }
470808b3d5SMasami Hiramatsu
print_configure_probe_event(int kerr,int uerr)480808b3d5SMasami Hiramatsu static bool print_configure_probe_event(int kerr, int uerr)
490808b3d5SMasami Hiramatsu {
500808b3d5SMasami Hiramatsu const char *config, *file;
510808b3d5SMasami Hiramatsu
520808b3d5SMasami Hiramatsu if (kerr == -ENOENT && uerr == -ENOENT) {
530808b3d5SMasami Hiramatsu file = "{k,u}probe_events";
540808b3d5SMasami Hiramatsu config = "CONFIG_KPROBE_EVENTS=y and CONFIG_UPROBE_EVENTS=y";
550808b3d5SMasami Hiramatsu } else if (kerr == -ENOENT) {
560808b3d5SMasami Hiramatsu file = "kprobe_events";
570808b3d5SMasami Hiramatsu config = "CONFIG_KPROBE_EVENTS=y";
580808b3d5SMasami Hiramatsu } else if (uerr == -ENOENT) {
590808b3d5SMasami Hiramatsu file = "uprobe_events";
600808b3d5SMasami Hiramatsu config = "CONFIG_UPROBE_EVENTS=y";
610808b3d5SMasami Hiramatsu } else
620808b3d5SMasami Hiramatsu return false;
630808b3d5SMasami Hiramatsu
640808b3d5SMasami Hiramatsu if (!debugfs__configured() && !tracefs__configured())
650808b3d5SMasami Hiramatsu pr_warning("Debugfs or tracefs is not mounted\n"
660808b3d5SMasami Hiramatsu "Please try 'sudo mount -t tracefs nodev /sys/kernel/tracing/'\n");
670808b3d5SMasami Hiramatsu else
680808b3d5SMasami Hiramatsu pr_warning("%s/%s does not exist.\nPlease rebuild kernel with %s.\n",
690808b3d5SMasami Hiramatsu tracing_path_mount(), file, config);
700808b3d5SMasami Hiramatsu
710808b3d5SMasami Hiramatsu return true;
720808b3d5SMasami Hiramatsu }
730808b3d5SMasami Hiramatsu
print_open_warning(int err,bool uprobe,bool readwrite)740808b3d5SMasami Hiramatsu static void print_open_warning(int err, bool uprobe, bool readwrite)
7592f6c72eSMasami Hiramatsu {
7692f6c72eSMasami Hiramatsu char sbuf[STRERR_BUFSIZE];
7792f6c72eSMasami Hiramatsu
780808b3d5SMasami Hiramatsu if (print_common_warning(err, readwrite))
790808b3d5SMasami Hiramatsu return;
8092f6c72eSMasami Hiramatsu
810808b3d5SMasami Hiramatsu if (print_configure_probe_event(uprobe ? 0 : err, uprobe ? err : 0))
820808b3d5SMasami Hiramatsu return;
8392f6c72eSMasami Hiramatsu
840808b3d5SMasami Hiramatsu pr_warning("Failed to open %s/%cprobe_events: %s\n",
850808b3d5SMasami Hiramatsu tracing_path_mount(), uprobe ? 'u' : 'k',
86c8b5f2c9SArnaldo Carvalho de Melo str_error_r(-err, sbuf, sizeof(sbuf)));
8792f6c72eSMasami Hiramatsu }
8892f6c72eSMasami Hiramatsu
print_both_open_warning(int kerr,int uerr,bool readwrite)890808b3d5SMasami Hiramatsu static void print_both_open_warning(int kerr, int uerr, bool readwrite)
9092f6c72eSMasami Hiramatsu {
9192f6c72eSMasami Hiramatsu char sbuf[STRERR_BUFSIZE];
920808b3d5SMasami Hiramatsu
930808b3d5SMasami Hiramatsu if (kerr == uerr && print_common_warning(kerr, readwrite))
940808b3d5SMasami Hiramatsu return;
950808b3d5SMasami Hiramatsu
960808b3d5SMasami Hiramatsu if (print_configure_probe_event(kerr, uerr))
970808b3d5SMasami Hiramatsu return;
980808b3d5SMasami Hiramatsu
990808b3d5SMasami Hiramatsu if (kerr < 0)
1000808b3d5SMasami Hiramatsu pr_warning("Failed to open %s/kprobe_events: %s.\n",
1010808b3d5SMasami Hiramatsu tracing_path_mount(),
102c8b5f2c9SArnaldo Carvalho de Melo str_error_r(-kerr, sbuf, sizeof(sbuf)));
1030808b3d5SMasami Hiramatsu if (uerr < 0)
1040808b3d5SMasami Hiramatsu pr_warning("Failed to open %s/uprobe_events: %s.\n",
1050808b3d5SMasami Hiramatsu tracing_path_mount(),
106c8b5f2c9SArnaldo Carvalho de Melo str_error_r(-uerr, sbuf, sizeof(sbuf)));
10792f6c72eSMasami Hiramatsu }
10892f6c72eSMasami Hiramatsu
open_trace_file(const char * trace_file,bool readwrite)109e491bc2fSNaveen N. Rao int open_trace_file(const char *trace_file, bool readwrite)
11092f6c72eSMasami Hiramatsu {
11192f6c72eSMasami Hiramatsu char buf[PATH_MAX];
11292f6c72eSMasami Hiramatsu int ret;
11392f6c72eSMasami Hiramatsu
11417c257e8SArnaldo Carvalho de Melo ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file);
11592f6c72eSMasami Hiramatsu if (ret >= 0) {
11692f6c72eSMasami Hiramatsu pr_debug("Opening %s write=%d\n", buf, readwrite);
11792f6c72eSMasami Hiramatsu if (readwrite && !probe_event_dry_run)
11892f6c72eSMasami Hiramatsu ret = open(buf, O_RDWR | O_APPEND, 0);
11992f6c72eSMasami Hiramatsu else
12092f6c72eSMasami Hiramatsu ret = open(buf, O_RDONLY, 0);
12192f6c72eSMasami Hiramatsu
12292f6c72eSMasami Hiramatsu if (ret < 0)
12392f6c72eSMasami Hiramatsu ret = -errno;
12492f6c72eSMasami Hiramatsu }
12592f6c72eSMasami Hiramatsu return ret;
12692f6c72eSMasami Hiramatsu }
12792f6c72eSMasami Hiramatsu
open_kprobe_events(bool readwrite)12892f6c72eSMasami Hiramatsu static int open_kprobe_events(bool readwrite)
12992f6c72eSMasami Hiramatsu {
130e491bc2fSNaveen N. Rao return open_trace_file("kprobe_events", readwrite);
13192f6c72eSMasami Hiramatsu }
13292f6c72eSMasami Hiramatsu
open_uprobe_events(bool readwrite)13392f6c72eSMasami Hiramatsu static int open_uprobe_events(bool readwrite)
13492f6c72eSMasami Hiramatsu {
135e491bc2fSNaveen N. Rao return open_trace_file("uprobe_events", readwrite);
13692f6c72eSMasami Hiramatsu }
13792f6c72eSMasami Hiramatsu
probe_file__open(int flag)13892f6c72eSMasami Hiramatsu int probe_file__open(int flag)
13992f6c72eSMasami Hiramatsu {
14092f6c72eSMasami Hiramatsu int fd;
14192f6c72eSMasami Hiramatsu
14292f6c72eSMasami Hiramatsu if (flag & PF_FL_UPROBE)
14392f6c72eSMasami Hiramatsu fd = open_uprobe_events(flag & PF_FL_RW);
14492f6c72eSMasami Hiramatsu else
14592f6c72eSMasami Hiramatsu fd = open_kprobe_events(flag & PF_FL_RW);
14692f6c72eSMasami Hiramatsu if (fd < 0)
1470808b3d5SMasami Hiramatsu print_open_warning(fd, flag & PF_FL_UPROBE, flag & PF_FL_RW);
14892f6c72eSMasami Hiramatsu
14992f6c72eSMasami Hiramatsu return fd;
15092f6c72eSMasami Hiramatsu }
15192f6c72eSMasami Hiramatsu
probe_file__open_both(int * kfd,int * ufd,int flag)15292f6c72eSMasami Hiramatsu int probe_file__open_both(int *kfd, int *ufd, int flag)
15392f6c72eSMasami Hiramatsu {
15492f6c72eSMasami Hiramatsu if (!kfd || !ufd)
15592f6c72eSMasami Hiramatsu return -EINVAL;
15692f6c72eSMasami Hiramatsu
15792f6c72eSMasami Hiramatsu *kfd = open_kprobe_events(flag & PF_FL_RW);
15892f6c72eSMasami Hiramatsu *ufd = open_uprobe_events(flag & PF_FL_RW);
15992f6c72eSMasami Hiramatsu if (*kfd < 0 && *ufd < 0) {
1600808b3d5SMasami Hiramatsu print_both_open_warning(*kfd, *ufd, flag & PF_FL_RW);
16192f6c72eSMasami Hiramatsu return *kfd;
16292f6c72eSMasami Hiramatsu }
16392f6c72eSMasami Hiramatsu
16492f6c72eSMasami Hiramatsu return 0;
16592f6c72eSMasami Hiramatsu }
16692f6c72eSMasami Hiramatsu
16792f6c72eSMasami Hiramatsu /* Get raw string list of current kprobe_events or uprobe_events */
probe_file__get_rawlist(int fd)16892f6c72eSMasami Hiramatsu struct strlist *probe_file__get_rawlist(int fd)
16992f6c72eSMasami Hiramatsu {
1700325862dSColin Ian King int ret, idx, fddup;
17192f6c72eSMasami Hiramatsu FILE *fp;
17292f6c72eSMasami Hiramatsu char buf[MAX_CMDLEN];
17392f6c72eSMasami Hiramatsu char *p;
17492f6c72eSMasami Hiramatsu struct strlist *sl;
17592f6c72eSMasami Hiramatsu
176421fd084SWang Nan if (fd < 0)
177421fd084SWang Nan return NULL;
178421fd084SWang Nan
17992f6c72eSMasami Hiramatsu sl = strlist__new(NULL, NULL);
18060ebc159SArnaldo Carvalho de Melo if (sl == NULL)
18160ebc159SArnaldo Carvalho de Melo return NULL;
18292f6c72eSMasami Hiramatsu
1830325862dSColin Ian King fddup = dup(fd);
1840325862dSColin Ian King if (fddup < 0)
1850325862dSColin Ian King goto out_free_sl;
1860325862dSColin Ian King
1870325862dSColin Ian King fp = fdopen(fddup, "r");
1880325862dSColin Ian King if (!fp)
1890325862dSColin Ian King goto out_close_fddup;
1900325862dSColin Ian King
19192f6c72eSMasami Hiramatsu while (!feof(fp)) {
19292f6c72eSMasami Hiramatsu p = fgets(buf, MAX_CMDLEN, fp);
19392f6c72eSMasami Hiramatsu if (!p)
19492f6c72eSMasami Hiramatsu break;
19592f6c72eSMasami Hiramatsu
19692f6c72eSMasami Hiramatsu idx = strlen(p) - 1;
19792f6c72eSMasami Hiramatsu if (p[idx] == '\n')
19892f6c72eSMasami Hiramatsu p[idx] = '\0';
19992f6c72eSMasami Hiramatsu ret = strlist__add(sl, buf);
20092f6c72eSMasami Hiramatsu if (ret < 0) {
20192f6c72eSMasami Hiramatsu pr_debug("strlist__add failed (%d)\n", ret);
20260ebc159SArnaldo Carvalho de Melo goto out_close_fp;
20392f6c72eSMasami Hiramatsu }
20492f6c72eSMasami Hiramatsu }
20592f6c72eSMasami Hiramatsu fclose(fp);
20692f6c72eSMasami Hiramatsu
20792f6c72eSMasami Hiramatsu return sl;
2080325862dSColin Ian King
20960ebc159SArnaldo Carvalho de Melo out_close_fp:
21060ebc159SArnaldo Carvalho de Melo fclose(fp);
21160ebc159SArnaldo Carvalho de Melo goto out_free_sl;
2120325862dSColin Ian King out_close_fddup:
2130325862dSColin Ian King close(fddup);
2140325862dSColin Ian King out_free_sl:
2150325862dSColin Ian King strlist__delete(sl);
2160325862dSColin Ian King return NULL;
21792f6c72eSMasami Hiramatsu }
21892f6c72eSMasami Hiramatsu
__probe_file__get_namelist(int fd,bool include_group)21992f6c72eSMasami Hiramatsu static struct strlist *__probe_file__get_namelist(int fd, bool include_group)
22092f6c72eSMasami Hiramatsu {
22192f6c72eSMasami Hiramatsu char buf[128];
22292f6c72eSMasami Hiramatsu struct strlist *sl, *rawlist;
22392f6c72eSMasami Hiramatsu struct str_node *ent;
22492f6c72eSMasami Hiramatsu struct probe_trace_event tev;
22592f6c72eSMasami Hiramatsu int ret = 0;
22692f6c72eSMasami Hiramatsu
22792f6c72eSMasami Hiramatsu memset(&tev, 0, sizeof(tev));
22892f6c72eSMasami Hiramatsu rawlist = probe_file__get_rawlist(fd);
22992f6c72eSMasami Hiramatsu if (!rawlist)
23092f6c72eSMasami Hiramatsu return NULL;
23192f6c72eSMasami Hiramatsu sl = strlist__new(NULL, NULL);
232602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(ent, rawlist) {
23392f6c72eSMasami Hiramatsu ret = parse_probe_trace_command(ent->s, &tev);
23492f6c72eSMasami Hiramatsu if (ret < 0)
23592f6c72eSMasami Hiramatsu break;
23692f6c72eSMasami Hiramatsu if (include_group) {
23792f6c72eSMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", tev.group,
23892f6c72eSMasami Hiramatsu tev.event);
23992f6c72eSMasami Hiramatsu if (ret >= 0)
24092f6c72eSMasami Hiramatsu ret = strlist__add(sl, buf);
24192f6c72eSMasami Hiramatsu } else
24292f6c72eSMasami Hiramatsu ret = strlist__add(sl, tev.event);
24392f6c72eSMasami Hiramatsu clear_probe_trace_event(&tev);
2446b8d68f1SMasami Hiramatsu /* Skip if there is same name multi-probe event in the list */
2456b8d68f1SMasami Hiramatsu if (ret == -EEXIST)
2466b8d68f1SMasami Hiramatsu ret = 0;
24792f6c72eSMasami Hiramatsu if (ret < 0)
24892f6c72eSMasami Hiramatsu break;
24992f6c72eSMasami Hiramatsu }
25092f6c72eSMasami Hiramatsu strlist__delete(rawlist);
25192f6c72eSMasami Hiramatsu
25292f6c72eSMasami Hiramatsu if (ret < 0) {
25392f6c72eSMasami Hiramatsu strlist__delete(sl);
25492f6c72eSMasami Hiramatsu return NULL;
25592f6c72eSMasami Hiramatsu }
25692f6c72eSMasami Hiramatsu return sl;
25792f6c72eSMasami Hiramatsu }
25892f6c72eSMasami Hiramatsu
25992f6c72eSMasami Hiramatsu /* Get current perf-probe event names */
probe_file__get_namelist(int fd)26092f6c72eSMasami Hiramatsu struct strlist *probe_file__get_namelist(int fd)
26192f6c72eSMasami Hiramatsu {
26292f6c72eSMasami Hiramatsu return __probe_file__get_namelist(fd, false);
26392f6c72eSMasami Hiramatsu }
26492f6c72eSMasami Hiramatsu
probe_file__add_event(int fd,struct probe_trace_event * tev)26592f6c72eSMasami Hiramatsu int probe_file__add_event(int fd, struct probe_trace_event *tev)
26692f6c72eSMasami Hiramatsu {
26792f6c72eSMasami Hiramatsu int ret = 0;
26892f6c72eSMasami Hiramatsu char *buf = synthesize_probe_trace_command(tev);
26992f6c72eSMasami Hiramatsu char sbuf[STRERR_BUFSIZE];
27092f6c72eSMasami Hiramatsu
27192f6c72eSMasami Hiramatsu if (!buf) {
27292f6c72eSMasami Hiramatsu pr_debug("Failed to synthesize probe trace event.\n");
27392f6c72eSMasami Hiramatsu return -EINVAL;
27492f6c72eSMasami Hiramatsu }
27592f6c72eSMasami Hiramatsu
27692f6c72eSMasami Hiramatsu pr_debug("Writing event: %s\n", buf);
27792f6c72eSMasami Hiramatsu if (!probe_event_dry_run) {
2786ed0720aSMasami Hiramatsu if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) {
27992f6c72eSMasami Hiramatsu ret = -errno;
28092f6c72eSMasami Hiramatsu pr_warning("Failed to write event: %s\n",
281c8b5f2c9SArnaldo Carvalho de Melo str_error_r(errno, sbuf, sizeof(sbuf)));
28292f6c72eSMasami Hiramatsu }
28392f6c72eSMasami Hiramatsu }
28492f6c72eSMasami Hiramatsu free(buf);
28592f6c72eSMasami Hiramatsu
28692f6c72eSMasami Hiramatsu return ret;
28792f6c72eSMasami Hiramatsu }
28892f6c72eSMasami Hiramatsu
__del_trace_probe_event(int fd,struct str_node * ent)28992f6c72eSMasami Hiramatsu static int __del_trace_probe_event(int fd, struct str_node *ent)
29092f6c72eSMasami Hiramatsu {
29192f6c72eSMasami Hiramatsu char *p;
29292f6c72eSMasami Hiramatsu char buf[128];
29392f6c72eSMasami Hiramatsu int ret;
29492f6c72eSMasami Hiramatsu
29592f6c72eSMasami Hiramatsu /* Convert from perf-probe event to trace-probe event */
29692f6c72eSMasami Hiramatsu ret = e_snprintf(buf, 128, "-:%s", ent->s);
29792f6c72eSMasami Hiramatsu if (ret < 0)
29892f6c72eSMasami Hiramatsu goto error;
29992f6c72eSMasami Hiramatsu
30092f6c72eSMasami Hiramatsu p = strchr(buf + 2, ':');
30192f6c72eSMasami Hiramatsu if (!p) {
30292f6c72eSMasami Hiramatsu pr_debug("Internal error: %s should have ':' but not.\n",
30392f6c72eSMasami Hiramatsu ent->s);
30492f6c72eSMasami Hiramatsu ret = -ENOTSUP;
30592f6c72eSMasami Hiramatsu goto error;
30692f6c72eSMasami Hiramatsu }
30792f6c72eSMasami Hiramatsu *p = '/';
30892f6c72eSMasami Hiramatsu
30992f6c72eSMasami Hiramatsu pr_debug("Writing event: %s\n", buf);
31092f6c72eSMasami Hiramatsu ret = write(fd, buf, strlen(buf));
31192f6c72eSMasami Hiramatsu if (ret < 0) {
31292f6c72eSMasami Hiramatsu ret = -errno;
31392f6c72eSMasami Hiramatsu goto error;
31492f6c72eSMasami Hiramatsu }
31592f6c72eSMasami Hiramatsu
31692f6c72eSMasami Hiramatsu return 0;
31792f6c72eSMasami Hiramatsu error:
31892f6c72eSMasami Hiramatsu pr_warning("Failed to delete event: %s\n",
319c8b5f2c9SArnaldo Carvalho de Melo str_error_r(-ret, buf, sizeof(buf)));
32092f6c72eSMasami Hiramatsu return ret;
32192f6c72eSMasami Hiramatsu }
32292f6c72eSMasami Hiramatsu
probe_file__get_events(int fd,struct strfilter * filter,struct strlist * plist)323e607f142SNamhyung Kim int probe_file__get_events(int fd, struct strfilter *filter,
324e7895e42SNamhyung Kim struct strlist *plist)
32592f6c72eSMasami Hiramatsu {
32692f6c72eSMasami Hiramatsu struct strlist *namelist;
32792f6c72eSMasami Hiramatsu struct str_node *ent;
32892f6c72eSMasami Hiramatsu const char *p;
32992f6c72eSMasami Hiramatsu int ret = -ENOENT;
33092f6c72eSMasami Hiramatsu
331421fd084SWang Nan if (!plist)
332421fd084SWang Nan return -EINVAL;
333421fd084SWang Nan
33492f6c72eSMasami Hiramatsu namelist = __probe_file__get_namelist(fd, true);
33592f6c72eSMasami Hiramatsu if (!namelist)
33692f6c72eSMasami Hiramatsu return -ENOENT;
33792f6c72eSMasami Hiramatsu
338602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(ent, namelist) {
33992f6c72eSMasami Hiramatsu p = strchr(ent->s, ':');
34092f6c72eSMasami Hiramatsu if ((p && strfilter__compare(filter, p + 1)) ||
34192f6c72eSMasami Hiramatsu strfilter__compare(filter, ent->s)) {
342bd862b1dSHe Zhe ret = strlist__add(plist, ent->s);
343bd862b1dSHe Zhe if (ret == -ENOMEM) {
344bd862b1dSHe Zhe pr_err("strlist__add failed with -ENOMEM\n");
345bd862b1dSHe Zhe goto out;
346bd862b1dSHe Zhe }
347e7895e42SNamhyung Kim ret = 0;
348e7895e42SNamhyung Kim }
349e7895e42SNamhyung Kim }
350bd862b1dSHe Zhe out:
351e7895e42SNamhyung Kim strlist__delete(namelist);
352e7895e42SNamhyung Kim
353e7895e42SNamhyung Kim return ret;
354e7895e42SNamhyung Kim }
355e7895e42SNamhyung Kim
probe_file__del_strlist(int fd,struct strlist * namelist)356e607f142SNamhyung Kim int probe_file__del_strlist(int fd, struct strlist *namelist)
357e7895e42SNamhyung Kim {
358e7895e42SNamhyung Kim int ret = 0;
359e7895e42SNamhyung Kim struct str_node *ent;
360e7895e42SNamhyung Kim
361602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(ent, namelist) {
36292f6c72eSMasami Hiramatsu ret = __del_trace_probe_event(fd, ent);
36392f6c72eSMasami Hiramatsu if (ret < 0)
36492f6c72eSMasami Hiramatsu break;
36592f6c72eSMasami Hiramatsu }
366e7895e42SNamhyung Kim return ret;
36792f6c72eSMasami Hiramatsu }
368e7895e42SNamhyung Kim
probe_file__del_events(int fd,struct strfilter * filter)369e7895e42SNamhyung Kim int probe_file__del_events(int fd, struct strfilter *filter)
370e7895e42SNamhyung Kim {
371e7895e42SNamhyung Kim struct strlist *namelist;
372e7895e42SNamhyung Kim int ret;
373e7895e42SNamhyung Kim
374e7895e42SNamhyung Kim namelist = strlist__new(NULL, NULL);
375e7895e42SNamhyung Kim if (!namelist)
376e7895e42SNamhyung Kim return -ENOMEM;
377e7895e42SNamhyung Kim
378e7895e42SNamhyung Kim ret = probe_file__get_events(fd, filter, namelist);
379e7895e42SNamhyung Kim if (ret < 0)
380*e0fa7ab4SRiccardo Mancini goto out;
381e7895e42SNamhyung Kim
382e7895e42SNamhyung Kim ret = probe_file__del_strlist(fd, namelist);
383*e0fa7ab4SRiccardo Mancini out:
38492f6c72eSMasami Hiramatsu strlist__delete(namelist);
38592f6c72eSMasami Hiramatsu return ret;
38692f6c72eSMasami Hiramatsu }
387dd975497SMasami Hiramatsu
388dd975497SMasami Hiramatsu /* Caller must ensure to remove this entry from list */
probe_cache_entry__delete(struct probe_cache_entry * entry)389dd975497SMasami Hiramatsu static void probe_cache_entry__delete(struct probe_cache_entry *entry)
390dd975497SMasami Hiramatsu {
391dd975497SMasami Hiramatsu if (entry) {
392dd975497SMasami Hiramatsu BUG_ON(!list_empty(&entry->node));
393dd975497SMasami Hiramatsu
394dd975497SMasami Hiramatsu strlist__delete(entry->tevlist);
395dd975497SMasami Hiramatsu clear_perf_probe_event(&entry->pev);
396dd975497SMasami Hiramatsu zfree(&entry->spev);
397dd975497SMasami Hiramatsu free(entry);
398dd975497SMasami Hiramatsu }
399dd975497SMasami Hiramatsu }
400dd975497SMasami Hiramatsu
401dd975497SMasami Hiramatsu static struct probe_cache_entry *
probe_cache_entry__new(struct perf_probe_event * pev)402dd975497SMasami Hiramatsu probe_cache_entry__new(struct perf_probe_event *pev)
403dd975497SMasami Hiramatsu {
404dd975497SMasami Hiramatsu struct probe_cache_entry *entry = zalloc(sizeof(*entry));
405dd975497SMasami Hiramatsu
406dd975497SMasami Hiramatsu if (entry) {
407dd975497SMasami Hiramatsu INIT_LIST_HEAD(&entry->node);
408dd975497SMasami Hiramatsu entry->tevlist = strlist__new(NULL, NULL);
409dd975497SMasami Hiramatsu if (!entry->tevlist)
410dd975497SMasami Hiramatsu zfree(&entry);
411dd975497SMasami Hiramatsu else if (pev) {
412dd975497SMasami Hiramatsu entry->spev = synthesize_perf_probe_command(pev);
413dd975497SMasami Hiramatsu if (!entry->spev ||
414dd975497SMasami Hiramatsu perf_probe_event__copy(&entry->pev, pev) < 0) {
415dd975497SMasami Hiramatsu probe_cache_entry__delete(entry);
416dd975497SMasami Hiramatsu return NULL;
417dd975497SMasami Hiramatsu }
418dd975497SMasami Hiramatsu }
419dd975497SMasami Hiramatsu }
420dd975497SMasami Hiramatsu
421dd975497SMasami Hiramatsu return entry;
422dd975497SMasami Hiramatsu }
423dd975497SMasami Hiramatsu
probe_cache_entry__get_event(struct probe_cache_entry * entry,struct probe_trace_event ** tevs)42442bba263SMasami Hiramatsu int probe_cache_entry__get_event(struct probe_cache_entry *entry,
42542bba263SMasami Hiramatsu struct probe_trace_event **tevs)
42642bba263SMasami Hiramatsu {
42742bba263SMasami Hiramatsu struct probe_trace_event *tev;
42842bba263SMasami Hiramatsu struct str_node *node;
42942bba263SMasami Hiramatsu int ret, i;
43042bba263SMasami Hiramatsu
43142bba263SMasami Hiramatsu ret = strlist__nr_entries(entry->tevlist);
43242bba263SMasami Hiramatsu if (ret > probe_conf.max_probes)
43342bba263SMasami Hiramatsu return -E2BIG;
43442bba263SMasami Hiramatsu
43542bba263SMasami Hiramatsu *tevs = zalloc(ret * sizeof(*tev));
43642bba263SMasami Hiramatsu if (!*tevs)
43742bba263SMasami Hiramatsu return -ENOMEM;
43842bba263SMasami Hiramatsu
43942bba263SMasami Hiramatsu i = 0;
44042bba263SMasami Hiramatsu strlist__for_each_entry(node, entry->tevlist) {
44142bba263SMasami Hiramatsu tev = &(*tevs)[i++];
44242bba263SMasami Hiramatsu ret = parse_probe_trace_command(node->s, tev);
44342bba263SMasami Hiramatsu if (ret < 0)
44442bba263SMasami Hiramatsu break;
44542bba263SMasami Hiramatsu }
44642bba263SMasami Hiramatsu return i;
44742bba263SMasami Hiramatsu }
44842bba263SMasami Hiramatsu
44942bba263SMasami Hiramatsu /* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */
probe_cache__open(struct probe_cache * pcache,const char * target,struct nsinfo * nsi)450f045b8c4SKrister Johansen static int probe_cache__open(struct probe_cache *pcache, const char *target,
451f045b8c4SKrister Johansen struct nsinfo *nsi)
452dd975497SMasami Hiramatsu {
453dd975497SMasami Hiramatsu char cpath[PATH_MAX];
454dd975497SMasami Hiramatsu char sbuildid[SBUILD_ID_SIZE];
4551f3736c9SMasami Hiramatsu char *dir_name = NULL;
45642bba263SMasami Hiramatsu bool is_kallsyms = false;
457dd975497SMasami Hiramatsu int ret, fd;
458f045b8c4SKrister Johansen struct nscookie nsc;
459dd975497SMasami Hiramatsu
4601f3736c9SMasami Hiramatsu if (target && build_id_cache__cached(target)) {
4611f3736c9SMasami Hiramatsu /* This is a cached buildid */
462bef0b897SArnaldo Carvalho de Melo strlcpy(sbuildid, target, SBUILD_ID_SIZE);
4631f3736c9SMasami Hiramatsu dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
4641f3736c9SMasami Hiramatsu goto found;
4651f3736c9SMasami Hiramatsu }
4661f3736c9SMasami Hiramatsu
46742bba263SMasami Hiramatsu if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {
468dd975497SMasami Hiramatsu target = DSO__NAME_KALLSYMS;
46942bba263SMasami Hiramatsu is_kallsyms = true;
470dd975497SMasami Hiramatsu ret = sysfs__sprintf_build_id("/", sbuildid);
471f045b8c4SKrister Johansen } else {
472f045b8c4SKrister Johansen nsinfo__mountns_enter(nsi, &nsc);
47342bba263SMasami Hiramatsu ret = filename__sprintf_build_id(target, sbuildid);
474f045b8c4SKrister Johansen nsinfo__mountns_exit(&nsc);
475f045b8c4SKrister Johansen }
47642bba263SMasami Hiramatsu
477dd975497SMasami Hiramatsu if (ret < 0) {
478dd975497SMasami Hiramatsu pr_debug("Failed to get build-id from %s.\n", target);
479dd975497SMasami Hiramatsu return ret;
480dd975497SMasami Hiramatsu }
481dd975497SMasami Hiramatsu
482dd975497SMasami Hiramatsu /* If we have no buildid cache, make it */
483dd975497SMasami Hiramatsu if (!build_id_cache__cached(sbuildid)) {
484f045b8c4SKrister Johansen ret = build_id_cache__add_s(sbuildid, target, nsi,
485dd975497SMasami Hiramatsu is_kallsyms, NULL);
486dd975497SMasami Hiramatsu if (ret < 0) {
487dd975497SMasami Hiramatsu pr_debug("Failed to add build-id cache: %s\n", target);
488dd975497SMasami Hiramatsu return ret;
489dd975497SMasami Hiramatsu }
490dd975497SMasami Hiramatsu }
491dd975497SMasami Hiramatsu
492f045b8c4SKrister Johansen dir_name = build_id_cache__cachedir(sbuildid, target, nsi, is_kallsyms,
493dd975497SMasami Hiramatsu false);
4941f3736c9SMasami Hiramatsu found:
4951f3736c9SMasami Hiramatsu if (!dir_name) {
4961f3736c9SMasami Hiramatsu pr_debug("Failed to get cache from %s\n", target);
497dd975497SMasami Hiramatsu return -ENOMEM;
4981f3736c9SMasami Hiramatsu }
499dd975497SMasami Hiramatsu
500dd975497SMasami Hiramatsu snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
501dd975497SMasami Hiramatsu fd = open(cpath, O_CREAT | O_RDWR, 0644);
502dd975497SMasami Hiramatsu if (fd < 0)
503dd975497SMasami Hiramatsu pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
504dd975497SMasami Hiramatsu free(dir_name);
505dd975497SMasami Hiramatsu pcache->fd = fd;
506dd975497SMasami Hiramatsu
507dd975497SMasami Hiramatsu return fd;
508dd975497SMasami Hiramatsu }
509dd975497SMasami Hiramatsu
probe_cache__load(struct probe_cache * pcache)510dd975497SMasami Hiramatsu static int probe_cache__load(struct probe_cache *pcache)
511dd975497SMasami Hiramatsu {
512dd975497SMasami Hiramatsu struct probe_cache_entry *entry = NULL;
513dd975497SMasami Hiramatsu char buf[MAX_CMDLEN], *p;
5140325862dSColin Ian King int ret = 0, fddup;
515dd975497SMasami Hiramatsu FILE *fp;
516dd975497SMasami Hiramatsu
5170325862dSColin Ian King fddup = dup(pcache->fd);
5180325862dSColin Ian King if (fddup < 0)
5190325862dSColin Ian King return -errno;
5200325862dSColin Ian King fp = fdopen(fddup, "r");
52160ebc159SArnaldo Carvalho de Melo if (!fp) {
52260ebc159SArnaldo Carvalho de Melo close(fddup);
523dd975497SMasami Hiramatsu return -EINVAL;
52460ebc159SArnaldo Carvalho de Melo }
525dd975497SMasami Hiramatsu
526dd975497SMasami Hiramatsu while (!feof(fp)) {
527dd975497SMasami Hiramatsu if (!fgets(buf, MAX_CMDLEN, fp))
528dd975497SMasami Hiramatsu break;
529dd975497SMasami Hiramatsu p = strchr(buf, '\n');
530dd975497SMasami Hiramatsu if (p)
531dd975497SMasami Hiramatsu *p = '\0';
5326430a94eSMasami Hiramatsu /* #perf_probe_event or %sdt_event */
5336430a94eSMasami Hiramatsu if (buf[0] == '#' || buf[0] == '%') {
534dd975497SMasami Hiramatsu entry = probe_cache_entry__new(NULL);
535dd975497SMasami Hiramatsu if (!entry) {
536dd975497SMasami Hiramatsu ret = -ENOMEM;
537dd975497SMasami Hiramatsu goto out;
538dd975497SMasami Hiramatsu }
5396430a94eSMasami Hiramatsu if (buf[0] == '%')
5406430a94eSMasami Hiramatsu entry->sdt = true;
541dd975497SMasami Hiramatsu entry->spev = strdup(buf + 1);
542dd975497SMasami Hiramatsu if (entry->spev)
543dd975497SMasami Hiramatsu ret = parse_perf_probe_command(buf + 1,
544dd975497SMasami Hiramatsu &entry->pev);
545dd975497SMasami Hiramatsu else
546dd975497SMasami Hiramatsu ret = -ENOMEM;
547dd975497SMasami Hiramatsu if (ret < 0) {
548dd975497SMasami Hiramatsu probe_cache_entry__delete(entry);
549dd975497SMasami Hiramatsu goto out;
550dd975497SMasami Hiramatsu }
551dd975497SMasami Hiramatsu list_add_tail(&entry->node, &pcache->entries);
552dd975497SMasami Hiramatsu } else { /* trace_probe_event */
553dd975497SMasami Hiramatsu if (!entry) {
554dd975497SMasami Hiramatsu ret = -EINVAL;
555dd975497SMasami Hiramatsu goto out;
556dd975497SMasami Hiramatsu }
557bd862b1dSHe Zhe ret = strlist__add(entry->tevlist, buf);
558bd862b1dSHe Zhe if (ret == -ENOMEM) {
559bd862b1dSHe Zhe pr_err("strlist__add failed with -ENOMEM\n");
560bd862b1dSHe Zhe goto out;
561bd862b1dSHe Zhe }
562dd975497SMasami Hiramatsu }
563dd975497SMasami Hiramatsu }
564dd975497SMasami Hiramatsu out:
565dd975497SMasami Hiramatsu fclose(fp);
566dd975497SMasami Hiramatsu return ret;
567dd975497SMasami Hiramatsu }
568dd975497SMasami Hiramatsu
probe_cache__alloc(void)569dd975497SMasami Hiramatsu static struct probe_cache *probe_cache__alloc(void)
570dd975497SMasami Hiramatsu {
571dd975497SMasami Hiramatsu struct probe_cache *pcache = zalloc(sizeof(*pcache));
572dd975497SMasami Hiramatsu
573dd975497SMasami Hiramatsu if (pcache) {
574dd975497SMasami Hiramatsu INIT_LIST_HEAD(&pcache->entries);
575dd975497SMasami Hiramatsu pcache->fd = -EINVAL;
576dd975497SMasami Hiramatsu }
577dd975497SMasami Hiramatsu return pcache;
578dd975497SMasami Hiramatsu }
579dd975497SMasami Hiramatsu
probe_cache__purge(struct probe_cache * pcache)580dd975497SMasami Hiramatsu void probe_cache__purge(struct probe_cache *pcache)
581dd975497SMasami Hiramatsu {
582dd975497SMasami Hiramatsu struct probe_cache_entry *entry, *n;
583dd975497SMasami Hiramatsu
584dd975497SMasami Hiramatsu list_for_each_entry_safe(entry, n, &pcache->entries, node) {
585dd975497SMasami Hiramatsu list_del_init(&entry->node);
586dd975497SMasami Hiramatsu probe_cache_entry__delete(entry);
587dd975497SMasami Hiramatsu }
588dd975497SMasami Hiramatsu }
589dd975497SMasami Hiramatsu
probe_cache__delete(struct probe_cache * pcache)590dd975497SMasami Hiramatsu void probe_cache__delete(struct probe_cache *pcache)
591dd975497SMasami Hiramatsu {
592dd975497SMasami Hiramatsu if (!pcache)
593dd975497SMasami Hiramatsu return;
594dd975497SMasami Hiramatsu
595dd975497SMasami Hiramatsu probe_cache__purge(pcache);
596dd975497SMasami Hiramatsu if (pcache->fd > 0)
597dd975497SMasami Hiramatsu close(pcache->fd);
598dd975497SMasami Hiramatsu free(pcache);
599dd975497SMasami Hiramatsu }
600dd975497SMasami Hiramatsu
probe_cache__new(const char * target,struct nsinfo * nsi)601f045b8c4SKrister Johansen struct probe_cache *probe_cache__new(const char *target, struct nsinfo *nsi)
602dd975497SMasami Hiramatsu {
603dd975497SMasami Hiramatsu struct probe_cache *pcache = probe_cache__alloc();
604dd975497SMasami Hiramatsu int ret;
605dd975497SMasami Hiramatsu
606dd975497SMasami Hiramatsu if (!pcache)
607dd975497SMasami Hiramatsu return NULL;
608dd975497SMasami Hiramatsu
609f045b8c4SKrister Johansen ret = probe_cache__open(pcache, target, nsi);
610dd975497SMasami Hiramatsu if (ret < 0) {
611dd975497SMasami Hiramatsu pr_debug("Cache open error: %d\n", ret);
612dd975497SMasami Hiramatsu goto out_err;
613dd975497SMasami Hiramatsu }
614dd975497SMasami Hiramatsu
615dd975497SMasami Hiramatsu ret = probe_cache__load(pcache);
616dd975497SMasami Hiramatsu if (ret < 0) {
617dd975497SMasami Hiramatsu pr_debug("Cache read error: %d\n", ret);
618dd975497SMasami Hiramatsu goto out_err;
619dd975497SMasami Hiramatsu }
620dd975497SMasami Hiramatsu
621dd975497SMasami Hiramatsu return pcache;
622dd975497SMasami Hiramatsu
623dd975497SMasami Hiramatsu out_err:
624dd975497SMasami Hiramatsu probe_cache__delete(pcache);
625dd975497SMasami Hiramatsu return NULL;
626dd975497SMasami Hiramatsu }
627dd975497SMasami Hiramatsu
streql(const char * a,const char * b)628dd975497SMasami Hiramatsu static bool streql(const char *a, const char *b)
629dd975497SMasami Hiramatsu {
630dd975497SMasami Hiramatsu if (a == b)
631dd975497SMasami Hiramatsu return true;
632dd975497SMasami Hiramatsu
633dd975497SMasami Hiramatsu if (!a || !b)
634dd975497SMasami Hiramatsu return false;
635dd975497SMasami Hiramatsu
636dd975497SMasami Hiramatsu return !strcmp(a, b);
637dd975497SMasami Hiramatsu }
638dd975497SMasami Hiramatsu
639bc062230SMasami Hiramatsu struct probe_cache_entry *
probe_cache__find(struct probe_cache * pcache,struct perf_probe_event * pev)640dd975497SMasami Hiramatsu probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
641dd975497SMasami Hiramatsu {
642dd975497SMasami Hiramatsu struct probe_cache_entry *entry = NULL;
643dd975497SMasami Hiramatsu char *cmd = synthesize_perf_probe_command(pev);
644dd975497SMasami Hiramatsu
645dd975497SMasami Hiramatsu if (!cmd)
646dd975497SMasami Hiramatsu return NULL;
647dd975497SMasami Hiramatsu
64805bf2c8aSMasami Hiramatsu for_each_probe_cache_entry(entry, pcache) {
64936a009feSMasami Hiramatsu if (pev->sdt) {
65036a009feSMasami Hiramatsu if (entry->pev.event &&
65136a009feSMasami Hiramatsu streql(entry->pev.event, pev->event) &&
65236a009feSMasami Hiramatsu (!pev->group ||
65336a009feSMasami Hiramatsu streql(entry->pev.group, pev->group)))
65436a009feSMasami Hiramatsu goto found;
65536a009feSMasami Hiramatsu
65636a009feSMasami Hiramatsu continue;
65736a009feSMasami Hiramatsu }
658dd975497SMasami Hiramatsu /* Hit if same event name or same command-string */
659dd975497SMasami Hiramatsu if ((pev->event &&
660dd975497SMasami Hiramatsu (streql(entry->pev.group, pev->group) &&
661dd975497SMasami Hiramatsu streql(entry->pev.event, pev->event))) ||
662dd975497SMasami Hiramatsu (!strcmp(entry->spev, cmd)))
663dd975497SMasami Hiramatsu goto found;
664dd975497SMasami Hiramatsu }
665dd975497SMasami Hiramatsu entry = NULL;
666dd975497SMasami Hiramatsu
667dd975497SMasami Hiramatsu found:
668dd975497SMasami Hiramatsu free(cmd);
669dd975497SMasami Hiramatsu return entry;
670dd975497SMasami Hiramatsu }
671dd975497SMasami Hiramatsu
672bc062230SMasami Hiramatsu struct probe_cache_entry *
probe_cache__find_by_name(struct probe_cache * pcache,const char * group,const char * event)673bc062230SMasami Hiramatsu probe_cache__find_by_name(struct probe_cache *pcache,
674bc062230SMasami Hiramatsu const char *group, const char *event)
675bc062230SMasami Hiramatsu {
676bc062230SMasami Hiramatsu struct probe_cache_entry *entry = NULL;
677bc062230SMasami Hiramatsu
67805bf2c8aSMasami Hiramatsu for_each_probe_cache_entry(entry, pcache) {
679bc062230SMasami Hiramatsu /* Hit if same event name or same command-string */
680bc062230SMasami Hiramatsu if (streql(entry->pev.group, group) &&
681bc062230SMasami Hiramatsu streql(entry->pev.event, event))
682bc062230SMasami Hiramatsu goto found;
683bc062230SMasami Hiramatsu }
684bc062230SMasami Hiramatsu entry = NULL;
685bc062230SMasami Hiramatsu
686bc062230SMasami Hiramatsu found:
687bc062230SMasami Hiramatsu return entry;
688bc062230SMasami Hiramatsu }
689bc062230SMasami Hiramatsu
probe_cache__add_entry(struct probe_cache * pcache,struct perf_probe_event * pev,struct probe_trace_event * tevs,int ntevs)690dd975497SMasami Hiramatsu int probe_cache__add_entry(struct probe_cache *pcache,
691dd975497SMasami Hiramatsu struct perf_probe_event *pev,
692dd975497SMasami Hiramatsu struct probe_trace_event *tevs, int ntevs)
693dd975497SMasami Hiramatsu {
694dd975497SMasami Hiramatsu struct probe_cache_entry *entry = NULL;
695dd975497SMasami Hiramatsu char *command;
696dd975497SMasami Hiramatsu int i, ret = 0;
697dd975497SMasami Hiramatsu
698dd975497SMasami Hiramatsu if (!pcache || !pev || !tevs || ntevs <= 0) {
699dd975497SMasami Hiramatsu ret = -EINVAL;
700dd975497SMasami Hiramatsu goto out_err;
701dd975497SMasami Hiramatsu }
702dd975497SMasami Hiramatsu
703dd975497SMasami Hiramatsu /* Remove old cache entry */
704dd975497SMasami Hiramatsu entry = probe_cache__find(pcache, pev);
705dd975497SMasami Hiramatsu if (entry) {
706dd975497SMasami Hiramatsu list_del_init(&entry->node);
707dd975497SMasami Hiramatsu probe_cache_entry__delete(entry);
708dd975497SMasami Hiramatsu }
709dd975497SMasami Hiramatsu
710dd975497SMasami Hiramatsu ret = -ENOMEM;
711dd975497SMasami Hiramatsu entry = probe_cache_entry__new(pev);
712dd975497SMasami Hiramatsu if (!entry)
713dd975497SMasami Hiramatsu goto out_err;
714dd975497SMasami Hiramatsu
715dd975497SMasami Hiramatsu for (i = 0; i < ntevs; i++) {
716dd975497SMasami Hiramatsu if (!tevs[i].point.symbol)
717dd975497SMasami Hiramatsu continue;
718dd975497SMasami Hiramatsu
719dd975497SMasami Hiramatsu command = synthesize_probe_trace_command(&tevs[i]);
720dd975497SMasami Hiramatsu if (!command)
721dd975497SMasami Hiramatsu goto out_err;
722bd862b1dSHe Zhe ret = strlist__add(entry->tevlist, command);
723bd862b1dSHe Zhe if (ret == -ENOMEM) {
724bd862b1dSHe Zhe pr_err("strlist__add failed with -ENOMEM\n");
725bd862b1dSHe Zhe goto out_err;
726bd862b1dSHe Zhe }
727bd862b1dSHe Zhe
728dd975497SMasami Hiramatsu free(command);
729dd975497SMasami Hiramatsu }
730dd975497SMasami Hiramatsu list_add_tail(&entry->node, &pcache->entries);
731dd975497SMasami Hiramatsu pr_debug("Added probe cache: %d\n", ntevs);
732dd975497SMasami Hiramatsu return 0;
733dd975497SMasami Hiramatsu
734dd975497SMasami Hiramatsu out_err:
735dd975497SMasami Hiramatsu pr_debug("Failed to add probe caches\n");
736dd975497SMasami Hiramatsu probe_cache_entry__delete(entry);
737dd975497SMasami Hiramatsu return ret;
738dd975497SMasami Hiramatsu }
739dd975497SMasami Hiramatsu
7401c1a3a47SArnaldo Carvalho de Melo #ifdef HAVE_GELF_GETNOTE_SUPPORT
sdt_note__get_addr(struct sdt_note * note)7416430a94eSMasami Hiramatsu static unsigned long long sdt_note__get_addr(struct sdt_note *note)
7426430a94eSMasami Hiramatsu {
7435a5e3d3cSRavi Bangoria return note->bit32 ?
7445a5e3d3cSRavi Bangoria (unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] :
7455a5e3d3cSRavi Bangoria (unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC];
7465a5e3d3cSRavi Bangoria }
7475a5e3d3cSRavi Bangoria
sdt_note__get_ref_ctr_offset(struct sdt_note * note)7485a5e3d3cSRavi Bangoria static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note)
7495a5e3d3cSRavi Bangoria {
7505a5e3d3cSRavi Bangoria return note->bit32 ?
7515a5e3d3cSRavi Bangoria (unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] :
7525a5e3d3cSRavi Bangoria (unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR];
7536430a94eSMasami Hiramatsu }
7546430a94eSMasami Hiramatsu
7553b1f8311SAlexis Berlemont static const char * const type_to_suffix[] = {
7563b1f8311SAlexis Berlemont ":s64", "", "", "", ":s32", "", ":s16", ":s8",
7573b1f8311SAlexis Berlemont "", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
7583b1f8311SAlexis Berlemont };
7593b1f8311SAlexis Berlemont
760d451a205SRavi Bangoria /*
761d451a205SRavi Bangoria * Isolate the string number and convert it into a decimal value;
762d451a205SRavi Bangoria * this will be an index to get suffix of the uprobe name (defining
763d451a205SRavi Bangoria * the type)
764d451a205SRavi Bangoria */
sdt_arg_parse_size(char * n_ptr,const char ** suffix)765d451a205SRavi Bangoria static int sdt_arg_parse_size(char *n_ptr, const char **suffix)
766d451a205SRavi Bangoria {
767d451a205SRavi Bangoria long type_idx;
768d451a205SRavi Bangoria
769d451a205SRavi Bangoria type_idx = strtol(n_ptr, NULL, 10);
770d451a205SRavi Bangoria if (type_idx < -8 || type_idx > 8) {
771d451a205SRavi Bangoria pr_debug4("Failed to get a valid sdt type\n");
772d451a205SRavi Bangoria return -1;
773d451a205SRavi Bangoria }
774d451a205SRavi Bangoria
775d451a205SRavi Bangoria *suffix = type_to_suffix[type_idx + 8];
776d451a205SRavi Bangoria return 0;
777d451a205SRavi Bangoria }
778d451a205SRavi Bangoria
synthesize_sdt_probe_arg(struct strbuf * buf,int i,const char * arg)7793b1f8311SAlexis Berlemont static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
7803b1f8311SAlexis Berlemont {
781d451a205SRavi Bangoria char *op, *desc = strdup(arg), *new_op = NULL;
782d451a205SRavi Bangoria const char *suffix = "";
7833b1f8311SAlexis Berlemont int ret = -1;
7843b1f8311SAlexis Berlemont
7853b1f8311SAlexis Berlemont if (desc == NULL) {
7863b1f8311SAlexis Berlemont pr_debug4("Allocation error\n");
7873b1f8311SAlexis Berlemont return ret;
7883b1f8311SAlexis Berlemont }
7893b1f8311SAlexis Berlemont
7903b1f8311SAlexis Berlemont /*
791d451a205SRavi Bangoria * Argument is in N@OP format. N is size of the argument and OP is
792d451a205SRavi Bangoria * the actual assembly operand. N can be omitted; in that case
793d451a205SRavi Bangoria * argument is just OP(without @).
7943b1f8311SAlexis Berlemont */
795d451a205SRavi Bangoria op = strchr(desc, '@');
796d451a205SRavi Bangoria if (op) {
797d451a205SRavi Bangoria op[0] = '\0';
798d451a205SRavi Bangoria op++;
799d451a205SRavi Bangoria
800d451a205SRavi Bangoria if (sdt_arg_parse_size(desc, &suffix))
8013b1f8311SAlexis Berlemont goto error;
802d451a205SRavi Bangoria } else {
803d451a205SRavi Bangoria op = desc;
8043b1f8311SAlexis Berlemont }
8053b1f8311SAlexis Berlemont
806d451a205SRavi Bangoria ret = arch_sdt_arg_parse_op(op, &new_op);
8073b1f8311SAlexis Berlemont
8083b1f8311SAlexis Berlemont if (ret < 0)
8093b1f8311SAlexis Berlemont goto error;
8103b1f8311SAlexis Berlemont
811d451a205SRavi Bangoria if (ret == SDT_ARG_VALID) {
812d451a205SRavi Bangoria ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);
813d451a205SRavi Bangoria if (ret < 0)
814d451a205SRavi Bangoria goto error;
8153b1f8311SAlexis Berlemont }
8163b1f8311SAlexis Berlemont
8173b1f8311SAlexis Berlemont ret = 0;
8183b1f8311SAlexis Berlemont error:
8193b1f8311SAlexis Berlemont free(desc);
820d451a205SRavi Bangoria free(new_op);
8213b1f8311SAlexis Berlemont return ret;
8223b1f8311SAlexis Berlemont }
8233b1f8311SAlexis Berlemont
synthesize_sdt_probe_command(struct sdt_note * note,const char * pathname,const char * sdtgrp)8243b1f8311SAlexis Berlemont static char *synthesize_sdt_probe_command(struct sdt_note *note,
8253b1f8311SAlexis Berlemont const char *pathname,
8263b1f8311SAlexis Berlemont const char *sdtgrp)
8273b1f8311SAlexis Berlemont {
8283b1f8311SAlexis Berlemont struct strbuf buf;
8295149303fSArnaldo Carvalho de Melo char *ret = NULL;
8305a5e3d3cSRavi Bangoria int i, args_count, err;
8315a5e3d3cSRavi Bangoria unsigned long long ref_ctr_offset;
832f19b5872SLeo Yan char *arg;
833f19b5872SLeo Yan int arg_idx = 0;
8343b1f8311SAlexis Berlemont
8353b1f8311SAlexis Berlemont if (strbuf_init(&buf, 32) < 0)
8363b1f8311SAlexis Berlemont return NULL;
8373b1f8311SAlexis Berlemont
8385a5e3d3cSRavi Bangoria err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
8393b1f8311SAlexis Berlemont sdtgrp, note->name, pathname,
8405a5e3d3cSRavi Bangoria sdt_note__get_addr(note));
8415a5e3d3cSRavi Bangoria
8425a5e3d3cSRavi Bangoria ref_ctr_offset = sdt_note__get_ref_ctr_offset(note);
8435a5e3d3cSRavi Bangoria if (ref_ctr_offset && err >= 0)
8445a5e3d3cSRavi Bangoria err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset);
8455a5e3d3cSRavi Bangoria
8465a5e3d3cSRavi Bangoria if (err < 0)
8473b1f8311SAlexis Berlemont goto error;
8483b1f8311SAlexis Berlemont
8493b1f8311SAlexis Berlemont if (!note->args)
8503b1f8311SAlexis Berlemont goto out;
8513b1f8311SAlexis Berlemont
8523b1f8311SAlexis Berlemont if (note->args) {
8535149303fSArnaldo Carvalho de Melo char **args = argv_split(note->args, &args_count);
8545149303fSArnaldo Carvalho de Melo
8555149303fSArnaldo Carvalho de Melo if (args == NULL)
8565149303fSArnaldo Carvalho de Melo goto error;
8573b1f8311SAlexis Berlemont
858f19b5872SLeo Yan for (i = 0; i < args_count; ) {
859f19b5872SLeo Yan /*
860f19b5872SLeo Yan * FIXUP: Arm64 ELF section '.note.stapsdt' uses string
861f19b5872SLeo Yan * format "-4@[sp, NUM]" if a probe is to access data in
862f19b5872SLeo Yan * the stack, e.g. below is an example for the SDT
863f19b5872SLeo Yan * Arguments:
864f19b5872SLeo Yan *
865f19b5872SLeo Yan * Arguments: -4@[sp, 12] -4@[sp, 8] -4@[sp, 4]
866f19b5872SLeo Yan *
867f19b5872SLeo Yan * Since the string introduces an extra space character
868f19b5872SLeo Yan * in the middle of square brackets, the argument is
869f19b5872SLeo Yan * divided into two items. Fixup for this case, if an
870f19b5872SLeo Yan * item contains sub string "[sp,", need to concatenate
871f19b5872SLeo Yan * the two items.
872f19b5872SLeo Yan */
873f19b5872SLeo Yan if (strstr(args[i], "[sp,") && (i+1) < args_count) {
874f19b5872SLeo Yan err = asprintf(&arg, "%s %s", args[i], args[i+1]);
875f19b5872SLeo Yan i += 2;
876f19b5872SLeo Yan } else {
877f19b5872SLeo Yan err = asprintf(&arg, "%s", args[i]);
878f19b5872SLeo Yan i += 1;
879f19b5872SLeo Yan }
880f19b5872SLeo Yan
881f19b5872SLeo Yan /* Failed to allocate memory */
882f19b5872SLeo Yan if (err < 0) {
8835149303fSArnaldo Carvalho de Melo argv_free(args);
8843b1f8311SAlexis Berlemont goto error;
8853b1f8311SAlexis Berlemont }
886f19b5872SLeo Yan
887f19b5872SLeo Yan if (synthesize_sdt_probe_arg(&buf, arg_idx, arg) < 0) {
888f19b5872SLeo Yan free(arg);
889f19b5872SLeo Yan argv_free(args);
890f19b5872SLeo Yan goto error;
891f19b5872SLeo Yan }
892f19b5872SLeo Yan
893f19b5872SLeo Yan free(arg);
894f19b5872SLeo Yan arg_idx++;
8953b1f8311SAlexis Berlemont }
8963b1f8311SAlexis Berlemont
8975149303fSArnaldo Carvalho de Melo argv_free(args);
8985149303fSArnaldo Carvalho de Melo }
8995149303fSArnaldo Carvalho de Melo
9003b1f8311SAlexis Berlemont out:
9013b1f8311SAlexis Berlemont ret = strbuf_detach(&buf, NULL);
9023b1f8311SAlexis Berlemont error:
9033b1f8311SAlexis Berlemont strbuf_release(&buf);
9043b1f8311SAlexis Berlemont return ret;
9053b1f8311SAlexis Berlemont }
9063b1f8311SAlexis Berlemont
probe_cache__scan_sdt(struct probe_cache * pcache,const char * pathname)9076430a94eSMasami Hiramatsu int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
9086430a94eSMasami Hiramatsu {
9096430a94eSMasami Hiramatsu struct probe_cache_entry *entry = NULL;
9106430a94eSMasami Hiramatsu struct list_head sdtlist;
9116430a94eSMasami Hiramatsu struct sdt_note *note;
9126430a94eSMasami Hiramatsu char *buf;
9136430a94eSMasami Hiramatsu char sdtgrp[64];
9146430a94eSMasami Hiramatsu int ret;
9156430a94eSMasami Hiramatsu
9166430a94eSMasami Hiramatsu INIT_LIST_HEAD(&sdtlist);
9176430a94eSMasami Hiramatsu ret = get_sdt_note_list(&sdtlist, pathname);
9186430a94eSMasami Hiramatsu if (ret < 0) {
919f9655200SAdrian Hunter pr_debug4("Failed to get sdt note: %d\n", ret);
9206430a94eSMasami Hiramatsu return ret;
9216430a94eSMasami Hiramatsu }
9226430a94eSMasami Hiramatsu list_for_each_entry(note, &sdtlist, note_list) {
9236430a94eSMasami Hiramatsu ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);
9246430a94eSMasami Hiramatsu if (ret < 0)
9256430a94eSMasami Hiramatsu break;
9266430a94eSMasami Hiramatsu /* Try to find same-name entry */
9276430a94eSMasami Hiramatsu entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
9286430a94eSMasami Hiramatsu if (!entry) {
9296430a94eSMasami Hiramatsu entry = probe_cache_entry__new(NULL);
9306430a94eSMasami Hiramatsu if (!entry) {
9316430a94eSMasami Hiramatsu ret = -ENOMEM;
9326430a94eSMasami Hiramatsu break;
9336430a94eSMasami Hiramatsu }
9346430a94eSMasami Hiramatsu entry->sdt = true;
9356430a94eSMasami Hiramatsu ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,
9366430a94eSMasami Hiramatsu note->name, note->name);
9376430a94eSMasami Hiramatsu if (ret < 0)
9386430a94eSMasami Hiramatsu break;
9396430a94eSMasami Hiramatsu entry->pev.event = strdup(note->name);
9406430a94eSMasami Hiramatsu entry->pev.group = strdup(sdtgrp);
9416430a94eSMasami Hiramatsu list_add_tail(&entry->node, &pcache->entries);
9426430a94eSMasami Hiramatsu }
9433b1f8311SAlexis Berlemont buf = synthesize_sdt_probe_command(note, pathname, sdtgrp);
9443b1f8311SAlexis Berlemont if (!buf) {
9453b1f8311SAlexis Berlemont ret = -ENOMEM;
9466430a94eSMasami Hiramatsu break;
9473b1f8311SAlexis Berlemont }
9483b1f8311SAlexis Berlemont
949bd862b1dSHe Zhe ret = strlist__add(entry->tevlist, buf);
950bd862b1dSHe Zhe
9516430a94eSMasami Hiramatsu free(buf);
9526430a94eSMasami Hiramatsu entry = NULL;
953bd862b1dSHe Zhe
954bd862b1dSHe Zhe if (ret == -ENOMEM) {
955bd862b1dSHe Zhe pr_err("strlist__add failed with -ENOMEM\n");
956bd862b1dSHe Zhe break;
957bd862b1dSHe Zhe }
9586430a94eSMasami Hiramatsu }
9596430a94eSMasami Hiramatsu if (entry) {
9606430a94eSMasami Hiramatsu list_del_init(&entry->node);
9616430a94eSMasami Hiramatsu probe_cache_entry__delete(entry);
9626430a94eSMasami Hiramatsu }
9636430a94eSMasami Hiramatsu cleanup_sdt_note_list(&sdtlist);
9646430a94eSMasami Hiramatsu return ret;
9656430a94eSMasami Hiramatsu }
9661c1a3a47SArnaldo Carvalho de Melo #endif
9676430a94eSMasami Hiramatsu
probe_cache_entry__write(struct probe_cache_entry * entry,int fd)968dd975497SMasami Hiramatsu static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
969dd975497SMasami Hiramatsu {
970dd975497SMasami Hiramatsu struct str_node *snode;
971dd975497SMasami Hiramatsu struct stat st;
972dd975497SMasami Hiramatsu struct iovec iov[3];
9736430a94eSMasami Hiramatsu const char *prefix = entry->sdt ? "%" : "#";
974dd975497SMasami Hiramatsu int ret;
975dd975497SMasami Hiramatsu /* Save stat for rollback */
976dd975497SMasami Hiramatsu ret = fstat(fd, &st);
977dd975497SMasami Hiramatsu if (ret < 0)
978dd975497SMasami Hiramatsu return ret;
979dd975497SMasami Hiramatsu
9806430a94eSMasami Hiramatsu pr_debug("Writing cache: %s%s\n", prefix, entry->spev);
9816430a94eSMasami Hiramatsu iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;
982dd975497SMasami Hiramatsu iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
983dd975497SMasami Hiramatsu iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
984dd975497SMasami Hiramatsu ret = writev(fd, iov, 3);
985dd975497SMasami Hiramatsu if (ret < (int)iov[1].iov_len + 2)
986dd975497SMasami Hiramatsu goto rollback;
987dd975497SMasami Hiramatsu
988602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(snode, entry->tevlist) {
989dd975497SMasami Hiramatsu iov[0].iov_base = (void *)snode->s;
990dd975497SMasami Hiramatsu iov[0].iov_len = strlen(snode->s);
991dd975497SMasami Hiramatsu iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1;
992dd975497SMasami Hiramatsu ret = writev(fd, iov, 2);
993dd975497SMasami Hiramatsu if (ret < (int)iov[0].iov_len + 1)
994dd975497SMasami Hiramatsu goto rollback;
995dd975497SMasami Hiramatsu }
996dd975497SMasami Hiramatsu return 0;
997dd975497SMasami Hiramatsu
998dd975497SMasami Hiramatsu rollback:
999dd975497SMasami Hiramatsu /* Rollback to avoid cache file corruption */
1000dd975497SMasami Hiramatsu if (ret > 0)
1001dd975497SMasami Hiramatsu ret = -1;
1002dd975497SMasami Hiramatsu if (ftruncate(fd, st.st_size) < 0)
1003dd975497SMasami Hiramatsu ret = -2;
1004dd975497SMasami Hiramatsu
1005dd975497SMasami Hiramatsu return ret;
1006dd975497SMasami Hiramatsu }
1007dd975497SMasami Hiramatsu
probe_cache__commit(struct probe_cache * pcache)1008dd975497SMasami Hiramatsu int probe_cache__commit(struct probe_cache *pcache)
1009dd975497SMasami Hiramatsu {
1010dd975497SMasami Hiramatsu struct probe_cache_entry *entry;
1011dd975497SMasami Hiramatsu int ret = 0;
1012dd975497SMasami Hiramatsu
1013dd975497SMasami Hiramatsu /* TBD: if we do not update existing entries, skip it */
1014dd975497SMasami Hiramatsu ret = lseek(pcache->fd, 0, SEEK_SET);
1015dd975497SMasami Hiramatsu if (ret < 0)
1016dd975497SMasami Hiramatsu goto out;
1017dd975497SMasami Hiramatsu
1018dd975497SMasami Hiramatsu ret = ftruncate(pcache->fd, 0);
1019dd975497SMasami Hiramatsu if (ret < 0)
1020dd975497SMasami Hiramatsu goto out;
1021dd975497SMasami Hiramatsu
102205bf2c8aSMasami Hiramatsu for_each_probe_cache_entry(entry, pcache) {
1023dd975497SMasami Hiramatsu ret = probe_cache_entry__write(entry, pcache->fd);
1024dd975497SMasami Hiramatsu pr_debug("Cache committed: %d\n", ret);
1025dd975497SMasami Hiramatsu if (ret < 0)
1026dd975497SMasami Hiramatsu break;
1027dd975497SMasami Hiramatsu }
1028dd975497SMasami Hiramatsu out:
1029dd975497SMasami Hiramatsu return ret;
1030dd975497SMasami Hiramatsu }
10311f3736c9SMasami Hiramatsu
probe_cache_entry__compare(struct probe_cache_entry * entry,struct strfilter * filter)10324a0f65c1SMasami Hiramatsu static bool probe_cache_entry__compare(struct probe_cache_entry *entry,
10334a0f65c1SMasami Hiramatsu struct strfilter *filter)
10344a0f65c1SMasami Hiramatsu {
10354a0f65c1SMasami Hiramatsu char buf[128], *ptr = entry->spev;
10364a0f65c1SMasami Hiramatsu
10374a0f65c1SMasami Hiramatsu if (entry->pev.event) {
10384a0f65c1SMasami Hiramatsu snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
10394a0f65c1SMasami Hiramatsu ptr = buf;
10404a0f65c1SMasami Hiramatsu }
10414a0f65c1SMasami Hiramatsu return strfilter__compare(filter, ptr);
10424a0f65c1SMasami Hiramatsu }
10434a0f65c1SMasami Hiramatsu
probe_cache__filter_purge(struct probe_cache * pcache,struct strfilter * filter)10444a0f65c1SMasami Hiramatsu int probe_cache__filter_purge(struct probe_cache *pcache,
10454a0f65c1SMasami Hiramatsu struct strfilter *filter)
10464a0f65c1SMasami Hiramatsu {
10474a0f65c1SMasami Hiramatsu struct probe_cache_entry *entry, *tmp;
10484a0f65c1SMasami Hiramatsu
10494a0f65c1SMasami Hiramatsu list_for_each_entry_safe(entry, tmp, &pcache->entries, node) {
10504a0f65c1SMasami Hiramatsu if (probe_cache_entry__compare(entry, filter)) {
10514a0f65c1SMasami Hiramatsu pr_info("Removed cached event: %s\n", entry->spev);
10524a0f65c1SMasami Hiramatsu list_del_init(&entry->node);
10534a0f65c1SMasami Hiramatsu probe_cache_entry__delete(entry);
10544a0f65c1SMasami Hiramatsu }
10554a0f65c1SMasami Hiramatsu }
10564a0f65c1SMasami Hiramatsu return 0;
10574a0f65c1SMasami Hiramatsu }
10584a0f65c1SMasami Hiramatsu
probe_cache__show_entries(struct probe_cache * pcache,struct strfilter * filter)10591f3736c9SMasami Hiramatsu static int probe_cache__show_entries(struct probe_cache *pcache,
10601f3736c9SMasami Hiramatsu struct strfilter *filter)
10611f3736c9SMasami Hiramatsu {
10621f3736c9SMasami Hiramatsu struct probe_cache_entry *entry;
10631f3736c9SMasami Hiramatsu
106405bf2c8aSMasami Hiramatsu for_each_probe_cache_entry(entry, pcache) {
10654a0f65c1SMasami Hiramatsu if (probe_cache_entry__compare(entry, filter))
10661f3736c9SMasami Hiramatsu printf("%s\n", entry->spev);
10671f3736c9SMasami Hiramatsu }
10681f3736c9SMasami Hiramatsu return 0;
10691f3736c9SMasami Hiramatsu }
10701f3736c9SMasami Hiramatsu
10711f3736c9SMasami Hiramatsu /* Show all cached probes */
probe_cache__show_all_caches(struct strfilter * filter)10721f3736c9SMasami Hiramatsu int probe_cache__show_all_caches(struct strfilter *filter)
10731f3736c9SMasami Hiramatsu {
10741f3736c9SMasami Hiramatsu struct probe_cache *pcache;
10751f3736c9SMasami Hiramatsu struct strlist *bidlist;
10761f3736c9SMasami Hiramatsu struct str_node *nd;
10771f3736c9SMasami Hiramatsu char *buf = strfilter__string(filter);
10781f3736c9SMasami Hiramatsu
10791f3736c9SMasami Hiramatsu pr_debug("list cache with filter: %s\n", buf);
10801f3736c9SMasami Hiramatsu free(buf);
10811f3736c9SMasami Hiramatsu
1082c3492a3aSMasami Hiramatsu bidlist = build_id_cache__list_all(true);
10831f3736c9SMasami Hiramatsu if (!bidlist) {
10841f3736c9SMasami Hiramatsu pr_debug("Failed to get buildids: %d\n", errno);
10851f3736c9SMasami Hiramatsu return -EINVAL;
10861f3736c9SMasami Hiramatsu }
10871f3736c9SMasami Hiramatsu strlist__for_each_entry(nd, bidlist) {
1088f045b8c4SKrister Johansen pcache = probe_cache__new(nd->s, NULL);
10891f3736c9SMasami Hiramatsu if (!pcache)
10901f3736c9SMasami Hiramatsu continue;
10911f3736c9SMasami Hiramatsu if (!list_empty(&pcache->entries)) {
10921f3736c9SMasami Hiramatsu buf = build_id_cache__origname(nd->s);
10931f3736c9SMasami Hiramatsu printf("%s (%s):\n", buf, nd->s);
10941f3736c9SMasami Hiramatsu free(buf);
10951f3736c9SMasami Hiramatsu probe_cache__show_entries(pcache, filter);
10961f3736c9SMasami Hiramatsu }
10971f3736c9SMasami Hiramatsu probe_cache__delete(pcache);
10981f3736c9SMasami Hiramatsu }
10991f3736c9SMasami Hiramatsu strlist__delete(bidlist);
11001f3736c9SMasami Hiramatsu
11011f3736c9SMasami Hiramatsu return 0;
11021f3736c9SMasami Hiramatsu }
1103180b2061SMasami Hiramatsu
11043da3ea7aSNaveen N. Rao enum ftrace_readme {
11053da3ea7aSNaveen N. Rao FTRACE_README_PROBE_TYPE_X = 0,
11067ab31d94SNaveen N. Rao FTRACE_README_KRETPROBE_OFFSET,
11075a5e3d3cSRavi Bangoria FTRACE_README_UPROBE_REF_CTR,
11081e032f7cSMasami Hiramatsu FTRACE_README_USER_ACCESS,
110972363540SMasami Hiramatsu FTRACE_README_MULTIPROBE_EVENT,
111066f69b21SMasami Hiramatsu FTRACE_README_IMMEDIATE_VALUE,
11113da3ea7aSNaveen N. Rao FTRACE_README_END,
11123da3ea7aSNaveen N. Rao };
11133da3ea7aSNaveen N. Rao
1114180b2061SMasami Hiramatsu static struct {
1115180b2061SMasami Hiramatsu const char *pattern;
1116180b2061SMasami Hiramatsu bool avail;
11173da3ea7aSNaveen N. Rao } ftrace_readme_table[] = {
11183da3ea7aSNaveen N. Rao #define DEFINE_TYPE(idx, pat) \
11193da3ea7aSNaveen N. Rao [idx] = {.pattern = pat, .avail = false}
11203da3ea7aSNaveen N. Rao DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
11217ab31d94SNaveen N. Rao DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
11225a5e3d3cSRavi Bangoria DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"),
11239256c303SSumanth Korikkar DEFINE_TYPE(FTRACE_README_USER_ACCESS, "*u]<offset>*"),
112472363540SMasami Hiramatsu DEFINE_TYPE(FTRACE_README_MULTIPROBE_EVENT, "*Create/append/*"),
112566f69b21SMasami Hiramatsu DEFINE_TYPE(FTRACE_README_IMMEDIATE_VALUE, "*\\imm-value,*"),
1126180b2061SMasami Hiramatsu };
1127180b2061SMasami Hiramatsu
scan_ftrace_readme(enum ftrace_readme type)11283da3ea7aSNaveen N. Rao static bool scan_ftrace_readme(enum ftrace_readme type)
1129180b2061SMasami Hiramatsu {
11303da3ea7aSNaveen N. Rao int fd;
1131180b2061SMasami Hiramatsu FILE *fp;
1132180b2061SMasami Hiramatsu char *buf = NULL;
1133180b2061SMasami Hiramatsu size_t len = 0;
11343da3ea7aSNaveen N. Rao bool ret = false;
11353da3ea7aSNaveen N. Rao static bool scanned = false;
1136180b2061SMasami Hiramatsu
11373da3ea7aSNaveen N. Rao if (scanned)
11383da3ea7aSNaveen N. Rao goto result;
1139180b2061SMasami Hiramatsu
1140e491bc2fSNaveen N. Rao fd = open_trace_file("README", false);
1141e491bc2fSNaveen N. Rao if (fd < 0)
1142180b2061SMasami Hiramatsu return ret;
1143180b2061SMasami Hiramatsu
1144e491bc2fSNaveen N. Rao fp = fdopen(fd, "r");
1145e491bc2fSNaveen N. Rao if (!fp) {
1146e491bc2fSNaveen N. Rao close(fd);
1147e491bc2fSNaveen N. Rao return ret;
1148e491bc2fSNaveen N. Rao }
1149180b2061SMasami Hiramatsu
11503da3ea7aSNaveen N. Rao while (getline(&buf, &len, fp) > 0)
11513da3ea7aSNaveen N. Rao for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++)
11523da3ea7aSNaveen N. Rao if (!ftrace_readme_table[i].avail)
11533da3ea7aSNaveen N. Rao ftrace_readme_table[i].avail =
11543da3ea7aSNaveen N. Rao strglobmatch(buf, ftrace_readme_table[i].pattern);
11553da3ea7aSNaveen N. Rao scanned = true;
1156180b2061SMasami Hiramatsu
1157180b2061SMasami Hiramatsu fclose(fp);
1158180b2061SMasami Hiramatsu free(buf);
1159180b2061SMasami Hiramatsu
11603da3ea7aSNaveen N. Rao result:
11613da3ea7aSNaveen N. Rao if (type >= FTRACE_README_END)
11623da3ea7aSNaveen N. Rao return false;
11633da3ea7aSNaveen N. Rao
11643da3ea7aSNaveen N. Rao return ftrace_readme_table[type].avail;
11653da3ea7aSNaveen N. Rao }
11663da3ea7aSNaveen N. Rao
probe_type_is_available(enum probe_type type)11673da3ea7aSNaveen N. Rao bool probe_type_is_available(enum probe_type type)
11683da3ea7aSNaveen N. Rao {
11693da3ea7aSNaveen N. Rao if (type >= PROBE_TYPE_END)
11703da3ea7aSNaveen N. Rao return false;
11713da3ea7aSNaveen N. Rao else if (type == PROBE_TYPE_X)
11723da3ea7aSNaveen N. Rao return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
11733da3ea7aSNaveen N. Rao
11743da3ea7aSNaveen N. Rao return true;
1175180b2061SMasami Hiramatsu }
11767ab31d94SNaveen N. Rao
kretprobe_offset_is_supported(void)11777ab31d94SNaveen N. Rao bool kretprobe_offset_is_supported(void)
11787ab31d94SNaveen N. Rao {
11797ab31d94SNaveen N. Rao return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
11807ab31d94SNaveen N. Rao }
11815a5e3d3cSRavi Bangoria
uprobe_ref_ctr_is_supported(void)11825a5e3d3cSRavi Bangoria bool uprobe_ref_ctr_is_supported(void)
11835a5e3d3cSRavi Bangoria {
11845a5e3d3cSRavi Bangoria return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR);
11855a5e3d3cSRavi Bangoria }
11861e032f7cSMasami Hiramatsu
user_access_is_supported(void)11871e032f7cSMasami Hiramatsu bool user_access_is_supported(void)
11881e032f7cSMasami Hiramatsu {
11891e032f7cSMasami Hiramatsu return scan_ftrace_readme(FTRACE_README_USER_ACCESS);
11901e032f7cSMasami Hiramatsu }
119172363540SMasami Hiramatsu
multiprobe_event_is_supported(void)119272363540SMasami Hiramatsu bool multiprobe_event_is_supported(void)
119372363540SMasami Hiramatsu {
119472363540SMasami Hiramatsu return scan_ftrace_readme(FTRACE_README_MULTIPROBE_EVENT);
119572363540SMasami Hiramatsu }
119666f69b21SMasami Hiramatsu
immediate_value_is_supported(void)119766f69b21SMasami Hiramatsu bool immediate_value_is_supported(void)
119866f69b21SMasami Hiramatsu {
119966f69b21SMasami Hiramatsu return scan_ftrace_readme(FTRACE_README_IMMEDIATE_VALUE);
120066f69b21SMasami Hiramatsu }
1201