18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include "util/debug.h"
38c2ecf20Sopenharmony_ci#include "util/event.h"
48c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
58c2ecf20Sopenharmony_ci#include "util/parse-branch-options.h"
68c2ecf20Sopenharmony_ci#include <stdlib.h>
78c2ecf20Sopenharmony_ci#include <string.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define BRANCH_OPT(n, m) \
108c2ecf20Sopenharmony_ci	{ .name = n, .mode = (m) }
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define BRANCH_END { .name = NULL }
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistruct branch_mode {
158c2ecf20Sopenharmony_ci	const char *name;
168c2ecf20Sopenharmony_ci	int mode;
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic const struct branch_mode branch_modes[] = {
208c2ecf20Sopenharmony_ci	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
218c2ecf20Sopenharmony_ci	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
228c2ecf20Sopenharmony_ci	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
238c2ecf20Sopenharmony_ci	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
248c2ecf20Sopenharmony_ci	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
258c2ecf20Sopenharmony_ci	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
268c2ecf20Sopenharmony_ci	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
278c2ecf20Sopenharmony_ci	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
288c2ecf20Sopenharmony_ci	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
298c2ecf20Sopenharmony_ci	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
308c2ecf20Sopenharmony_ci	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
318c2ecf20Sopenharmony_ci	BRANCH_OPT("ind_jmp", PERF_SAMPLE_BRANCH_IND_JUMP),
328c2ecf20Sopenharmony_ci	BRANCH_OPT("call", PERF_SAMPLE_BRANCH_CALL),
338c2ecf20Sopenharmony_ci	BRANCH_OPT("save_type", PERF_SAMPLE_BRANCH_TYPE_SAVE),
348c2ecf20Sopenharmony_ci	BRANCH_OPT("stack", PERF_SAMPLE_BRANCH_CALL_STACK),
358c2ecf20Sopenharmony_ci	BRANCH_END
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciint parse_branch_str(const char *str, __u64 *mode)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci#define ONLY_PLM \
418c2ecf20Sopenharmony_ci	(PERF_SAMPLE_BRANCH_USER	|\
428c2ecf20Sopenharmony_ci	 PERF_SAMPLE_BRANCH_KERNEL	|\
438c2ecf20Sopenharmony_ci	 PERF_SAMPLE_BRANCH_HV)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	int ret = 0;
468c2ecf20Sopenharmony_ci	char *p, *s;
478c2ecf20Sopenharmony_ci	char *os = NULL;
488c2ecf20Sopenharmony_ci	const struct branch_mode *br;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (str == NULL) {
518c2ecf20Sopenharmony_ci		*mode = PERF_SAMPLE_BRANCH_ANY;
528c2ecf20Sopenharmony_ci		return 0;
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	/* because str is read-only */
568c2ecf20Sopenharmony_ci	s = os = strdup(str);
578c2ecf20Sopenharmony_ci	if (!s)
588c2ecf20Sopenharmony_ci		return -1;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	for (;;) {
618c2ecf20Sopenharmony_ci		p = strchr(s, ',');
628c2ecf20Sopenharmony_ci		if (p)
638c2ecf20Sopenharmony_ci			*p = '\0';
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		for (br = branch_modes; br->name; br++) {
668c2ecf20Sopenharmony_ci			if (!strcasecmp(s, br->name))
678c2ecf20Sopenharmony_ci				break;
688c2ecf20Sopenharmony_ci		}
698c2ecf20Sopenharmony_ci		if (!br->name) {
708c2ecf20Sopenharmony_ci			ret = -1;
718c2ecf20Sopenharmony_ci			pr_warning("unknown branch filter %s,"
728c2ecf20Sopenharmony_ci				    " check man page\n", s);
738c2ecf20Sopenharmony_ci			goto error;
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci		*mode |= br->mode;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		if (!p)
798c2ecf20Sopenharmony_ci			break;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci		s = p + 1;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/* default to any branch */
858c2ecf20Sopenharmony_ci	if ((*mode & ~ONLY_PLM) == 0) {
868c2ecf20Sopenharmony_ci		*mode = PERF_SAMPLE_BRANCH_ANY;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_cierror:
898c2ecf20Sopenharmony_ci	free(os);
908c2ecf20Sopenharmony_ci	return ret;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciint
948c2ecf20Sopenharmony_ciparse_branch_stack(const struct option *opt, const char *str, int unset)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	__u64 *mode = (__u64 *)opt->value;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (unset)
998c2ecf20Sopenharmony_ci		return 0;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/*
1028c2ecf20Sopenharmony_ci	 * cannot set it twice, -b + --branch-filter for instance
1038c2ecf20Sopenharmony_ci	 */
1048c2ecf20Sopenharmony_ci	if (*mode)
1058c2ecf20Sopenharmony_ci		return -1;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return parse_branch_str(str, mode);
1088c2ecf20Sopenharmony_ci}
109