cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

probe-file.c (26279B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * probe-file.c : operate ftrace k/uprobe events files
      4 *
      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 4094
     34
     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	else
     43		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	} else
     62		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	else
     68		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		else
    120			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	else
    145		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		} else
    242			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			else
    546				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_SUPPORT
    741static 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 (defining
    763 * 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 is
    792	 * the actual assembly operand. N can be omitted; in that case
    793	 * 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 string
    861			 * format "-4@[sp, NUM]" if a probe is to access data in
    862			 * the stack, e.g. below is an example for the SDT
    863			 * Arguments:
    864			 *
    865			 *   Arguments: -4@[sp, 12] -4@[sp, 8] -4@[sp, 4]
    866			 *
    867			 * Since the string introduces an extra space character
    868			 * in the middle of square brackets, the argument is
    869			 * divided into two items.  Fixup for this case, if an
    870			 * item contains sub string "[sp,", need to concatenate
    871			 * 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#endif
    967
    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}