183 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <errno.h>3#include <regex.h>4#include <string.h>5#include <sys/auxv.h>6#include <linux/kernel.h>7#include <linux/zalloc.h>8 9#include "perf_regs.h"10#include "../../../perf-sys.h"11#include "../../../util/debug.h"12#include "../../../util/event.h"13#include "../../../util/perf_regs.h"14 15#ifndef HWCAP_SVE16#define HWCAP_SVE (1 << 22)17#endif18 19static const struct sample_reg sample_reg_masks[] = {20 SMPL_REG(x0, PERF_REG_ARM64_X0),21 SMPL_REG(x1, PERF_REG_ARM64_X1),22 SMPL_REG(x2, PERF_REG_ARM64_X2),23 SMPL_REG(x3, PERF_REG_ARM64_X3),24 SMPL_REG(x4, PERF_REG_ARM64_X4),25 SMPL_REG(x5, PERF_REG_ARM64_X5),26 SMPL_REG(x6, PERF_REG_ARM64_X6),27 SMPL_REG(x7, PERF_REG_ARM64_X7),28 SMPL_REG(x8, PERF_REG_ARM64_X8),29 SMPL_REG(x9, PERF_REG_ARM64_X9),30 SMPL_REG(x10, PERF_REG_ARM64_X10),31 SMPL_REG(x11, PERF_REG_ARM64_X11),32 SMPL_REG(x12, PERF_REG_ARM64_X12),33 SMPL_REG(x13, PERF_REG_ARM64_X13),34 SMPL_REG(x14, PERF_REG_ARM64_X14),35 SMPL_REG(x15, PERF_REG_ARM64_X15),36 SMPL_REG(x16, PERF_REG_ARM64_X16),37 SMPL_REG(x17, PERF_REG_ARM64_X17),38 SMPL_REG(x18, PERF_REG_ARM64_X18),39 SMPL_REG(x19, PERF_REG_ARM64_X19),40 SMPL_REG(x20, PERF_REG_ARM64_X20),41 SMPL_REG(x21, PERF_REG_ARM64_X21),42 SMPL_REG(x22, PERF_REG_ARM64_X22),43 SMPL_REG(x23, PERF_REG_ARM64_X23),44 SMPL_REG(x24, PERF_REG_ARM64_X24),45 SMPL_REG(x25, PERF_REG_ARM64_X25),46 SMPL_REG(x26, PERF_REG_ARM64_X26),47 SMPL_REG(x27, PERF_REG_ARM64_X27),48 SMPL_REG(x28, PERF_REG_ARM64_X28),49 SMPL_REG(x29, PERF_REG_ARM64_X29),50 SMPL_REG(lr, PERF_REG_ARM64_LR),51 SMPL_REG(sp, PERF_REG_ARM64_SP),52 SMPL_REG(pc, PERF_REG_ARM64_PC),53 SMPL_REG(vg, PERF_REG_ARM64_VG),54 SMPL_REG_END55};56 57/* %xNUM */58#define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$"59 60/* [sp], [sp, NUM] */61#define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$"62 63static regex_t sdt_op_regex1, sdt_op_regex2;64 65static int sdt_init_op_regex(void)66{67 static int initialized;68 int ret = 0;69 70 if (initialized)71 return 0;72 73 ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);74 if (ret)75 goto error;76 77 ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);78 if (ret)79 goto free_regex1;80 81 initialized = 1;82 return 0;83 84free_regex1:85 regfree(&sdt_op_regex1);86error:87 pr_debug4("Regex compilation error.\n");88 return ret;89}90 91/*92 * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently93 * support these two formats.94 */95int arch_sdt_arg_parse_op(char *old_op, char **new_op)96{97 int ret, new_len;98 regmatch_t rm[5];99 100 ret = sdt_init_op_regex();101 if (ret < 0)102 return ret;103 104 if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {105 /* Extract xNUM */106 new_len = 2; /* % NULL */107 new_len += (int)(rm[1].rm_eo - rm[1].rm_so);108 109 *new_op = zalloc(new_len);110 if (!*new_op)111 return -ENOMEM;112 113 scnprintf(*new_op, new_len, "%%%.*s",114 (int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);115 } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {116 /* [sp], [sp, NUM] or [sp,NUM] */117 new_len = 7; /* + ( % s p ) NULL */118 119 /* If the argument is [sp], need to fill offset '0' */120 if (rm[2].rm_so == -1)121 new_len += 1;122 else123 new_len += (int)(rm[2].rm_eo - rm[2].rm_so);124 125 *new_op = zalloc(new_len);126 if (!*new_op)127 return -ENOMEM;128 129 if (rm[2].rm_so == -1)130 scnprintf(*new_op, new_len, "+0(%%sp)");131 else132 scnprintf(*new_op, new_len, "+%.*s(%%sp)",133 (int)(rm[2].rm_eo - rm[2].rm_so),134 old_op + rm[2].rm_so);135 } else {136 pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);137 return SDT_ARG_SKIP;138 }139 140 return SDT_ARG_VALID;141}142 143uint64_t arch__intr_reg_mask(void)144{145 return PERF_REGS_MASK;146}147 148uint64_t arch__user_reg_mask(void)149{150 struct perf_event_attr attr = {151 .type = PERF_TYPE_HARDWARE,152 .config = PERF_COUNT_HW_CPU_CYCLES,153 .sample_type = PERF_SAMPLE_REGS_USER,154 .disabled = 1,155 .exclude_kernel = 1,156 .sample_period = 1,157 .sample_regs_user = PERF_REGS_MASK158 };159 int fd;160 161 if (getauxval(AT_HWCAP) & HWCAP_SVE)162 attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);163 164 /*165 * Check if the pmu supports perf extended regs, before166 * returning the register mask to sample.167 */168 if (attr.sample_regs_user != PERF_REGS_MASK) {169 event_attr_init(&attr);170 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);171 if (fd != -1) {172 close(fd);173 return attr.sample_regs_user;174 }175 }176 return PERF_REGS_MASK;177}178 179const struct sample_reg *arch__sample_reg_masks(void)180{181 return sample_reg_masks;182}183