brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · 0930866 Raw
183 lines · c
1// SPDX-License-Identifier: GPL-2.02#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#ifndef HWCAP_SVE16#define HWCAP_SVE	(1 << 22)17#endif18 19static const struct sample_reg sample_reg_masks[] = {20	SMPL_REG(x0, PERF_REG_ARM64_X0),21	SMPL_REG(x1, PERF_REG_ARM64_X1),22	SMPL_REG(x2, PERF_REG_ARM64_X2),23	SMPL_REG(x3, PERF_REG_ARM64_X3),24	SMPL_REG(x4, PERF_REG_ARM64_X4),25	SMPL_REG(x5, PERF_REG_ARM64_X5),26	SMPL_REG(x6, PERF_REG_ARM64_X6),27	SMPL_REG(x7, PERF_REG_ARM64_X7),28	SMPL_REG(x8, PERF_REG_ARM64_X8),29	SMPL_REG(x9, PERF_REG_ARM64_X9),30	SMPL_REG(x10, PERF_REG_ARM64_X10),31	SMPL_REG(x11, PERF_REG_ARM64_X11),32	SMPL_REG(x12, PERF_REG_ARM64_X12),33	SMPL_REG(x13, PERF_REG_ARM64_X13),34	SMPL_REG(x14, PERF_REG_ARM64_X14),35	SMPL_REG(x15, PERF_REG_ARM64_X15),36	SMPL_REG(x16, PERF_REG_ARM64_X16),37	SMPL_REG(x17, PERF_REG_ARM64_X17),38	SMPL_REG(x18, PERF_REG_ARM64_X18),39	SMPL_REG(x19, PERF_REG_ARM64_X19),40	SMPL_REG(x20, PERF_REG_ARM64_X20),41	SMPL_REG(x21, PERF_REG_ARM64_X21),42	SMPL_REG(x22, PERF_REG_ARM64_X22),43	SMPL_REG(x23, PERF_REG_ARM64_X23),44	SMPL_REG(x24, PERF_REG_ARM64_X24),45	SMPL_REG(x25, PERF_REG_ARM64_X25),46	SMPL_REG(x26, PERF_REG_ARM64_X26),47	SMPL_REG(x27, PERF_REG_ARM64_X27),48	SMPL_REG(x28, PERF_REG_ARM64_X28),49	SMPL_REG(x29, PERF_REG_ARM64_X29),50	SMPL_REG(lr, PERF_REG_ARM64_LR),51	SMPL_REG(sp, PERF_REG_ARM64_SP),52	SMPL_REG(pc, PERF_REG_ARM64_PC),53	SMPL_REG(vg, PERF_REG_ARM64_VG),54	SMPL_REG_END55};56 57/* %xNUM */58#define SDT_OP_REGEX1  "^(x[1-2]?[0-9]|3[0-1])$"59 60/* [sp], [sp, NUM] */61#define SDT_OP_REGEX2  "^\\[sp(, )?([0-9]+)?\\]$"62 63static regex_t sdt_op_regex1, sdt_op_regex2;64 65static int sdt_init_op_regex(void)66{67	static int initialized;68	int ret = 0;69 70	if (initialized)71		return 0;72 73	ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);74	if (ret)75		goto error;76 77	ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);78	if (ret)79		goto free_regex1;80 81	initialized = 1;82	return 0;83 84free_regex1:85	regfree(&sdt_op_regex1);86error:87	pr_debug4("Regex compilation error.\n");88	return ret;89}90 91/*92 * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently93 * support these two formats.94 */95int arch_sdt_arg_parse_op(char *old_op, char **new_op)96{97	int ret, new_len;98	regmatch_t rm[5];99 100	ret = sdt_init_op_regex();101	if (ret < 0)102		return ret;103 104	if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {105		/* Extract xNUM */106		new_len = 2;	/* % NULL */107		new_len += (int)(rm[1].rm_eo - rm[1].rm_so);108 109		*new_op = zalloc(new_len);110		if (!*new_op)111			return -ENOMEM;112 113		scnprintf(*new_op, new_len, "%%%.*s",114			(int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);115	} else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {116		/* [sp], [sp, NUM] or [sp,NUM] */117		new_len = 7;	/* + ( % s p ) NULL */118 119		/* If the argument is [sp], need to fill offset '0' */120		if (rm[2].rm_so == -1)121			new_len += 1;122		else123			new_len += (int)(rm[2].rm_eo - rm[2].rm_so);124 125		*new_op = zalloc(new_len);126		if (!*new_op)127			return -ENOMEM;128 129		if (rm[2].rm_so == -1)130			scnprintf(*new_op, new_len, "+0(%%sp)");131		else132			scnprintf(*new_op, new_len, "+%.*s(%%sp)",133				  (int)(rm[2].rm_eo - rm[2].rm_so),134				  old_op + rm[2].rm_so);135	} else {136		pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);137		return SDT_ARG_SKIP;138	}139 140	return SDT_ARG_VALID;141}142 143uint64_t arch__intr_reg_mask(void)144{145	return PERF_REGS_MASK;146}147 148uint64_t arch__user_reg_mask(void)149{150	struct perf_event_attr attr = {151		.type                   = PERF_TYPE_HARDWARE,152		.config                 = PERF_COUNT_HW_CPU_CYCLES,153		.sample_type            = PERF_SAMPLE_REGS_USER,154		.disabled               = 1,155		.exclude_kernel         = 1,156		.sample_period		= 1,157		.sample_regs_user	= PERF_REGS_MASK158	};159	int fd;160 161	if (getauxval(AT_HWCAP) & HWCAP_SVE)162		attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);163 164	/*165	 * Check if the pmu supports perf extended regs, before166	 * returning the register mask to sample.167	 */168	if (attr.sample_regs_user != PERF_REGS_MASK) {169		event_attr_init(&attr);170		fd = sys_perf_event_open(&attr, 0, -1, -1, 0);171		if (fd != -1) {172			close(fd);173			return attr.sample_regs_user;174		}175	}176	return PERF_REGS_MASK;177}178 179const struct sample_reg *arch__sample_reg_masks(void)180{181	return sample_reg_masks;182}183