162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <stdbool.h>
362306a36Sopenharmony_ci#include <stdlib.h>
462306a36Sopenharmony_ci#include <stdint.h>
562306a36Sopenharmony_ci#include <string.h>
662306a36Sopenharmony_ci#include <stdio.h>
762306a36Sopenharmony_ci#include "util/debug.h"
862306a36Sopenharmony_ci#include <subcmd/parse-options.h>
962306a36Sopenharmony_ci#include "util/perf_regs.h"
1062306a36Sopenharmony_ci#include "util/parse-regs-options.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic int
1362306a36Sopenharmony_ci__parse_regs(const struct option *opt, const char *str, int unset, bool intr)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	uint64_t *mode = (uint64_t *)opt->value;
1662306a36Sopenharmony_ci	const struct sample_reg *r = NULL;
1762306a36Sopenharmony_ci	char *s, *os = NULL, *p;
1862306a36Sopenharmony_ci	int ret = -1;
1962306a36Sopenharmony_ci	uint64_t mask;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	if (unset)
2262306a36Sopenharmony_ci		return 0;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	/*
2562306a36Sopenharmony_ci	 * cannot set it twice
2662306a36Sopenharmony_ci	 */
2762306a36Sopenharmony_ci	if (*mode)
2862306a36Sopenharmony_ci		return -1;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (intr)
3162306a36Sopenharmony_ci		mask = arch__intr_reg_mask();
3262306a36Sopenharmony_ci	else
3362306a36Sopenharmony_ci		mask = arch__user_reg_mask();
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* str may be NULL in case no arg is passed to -I */
3662306a36Sopenharmony_ci	if (str) {
3762306a36Sopenharmony_ci		/* because str is read-only */
3862306a36Sopenharmony_ci		s = os = strdup(str);
3962306a36Sopenharmony_ci		if (!s)
4062306a36Sopenharmony_ci			return -1;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		for (;;) {
4362306a36Sopenharmony_ci			p = strchr(s, ',');
4462306a36Sopenharmony_ci			if (p)
4562306a36Sopenharmony_ci				*p = '\0';
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci			if (!strcmp(s, "?")) {
4862306a36Sopenharmony_ci				fprintf(stderr, "available registers: ");
4962306a36Sopenharmony_ci#ifdef HAVE_PERF_REGS_SUPPORT
5062306a36Sopenharmony_ci				for (r = sample_reg_masks; r->name; r++) {
5162306a36Sopenharmony_ci					if (r->mask & mask)
5262306a36Sopenharmony_ci						fprintf(stderr, "%s ", r->name);
5362306a36Sopenharmony_ci				}
5462306a36Sopenharmony_ci#endif
5562306a36Sopenharmony_ci				fputc('\n', stderr);
5662306a36Sopenharmony_ci				/* just printing available regs */
5762306a36Sopenharmony_ci				goto error;
5862306a36Sopenharmony_ci			}
5962306a36Sopenharmony_ci#ifdef HAVE_PERF_REGS_SUPPORT
6062306a36Sopenharmony_ci			for (r = sample_reg_masks; r->name; r++) {
6162306a36Sopenharmony_ci				if ((r->mask & mask) && !strcasecmp(s, r->name))
6262306a36Sopenharmony_ci					break;
6362306a36Sopenharmony_ci			}
6462306a36Sopenharmony_ci#endif
6562306a36Sopenharmony_ci			if (!r || !r->name) {
6662306a36Sopenharmony_ci				ui__warning("Unknown register \"%s\", check man page or run \"perf record %s?\"\n",
6762306a36Sopenharmony_ci					    s, intr ? "-I" : "--user-regs=");
6862306a36Sopenharmony_ci				goto error;
6962306a36Sopenharmony_ci			}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci			*mode |= r->mask;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci			if (!p)
7462306a36Sopenharmony_ci				break;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci			s = p + 1;
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	ret = 0;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* default to all possible regs */
8262306a36Sopenharmony_ci	if (*mode == 0)
8362306a36Sopenharmony_ci		*mode = mask;
8462306a36Sopenharmony_cierror:
8562306a36Sopenharmony_ci	free(os);
8662306a36Sopenharmony_ci	return ret;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ciint
9062306a36Sopenharmony_ciparse_user_regs(const struct option *opt, const char *str, int unset)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	return __parse_regs(opt, str, unset, false);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ciint
9662306a36Sopenharmony_ciparse_intr_regs(const struct option *opt, const char *str, int unset)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	return __parse_regs(opt, str, unset, true);
9962306a36Sopenharmony_ci}
100