0001
0002 #include <errno.h>
0003 #include <regex.h>
0004 #include <string.h>
0005 #include <sys/auxv.h>
0006 #include <linux/kernel.h>
0007 #include <linux/zalloc.h>
0008
0009 #include "../../../perf-sys.h"
0010 #include "../../../util/debug.h"
0011 #include "../../../util/event.h"
0012 #include "../../../util/perf_regs.h"
0013
0014 #ifndef HWCAP_SVE
0015 #define HWCAP_SVE (1 << 22)
0016 #endif
0017
0018 const struct sample_reg sample_reg_masks[] = {
0019 SMPL_REG(x0, PERF_REG_ARM64_X0),
0020 SMPL_REG(x1, PERF_REG_ARM64_X1),
0021 SMPL_REG(x2, PERF_REG_ARM64_X2),
0022 SMPL_REG(x3, PERF_REG_ARM64_X3),
0023 SMPL_REG(x4, PERF_REG_ARM64_X4),
0024 SMPL_REG(x5, PERF_REG_ARM64_X5),
0025 SMPL_REG(x6, PERF_REG_ARM64_X6),
0026 SMPL_REG(x7, PERF_REG_ARM64_X7),
0027 SMPL_REG(x8, PERF_REG_ARM64_X8),
0028 SMPL_REG(x9, PERF_REG_ARM64_X9),
0029 SMPL_REG(x10, PERF_REG_ARM64_X10),
0030 SMPL_REG(x11, PERF_REG_ARM64_X11),
0031 SMPL_REG(x12, PERF_REG_ARM64_X12),
0032 SMPL_REG(x13, PERF_REG_ARM64_X13),
0033 SMPL_REG(x14, PERF_REG_ARM64_X14),
0034 SMPL_REG(x15, PERF_REG_ARM64_X15),
0035 SMPL_REG(x16, PERF_REG_ARM64_X16),
0036 SMPL_REG(x17, PERF_REG_ARM64_X17),
0037 SMPL_REG(x18, PERF_REG_ARM64_X18),
0038 SMPL_REG(x19, PERF_REG_ARM64_X19),
0039 SMPL_REG(x20, PERF_REG_ARM64_X20),
0040 SMPL_REG(x21, PERF_REG_ARM64_X21),
0041 SMPL_REG(x22, PERF_REG_ARM64_X22),
0042 SMPL_REG(x23, PERF_REG_ARM64_X23),
0043 SMPL_REG(x24, PERF_REG_ARM64_X24),
0044 SMPL_REG(x25, PERF_REG_ARM64_X25),
0045 SMPL_REG(x26, PERF_REG_ARM64_X26),
0046 SMPL_REG(x27, PERF_REG_ARM64_X27),
0047 SMPL_REG(x28, PERF_REG_ARM64_X28),
0048 SMPL_REG(x29, PERF_REG_ARM64_X29),
0049 SMPL_REG(lr, PERF_REG_ARM64_LR),
0050 SMPL_REG(sp, PERF_REG_ARM64_SP),
0051 SMPL_REG(pc, PERF_REG_ARM64_PC),
0052 SMPL_REG(vg, PERF_REG_ARM64_VG),
0053 SMPL_REG_END
0054 };
0055
0056
0057 #define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$"
0058
0059
0060 #define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$"
0061
0062 static regex_t sdt_op_regex1, sdt_op_regex2;
0063
0064 static int sdt_init_op_regex(void)
0065 {
0066 static int initialized;
0067 int ret = 0;
0068
0069 if (initialized)
0070 return 0;
0071
0072 ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
0073 if (ret)
0074 goto error;
0075
0076 ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
0077 if (ret)
0078 goto free_regex1;
0079
0080 initialized = 1;
0081 return 0;
0082
0083 free_regex1:
0084 regfree(&sdt_op_regex1);
0085 error:
0086 pr_debug4("Regex compilation error.\n");
0087 return ret;
0088 }
0089
0090
0091
0092
0093
0094 int arch_sdt_arg_parse_op(char *old_op, char **new_op)
0095 {
0096 int ret, new_len;
0097 regmatch_t rm[5];
0098
0099 ret = sdt_init_op_regex();
0100 if (ret < 0)
0101 return ret;
0102
0103 if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
0104
0105 new_len = 2;
0106 new_len += (int)(rm[1].rm_eo - rm[1].rm_so);
0107
0108 *new_op = zalloc(new_len);
0109 if (!*new_op)
0110 return -ENOMEM;
0111
0112 scnprintf(*new_op, new_len, "%%%.*s",
0113 (int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);
0114 } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
0115
0116 new_len = 7;
0117
0118
0119 if (rm[2].rm_so == -1)
0120 new_len += 1;
0121 else
0122 new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
0123
0124 *new_op = zalloc(new_len);
0125 if (!*new_op)
0126 return -ENOMEM;
0127
0128 if (rm[2].rm_so == -1)
0129 scnprintf(*new_op, new_len, "+0(%%sp)");
0130 else
0131 scnprintf(*new_op, new_len, "+%.*s(%%sp)",
0132 (int)(rm[2].rm_eo - rm[2].rm_so),
0133 old_op + rm[2].rm_so);
0134 } else {
0135 pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
0136 return SDT_ARG_SKIP;
0137 }
0138
0139 return SDT_ARG_VALID;
0140 }
0141
0142 uint64_t arch__user_reg_mask(void)
0143 {
0144 struct perf_event_attr attr = {
0145 .type = PERF_TYPE_HARDWARE,
0146 .config = PERF_COUNT_HW_CPU_CYCLES,
0147 .sample_type = PERF_SAMPLE_REGS_USER,
0148 .disabled = 1,
0149 .exclude_kernel = 1,
0150 .sample_period = 1,
0151 .sample_regs_user = PERF_REGS_MASK
0152 };
0153 int fd;
0154
0155 if (getauxval(AT_HWCAP) & HWCAP_SVE)
0156 attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);
0157
0158
0159
0160
0161
0162 if (attr.sample_regs_user != PERF_REGS_MASK) {
0163 event_attr_init(&attr);
0164 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
0165 if (fd != -1) {
0166 close(fd);
0167 return attr.sample_regs_user;
0168 }
0169 }
0170 return PERF_REGS_MASK;
0171 }