1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * probe-file.c : operate ftrace k/uprobe events files
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include <errno.h>
8*4882a593Smuzhiyun #include <fcntl.h>
9*4882a593Smuzhiyun #include <sys/stat.h>
10*4882a593Smuzhiyun #include <sys/types.h>
11*4882a593Smuzhiyun #include <sys/uio.h>
12*4882a593Smuzhiyun #include <unistd.h>
13*4882a593Smuzhiyun #include <linux/zalloc.h>
14*4882a593Smuzhiyun #include "namespaces.h"
15*4882a593Smuzhiyun #include "event.h"
16*4882a593Smuzhiyun #include "strlist.h"
17*4882a593Smuzhiyun #include "strfilter.h"
18*4882a593Smuzhiyun #include "debug.h"
19*4882a593Smuzhiyun #include "build-id.h"
20*4882a593Smuzhiyun #include "dso.h"
21*4882a593Smuzhiyun #include "color.h"
22*4882a593Smuzhiyun #include "symbol.h"
23*4882a593Smuzhiyun #include "strbuf.h"
24*4882a593Smuzhiyun #include <api/fs/tracing_path.h>
25*4882a593Smuzhiyun #include "probe-event.h"
26*4882a593Smuzhiyun #include "probe-file.h"
27*4882a593Smuzhiyun #include "session.h"
28*4882a593Smuzhiyun #include "perf_regs.h"
29*4882a593Smuzhiyun #include "string2.h"
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /* 4096 - 2 ('\n' + '\0') */
32*4882a593Smuzhiyun #define MAX_CMDLEN 4094
33*4882a593Smuzhiyun
print_open_warning(int err,bool uprobe)34*4882a593Smuzhiyun static void print_open_warning(int err, bool uprobe)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun char sbuf[STRERR_BUFSIZE];
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun if (err == -ENOENT) {
39*4882a593Smuzhiyun const char *config;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun if (uprobe)
42*4882a593Smuzhiyun config = "CONFIG_UPROBE_EVENTS";
43*4882a593Smuzhiyun else
44*4882a593Smuzhiyun config = "CONFIG_KPROBE_EVENTS";
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun pr_warning("%cprobe_events file does not exist"
47*4882a593Smuzhiyun " - please rebuild kernel with %s.\n",
48*4882a593Smuzhiyun uprobe ? 'u' : 'k', config);
49*4882a593Smuzhiyun } else if (err == -ENOTSUP)
50*4882a593Smuzhiyun pr_warning("Tracefs or debugfs is not mounted.\n");
51*4882a593Smuzhiyun else
52*4882a593Smuzhiyun pr_warning("Failed to open %cprobe_events: %s\n",
53*4882a593Smuzhiyun uprobe ? 'u' : 'k',
54*4882a593Smuzhiyun str_error_r(-err, sbuf, sizeof(sbuf)));
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
print_both_open_warning(int kerr,int uerr)57*4882a593Smuzhiyun static void print_both_open_warning(int kerr, int uerr)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun /* Both kprobes and uprobes are disabled, warn it. */
60*4882a593Smuzhiyun if (kerr == -ENOTSUP && uerr == -ENOTSUP)
61*4882a593Smuzhiyun pr_warning("Tracefs or debugfs is not mounted.\n");
62*4882a593Smuzhiyun else if (kerr == -ENOENT && uerr == -ENOENT)
63*4882a593Smuzhiyun pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
64*4882a593Smuzhiyun "or/and CONFIG_UPROBE_EVENTS.\n");
65*4882a593Smuzhiyun else {
66*4882a593Smuzhiyun char sbuf[STRERR_BUFSIZE];
67*4882a593Smuzhiyun pr_warning("Failed to open kprobe events: %s.\n",
68*4882a593Smuzhiyun str_error_r(-kerr, sbuf, sizeof(sbuf)));
69*4882a593Smuzhiyun pr_warning("Failed to open uprobe events: %s.\n",
70*4882a593Smuzhiyun str_error_r(-uerr, sbuf, sizeof(sbuf)));
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
open_trace_file(const char * trace_file,bool readwrite)74*4882a593Smuzhiyun int open_trace_file(const char *trace_file, bool readwrite)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun char buf[PATH_MAX];
77*4882a593Smuzhiyun int ret;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file);
80*4882a593Smuzhiyun if (ret >= 0) {
81*4882a593Smuzhiyun pr_debug("Opening %s write=%d\n", buf, readwrite);
82*4882a593Smuzhiyun if (readwrite && !probe_event_dry_run)
83*4882a593Smuzhiyun ret = open(buf, O_RDWR | O_APPEND, 0);
84*4882a593Smuzhiyun else
85*4882a593Smuzhiyun ret = open(buf, O_RDONLY, 0);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (ret < 0)
88*4882a593Smuzhiyun ret = -errno;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun return ret;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
open_kprobe_events(bool readwrite)93*4882a593Smuzhiyun static int open_kprobe_events(bool readwrite)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun return open_trace_file("kprobe_events", readwrite);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
open_uprobe_events(bool readwrite)98*4882a593Smuzhiyun static int open_uprobe_events(bool readwrite)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun return open_trace_file("uprobe_events", readwrite);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
probe_file__open(int flag)103*4882a593Smuzhiyun int probe_file__open(int flag)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun int fd;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (flag & PF_FL_UPROBE)
108*4882a593Smuzhiyun fd = open_uprobe_events(flag & PF_FL_RW);
109*4882a593Smuzhiyun else
110*4882a593Smuzhiyun fd = open_kprobe_events(flag & PF_FL_RW);
111*4882a593Smuzhiyun if (fd < 0)
112*4882a593Smuzhiyun print_open_warning(fd, flag & PF_FL_UPROBE);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun return fd;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
probe_file__open_both(int * kfd,int * ufd,int flag)117*4882a593Smuzhiyun int probe_file__open_both(int *kfd, int *ufd, int flag)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun if (!kfd || !ufd)
120*4882a593Smuzhiyun return -EINVAL;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun *kfd = open_kprobe_events(flag & PF_FL_RW);
123*4882a593Smuzhiyun *ufd = open_uprobe_events(flag & PF_FL_RW);
124*4882a593Smuzhiyun if (*kfd < 0 && *ufd < 0) {
125*4882a593Smuzhiyun print_both_open_warning(*kfd, *ufd);
126*4882a593Smuzhiyun return *kfd;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun return 0;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /* Get raw string list of current kprobe_events or uprobe_events */
probe_file__get_rawlist(int fd)133*4882a593Smuzhiyun struct strlist *probe_file__get_rawlist(int fd)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun int ret, idx, fddup;
136*4882a593Smuzhiyun FILE *fp;
137*4882a593Smuzhiyun char buf[MAX_CMDLEN];
138*4882a593Smuzhiyun char *p;
139*4882a593Smuzhiyun struct strlist *sl;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (fd < 0)
142*4882a593Smuzhiyun return NULL;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun sl = strlist__new(NULL, NULL);
145*4882a593Smuzhiyun if (sl == NULL)
146*4882a593Smuzhiyun return NULL;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun fddup = dup(fd);
149*4882a593Smuzhiyun if (fddup < 0)
150*4882a593Smuzhiyun goto out_free_sl;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun fp = fdopen(fddup, "r");
153*4882a593Smuzhiyun if (!fp)
154*4882a593Smuzhiyun goto out_close_fddup;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun while (!feof(fp)) {
157*4882a593Smuzhiyun p = fgets(buf, MAX_CMDLEN, fp);
158*4882a593Smuzhiyun if (!p)
159*4882a593Smuzhiyun break;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun idx = strlen(p) - 1;
162*4882a593Smuzhiyun if (p[idx] == '\n')
163*4882a593Smuzhiyun p[idx] = '\0';
164*4882a593Smuzhiyun ret = strlist__add(sl, buf);
165*4882a593Smuzhiyun if (ret < 0) {
166*4882a593Smuzhiyun pr_debug("strlist__add failed (%d)\n", ret);
167*4882a593Smuzhiyun goto out_close_fp;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun fclose(fp);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return sl;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun out_close_fp:
175*4882a593Smuzhiyun fclose(fp);
176*4882a593Smuzhiyun goto out_free_sl;
177*4882a593Smuzhiyun out_close_fddup:
178*4882a593Smuzhiyun close(fddup);
179*4882a593Smuzhiyun out_free_sl:
180*4882a593Smuzhiyun strlist__delete(sl);
181*4882a593Smuzhiyun return NULL;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
__probe_file__get_namelist(int fd,bool include_group)184*4882a593Smuzhiyun static struct strlist *__probe_file__get_namelist(int fd, bool include_group)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun char buf[128];
187*4882a593Smuzhiyun struct strlist *sl, *rawlist;
188*4882a593Smuzhiyun struct str_node *ent;
189*4882a593Smuzhiyun struct probe_trace_event tev;
190*4882a593Smuzhiyun int ret = 0;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun memset(&tev, 0, sizeof(tev));
193*4882a593Smuzhiyun rawlist = probe_file__get_rawlist(fd);
194*4882a593Smuzhiyun if (!rawlist)
195*4882a593Smuzhiyun return NULL;
196*4882a593Smuzhiyun sl = strlist__new(NULL, NULL);
197*4882a593Smuzhiyun strlist__for_each_entry(ent, rawlist) {
198*4882a593Smuzhiyun ret = parse_probe_trace_command(ent->s, &tev);
199*4882a593Smuzhiyun if (ret < 0)
200*4882a593Smuzhiyun break;
201*4882a593Smuzhiyun if (include_group) {
202*4882a593Smuzhiyun ret = e_snprintf(buf, 128, "%s:%s", tev.group,
203*4882a593Smuzhiyun tev.event);
204*4882a593Smuzhiyun if (ret >= 0)
205*4882a593Smuzhiyun ret = strlist__add(sl, buf);
206*4882a593Smuzhiyun } else
207*4882a593Smuzhiyun ret = strlist__add(sl, tev.event);
208*4882a593Smuzhiyun clear_probe_trace_event(&tev);
209*4882a593Smuzhiyun /* Skip if there is same name multi-probe event in the list */
210*4882a593Smuzhiyun if (ret == -EEXIST)
211*4882a593Smuzhiyun ret = 0;
212*4882a593Smuzhiyun if (ret < 0)
213*4882a593Smuzhiyun break;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun strlist__delete(rawlist);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun if (ret < 0) {
218*4882a593Smuzhiyun strlist__delete(sl);
219*4882a593Smuzhiyun return NULL;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun return sl;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* Get current perf-probe event names */
probe_file__get_namelist(int fd)225*4882a593Smuzhiyun struct strlist *probe_file__get_namelist(int fd)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun return __probe_file__get_namelist(fd, false);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
probe_file__add_event(int fd,struct probe_trace_event * tev)230*4882a593Smuzhiyun int probe_file__add_event(int fd, struct probe_trace_event *tev)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun int ret = 0;
233*4882a593Smuzhiyun char *buf = synthesize_probe_trace_command(tev);
234*4882a593Smuzhiyun char sbuf[STRERR_BUFSIZE];
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun if (!buf) {
237*4882a593Smuzhiyun pr_debug("Failed to synthesize probe trace event.\n");
238*4882a593Smuzhiyun return -EINVAL;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun pr_debug("Writing event: %s\n", buf);
242*4882a593Smuzhiyun if (!probe_event_dry_run) {
243*4882a593Smuzhiyun if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) {
244*4882a593Smuzhiyun ret = -errno;
245*4882a593Smuzhiyun pr_warning("Failed to write event: %s\n",
246*4882a593Smuzhiyun str_error_r(errno, sbuf, sizeof(sbuf)));
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun free(buf);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return ret;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
__del_trace_probe_event(int fd,struct str_node * ent)254*4882a593Smuzhiyun static int __del_trace_probe_event(int fd, struct str_node *ent)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun char *p;
257*4882a593Smuzhiyun char buf[128];
258*4882a593Smuzhiyun int ret;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /* Convert from perf-probe event to trace-probe event */
261*4882a593Smuzhiyun ret = e_snprintf(buf, 128, "-:%s", ent->s);
262*4882a593Smuzhiyun if (ret < 0)
263*4882a593Smuzhiyun goto error;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun p = strchr(buf + 2, ':');
266*4882a593Smuzhiyun if (!p) {
267*4882a593Smuzhiyun pr_debug("Internal error: %s should have ':' but not.\n",
268*4882a593Smuzhiyun ent->s);
269*4882a593Smuzhiyun ret = -ENOTSUP;
270*4882a593Smuzhiyun goto error;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun *p = '/';
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun pr_debug("Writing event: %s\n", buf);
275*4882a593Smuzhiyun ret = write(fd, buf, strlen(buf));
276*4882a593Smuzhiyun if (ret < 0) {
277*4882a593Smuzhiyun ret = -errno;
278*4882a593Smuzhiyun goto error;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun error:
283*4882a593Smuzhiyun pr_warning("Failed to delete event: %s\n",
284*4882a593Smuzhiyun str_error_r(-ret, buf, sizeof(buf)));
285*4882a593Smuzhiyun return ret;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
probe_file__get_events(int fd,struct strfilter * filter,struct strlist * plist)288*4882a593Smuzhiyun int probe_file__get_events(int fd, struct strfilter *filter,
289*4882a593Smuzhiyun struct strlist *plist)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun struct strlist *namelist;
292*4882a593Smuzhiyun struct str_node *ent;
293*4882a593Smuzhiyun const char *p;
294*4882a593Smuzhiyun int ret = -ENOENT;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if (!plist)
297*4882a593Smuzhiyun return -EINVAL;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun namelist = __probe_file__get_namelist(fd, true);
300*4882a593Smuzhiyun if (!namelist)
301*4882a593Smuzhiyun return -ENOENT;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun strlist__for_each_entry(ent, namelist) {
304*4882a593Smuzhiyun p = strchr(ent->s, ':');
305*4882a593Smuzhiyun if ((p && strfilter__compare(filter, p + 1)) ||
306*4882a593Smuzhiyun strfilter__compare(filter, ent->s)) {
307*4882a593Smuzhiyun ret = strlist__add(plist, ent->s);
308*4882a593Smuzhiyun if (ret == -ENOMEM) {
309*4882a593Smuzhiyun pr_err("strlist__add failed with -ENOMEM\n");
310*4882a593Smuzhiyun goto out;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun ret = 0;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun out:
316*4882a593Smuzhiyun strlist__delete(namelist);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun return ret;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
probe_file__del_strlist(int fd,struct strlist * namelist)321*4882a593Smuzhiyun int probe_file__del_strlist(int fd, struct strlist *namelist)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun int ret = 0;
324*4882a593Smuzhiyun struct str_node *ent;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun strlist__for_each_entry(ent, namelist) {
327*4882a593Smuzhiyun ret = __del_trace_probe_event(fd, ent);
328*4882a593Smuzhiyun if (ret < 0)
329*4882a593Smuzhiyun break;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun return ret;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
probe_file__del_events(int fd,struct strfilter * filter)334*4882a593Smuzhiyun int probe_file__del_events(int fd, struct strfilter *filter)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun struct strlist *namelist;
337*4882a593Smuzhiyun int ret;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun namelist = strlist__new(NULL, NULL);
340*4882a593Smuzhiyun if (!namelist)
341*4882a593Smuzhiyun return -ENOMEM;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun ret = probe_file__get_events(fd, filter, namelist);
344*4882a593Smuzhiyun if (ret < 0)
345*4882a593Smuzhiyun goto out;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun ret = probe_file__del_strlist(fd, namelist);
348*4882a593Smuzhiyun out:
349*4882a593Smuzhiyun strlist__delete(namelist);
350*4882a593Smuzhiyun return ret;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /* Caller must ensure to remove this entry from list */
probe_cache_entry__delete(struct probe_cache_entry * entry)354*4882a593Smuzhiyun static void probe_cache_entry__delete(struct probe_cache_entry *entry)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun if (entry) {
357*4882a593Smuzhiyun BUG_ON(!list_empty(&entry->node));
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun strlist__delete(entry->tevlist);
360*4882a593Smuzhiyun clear_perf_probe_event(&entry->pev);
361*4882a593Smuzhiyun zfree(&entry->spev);
362*4882a593Smuzhiyun free(entry);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun static struct probe_cache_entry *
probe_cache_entry__new(struct perf_probe_event * pev)367*4882a593Smuzhiyun probe_cache_entry__new(struct perf_probe_event *pev)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun struct probe_cache_entry *entry = zalloc(sizeof(*entry));
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (entry) {
372*4882a593Smuzhiyun INIT_LIST_HEAD(&entry->node);
373*4882a593Smuzhiyun entry->tevlist = strlist__new(NULL, NULL);
374*4882a593Smuzhiyun if (!entry->tevlist)
375*4882a593Smuzhiyun zfree(&entry);
376*4882a593Smuzhiyun else if (pev) {
377*4882a593Smuzhiyun entry->spev = synthesize_perf_probe_command(pev);
378*4882a593Smuzhiyun if (!entry->spev ||
379*4882a593Smuzhiyun perf_probe_event__copy(&entry->pev, pev) < 0) {
380*4882a593Smuzhiyun probe_cache_entry__delete(entry);
381*4882a593Smuzhiyun return NULL;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun return entry;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
probe_cache_entry__get_event(struct probe_cache_entry * entry,struct probe_trace_event ** tevs)389*4882a593Smuzhiyun int probe_cache_entry__get_event(struct probe_cache_entry *entry,
390*4882a593Smuzhiyun struct probe_trace_event **tevs)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun struct probe_trace_event *tev;
393*4882a593Smuzhiyun struct str_node *node;
394*4882a593Smuzhiyun int ret, i;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun ret = strlist__nr_entries(entry->tevlist);
397*4882a593Smuzhiyun if (ret > probe_conf.max_probes)
398*4882a593Smuzhiyun return -E2BIG;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun *tevs = zalloc(ret * sizeof(*tev));
401*4882a593Smuzhiyun if (!*tevs)
402*4882a593Smuzhiyun return -ENOMEM;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun i = 0;
405*4882a593Smuzhiyun strlist__for_each_entry(node, entry->tevlist) {
406*4882a593Smuzhiyun tev = &(*tevs)[i++];
407*4882a593Smuzhiyun ret = parse_probe_trace_command(node->s, tev);
408*4882a593Smuzhiyun if (ret < 0)
409*4882a593Smuzhiyun break;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun return i;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun /* 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)415*4882a593Smuzhiyun static int probe_cache__open(struct probe_cache *pcache, const char *target,
416*4882a593Smuzhiyun struct nsinfo *nsi)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun char cpath[PATH_MAX];
419*4882a593Smuzhiyun char sbuildid[SBUILD_ID_SIZE];
420*4882a593Smuzhiyun char *dir_name = NULL;
421*4882a593Smuzhiyun bool is_kallsyms = false;
422*4882a593Smuzhiyun int ret, fd;
423*4882a593Smuzhiyun struct nscookie nsc;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun if (target && build_id_cache__cached(target)) {
426*4882a593Smuzhiyun /* This is a cached buildid */
427*4882a593Smuzhiyun strlcpy(sbuildid, target, SBUILD_ID_SIZE);
428*4882a593Smuzhiyun dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
429*4882a593Smuzhiyun goto found;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {
433*4882a593Smuzhiyun target = DSO__NAME_KALLSYMS;
434*4882a593Smuzhiyun is_kallsyms = true;
435*4882a593Smuzhiyun ret = sysfs__sprintf_build_id("/", sbuildid);
436*4882a593Smuzhiyun } else {
437*4882a593Smuzhiyun nsinfo__mountns_enter(nsi, &nsc);
438*4882a593Smuzhiyun ret = filename__sprintf_build_id(target, sbuildid);
439*4882a593Smuzhiyun nsinfo__mountns_exit(&nsc);
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun if (ret < 0) {
443*4882a593Smuzhiyun pr_debug("Failed to get build-id from %s.\n", target);
444*4882a593Smuzhiyun return ret;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun /* If we have no buildid cache, make it */
448*4882a593Smuzhiyun if (!build_id_cache__cached(sbuildid)) {
449*4882a593Smuzhiyun ret = build_id_cache__add_s(sbuildid, target, nsi,
450*4882a593Smuzhiyun is_kallsyms, NULL);
451*4882a593Smuzhiyun if (ret < 0) {
452*4882a593Smuzhiyun pr_debug("Failed to add build-id cache: %s\n", target);
453*4882a593Smuzhiyun return ret;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun dir_name = build_id_cache__cachedir(sbuildid, target, nsi, is_kallsyms,
458*4882a593Smuzhiyun false);
459*4882a593Smuzhiyun found:
460*4882a593Smuzhiyun if (!dir_name) {
461*4882a593Smuzhiyun pr_debug("Failed to get cache from %s\n", target);
462*4882a593Smuzhiyun return -ENOMEM;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
466*4882a593Smuzhiyun fd = open(cpath, O_CREAT | O_RDWR, 0644);
467*4882a593Smuzhiyun if (fd < 0)
468*4882a593Smuzhiyun pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
469*4882a593Smuzhiyun free(dir_name);
470*4882a593Smuzhiyun pcache->fd = fd;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun return fd;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
probe_cache__load(struct probe_cache * pcache)475*4882a593Smuzhiyun static int probe_cache__load(struct probe_cache *pcache)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun struct probe_cache_entry *entry = NULL;
478*4882a593Smuzhiyun char buf[MAX_CMDLEN], *p;
479*4882a593Smuzhiyun int ret = 0, fddup;
480*4882a593Smuzhiyun FILE *fp;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun fddup = dup(pcache->fd);
483*4882a593Smuzhiyun if (fddup < 0)
484*4882a593Smuzhiyun return -errno;
485*4882a593Smuzhiyun fp = fdopen(fddup, "r");
486*4882a593Smuzhiyun if (!fp) {
487*4882a593Smuzhiyun close(fddup);
488*4882a593Smuzhiyun return -EINVAL;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun while (!feof(fp)) {
492*4882a593Smuzhiyun if (!fgets(buf, MAX_CMDLEN, fp))
493*4882a593Smuzhiyun break;
494*4882a593Smuzhiyun p = strchr(buf, '\n');
495*4882a593Smuzhiyun if (p)
496*4882a593Smuzhiyun *p = '\0';
497*4882a593Smuzhiyun /* #perf_probe_event or %sdt_event */
498*4882a593Smuzhiyun if (buf[0] == '#' || buf[0] == '%') {
499*4882a593Smuzhiyun entry = probe_cache_entry__new(NULL);
500*4882a593Smuzhiyun if (!entry) {
501*4882a593Smuzhiyun ret = -ENOMEM;
502*4882a593Smuzhiyun goto out;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun if (buf[0] == '%')
505*4882a593Smuzhiyun entry->sdt = true;
506*4882a593Smuzhiyun entry->spev = strdup(buf + 1);
507*4882a593Smuzhiyun if (entry->spev)
508*4882a593Smuzhiyun ret = parse_perf_probe_command(buf + 1,
509*4882a593Smuzhiyun &entry->pev);
510*4882a593Smuzhiyun else
511*4882a593Smuzhiyun ret = -ENOMEM;
512*4882a593Smuzhiyun if (ret < 0) {
513*4882a593Smuzhiyun probe_cache_entry__delete(entry);
514*4882a593Smuzhiyun goto out;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun list_add_tail(&entry->node, &pcache->entries);
517*4882a593Smuzhiyun } else { /* trace_probe_event */
518*4882a593Smuzhiyun if (!entry) {
519*4882a593Smuzhiyun ret = -EINVAL;
520*4882a593Smuzhiyun goto out;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun ret = strlist__add(entry->tevlist, buf);
523*4882a593Smuzhiyun if (ret == -ENOMEM) {
524*4882a593Smuzhiyun pr_err("strlist__add failed with -ENOMEM\n");
525*4882a593Smuzhiyun goto out;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun out:
530*4882a593Smuzhiyun fclose(fp);
531*4882a593Smuzhiyun return ret;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
probe_cache__alloc(void)534*4882a593Smuzhiyun static struct probe_cache *probe_cache__alloc(void)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun struct probe_cache *pcache = zalloc(sizeof(*pcache));
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun if (pcache) {
539*4882a593Smuzhiyun INIT_LIST_HEAD(&pcache->entries);
540*4882a593Smuzhiyun pcache->fd = -EINVAL;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun return pcache;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
probe_cache__purge(struct probe_cache * pcache)545*4882a593Smuzhiyun void probe_cache__purge(struct probe_cache *pcache)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun struct probe_cache_entry *entry, *n;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun list_for_each_entry_safe(entry, n, &pcache->entries, node) {
550*4882a593Smuzhiyun list_del_init(&entry->node);
551*4882a593Smuzhiyun probe_cache_entry__delete(entry);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
probe_cache__delete(struct probe_cache * pcache)555*4882a593Smuzhiyun void probe_cache__delete(struct probe_cache *pcache)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun if (!pcache)
558*4882a593Smuzhiyun return;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun probe_cache__purge(pcache);
561*4882a593Smuzhiyun if (pcache->fd > 0)
562*4882a593Smuzhiyun close(pcache->fd);
563*4882a593Smuzhiyun free(pcache);
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
probe_cache__new(const char * target,struct nsinfo * nsi)566*4882a593Smuzhiyun struct probe_cache *probe_cache__new(const char *target, struct nsinfo *nsi)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun struct probe_cache *pcache = probe_cache__alloc();
569*4882a593Smuzhiyun int ret;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun if (!pcache)
572*4882a593Smuzhiyun return NULL;
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun ret = probe_cache__open(pcache, target, nsi);
575*4882a593Smuzhiyun if (ret < 0) {
576*4882a593Smuzhiyun pr_debug("Cache open error: %d\n", ret);
577*4882a593Smuzhiyun goto out_err;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun ret = probe_cache__load(pcache);
581*4882a593Smuzhiyun if (ret < 0) {
582*4882a593Smuzhiyun pr_debug("Cache read error: %d\n", ret);
583*4882a593Smuzhiyun goto out_err;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun return pcache;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun out_err:
589*4882a593Smuzhiyun probe_cache__delete(pcache);
590*4882a593Smuzhiyun return NULL;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
streql(const char * a,const char * b)593*4882a593Smuzhiyun static bool streql(const char *a, const char *b)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun if (a == b)
596*4882a593Smuzhiyun return true;
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun if (!a || !b)
599*4882a593Smuzhiyun return false;
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun return !strcmp(a, b);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun struct probe_cache_entry *
probe_cache__find(struct probe_cache * pcache,struct perf_probe_event * pev)605*4882a593Smuzhiyun probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun struct probe_cache_entry *entry = NULL;
608*4882a593Smuzhiyun char *cmd = synthesize_perf_probe_command(pev);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun if (!cmd)
611*4882a593Smuzhiyun return NULL;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun for_each_probe_cache_entry(entry, pcache) {
614*4882a593Smuzhiyun if (pev->sdt) {
615*4882a593Smuzhiyun if (entry->pev.event &&
616*4882a593Smuzhiyun streql(entry->pev.event, pev->event) &&
617*4882a593Smuzhiyun (!pev->group ||
618*4882a593Smuzhiyun streql(entry->pev.group, pev->group)))
619*4882a593Smuzhiyun goto found;
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun continue;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun /* Hit if same event name or same command-string */
624*4882a593Smuzhiyun if ((pev->event &&
625*4882a593Smuzhiyun (streql(entry->pev.group, pev->group) &&
626*4882a593Smuzhiyun streql(entry->pev.event, pev->event))) ||
627*4882a593Smuzhiyun (!strcmp(entry->spev, cmd)))
628*4882a593Smuzhiyun goto found;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun entry = NULL;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun found:
633*4882a593Smuzhiyun free(cmd);
634*4882a593Smuzhiyun return entry;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun struct probe_cache_entry *
probe_cache__find_by_name(struct probe_cache * pcache,const char * group,const char * event)638*4882a593Smuzhiyun probe_cache__find_by_name(struct probe_cache *pcache,
639*4882a593Smuzhiyun const char *group, const char *event)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun struct probe_cache_entry *entry = NULL;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun for_each_probe_cache_entry(entry, pcache) {
644*4882a593Smuzhiyun /* Hit if same event name or same command-string */
645*4882a593Smuzhiyun if (streql(entry->pev.group, group) &&
646*4882a593Smuzhiyun streql(entry->pev.event, event))
647*4882a593Smuzhiyun goto found;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun entry = NULL;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun found:
652*4882a593Smuzhiyun return entry;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun
probe_cache__add_entry(struct probe_cache * pcache,struct perf_probe_event * pev,struct probe_trace_event * tevs,int ntevs)655*4882a593Smuzhiyun int probe_cache__add_entry(struct probe_cache *pcache,
656*4882a593Smuzhiyun struct perf_probe_event *pev,
657*4882a593Smuzhiyun struct probe_trace_event *tevs, int ntevs)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun struct probe_cache_entry *entry = NULL;
660*4882a593Smuzhiyun char *command;
661*4882a593Smuzhiyun int i, ret = 0;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun if (!pcache || !pev || !tevs || ntevs <= 0) {
664*4882a593Smuzhiyun ret = -EINVAL;
665*4882a593Smuzhiyun goto out_err;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun /* Remove old cache entry */
669*4882a593Smuzhiyun entry = probe_cache__find(pcache, pev);
670*4882a593Smuzhiyun if (entry) {
671*4882a593Smuzhiyun list_del_init(&entry->node);
672*4882a593Smuzhiyun probe_cache_entry__delete(entry);
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun ret = -ENOMEM;
676*4882a593Smuzhiyun entry = probe_cache_entry__new(pev);
677*4882a593Smuzhiyun if (!entry)
678*4882a593Smuzhiyun goto out_err;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun for (i = 0; i < ntevs; i++) {
681*4882a593Smuzhiyun if (!tevs[i].point.symbol)
682*4882a593Smuzhiyun continue;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun command = synthesize_probe_trace_command(&tevs[i]);
685*4882a593Smuzhiyun if (!command)
686*4882a593Smuzhiyun goto out_err;
687*4882a593Smuzhiyun ret = strlist__add(entry->tevlist, command);
688*4882a593Smuzhiyun if (ret == -ENOMEM) {
689*4882a593Smuzhiyun pr_err("strlist__add failed with -ENOMEM\n");
690*4882a593Smuzhiyun goto out_err;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun free(command);
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun list_add_tail(&entry->node, &pcache->entries);
696*4882a593Smuzhiyun pr_debug("Added probe cache: %d\n", ntevs);
697*4882a593Smuzhiyun return 0;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun out_err:
700*4882a593Smuzhiyun pr_debug("Failed to add probe caches\n");
701*4882a593Smuzhiyun probe_cache_entry__delete(entry);
702*4882a593Smuzhiyun return ret;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun #ifdef HAVE_GELF_GETNOTE_SUPPORT
sdt_note__get_addr(struct sdt_note * note)706*4882a593Smuzhiyun static unsigned long long sdt_note__get_addr(struct sdt_note *note)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun return note->bit32 ?
709*4882a593Smuzhiyun (unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] :
710*4882a593Smuzhiyun (unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC];
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun
sdt_note__get_ref_ctr_offset(struct sdt_note * note)713*4882a593Smuzhiyun static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun return note->bit32 ?
716*4882a593Smuzhiyun (unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] :
717*4882a593Smuzhiyun (unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR];
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun static const char * const type_to_suffix[] = {
721*4882a593Smuzhiyun ":s64", "", "", "", ":s32", "", ":s16", ":s8",
722*4882a593Smuzhiyun "", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
723*4882a593Smuzhiyun };
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun /*
726*4882a593Smuzhiyun * Isolate the string number and convert it into a decimal value;
727*4882a593Smuzhiyun * this will be an index to get suffix of the uprobe name (defining
728*4882a593Smuzhiyun * the type)
729*4882a593Smuzhiyun */
sdt_arg_parse_size(char * n_ptr,const char ** suffix)730*4882a593Smuzhiyun static int sdt_arg_parse_size(char *n_ptr, const char **suffix)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun long type_idx;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun type_idx = strtol(n_ptr, NULL, 10);
735*4882a593Smuzhiyun if (type_idx < -8 || type_idx > 8) {
736*4882a593Smuzhiyun pr_debug4("Failed to get a valid sdt type\n");
737*4882a593Smuzhiyun return -1;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun *suffix = type_to_suffix[type_idx + 8];
741*4882a593Smuzhiyun return 0;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun
synthesize_sdt_probe_arg(struct strbuf * buf,int i,const char * arg)744*4882a593Smuzhiyun static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun char *op, *desc = strdup(arg), *new_op = NULL;
747*4882a593Smuzhiyun const char *suffix = "";
748*4882a593Smuzhiyun int ret = -1;
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun if (desc == NULL) {
751*4882a593Smuzhiyun pr_debug4("Allocation error\n");
752*4882a593Smuzhiyun return ret;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun /*
756*4882a593Smuzhiyun * Argument is in N@OP format. N is size of the argument and OP is
757*4882a593Smuzhiyun * the actual assembly operand. N can be omitted; in that case
758*4882a593Smuzhiyun * argument is just OP(without @).
759*4882a593Smuzhiyun */
760*4882a593Smuzhiyun op = strchr(desc, '@');
761*4882a593Smuzhiyun if (op) {
762*4882a593Smuzhiyun op[0] = '\0';
763*4882a593Smuzhiyun op++;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun if (sdt_arg_parse_size(desc, &suffix))
766*4882a593Smuzhiyun goto error;
767*4882a593Smuzhiyun } else {
768*4882a593Smuzhiyun op = desc;
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun ret = arch_sdt_arg_parse_op(op, &new_op);
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun if (ret < 0)
774*4882a593Smuzhiyun goto error;
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun if (ret == SDT_ARG_VALID) {
777*4882a593Smuzhiyun ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);
778*4882a593Smuzhiyun if (ret < 0)
779*4882a593Smuzhiyun goto error;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun ret = 0;
783*4882a593Smuzhiyun error:
784*4882a593Smuzhiyun free(desc);
785*4882a593Smuzhiyun free(new_op);
786*4882a593Smuzhiyun return ret;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun
synthesize_sdt_probe_command(struct sdt_note * note,const char * pathname,const char * sdtgrp)789*4882a593Smuzhiyun static char *synthesize_sdt_probe_command(struct sdt_note *note,
790*4882a593Smuzhiyun const char *pathname,
791*4882a593Smuzhiyun const char *sdtgrp)
792*4882a593Smuzhiyun {
793*4882a593Smuzhiyun struct strbuf buf;
794*4882a593Smuzhiyun char *ret = NULL;
795*4882a593Smuzhiyun int i, args_count, err;
796*4882a593Smuzhiyun unsigned long long ref_ctr_offset;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun if (strbuf_init(&buf, 32) < 0)
799*4882a593Smuzhiyun return NULL;
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
802*4882a593Smuzhiyun sdtgrp, note->name, pathname,
803*4882a593Smuzhiyun sdt_note__get_addr(note));
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun ref_ctr_offset = sdt_note__get_ref_ctr_offset(note);
806*4882a593Smuzhiyun if (ref_ctr_offset && err >= 0)
807*4882a593Smuzhiyun err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset);
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun if (err < 0)
810*4882a593Smuzhiyun goto error;
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun if (!note->args)
813*4882a593Smuzhiyun goto out;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun if (note->args) {
816*4882a593Smuzhiyun char **args = argv_split(note->args, &args_count);
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun if (args == NULL)
819*4882a593Smuzhiyun goto error;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun for (i = 0; i < args_count; ++i) {
822*4882a593Smuzhiyun if (synthesize_sdt_probe_arg(&buf, i, args[i]) < 0) {
823*4882a593Smuzhiyun argv_free(args);
824*4882a593Smuzhiyun goto error;
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun argv_free(args);
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun out:
832*4882a593Smuzhiyun ret = strbuf_detach(&buf, NULL);
833*4882a593Smuzhiyun error:
834*4882a593Smuzhiyun strbuf_release(&buf);
835*4882a593Smuzhiyun return ret;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun
probe_cache__scan_sdt(struct probe_cache * pcache,const char * pathname)838*4882a593Smuzhiyun int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun struct probe_cache_entry *entry = NULL;
841*4882a593Smuzhiyun struct list_head sdtlist;
842*4882a593Smuzhiyun struct sdt_note *note;
843*4882a593Smuzhiyun char *buf;
844*4882a593Smuzhiyun char sdtgrp[64];
845*4882a593Smuzhiyun int ret;
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun INIT_LIST_HEAD(&sdtlist);
848*4882a593Smuzhiyun ret = get_sdt_note_list(&sdtlist, pathname);
849*4882a593Smuzhiyun if (ret < 0) {
850*4882a593Smuzhiyun pr_debug4("Failed to get sdt note: %d\n", ret);
851*4882a593Smuzhiyun return ret;
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun list_for_each_entry(note, &sdtlist, note_list) {
854*4882a593Smuzhiyun ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);
855*4882a593Smuzhiyun if (ret < 0)
856*4882a593Smuzhiyun break;
857*4882a593Smuzhiyun /* Try to find same-name entry */
858*4882a593Smuzhiyun entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
859*4882a593Smuzhiyun if (!entry) {
860*4882a593Smuzhiyun entry = probe_cache_entry__new(NULL);
861*4882a593Smuzhiyun if (!entry) {
862*4882a593Smuzhiyun ret = -ENOMEM;
863*4882a593Smuzhiyun break;
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun entry->sdt = true;
866*4882a593Smuzhiyun ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,
867*4882a593Smuzhiyun note->name, note->name);
868*4882a593Smuzhiyun if (ret < 0)
869*4882a593Smuzhiyun break;
870*4882a593Smuzhiyun entry->pev.event = strdup(note->name);
871*4882a593Smuzhiyun entry->pev.group = strdup(sdtgrp);
872*4882a593Smuzhiyun list_add_tail(&entry->node, &pcache->entries);
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun buf = synthesize_sdt_probe_command(note, pathname, sdtgrp);
875*4882a593Smuzhiyun if (!buf) {
876*4882a593Smuzhiyun ret = -ENOMEM;
877*4882a593Smuzhiyun break;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun ret = strlist__add(entry->tevlist, buf);
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun free(buf);
883*4882a593Smuzhiyun entry = NULL;
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun if (ret == -ENOMEM) {
886*4882a593Smuzhiyun pr_err("strlist__add failed with -ENOMEM\n");
887*4882a593Smuzhiyun break;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun if (entry) {
891*4882a593Smuzhiyun list_del_init(&entry->node);
892*4882a593Smuzhiyun probe_cache_entry__delete(entry);
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun cleanup_sdt_note_list(&sdtlist);
895*4882a593Smuzhiyun return ret;
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun #endif
898*4882a593Smuzhiyun
probe_cache_entry__write(struct probe_cache_entry * entry,int fd)899*4882a593Smuzhiyun static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun struct str_node *snode;
902*4882a593Smuzhiyun struct stat st;
903*4882a593Smuzhiyun struct iovec iov[3];
904*4882a593Smuzhiyun const char *prefix = entry->sdt ? "%" : "#";
905*4882a593Smuzhiyun int ret;
906*4882a593Smuzhiyun /* Save stat for rollback */
907*4882a593Smuzhiyun ret = fstat(fd, &st);
908*4882a593Smuzhiyun if (ret < 0)
909*4882a593Smuzhiyun return ret;
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun pr_debug("Writing cache: %s%s\n", prefix, entry->spev);
912*4882a593Smuzhiyun iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;
913*4882a593Smuzhiyun iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
914*4882a593Smuzhiyun iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
915*4882a593Smuzhiyun ret = writev(fd, iov, 3);
916*4882a593Smuzhiyun if (ret < (int)iov[1].iov_len + 2)
917*4882a593Smuzhiyun goto rollback;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun strlist__for_each_entry(snode, entry->tevlist) {
920*4882a593Smuzhiyun iov[0].iov_base = (void *)snode->s;
921*4882a593Smuzhiyun iov[0].iov_len = strlen(snode->s);
922*4882a593Smuzhiyun iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1;
923*4882a593Smuzhiyun ret = writev(fd, iov, 2);
924*4882a593Smuzhiyun if (ret < (int)iov[0].iov_len + 1)
925*4882a593Smuzhiyun goto rollback;
926*4882a593Smuzhiyun }
927*4882a593Smuzhiyun return 0;
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun rollback:
930*4882a593Smuzhiyun /* Rollback to avoid cache file corruption */
931*4882a593Smuzhiyun if (ret > 0)
932*4882a593Smuzhiyun ret = -1;
933*4882a593Smuzhiyun if (ftruncate(fd, st.st_size) < 0)
934*4882a593Smuzhiyun ret = -2;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun return ret;
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun
probe_cache__commit(struct probe_cache * pcache)939*4882a593Smuzhiyun int probe_cache__commit(struct probe_cache *pcache)
940*4882a593Smuzhiyun {
941*4882a593Smuzhiyun struct probe_cache_entry *entry;
942*4882a593Smuzhiyun int ret = 0;
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun /* TBD: if we do not update existing entries, skip it */
945*4882a593Smuzhiyun ret = lseek(pcache->fd, 0, SEEK_SET);
946*4882a593Smuzhiyun if (ret < 0)
947*4882a593Smuzhiyun goto out;
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun ret = ftruncate(pcache->fd, 0);
950*4882a593Smuzhiyun if (ret < 0)
951*4882a593Smuzhiyun goto out;
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun for_each_probe_cache_entry(entry, pcache) {
954*4882a593Smuzhiyun ret = probe_cache_entry__write(entry, pcache->fd);
955*4882a593Smuzhiyun pr_debug("Cache committed: %d\n", ret);
956*4882a593Smuzhiyun if (ret < 0)
957*4882a593Smuzhiyun break;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun out:
960*4882a593Smuzhiyun return ret;
961*4882a593Smuzhiyun }
962*4882a593Smuzhiyun
probe_cache_entry__compare(struct probe_cache_entry * entry,struct strfilter * filter)963*4882a593Smuzhiyun static bool probe_cache_entry__compare(struct probe_cache_entry *entry,
964*4882a593Smuzhiyun struct strfilter *filter)
965*4882a593Smuzhiyun {
966*4882a593Smuzhiyun char buf[128], *ptr = entry->spev;
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun if (entry->pev.event) {
969*4882a593Smuzhiyun snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
970*4882a593Smuzhiyun ptr = buf;
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun return strfilter__compare(filter, ptr);
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun
probe_cache__filter_purge(struct probe_cache * pcache,struct strfilter * filter)975*4882a593Smuzhiyun int probe_cache__filter_purge(struct probe_cache *pcache,
976*4882a593Smuzhiyun struct strfilter *filter)
977*4882a593Smuzhiyun {
978*4882a593Smuzhiyun struct probe_cache_entry *entry, *tmp;
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun list_for_each_entry_safe(entry, tmp, &pcache->entries, node) {
981*4882a593Smuzhiyun if (probe_cache_entry__compare(entry, filter)) {
982*4882a593Smuzhiyun pr_info("Removed cached event: %s\n", entry->spev);
983*4882a593Smuzhiyun list_del_init(&entry->node);
984*4882a593Smuzhiyun probe_cache_entry__delete(entry);
985*4882a593Smuzhiyun }
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun return 0;
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun
probe_cache__show_entries(struct probe_cache * pcache,struct strfilter * filter)990*4882a593Smuzhiyun static int probe_cache__show_entries(struct probe_cache *pcache,
991*4882a593Smuzhiyun struct strfilter *filter)
992*4882a593Smuzhiyun {
993*4882a593Smuzhiyun struct probe_cache_entry *entry;
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun for_each_probe_cache_entry(entry, pcache) {
996*4882a593Smuzhiyun if (probe_cache_entry__compare(entry, filter))
997*4882a593Smuzhiyun printf("%s\n", entry->spev);
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun return 0;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun /* Show all cached probes */
probe_cache__show_all_caches(struct strfilter * filter)1003*4882a593Smuzhiyun int probe_cache__show_all_caches(struct strfilter *filter)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun struct probe_cache *pcache;
1006*4882a593Smuzhiyun struct strlist *bidlist;
1007*4882a593Smuzhiyun struct str_node *nd;
1008*4882a593Smuzhiyun char *buf = strfilter__string(filter);
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun pr_debug("list cache with filter: %s\n", buf);
1011*4882a593Smuzhiyun free(buf);
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun bidlist = build_id_cache__list_all(true);
1014*4882a593Smuzhiyun if (!bidlist) {
1015*4882a593Smuzhiyun pr_debug("Failed to get buildids: %d\n", errno);
1016*4882a593Smuzhiyun return -EINVAL;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun strlist__for_each_entry(nd, bidlist) {
1019*4882a593Smuzhiyun pcache = probe_cache__new(nd->s, NULL);
1020*4882a593Smuzhiyun if (!pcache)
1021*4882a593Smuzhiyun continue;
1022*4882a593Smuzhiyun if (!list_empty(&pcache->entries)) {
1023*4882a593Smuzhiyun buf = build_id_cache__origname(nd->s);
1024*4882a593Smuzhiyun printf("%s (%s):\n", buf, nd->s);
1025*4882a593Smuzhiyun free(buf);
1026*4882a593Smuzhiyun probe_cache__show_entries(pcache, filter);
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun probe_cache__delete(pcache);
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun strlist__delete(bidlist);
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun return 0;
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun enum ftrace_readme {
1036*4882a593Smuzhiyun FTRACE_README_PROBE_TYPE_X = 0,
1037*4882a593Smuzhiyun FTRACE_README_KRETPROBE_OFFSET,
1038*4882a593Smuzhiyun FTRACE_README_UPROBE_REF_CTR,
1039*4882a593Smuzhiyun FTRACE_README_USER_ACCESS,
1040*4882a593Smuzhiyun FTRACE_README_MULTIPROBE_EVENT,
1041*4882a593Smuzhiyun FTRACE_README_IMMEDIATE_VALUE,
1042*4882a593Smuzhiyun FTRACE_README_END,
1043*4882a593Smuzhiyun };
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun static struct {
1046*4882a593Smuzhiyun const char *pattern;
1047*4882a593Smuzhiyun bool avail;
1048*4882a593Smuzhiyun } ftrace_readme_table[] = {
1049*4882a593Smuzhiyun #define DEFINE_TYPE(idx, pat) \
1050*4882a593Smuzhiyun [idx] = {.pattern = pat, .avail = false}
1051*4882a593Smuzhiyun DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
1052*4882a593Smuzhiyun DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
1053*4882a593Smuzhiyun DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"),
1054*4882a593Smuzhiyun DEFINE_TYPE(FTRACE_README_USER_ACCESS, "*u]<offset>*"),
1055*4882a593Smuzhiyun DEFINE_TYPE(FTRACE_README_MULTIPROBE_EVENT, "*Create/append/*"),
1056*4882a593Smuzhiyun DEFINE_TYPE(FTRACE_README_IMMEDIATE_VALUE, "*\\imm-value,*"),
1057*4882a593Smuzhiyun };
1058*4882a593Smuzhiyun
scan_ftrace_readme(enum ftrace_readme type)1059*4882a593Smuzhiyun static bool scan_ftrace_readme(enum ftrace_readme type)
1060*4882a593Smuzhiyun {
1061*4882a593Smuzhiyun int fd;
1062*4882a593Smuzhiyun FILE *fp;
1063*4882a593Smuzhiyun char *buf = NULL;
1064*4882a593Smuzhiyun size_t len = 0;
1065*4882a593Smuzhiyun bool ret = false;
1066*4882a593Smuzhiyun static bool scanned = false;
1067*4882a593Smuzhiyun
1068*4882a593Smuzhiyun if (scanned)
1069*4882a593Smuzhiyun goto result;
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun fd = open_trace_file("README", false);
1072*4882a593Smuzhiyun if (fd < 0)
1073*4882a593Smuzhiyun return ret;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun fp = fdopen(fd, "r");
1076*4882a593Smuzhiyun if (!fp) {
1077*4882a593Smuzhiyun close(fd);
1078*4882a593Smuzhiyun return ret;
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun while (getline(&buf, &len, fp) > 0)
1082*4882a593Smuzhiyun for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++)
1083*4882a593Smuzhiyun if (!ftrace_readme_table[i].avail)
1084*4882a593Smuzhiyun ftrace_readme_table[i].avail =
1085*4882a593Smuzhiyun strglobmatch(buf, ftrace_readme_table[i].pattern);
1086*4882a593Smuzhiyun scanned = true;
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun fclose(fp);
1089*4882a593Smuzhiyun free(buf);
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun result:
1092*4882a593Smuzhiyun if (type >= FTRACE_README_END)
1093*4882a593Smuzhiyun return false;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun return ftrace_readme_table[type].avail;
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun
probe_type_is_available(enum probe_type type)1098*4882a593Smuzhiyun bool probe_type_is_available(enum probe_type type)
1099*4882a593Smuzhiyun {
1100*4882a593Smuzhiyun if (type >= PROBE_TYPE_END)
1101*4882a593Smuzhiyun return false;
1102*4882a593Smuzhiyun else if (type == PROBE_TYPE_X)
1103*4882a593Smuzhiyun return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun return true;
1106*4882a593Smuzhiyun }
1107*4882a593Smuzhiyun
kretprobe_offset_is_supported(void)1108*4882a593Smuzhiyun bool kretprobe_offset_is_supported(void)
1109*4882a593Smuzhiyun {
1110*4882a593Smuzhiyun return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun
uprobe_ref_ctr_is_supported(void)1113*4882a593Smuzhiyun bool uprobe_ref_ctr_is_supported(void)
1114*4882a593Smuzhiyun {
1115*4882a593Smuzhiyun return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR);
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun
user_access_is_supported(void)1118*4882a593Smuzhiyun bool user_access_is_supported(void)
1119*4882a593Smuzhiyun {
1120*4882a593Smuzhiyun return scan_ftrace_readme(FTRACE_README_USER_ACCESS);
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun
multiprobe_event_is_supported(void)1123*4882a593Smuzhiyun bool multiprobe_event_is_supported(void)
1124*4882a593Smuzhiyun {
1125*4882a593Smuzhiyun return scan_ftrace_readme(FTRACE_README_MULTIPROBE_EVENT);
1126*4882a593Smuzhiyun }
1127*4882a593Smuzhiyun
immediate_value_is_supported(void)1128*4882a593Smuzhiyun bool immediate_value_is_supported(void)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun return scan_ftrace_readme(FTRACE_README_IMMEDIATE_VALUE);
1131*4882a593Smuzhiyun }
1132