Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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 /* %xNUM */
0057 #define SDT_OP_REGEX1  "^(x[1-2]?[0-9]|3[0-1])$"
0058 
0059 /* [sp], [sp, NUM] */
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  * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently
0092  * support these two formats.
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         /* Extract xNUM */
0105         new_len = 2;    /* % NULL */
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         /* [sp], [sp, NUM] or [sp,NUM] */
0116         new_len = 7;    /* + ( % s p ) NULL */
0117 
0118         /* If the argument is [sp], need to fill offset '0' */
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      * Check if the pmu supports perf extended regs, before
0160      * returning the register mask to sample.
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 }