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