1 // SPDX-License-Identifier: GPL-2.0
5 #include <linux/kernel.h>
6 #include <linux/zalloc.h>
8 #include "../../../perf-sys.h"
9 #include "../../../util/perf_regs.h"
10 #include "../../../util/debug.h"
11 #include "../../../util/event.h"
13 const struct sample_reg sample_reg_masks
[] = {
14 SMPL_REG(AX
, PERF_REG_X86_AX
),
15 SMPL_REG(BX
, PERF_REG_X86_BX
),
16 SMPL_REG(CX
, PERF_REG_X86_CX
),
17 SMPL_REG(DX
, PERF_REG_X86_DX
),
18 SMPL_REG(SI
, PERF_REG_X86_SI
),
19 SMPL_REG(DI
, PERF_REG_X86_DI
),
20 SMPL_REG(BP
, PERF_REG_X86_BP
),
21 SMPL_REG(SP
, PERF_REG_X86_SP
),
22 SMPL_REG(IP
, PERF_REG_X86_IP
),
23 SMPL_REG(FLAGS
, PERF_REG_X86_FLAGS
),
24 SMPL_REG(CS
, PERF_REG_X86_CS
),
25 SMPL_REG(SS
, PERF_REG_X86_SS
),
26 #ifdef HAVE_ARCH_X86_64_SUPPORT
27 SMPL_REG(R8
, PERF_REG_X86_R8
),
28 SMPL_REG(R9
, PERF_REG_X86_R9
),
29 SMPL_REG(R10
, PERF_REG_X86_R10
),
30 SMPL_REG(R11
, PERF_REG_X86_R11
),
31 SMPL_REG(R12
, PERF_REG_X86_R12
),
32 SMPL_REG(R13
, PERF_REG_X86_R13
),
33 SMPL_REG(R14
, PERF_REG_X86_R14
),
34 SMPL_REG(R15
, PERF_REG_X86_R15
),
36 SMPL_REG2(XMM0
, PERF_REG_X86_XMM0
),
37 SMPL_REG2(XMM1
, PERF_REG_X86_XMM1
),
38 SMPL_REG2(XMM2
, PERF_REG_X86_XMM2
),
39 SMPL_REG2(XMM3
, PERF_REG_X86_XMM3
),
40 SMPL_REG2(XMM4
, PERF_REG_X86_XMM4
),
41 SMPL_REG2(XMM5
, PERF_REG_X86_XMM5
),
42 SMPL_REG2(XMM6
, PERF_REG_X86_XMM6
),
43 SMPL_REG2(XMM7
, PERF_REG_X86_XMM7
),
44 SMPL_REG2(XMM8
, PERF_REG_X86_XMM8
),
45 SMPL_REG2(XMM9
, PERF_REG_X86_XMM9
),
46 SMPL_REG2(XMM10
, PERF_REG_X86_XMM10
),
47 SMPL_REG2(XMM11
, PERF_REG_X86_XMM11
),
48 SMPL_REG2(XMM12
, PERF_REG_X86_XMM12
),
49 SMPL_REG2(XMM13
, PERF_REG_X86_XMM13
),
50 SMPL_REG2(XMM14
, PERF_REG_X86_XMM14
),
51 SMPL_REG2(XMM15
, PERF_REG_X86_XMM15
),
57 const char *uprobe_name
;
59 #define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
60 #define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
62 static const struct sdt_name_reg sdt_reg_tbl
[] = {
63 SDT_NAME_REG(eax
, ax
),
64 SDT_NAME_REG(rax
, ax
),
67 SDT_NAME_REG(ebx
, bx
),
68 SDT_NAME_REG(rbx
, bx
),
71 SDT_NAME_REG(ecx
, cx
),
72 SDT_NAME_REG(rcx
, cx
),
75 SDT_NAME_REG(edx
, dx
),
76 SDT_NAME_REG(rdx
, dx
),
79 SDT_NAME_REG(esi
, si
),
80 SDT_NAME_REG(rsi
, si
),
81 SDT_NAME_REG(sil
, si
),
82 SDT_NAME_REG(edi
, di
),
83 SDT_NAME_REG(rdi
, di
),
84 SDT_NAME_REG(dil
, di
),
85 SDT_NAME_REG(ebp
, bp
),
86 SDT_NAME_REG(rbp
, bp
),
87 SDT_NAME_REG(bpl
, bp
),
88 SDT_NAME_REG(rsp
, sp
),
89 SDT_NAME_REG(esp
, sp
),
90 SDT_NAME_REG(spl
, sp
),
93 SDT_NAME_REG(r8b
, r8
),
94 SDT_NAME_REG(r8w
, r8
),
95 SDT_NAME_REG(r8d
, r8
),
96 SDT_NAME_REG(r9b
, r9
),
97 SDT_NAME_REG(r9w
, r9
),
98 SDT_NAME_REG(r9d
, r9
),
99 SDT_NAME_REG(r10b
, r10
),
100 SDT_NAME_REG(r10w
, r10
),
101 SDT_NAME_REG(r10d
, r10
),
102 SDT_NAME_REG(r11b
, r11
),
103 SDT_NAME_REG(r11w
, r11
),
104 SDT_NAME_REG(r11d
, r11
),
105 SDT_NAME_REG(r12b
, r12
),
106 SDT_NAME_REG(r12w
, r12
),
107 SDT_NAME_REG(r12d
, r12
),
108 SDT_NAME_REG(r13b
, r13
),
109 SDT_NAME_REG(r13w
, r13
),
110 SDT_NAME_REG(r13d
, r13
),
111 SDT_NAME_REG(r14b
, r14
),
112 SDT_NAME_REG(r14w
, r14
),
113 SDT_NAME_REG(r14d
, r14
),
114 SDT_NAME_REG(r15b
, r15
),
115 SDT_NAME_REG(r15w
, r15
),
116 SDT_NAME_REG(r15d
, r15
),
121 * Perf only supports OP which is in +/-NUM(REG) form.
122 * Here plus-minus sign, NUM and parenthesis are optional,
123 * only REG is mandatory.
125 * SDT events also supports indirect addressing mode with a
126 * symbol as offset, scaled mode and constants in OP. But
127 * perf does not support them yet. Below are few examples.
129 * OP with scaled mode:
133 * OP with indirect addressing mode:
138 * OP with constant values:
143 #define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
145 static regex_t sdt_op_regex
;
147 static int sdt_init_op_regex(void)
149 static int initialized
;
155 ret
= regcomp(&sdt_op_regex
, SDT_OP_REGEX
, REG_EXTENDED
);
157 pr_debug4("Regex compilation error.\n");
166 * Max x86 register name length is 5(ex: %r15d). So, 6th char
167 * should always contain NULL. This helps to find register name
168 * length using strlen, insted of maintaing one more variable.
170 #define SDT_REG_NAME_SIZE 6
173 * The uprobe parser does not support all gas register names;
174 * so, we have to replace them (ex. for x86_64: %rax -> %ax).
175 * Note: If register does not require renaming, just copy
176 * paste as it is, but don't leave it empty.
178 static void sdt_rename_register(char *sdt_reg
, int sdt_len
, char *uprobe_reg
)
182 for (i
= 0; sdt_reg_tbl
[i
].sdt_name
!= NULL
; i
++) {
183 if (!strncmp(sdt_reg_tbl
[i
].sdt_name
, sdt_reg
, sdt_len
)) {
184 strcpy(uprobe_reg
, sdt_reg_tbl
[i
].uprobe_name
);
189 strncpy(uprobe_reg
, sdt_reg
, sdt_len
);
192 int arch_sdt_arg_parse_op(char *old_op
, char **new_op
)
194 char new_reg
[SDT_REG_NAME_SIZE
] = {0};
195 int new_len
= 0, ret
;
206 * Max prefix length is 2 as it may contains sign(+/-)
207 * and displacement 0 (Both sign and displacement 0 are
208 * optional so it may be empty). Use one more character
209 * to hold last NULL so that strlen can be used to find
210 * prefix length, instead of maintaing one more variable.
212 char prefix
[3] = {0};
214 ret
= sdt_init_op_regex();
219 * If unsupported OR does not match with regex OR
220 * register name too long, skip it.
222 if (strchr(old_op
, ',') || strchr(old_op
, '$') ||
223 regexec(&sdt_op_regex
, old_op
, 6, rm
, 0) ||
224 rm
[4].rm_eo
- rm
[4].rm_so
> SDT_REG_NAME_SIZE
) {
225 pr_debug4("Skipping unsupported SDT argument: %s\n", old_op
);
231 * If SDT OP has parenthesis but does not provide
232 * displacement, add 0 for displacement.
234 * -----------------------------
235 * +24(%rdi) +24(%di) +
236 * 24(%rdi) +24(%di) +
239 * -80(%rbx) -80(%bx) -
241 if (rm
[3].rm_so
!= rm
[3].rm_eo
) {
242 if (rm
[1].rm_so
!= rm
[1].rm_eo
)
243 prefix
[0] = *(old_op
+ rm
[1].rm_so
);
244 else if (rm
[2].rm_so
!= rm
[2].rm_eo
)
247 scnprintf(prefix
, sizeof(prefix
), "+0");
250 /* Rename register */
251 sdt_rename_register(old_op
+ rm
[4].rm_so
, rm
[4].rm_eo
- rm
[4].rm_so
,
254 /* Prepare final OP which should be valid for uprobe_events */
255 new_len
= strlen(prefix
) +
256 (rm
[2].rm_eo
- rm
[2].rm_so
) +
257 (rm
[3].rm_eo
- rm
[3].rm_so
) +
259 (rm
[5].rm_eo
- rm
[5].rm_so
) +
262 *new_op
= zalloc(new_len
);
266 scnprintf(*new_op
, new_len
, "%.*s%.*s%.*s%.*s%.*s",
267 strlen(prefix
), prefix
,
268 (int)(rm
[2].rm_eo
- rm
[2].rm_so
), old_op
+ rm
[2].rm_so
,
269 (int)(rm
[3].rm_eo
- rm
[3].rm_so
), old_op
+ rm
[3].rm_so
,
270 strlen(new_reg
), new_reg
,
271 (int)(rm
[5].rm_eo
- rm
[5].rm_so
), old_op
+ rm
[5].rm_so
);
273 return SDT_ARG_VALID
;
276 uint64_t arch__intr_reg_mask(void)
278 struct perf_event_attr attr
= {
279 .type
= PERF_TYPE_HARDWARE
,
280 .config
= PERF_COUNT_HW_CPU_CYCLES
,
281 .sample_type
= PERF_SAMPLE_REGS_INTR
,
282 .sample_regs_intr
= PERF_REG_EXTENDED_MASK
,
289 * In an unnamed union, init it here to build on older gcc versions
291 attr
.sample_period
= 1;
293 event_attr_init(&attr
);
295 fd
= sys_perf_event_open(&attr
, 0, -1, -1, 0);
298 return (PERF_REG_EXTENDED_MASK
| PERF_REGS_MASK
);
301 return PERF_REGS_MASK
;