18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <stdbool.h>
38c2ecf20Sopenharmony_ci#include <stdlib.h>
48c2ecf20Sopenharmony_ci#include <stdint.h>
58c2ecf20Sopenharmony_ci#include <string.h>
68c2ecf20Sopenharmony_ci#include <stdio.h>
78c2ecf20Sopenharmony_ci#include "util/debug.h"
88c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
98c2ecf20Sopenharmony_ci#include "util/perf_regs.h"
108c2ecf20Sopenharmony_ci#include "util/parse-regs-options.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic int
138c2ecf20Sopenharmony_ci__parse_regs(const struct option *opt, const char *str, int unset, bool intr)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	uint64_t *mode = (uint64_t *)opt->value;
168c2ecf20Sopenharmony_ci	const struct sample_reg *r = NULL;
178c2ecf20Sopenharmony_ci	char *s, *os = NULL, *p;
188c2ecf20Sopenharmony_ci	int ret = -1;
198c2ecf20Sopenharmony_ci	uint64_t mask;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	if (unset)
228c2ecf20Sopenharmony_ci		return 0;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	/*
258c2ecf20Sopenharmony_ci	 * cannot set it twice
268c2ecf20Sopenharmony_ci	 */
278c2ecf20Sopenharmony_ci	if (*mode)
288c2ecf20Sopenharmony_ci		return -1;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	if (intr)
318c2ecf20Sopenharmony_ci		mask = arch__intr_reg_mask();
328c2ecf20Sopenharmony_ci	else
338c2ecf20Sopenharmony_ci		mask = arch__user_reg_mask();
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* str may be NULL in case no arg is passed to -I */
368c2ecf20Sopenharmony_ci	if (str) {
378c2ecf20Sopenharmony_ci		/* because str is read-only */
388c2ecf20Sopenharmony_ci		s = os = strdup(str);
398c2ecf20Sopenharmony_ci		if (!s)
408c2ecf20Sopenharmony_ci			return -1;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci		for (;;) {
438c2ecf20Sopenharmony_ci			p = strchr(s, ',');
448c2ecf20Sopenharmony_ci			if (p)
458c2ecf20Sopenharmony_ci				*p = '\0';
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci			if (!strcmp(s, "?")) {
488c2ecf20Sopenharmony_ci				fprintf(stderr, "available registers: ");
498c2ecf20Sopenharmony_ci#ifdef HAVE_PERF_REGS_SUPPORT
508c2ecf20Sopenharmony_ci				for (r = sample_reg_masks; r->name; r++) {
518c2ecf20Sopenharmony_ci					if (r->mask & mask)
528c2ecf20Sopenharmony_ci						fprintf(stderr, "%s ", r->name);
538c2ecf20Sopenharmony_ci				}
548c2ecf20Sopenharmony_ci#endif
558c2ecf20Sopenharmony_ci				fputc('\n', stderr);
568c2ecf20Sopenharmony_ci				/* just printing available regs */
578c2ecf20Sopenharmony_ci				goto error;
588c2ecf20Sopenharmony_ci			}
598c2ecf20Sopenharmony_ci#ifdef HAVE_PERF_REGS_SUPPORT
608c2ecf20Sopenharmony_ci			for (r = sample_reg_masks; r->name; r++) {
618c2ecf20Sopenharmony_ci				if ((r->mask & mask) && !strcasecmp(s, r->name))
628c2ecf20Sopenharmony_ci					break;
638c2ecf20Sopenharmony_ci			}
648c2ecf20Sopenharmony_ci#endif
658c2ecf20Sopenharmony_ci			if (!r || !r->name) {
668c2ecf20Sopenharmony_ci				ui__warning("Unknown register \"%s\", check man page or run \"perf record %s?\"\n",
678c2ecf20Sopenharmony_ci					    s, intr ? "-I" : "--user-regs=");
688c2ecf20Sopenharmony_ci				goto error;
698c2ecf20Sopenharmony_ci			}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci			*mode |= r->mask;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci			if (!p)
748c2ecf20Sopenharmony_ci				break;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci			s = p + 1;
778c2ecf20Sopenharmony_ci		}
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	ret = 0;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* default to all possible regs */
828c2ecf20Sopenharmony_ci	if (*mode == 0)
838c2ecf20Sopenharmony_ci		*mode = mask;
848c2ecf20Sopenharmony_cierror:
858c2ecf20Sopenharmony_ci	free(os);
868c2ecf20Sopenharmony_ci	return ret;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ciint
908c2ecf20Sopenharmony_ciparse_user_regs(const struct option *opt, const char *str, int unset)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	return __parse_regs(opt, str, unset, false);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ciint
968c2ecf20Sopenharmony_ciparse_intr_regs(const struct option *opt, const char *str, int unset)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	return __parse_regs(opt, str, unset, true);
998c2ecf20Sopenharmony_ci}
100