Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function

In line with the previous patch, the __weak arch_sdt_arg_parse_op()
function is removed.

Architectural-specific implementations in the arch/ directory are now
converted into sub-functions within the util/perf-regs-arch/ directory.

The perf_sdt_arg_parse_op() function will call these sub-functions based
on the EM_HOST.

This change enables cross-architecture calls to arch_sdt_arg_parse_op().

No functional changes are intended.

Suggested-by: Ian Rogers <irogers@google.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Guo Ren <guoren@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Walmsley <pjw@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Cc: Will Deacon <will@kernel.org>
Cc: Xudong Hao <xudong.hao@intel.com>
Cc: Zide Chen <zide.chen@intel.com>
[ Fixed up somme fuzz with powerpc and x86 Build files wrt removing perf_regs.o ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Dapeng Mi and committed by
Arnaldo Carvalho de Melo
e5e66adf 16dccbb8

+441 -473
-1
tools/perf/arch/arm64/util/Build
··· 7 7 perf-util-y += hisi-ptt.o 8 8 perf-util-y += machine.o 9 9 perf-util-y += mem-events.o 10 - perf-util-y += perf_regs.o 11 10 perf-util-y += pmu.o 12 11 perf-util-y += tsc.o
-105
tools/perf/arch/arm64/util/perf_regs.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #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 - #define SMPL_REG_MASK(b) (1ULL << (b)) 16 - 17 - #ifndef HWCAP_SVE 18 - #define HWCAP_SVE (1 << 22) 19 - #endif 20 - 21 - /* %xNUM */ 22 - #define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$" 23 - 24 - /* [sp], [sp, NUM] */ 25 - #define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$" 26 - 27 - static regex_t sdt_op_regex1, sdt_op_regex2; 28 - 29 - static int sdt_init_op_regex(void) 30 - { 31 - static int initialized; 32 - int ret = 0; 33 - 34 - if (initialized) 35 - return 0; 36 - 37 - ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED); 38 - if (ret) 39 - goto error; 40 - 41 - ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED); 42 - if (ret) 43 - goto free_regex1; 44 - 45 - initialized = 1; 46 - return 0; 47 - 48 - free_regex1: 49 - regfree(&sdt_op_regex1); 50 - error: 51 - pr_debug4("Regex compilation error.\n"); 52 - return ret; 53 - } 54 - 55 - /* 56 - * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently 57 - * support these two formats. 58 - */ 59 - int arch_sdt_arg_parse_op(char *old_op, char **new_op) 60 - { 61 - int ret, new_len; 62 - regmatch_t rm[5]; 63 - 64 - ret = sdt_init_op_regex(); 65 - if (ret < 0) 66 - return ret; 67 - 68 - if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) { 69 - /* Extract xNUM */ 70 - new_len = 2; /* % NULL */ 71 - new_len += (int)(rm[1].rm_eo - rm[1].rm_so); 72 - 73 - *new_op = zalloc(new_len); 74 - if (!*new_op) 75 - return -ENOMEM; 76 - 77 - scnprintf(*new_op, new_len, "%%%.*s", 78 - (int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so); 79 - } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) { 80 - /* [sp], [sp, NUM] or [sp,NUM] */ 81 - new_len = 7; /* + ( % s p ) NULL */ 82 - 83 - /* If the argument is [sp], need to fill offset '0' */ 84 - if (rm[2].rm_so == -1) 85 - new_len += 1; 86 - else 87 - new_len += (int)(rm[2].rm_eo - rm[2].rm_so); 88 - 89 - *new_op = zalloc(new_len); 90 - if (!*new_op) 91 - return -ENOMEM; 92 - 93 - if (rm[2].rm_so == -1) 94 - scnprintf(*new_op, new_len, "+0(%%sp)"); 95 - else 96 - scnprintf(*new_op, new_len, "+%.*s(%%sp)", 97 - (int)(rm[2].rm_eo - rm[2].rm_so), 98 - old_op + rm[2].rm_so); 99 - } else { 100 - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 101 - return SDT_ARG_SKIP; 102 - } 103 - 104 - return SDT_ARG_VALID; 105 - }
-1
tools/perf/arch/powerpc/util/Build
··· 1 1 perf-util-y += header.o 2 - perf-util-y += perf_regs.o 3 2 perf-util-y += mem-events.o 4 3 perf-util-y += pmu.o 5 4 perf-util-y += sym-handling.o
-125
tools/perf/arch/powerpc/util/perf_regs.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <errno.h> 3 - #include <string.h> 4 - #include <regex.h> 5 - #include <linux/zalloc.h> 6 - 7 - #include "perf_regs.h" 8 - #include "../../../util/perf_regs.h" 9 - #include "../../../util/debug.h" 10 - #include "../../../util/event.h" 11 - #include "../../../util/header.h" 12 - #include "../../../perf-sys.h" 13 - #include "utils_header.h" 14 - 15 - #include <linux/kernel.h> 16 - 17 - #define PVR_POWER9 0x004E 18 - #define PVR_POWER10 0x0080 19 - #define PVR_POWER11 0x0082 20 - 21 - /* REG or %rREG */ 22 - #define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$" 23 - 24 - /* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */ 25 - #define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$" 26 - 27 - static regex_t sdt_op_regex1, sdt_op_regex2; 28 - 29 - static int sdt_init_op_regex(void) 30 - { 31 - static int initialized; 32 - int ret = 0; 33 - 34 - if (initialized) 35 - return 0; 36 - 37 - ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED); 38 - if (ret) 39 - goto error; 40 - 41 - ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED); 42 - if (ret) 43 - goto free_regex1; 44 - 45 - initialized = 1; 46 - return 0; 47 - 48 - free_regex1: 49 - regfree(&sdt_op_regex1); 50 - error: 51 - pr_debug4("Regex compilation error.\n"); 52 - return ret; 53 - } 54 - 55 - /* 56 - * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG). 57 - * Possible variants of OP are: 58 - * Format Example 59 - * ------------------------- 60 - * NUM(REG) 48(18) 61 - * -NUM(REG) -48(18) 62 - * NUM(%rREG) 48(%r18) 63 - * -NUM(%rREG) -48(%r18) 64 - * REG 18 65 - * %rREG %r18 66 - * iNUM i0 67 - * i-NUM i-1 68 - * 69 - * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag 70 - * and REG form with -mno-regnames. Here REG is general purpose register, 71 - * which is in 0 to 31 range. 72 - */ 73 - int arch_sdt_arg_parse_op(char *old_op, char **new_op) 74 - { 75 - int ret, new_len; 76 - regmatch_t rm[5]; 77 - char prefix; 78 - 79 - /* Constant argument. Uprobe does not support it */ 80 - if (old_op[0] == 'i') { 81 - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 82 - return SDT_ARG_SKIP; 83 - } 84 - 85 - ret = sdt_init_op_regex(); 86 - if (ret < 0) 87 - return ret; 88 - 89 - if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) { 90 - /* REG or %rREG --> %gprREG */ 91 - 92 - new_len = 5; /* % g p r NULL */ 93 - new_len += (int)(rm[2].rm_eo - rm[2].rm_so); 94 - 95 - *new_op = zalloc(new_len); 96 - if (!*new_op) 97 - return -ENOMEM; 98 - 99 - scnprintf(*new_op, new_len, "%%gpr%.*s", 100 - (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so); 101 - } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) { 102 - /* 103 - * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) --> 104 - * +/-NUM(%gprREG) 105 - */ 106 - prefix = (rm[1].rm_so == -1) ? '+' : '-'; 107 - 108 - new_len = 8; /* +/- ( % g p r ) NULL */ 109 - new_len += (int)(rm[2].rm_eo - rm[2].rm_so); 110 - new_len += (int)(rm[4].rm_eo - rm[4].rm_so); 111 - 112 - *new_op = zalloc(new_len); 113 - if (!*new_op) 114 - return -ENOMEM; 115 - 116 - scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix, 117 - (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so, 118 - (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so); 119 - } else { 120 - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 121 - return SDT_ARG_SKIP; 122 - } 123 - 124 - return SDT_ARG_VALID; 125 - }
-1
tools/perf/arch/x86/util/Build
··· 1 1 perf-util-y += header.o 2 2 perf-util-y += tsc.o 3 3 perf-util-y += pmu.o 4 - perf-util-y += perf_regs.o 5 4 perf-util-y += topdown.o 6 5 perf-util-y += machine.o 7 6 perf-util-y += event.o
-235
tools/perf/arch/x86/util/perf_regs.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <errno.h> 3 - #include <string.h> 4 - #include <regex.h> 5 - #include <linux/kernel.h> 6 - #include <linux/zalloc.h> 7 - 8 - #include "perf_regs.h" 9 - #include "../../../perf-sys.h" 10 - #include "../../../util/perf_regs.h" 11 - #include "../../../util/debug.h" 12 - #include "../../../util/event.h" 13 - #include "../../../util/pmu.h" 14 - #include "../../../util/pmus.h" 15 - 16 - struct sdt_name_reg { 17 - const char *sdt_name; 18 - const char *uprobe_name; 19 - }; 20 - #define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m} 21 - #define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL} 22 - 23 - static const struct sdt_name_reg sdt_reg_tbl[] = { 24 - SDT_NAME_REG(eax, ax), 25 - SDT_NAME_REG(rax, ax), 26 - SDT_NAME_REG(al, ax), 27 - SDT_NAME_REG(ah, ax), 28 - SDT_NAME_REG(ebx, bx), 29 - SDT_NAME_REG(rbx, bx), 30 - SDT_NAME_REG(bl, bx), 31 - SDT_NAME_REG(bh, bx), 32 - SDT_NAME_REG(ecx, cx), 33 - SDT_NAME_REG(rcx, cx), 34 - SDT_NAME_REG(cl, cx), 35 - SDT_NAME_REG(ch, cx), 36 - SDT_NAME_REG(edx, dx), 37 - SDT_NAME_REG(rdx, dx), 38 - SDT_NAME_REG(dl, dx), 39 - SDT_NAME_REG(dh, dx), 40 - SDT_NAME_REG(esi, si), 41 - SDT_NAME_REG(rsi, si), 42 - SDT_NAME_REG(sil, si), 43 - SDT_NAME_REG(edi, di), 44 - SDT_NAME_REG(rdi, di), 45 - SDT_NAME_REG(dil, di), 46 - SDT_NAME_REG(ebp, bp), 47 - SDT_NAME_REG(rbp, bp), 48 - SDT_NAME_REG(bpl, bp), 49 - SDT_NAME_REG(rsp, sp), 50 - SDT_NAME_REG(esp, sp), 51 - SDT_NAME_REG(spl, sp), 52 - 53 - /* rNN registers */ 54 - SDT_NAME_REG(r8b, r8), 55 - SDT_NAME_REG(r8w, r8), 56 - SDT_NAME_REG(r8d, r8), 57 - SDT_NAME_REG(r9b, r9), 58 - SDT_NAME_REG(r9w, r9), 59 - SDT_NAME_REG(r9d, r9), 60 - SDT_NAME_REG(r10b, r10), 61 - SDT_NAME_REG(r10w, r10), 62 - SDT_NAME_REG(r10d, r10), 63 - SDT_NAME_REG(r11b, r11), 64 - SDT_NAME_REG(r11w, r11), 65 - SDT_NAME_REG(r11d, r11), 66 - SDT_NAME_REG(r12b, r12), 67 - SDT_NAME_REG(r12w, r12), 68 - SDT_NAME_REG(r12d, r12), 69 - SDT_NAME_REG(r13b, r13), 70 - SDT_NAME_REG(r13w, r13), 71 - SDT_NAME_REG(r13d, r13), 72 - SDT_NAME_REG(r14b, r14), 73 - SDT_NAME_REG(r14w, r14), 74 - SDT_NAME_REG(r14d, r14), 75 - SDT_NAME_REG(r15b, r15), 76 - SDT_NAME_REG(r15w, r15), 77 - SDT_NAME_REG(r15d, r15), 78 - SDT_NAME_REG_END, 79 - }; 80 - 81 - /* 82 - * Perf only supports OP which is in +/-NUM(REG) form. 83 - * Here plus-minus sign, NUM and parenthesis are optional, 84 - * only REG is mandatory. 85 - * 86 - * SDT events also supports indirect addressing mode with a 87 - * symbol as offset, scaled mode and constants in OP. But 88 - * perf does not support them yet. Below are few examples. 89 - * 90 - * OP with scaled mode: 91 - * (%rax,%rsi,8) 92 - * 10(%ras,%rsi,8) 93 - * 94 - * OP with indirect addressing mode: 95 - * check_action(%rip) 96 - * mp_+52(%rip) 97 - * 44+mp_(%rip) 98 - * 99 - * OP with constant values: 100 - * $0 101 - * $123 102 - * $-1 103 - */ 104 - #define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$" 105 - 106 - static regex_t sdt_op_regex; 107 - 108 - static int sdt_init_op_regex(void) 109 - { 110 - static int initialized; 111 - int ret = 0; 112 - 113 - if (initialized) 114 - return 0; 115 - 116 - ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED); 117 - if (ret < 0) { 118 - pr_debug4("Regex compilation error.\n"); 119 - return ret; 120 - } 121 - 122 - initialized = 1; 123 - return 0; 124 - } 125 - 126 - /* 127 - * Max x86 register name length is 5(ex: %r15d). So, 6th char 128 - * should always contain NULL. This helps to find register name 129 - * length using strlen, instead of maintaining one more variable. 130 - */ 131 - #define SDT_REG_NAME_SIZE 6 132 - 133 - /* 134 - * The uprobe parser does not support all gas register names; 135 - * so, we have to replace them (ex. for x86_64: %rax -> %ax). 136 - * Note: If register does not require renaming, just copy 137 - * paste as it is, but don't leave it empty. 138 - */ 139 - static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg) 140 - { 141 - int i = 0; 142 - 143 - for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) { 144 - if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) { 145 - strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name); 146 - return; 147 - } 148 - } 149 - 150 - strncpy(uprobe_reg, sdt_reg, sdt_len); 151 - } 152 - 153 - int arch_sdt_arg_parse_op(char *old_op, char **new_op) 154 - { 155 - char new_reg[SDT_REG_NAME_SIZE] = {0}; 156 - int new_len = 0, ret; 157 - /* 158 - * rm[0]: +/-NUM(REG) 159 - * rm[1]: +/- 160 - * rm[2]: NUM 161 - * rm[3]: ( 162 - * rm[4]: REG 163 - * rm[5]: ) 164 - */ 165 - regmatch_t rm[6]; 166 - /* 167 - * Max prefix length is 2 as it may contains sign(+/-) 168 - * and displacement 0 (Both sign and displacement 0 are 169 - * optional so it may be empty). Use one more character 170 - * to hold last NULL so that strlen can be used to find 171 - * prefix length, instead of maintaining one more variable. 172 - */ 173 - char prefix[3] = {0}; 174 - 175 - ret = sdt_init_op_regex(); 176 - if (ret < 0) 177 - return ret; 178 - 179 - /* 180 - * If unsupported OR does not match with regex OR 181 - * register name too long, skip it. 182 - */ 183 - if (strchr(old_op, ',') || strchr(old_op, '$') || 184 - regexec(&sdt_op_regex, old_op, 6, rm, 0) || 185 - rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) { 186 - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 187 - return SDT_ARG_SKIP; 188 - } 189 - 190 - /* 191 - * Prepare prefix. 192 - * If SDT OP has parenthesis but does not provide 193 - * displacement, add 0 for displacement. 194 - * SDT Uprobe Prefix 195 - * ----------------------------- 196 - * +24(%rdi) +24(%di) + 197 - * 24(%rdi) +24(%di) + 198 - * %rdi %di 199 - * (%rdi) +0(%di) +0 200 - * -80(%rbx) -80(%bx) - 201 - */ 202 - if (rm[3].rm_so != rm[3].rm_eo) { 203 - if (rm[1].rm_so != rm[1].rm_eo) 204 - prefix[0] = *(old_op + rm[1].rm_so); 205 - else if (rm[2].rm_so != rm[2].rm_eo) 206 - prefix[0] = '+'; 207 - else 208 - scnprintf(prefix, sizeof(prefix), "+0"); 209 - } 210 - 211 - /* Rename register */ 212 - sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so, 213 - new_reg); 214 - 215 - /* Prepare final OP which should be valid for uprobe_events */ 216 - new_len = strlen(prefix) + 217 - (rm[2].rm_eo - rm[2].rm_so) + 218 - (rm[3].rm_eo - rm[3].rm_so) + 219 - strlen(new_reg) + 220 - (rm[5].rm_eo - rm[5].rm_so) + 221 - 1; /* NULL */ 222 - 223 - *new_op = zalloc(new_len); 224 - if (!*new_op) 225 - return -ENOMEM; 226 - 227 - scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s", 228 - strlen(prefix), prefix, 229 - (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so, 230 - (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so, 231 - strlen(new_reg), new_reg, 232 - (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so); 233 - 234 - return SDT_ARG_VALID; 235 - }
+86
tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
··· 18 18 #define HWCAP_SVE (1 << 22) 19 19 #endif 20 20 21 + /* %xNUM */ 22 + #define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$" 23 + 24 + /* [sp], [sp, NUM] */ 25 + #define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$" 26 + 27 + static regex_t sdt_op_regex1, sdt_op_regex2; 28 + 29 + static int sdt_init_op_regex(void) 30 + { 31 + static int initialized; 32 + int ret = 0; 33 + 34 + if (initialized) 35 + return 0; 36 + 37 + ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED); 38 + if (ret) 39 + goto error; 40 + 41 + ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED); 42 + if (ret) 43 + goto free_regex1; 44 + 45 + initialized = 1; 46 + return 0; 47 + 48 + free_regex1: 49 + regfree(&sdt_op_regex1); 50 + error: 51 + pr_debug4("Regex compilation error.\n"); 52 + return ret; 53 + } 54 + 55 + /* 56 + * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently 57 + * support these two formats. 58 + */ 59 + int __perf_sdt_arg_parse_op_arm64(char *old_op, char **new_op) 60 + { 61 + int ret, new_len; 62 + regmatch_t rm[5]; 63 + 64 + ret = sdt_init_op_regex(); 65 + if (ret < 0) 66 + return ret; 67 + 68 + if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) { 69 + /* Extract xNUM */ 70 + new_len = 2; /* % NULL */ 71 + new_len += (int)(rm[1].rm_eo - rm[1].rm_so); 72 + 73 + *new_op = zalloc(new_len); 74 + if (!*new_op) 75 + return -ENOMEM; 76 + 77 + scnprintf(*new_op, new_len, "%%%.*s", 78 + (int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so); 79 + } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) { 80 + /* [sp], [sp, NUM] or [sp,NUM] */ 81 + new_len = 7; /* + ( % s p ) NULL */ 82 + 83 + /* If the argument is [sp], need to fill offset '0' */ 84 + if (rm[2].rm_so == -1) 85 + new_len += 1; 86 + else 87 + new_len += (int)(rm[2].rm_eo - rm[2].rm_so); 88 + 89 + *new_op = zalloc(new_len); 90 + if (!*new_op) 91 + return -ENOMEM; 92 + 93 + if (rm[2].rm_so == -1) 94 + scnprintf(*new_op, new_len, "+0(%%sp)"); 95 + else 96 + scnprintf(*new_op, new_len, "+%.*s(%%sp)", 97 + (int)(rm[2].rm_eo - rm[2].rm_so), 98 + old_op + rm[2].rm_so); 99 + } else { 100 + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 101 + return SDT_ARG_SKIP; 102 + } 103 + 104 + return SDT_ARG_VALID; 105 + } 106 + 21 107 uint64_t __perf_reg_mask_arm64(bool intr) 22 108 { 23 109 struct perf_event_attr attr = {
+106
tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
··· 19 19 #define PVR_POWER10 0x0080 20 20 #define PVR_POWER11 0x0082 21 21 22 + /* REG or %rREG */ 23 + #define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$" 24 + 25 + /* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */ 26 + #define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$" 27 + 28 + static regex_t sdt_op_regex1, sdt_op_regex2; 29 + 30 + static int sdt_init_op_regex(void) 31 + { 32 + static int initialized; 33 + int ret = 0; 34 + 35 + if (initialized) 36 + return 0; 37 + 38 + ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED); 39 + if (ret) 40 + goto error; 41 + 42 + ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED); 43 + if (ret) 44 + goto free_regex1; 45 + 46 + initialized = 1; 47 + return 0; 48 + 49 + free_regex1: 50 + regfree(&sdt_op_regex1); 51 + error: 52 + pr_debug4("Regex compilation error.\n"); 53 + return ret; 54 + } 55 + 56 + /* 57 + * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG). 58 + * Possible variants of OP are: 59 + * Format Example 60 + * ------------------------- 61 + * NUM(REG) 48(18) 62 + * -NUM(REG) -48(18) 63 + * NUM(%rREG) 48(%r18) 64 + * -NUM(%rREG) -48(%r18) 65 + * REG 18 66 + * %rREG %r18 67 + * iNUM i0 68 + * i-NUM i-1 69 + * 70 + * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag 71 + * and REG form with -mno-regnames. Here REG is general purpose register, 72 + * which is in 0 to 31 range. 73 + */ 74 + int __perf_sdt_arg_parse_op_powerpc(char *old_op, char **new_op) 75 + { 76 + int ret, new_len; 77 + regmatch_t rm[5]; 78 + char prefix; 79 + 80 + /* Constant argument. Uprobe does not support it */ 81 + if (old_op[0] == 'i') { 82 + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 83 + return SDT_ARG_SKIP; 84 + } 85 + 86 + ret = sdt_init_op_regex(); 87 + if (ret < 0) 88 + return ret; 89 + 90 + if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) { 91 + /* REG or %rREG --> %gprREG */ 92 + 93 + new_len = 5; /* % g p r NULL */ 94 + new_len += (int)(rm[2].rm_eo - rm[2].rm_so); 95 + 96 + *new_op = zalloc(new_len); 97 + if (!*new_op) 98 + return -ENOMEM; 99 + 100 + scnprintf(*new_op, new_len, "%%gpr%.*s", 101 + (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so); 102 + } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) { 103 + /* 104 + * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) --> 105 + * +/-NUM(%gprREG) 106 + */ 107 + prefix = (rm[1].rm_so == -1) ? '+' : '-'; 108 + 109 + new_len = 8; /* +/- ( % g p r ) NULL */ 110 + new_len += (int)(rm[2].rm_eo - rm[2].rm_so); 111 + new_len += (int)(rm[4].rm_eo - rm[4].rm_so); 112 + 113 + *new_op = zalloc(new_len); 114 + if (!*new_op) 115 + return -ENOMEM; 116 + 117 + scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix, 118 + (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so, 119 + (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so); 120 + } else { 121 + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 122 + return SDT_ARG_SKIP; 123 + } 124 + 125 + return SDT_ARG_VALID; 126 + } 127 + 22 128 /* 23 129 * mfspr is a POWERPC specific instruction, ensure it's only 24 130 * built and called on POWERPC by guarding with __powerpc64__
+221
tools/perf/util/perf-regs-arch/perf_regs_x86.c
··· 14 14 #include "../../perf-sys.h" 15 15 #include "../../arch/x86/include/perf_regs.h" 16 16 17 + struct sdt_name_reg { 18 + const char *sdt_name; 19 + const char *uprobe_name; 20 + }; 21 + #define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m} 22 + #define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL} 23 + 24 + static const struct sdt_name_reg sdt_reg_tbl[] = { 25 + SDT_NAME_REG(eax, ax), 26 + SDT_NAME_REG(rax, ax), 27 + SDT_NAME_REG(al, ax), 28 + SDT_NAME_REG(ah, ax), 29 + SDT_NAME_REG(ebx, bx), 30 + SDT_NAME_REG(rbx, bx), 31 + SDT_NAME_REG(bl, bx), 32 + SDT_NAME_REG(bh, bx), 33 + SDT_NAME_REG(ecx, cx), 34 + SDT_NAME_REG(rcx, cx), 35 + SDT_NAME_REG(cl, cx), 36 + SDT_NAME_REG(ch, cx), 37 + SDT_NAME_REG(edx, dx), 38 + SDT_NAME_REG(rdx, dx), 39 + SDT_NAME_REG(dl, dx), 40 + SDT_NAME_REG(dh, dx), 41 + SDT_NAME_REG(esi, si), 42 + SDT_NAME_REG(rsi, si), 43 + SDT_NAME_REG(sil, si), 44 + SDT_NAME_REG(edi, di), 45 + SDT_NAME_REG(rdi, di), 46 + SDT_NAME_REG(dil, di), 47 + SDT_NAME_REG(ebp, bp), 48 + SDT_NAME_REG(rbp, bp), 49 + SDT_NAME_REG(bpl, bp), 50 + SDT_NAME_REG(rsp, sp), 51 + SDT_NAME_REG(esp, sp), 52 + SDT_NAME_REG(spl, sp), 53 + 54 + /* rNN registers */ 55 + SDT_NAME_REG(r8b, r8), 56 + SDT_NAME_REG(r8w, r8), 57 + SDT_NAME_REG(r8d, r8), 58 + SDT_NAME_REG(r9b, r9), 59 + SDT_NAME_REG(r9w, r9), 60 + SDT_NAME_REG(r9d, r9), 61 + SDT_NAME_REG(r10b, r10), 62 + SDT_NAME_REG(r10w, r10), 63 + SDT_NAME_REG(r10d, r10), 64 + SDT_NAME_REG(r11b, r11), 65 + SDT_NAME_REG(r11w, r11), 66 + SDT_NAME_REG(r11d, r11), 67 + SDT_NAME_REG(r12b, r12), 68 + SDT_NAME_REG(r12w, r12), 69 + SDT_NAME_REG(r12d, r12), 70 + SDT_NAME_REG(r13b, r13), 71 + SDT_NAME_REG(r13w, r13), 72 + SDT_NAME_REG(r13d, r13), 73 + SDT_NAME_REG(r14b, r14), 74 + SDT_NAME_REG(r14w, r14), 75 + SDT_NAME_REG(r14d, r14), 76 + SDT_NAME_REG(r15b, r15), 77 + SDT_NAME_REG(r15w, r15), 78 + SDT_NAME_REG(r15d, r15), 79 + SDT_NAME_REG_END, 80 + }; 81 + 82 + /* 83 + * Perf only supports OP which is in +/-NUM(REG) form. 84 + * Here plus-minus sign, NUM and parenthesis are optional, 85 + * only REG is mandatory. 86 + * 87 + * SDT events also supports indirect addressing mode with a 88 + * symbol as offset, scaled mode and constants in OP. But 89 + * perf does not support them yet. Below are few examples. 90 + * 91 + * OP with scaled mode: 92 + * (%rax,%rsi,8) 93 + * 10(%ras,%rsi,8) 94 + * 95 + * OP with indirect addressing mode: 96 + * check_action(%rip) 97 + * mp_+52(%rip) 98 + * 44+mp_(%rip) 99 + * 100 + * OP with constant values: 101 + * $0 102 + * $123 103 + * $-1 104 + */ 105 + #define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$" 106 + 107 + static regex_t sdt_op_regex; 108 + 109 + static int sdt_init_op_regex(void) 110 + { 111 + static int initialized; 112 + int ret = 0; 113 + 114 + if (initialized) 115 + return 0; 116 + 117 + ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED); 118 + if (ret < 0) { 119 + pr_debug4("Regex compilation error.\n"); 120 + return ret; 121 + } 122 + 123 + initialized = 1; 124 + return 0; 125 + } 126 + 127 + /* 128 + * Max x86 register name length is 5(ex: %r15d). So, 6th char 129 + * should always contain NULL. This helps to find register name 130 + * length using strlen, instead of maintaining one more variable. 131 + */ 132 + #define SDT_REG_NAME_SIZE 6 133 + 134 + /* 135 + * The uprobe parser does not support all gas register names; 136 + * so, we have to replace them (ex. for x86_64: %rax -> %ax). 137 + * Note: If register does not require renaming, just copy 138 + * paste as it is, but don't leave it empty. 139 + */ 140 + static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg) 141 + { 142 + int i = 0; 143 + 144 + for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) { 145 + if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) { 146 + strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name); 147 + return; 148 + } 149 + } 150 + 151 + strncpy(uprobe_reg, sdt_reg, sdt_len); 152 + } 153 + 154 + int __perf_sdt_arg_parse_op_x86(char *old_op, char **new_op) 155 + { 156 + char new_reg[SDT_REG_NAME_SIZE] = {0}; 157 + int new_len = 0, ret; 158 + /* 159 + * rm[0]: +/-NUM(REG) 160 + * rm[1]: +/- 161 + * rm[2]: NUM 162 + * rm[3]: ( 163 + * rm[4]: REG 164 + * rm[5]: ) 165 + */ 166 + regmatch_t rm[6]; 167 + /* 168 + * Max prefix length is 2 as it may contains sign(+/-) 169 + * and displacement 0 (Both sign and displacement 0 are 170 + * optional so it may be empty). Use one more character 171 + * to hold last NULL so that strlen can be used to find 172 + * prefix length, instead of maintaining one more variable. 173 + */ 174 + char prefix[3] = {0}; 175 + 176 + ret = sdt_init_op_regex(); 177 + if (ret < 0) 178 + return ret; 179 + 180 + /* 181 + * If unsupported OR does not match with regex OR 182 + * register name too long, skip it. 183 + */ 184 + if (strchr(old_op, ',') || strchr(old_op, '$') || 185 + regexec(&sdt_op_regex, old_op, 6, rm, 0) || 186 + rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) { 187 + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 188 + return SDT_ARG_SKIP; 189 + } 190 + 191 + /* 192 + * Prepare prefix. 193 + * If SDT OP has parenthesis but does not provide 194 + * displacement, add 0 for displacement. 195 + * SDT Uprobe Prefix 196 + * ----------------------------- 197 + * +24(%rdi) +24(%di) + 198 + * 24(%rdi) +24(%di) + 199 + * %rdi %di 200 + * (%rdi) +0(%di) +0 201 + * -80(%rbx) -80(%bx) - 202 + */ 203 + if (rm[3].rm_so != rm[3].rm_eo) { 204 + if (rm[1].rm_so != rm[1].rm_eo) 205 + prefix[0] = *(old_op + rm[1].rm_so); 206 + else if (rm[2].rm_so != rm[2].rm_eo) 207 + prefix[0] = '+'; 208 + else 209 + scnprintf(prefix, sizeof(prefix), "+0"); 210 + } 211 + 212 + /* Rename register */ 213 + sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so, 214 + new_reg); 215 + 216 + /* Prepare final OP which should be valid for uprobe_events */ 217 + new_len = strlen(prefix) + 218 + (rm[2].rm_eo - rm[2].rm_so) + 219 + (rm[3].rm_eo - rm[3].rm_so) + 220 + strlen(new_reg) + 221 + (rm[5].rm_eo - rm[5].rm_so) + 222 + 1; /* NULL */ 223 + 224 + *new_op = zalloc(new_len); 225 + if (!*new_op) 226 + return -ENOMEM; 227 + 228 + scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s", 229 + strlen(prefix), prefix, 230 + (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so, 231 + (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so, 232 + strlen(new_reg), new_reg, 233 + (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so); 234 + 235 + return SDT_ARG_VALID; 236 + } 237 + 17 238 uint64_t __perf_reg_mask_x86(bool intr) 18 239 { 19 240 struct perf_event_attr attr = {
+22 -3
tools/perf/util/perf_regs.c
··· 7 7 #include "util/sample.h" 8 8 #include "debug.h" 9 9 10 - int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused, 11 - char **new_op __maybe_unused) 10 + int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op) 12 11 { 13 - return SDT_ARG_SKIP; 12 + int ret = SDT_ARG_SKIP; 13 + 14 + switch (e_machine) { 15 + case EM_AARCH64: 16 + ret = __perf_sdt_arg_parse_op_arm64(old_op, new_op); 17 + break; 18 + case EM_PPC: 19 + case EM_PPC64: 20 + ret = __perf_sdt_arg_parse_op_powerpc(old_op, new_op); 21 + break; 22 + case EM_386: 23 + case EM_X86_64: 24 + ret = __perf_sdt_arg_parse_op_x86(old_op, new_op); 25 + break; 26 + default: 27 + pr_debug("Unknown ELF machine %d, standard arguments parse will be skipped.\n", 28 + e_machine); 29 + break; 30 + } 31 + 32 + return ret; 14 33 } 15 34 16 35 uint64_t perf_intr_reg_mask(uint16_t e_machine)
+4 -1
tools/perf/util/perf_regs.h
··· 12 12 SDT_ARG_SKIP, 13 13 }; 14 14 15 - int arch_sdt_arg_parse_op(char *old_op, char **new_op); 15 + int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op); 16 16 uint64_t perf_intr_reg_mask(uint16_t e_machine); 17 17 uint64_t perf_user_reg_mask(uint16_t e_machine); 18 18 ··· 21 21 uint64_t perf_arch_reg_ip(uint16_t e_machine); 22 22 uint64_t perf_arch_reg_sp(uint16_t e_machine); 23 23 24 + int __perf_sdt_arg_parse_op_arm64(char *old_op, char **new_op); 24 25 uint64_t __perf_reg_mask_arm64(bool intr); 25 26 const char *__perf_reg_name_arm64(int id); 26 27 uint64_t __perf_reg_ip_arm64(void); ··· 47 46 uint64_t __perf_reg_ip_mips(void); 48 47 uint64_t __perf_reg_sp_mips(void); 49 48 49 + int __perf_sdt_arg_parse_op_powerpc(char *old_op, char **new_op); 50 50 uint64_t __perf_reg_mask_powerpc(bool intr); 51 51 const char *__perf_reg_name_powerpc(int id); 52 52 uint64_t __perf_reg_ip_powerpc(void); ··· 63 61 uint64_t __perf_reg_ip_s390(void); 64 62 uint64_t __perf_reg_sp_s390(void); 65 63 64 + int __perf_sdt_arg_parse_op_x86(char *old_op, char **new_op); 66 65 uint64_t __perf_reg_mask_x86(bool intr); 67 66 const char *__perf_reg_name_x86(int id); 68 67 uint64_t __perf_reg_ip_x86(void);
+2 -1
tools/perf/util/probe-file.c
··· 28 28 #include "session.h" 29 29 #include "perf_regs.h" 30 30 #include "string2.h" 31 + #include "dwarf-regs.h" 31 32 32 33 /* 4096 - 2 ('\n' + '\0') */ 33 34 #define MAX_CMDLEN 4094 ··· 785 784 op = desc; 786 785 } 787 786 788 - ret = arch_sdt_arg_parse_op(op, &new_op); 787 + ret = perf_sdt_arg_parse_op(EM_HOST, op, &new_op); 789 788 790 789 if (ret < 0) 791 790 goto error;