brintos

brintos / linux-shallow public Read only

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