xref: /linux/tools/perf/util/perf-regs-arch/perf_regs_x86.c (revision c7decec2f2d2ab0366567f9e30c0e1418cece43f)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <errno.h>
4 #include <string.h>
5 #include <regex.h>
6 #include <linux/kernel.h>
7 #include <linux/zalloc.h>
8 
9 #include "../debug.h"
10 #include "../event.h"
11 #include "../pmu.h"
12 #include "../pmus.h"
13 #include "../perf_regs.h"
14 #include "../../perf-sys.h"
15 #include "../../arch/x86/include/perf_regs.h"
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 
sdt_init_op_regex(void)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  */
sdt_rename_register(char * sdt_reg,int sdt_len,char * uprobe_reg)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 
__perf_sdt_arg_parse_op_x86(char * old_op,char ** new_op)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 
__perf_reg_mask_x86(bool intr)238 uint64_t __perf_reg_mask_x86(bool intr)
239 {
240 	struct perf_event_attr attr = {
241 		.type			= PERF_TYPE_HARDWARE,
242 		.config			= PERF_COUNT_HW_CPU_CYCLES,
243 		.sample_type		= PERF_SAMPLE_REGS_INTR,
244 		.sample_regs_intr	= PERF_REG_EXTENDED_MASK,
245 		.precise_ip		= 1,
246 		.disabled		= 1,
247 		.exclude_kernel		= 1,
248 	};
249 	int fd;
250 
251 	if (!intr)
252 		return PERF_REGS_MASK;
253 
254 	/*
255 	 * In an unnamed union, init it here to build on older gcc versions
256 	 */
257 	attr.sample_period = 1;
258 
259 	if (perf_pmus__num_core_pmus() > 1) {
260 		struct perf_pmu *pmu = NULL;
261 		__u64 type = PERF_TYPE_RAW;
262 
263 		/*
264 		 * The same register set is supported among different hybrid PMUs.
265 		 * Only check the first available one.
266 		 */
267 		while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
268 			type = pmu->type;
269 			break;
270 		}
271 		attr.config |= type << PERF_PMU_TYPE_SHIFT;
272 	}
273 
274 	event_attr_init(&attr);
275 	fd = sys_perf_event_open(&attr, /*pid=*/0, /*cpu=*/-1,
276 				 /*group_fd=*/-1, /*flags=*/0);
277 	if (fd != -1) {
278 		close(fd);
279 		return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
280 	}
281 
282 	return PERF_REGS_MASK;
283 }
284 
__perf_reg_name_x86(int id)285 const char *__perf_reg_name_x86(int id)
286 {
287 	switch (id) {
288 	case PERF_REG_X86_AX:
289 		return "AX";
290 	case PERF_REG_X86_BX:
291 		return "BX";
292 	case PERF_REG_X86_CX:
293 		return "CX";
294 	case PERF_REG_X86_DX:
295 		return "DX";
296 	case PERF_REG_X86_SI:
297 		return "SI";
298 	case PERF_REG_X86_DI:
299 		return "DI";
300 	case PERF_REG_X86_BP:
301 		return "BP";
302 	case PERF_REG_X86_SP:
303 		return "SP";
304 	case PERF_REG_X86_IP:
305 		return "IP";
306 	case PERF_REG_X86_FLAGS:
307 		return "FLAGS";
308 	case PERF_REG_X86_CS:
309 		return "CS";
310 	case PERF_REG_X86_SS:
311 		return "SS";
312 	case PERF_REG_X86_DS:
313 		return "DS";
314 	case PERF_REG_X86_ES:
315 		return "ES";
316 	case PERF_REG_X86_FS:
317 		return "FS";
318 	case PERF_REG_X86_GS:
319 		return "GS";
320 	case PERF_REG_X86_R8:
321 		return "R8";
322 	case PERF_REG_X86_R9:
323 		return "R9";
324 	case PERF_REG_X86_R10:
325 		return "R10";
326 	case PERF_REG_X86_R11:
327 		return "R11";
328 	case PERF_REG_X86_R12:
329 		return "R12";
330 	case PERF_REG_X86_R13:
331 		return "R13";
332 	case PERF_REG_X86_R14:
333 		return "R14";
334 	case PERF_REG_X86_R15:
335 		return "R15";
336 
337 #define XMM(x) \
338 	case PERF_REG_X86_XMM ## x:	\
339 	case PERF_REG_X86_XMM ## x + 1:	\
340 		return "XMM" #x;
341 	XMM(0)
342 	XMM(1)
343 	XMM(2)
344 	XMM(3)
345 	XMM(4)
346 	XMM(5)
347 	XMM(6)
348 	XMM(7)
349 	XMM(8)
350 	XMM(9)
351 	XMM(10)
352 	XMM(11)
353 	XMM(12)
354 	XMM(13)
355 	XMM(14)
356 	XMM(15)
357 #undef XMM
358 	default:
359 		return NULL;
360 	}
361 
362 	return NULL;
363 }
364 
__perf_reg_ip_x86(void)365 uint64_t __perf_reg_ip_x86(void)
366 {
367 	return PERF_REG_X86_IP;
368 }
369 
__perf_reg_sp_x86(void)370 uint64_t __perf_reg_sp_x86(void)
371 {
372 	return PERF_REG_X86_SP;
373 }
374