Path: blob/master/tools/perf/arch/arm64/util/perf_regs.c
26292 views
// SPDX-License-Identifier: GPL-2.01#include <errno.h>2#include <regex.h>3#include <string.h>4#include <sys/auxv.h>5#include <linux/kernel.h>6#include <linux/zalloc.h>78#include "perf_regs.h"9#include "../../../perf-sys.h"10#include "../../../util/debug.h"11#include "../../../util/event.h"12#include "../../../util/perf_regs.h"1314#ifndef HWCAP_SVE15#define HWCAP_SVE (1 << 22)16#endif1718static const struct sample_reg sample_reg_masks[] = {19SMPL_REG(x0, PERF_REG_ARM64_X0),20SMPL_REG(x1, PERF_REG_ARM64_X1),21SMPL_REG(x2, PERF_REG_ARM64_X2),22SMPL_REG(x3, PERF_REG_ARM64_X3),23SMPL_REG(x4, PERF_REG_ARM64_X4),24SMPL_REG(x5, PERF_REG_ARM64_X5),25SMPL_REG(x6, PERF_REG_ARM64_X6),26SMPL_REG(x7, PERF_REG_ARM64_X7),27SMPL_REG(x8, PERF_REG_ARM64_X8),28SMPL_REG(x9, PERF_REG_ARM64_X9),29SMPL_REG(x10, PERF_REG_ARM64_X10),30SMPL_REG(x11, PERF_REG_ARM64_X11),31SMPL_REG(x12, PERF_REG_ARM64_X12),32SMPL_REG(x13, PERF_REG_ARM64_X13),33SMPL_REG(x14, PERF_REG_ARM64_X14),34SMPL_REG(x15, PERF_REG_ARM64_X15),35SMPL_REG(x16, PERF_REG_ARM64_X16),36SMPL_REG(x17, PERF_REG_ARM64_X17),37SMPL_REG(x18, PERF_REG_ARM64_X18),38SMPL_REG(x19, PERF_REG_ARM64_X19),39SMPL_REG(x20, PERF_REG_ARM64_X20),40SMPL_REG(x21, PERF_REG_ARM64_X21),41SMPL_REG(x22, PERF_REG_ARM64_X22),42SMPL_REG(x23, PERF_REG_ARM64_X23),43SMPL_REG(x24, PERF_REG_ARM64_X24),44SMPL_REG(x25, PERF_REG_ARM64_X25),45SMPL_REG(x26, PERF_REG_ARM64_X26),46SMPL_REG(x27, PERF_REG_ARM64_X27),47SMPL_REG(x28, PERF_REG_ARM64_X28),48SMPL_REG(x29, PERF_REG_ARM64_X29),49SMPL_REG(lr, PERF_REG_ARM64_LR),50SMPL_REG(sp, PERF_REG_ARM64_SP),51SMPL_REG(pc, PERF_REG_ARM64_PC),52SMPL_REG(vg, PERF_REG_ARM64_VG),53SMPL_REG_END54};5556/* %xNUM */57#define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$"5859/* [sp], [sp, NUM] */60#define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$"6162static regex_t sdt_op_regex1, sdt_op_regex2;6364static int sdt_init_op_regex(void)65{66static int initialized;67int ret = 0;6869if (initialized)70return 0;7172ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);73if (ret)74goto error;7576ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);77if (ret)78goto free_regex1;7980initialized = 1;81return 0;8283free_regex1:84regfree(&sdt_op_regex1);85error:86pr_debug4("Regex compilation error.\n");87return ret;88}8990/*91* SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently92* support these two formats.93*/94int arch_sdt_arg_parse_op(char *old_op, char **new_op)95{96int ret, new_len;97regmatch_t rm[5];9899ret = sdt_init_op_regex();100if (ret < 0)101return ret;102103if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {104/* Extract xNUM */105new_len = 2; /* % NULL */106new_len += (int)(rm[1].rm_eo - rm[1].rm_so);107108*new_op = zalloc(new_len);109if (!*new_op)110return -ENOMEM;111112scnprintf(*new_op, new_len, "%%%.*s",113(int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);114} else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {115/* [sp], [sp, NUM] or [sp,NUM] */116new_len = 7; /* + ( % s p ) NULL */117118/* If the argument is [sp], need to fill offset '0' */119if (rm[2].rm_so == -1)120new_len += 1;121else122new_len += (int)(rm[2].rm_eo - rm[2].rm_so);123124*new_op = zalloc(new_len);125if (!*new_op)126return -ENOMEM;127128if (rm[2].rm_so == -1)129scnprintf(*new_op, new_len, "+0(%%sp)");130else131scnprintf(*new_op, new_len, "+%.*s(%%sp)",132(int)(rm[2].rm_eo - rm[2].rm_so),133old_op + rm[2].rm_so);134} else {135pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);136return SDT_ARG_SKIP;137}138139return SDT_ARG_VALID;140}141142uint64_t arch__intr_reg_mask(void)143{144return PERF_REGS_MASK;145}146147uint64_t arch__user_reg_mask(void)148{149struct perf_event_attr attr = {150.type = PERF_TYPE_HARDWARE,151.config = PERF_COUNT_HW_CPU_CYCLES,152.sample_type = PERF_SAMPLE_REGS_USER,153.disabled = 1,154.exclude_kernel = 1,155.sample_period = 1,156.sample_regs_user = PERF_REGS_MASK157};158int fd;159160if (getauxval(AT_HWCAP) & HWCAP_SVE)161attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);162163/*164* Check if the pmu supports perf extended regs, before165* returning the register mask to sample.166*/167if (attr.sample_regs_user != PERF_REGS_MASK) {168event_attr_init(&attr);169fd = sys_perf_event_open(&attr, 0, -1, -1, 0);170if (fd != -1) {171close(fd);172return attr.sample_regs_user;173}174}175return PERF_REGS_MASK;176}177178const struct sample_reg *arch__sample_reg_masks(void)179{180return sample_reg_masks;181}182183184