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

MIPS: kernel: Support extracting off-line stack traces from user-space with perf

Add perf_event_mips_regs/perf_reg_value/perf_reg_validate to support
features HAVE_PERF_REGS/HAVE_PERF_USER_STACK_DUMP in kernel.

[ayan@wavecomp.com: Repick this patch for unwinding userstack backtrace
by perf and libunwind on MIPS based CPU.]

[ralf@linux-mips.org: Add perf_get_regs_user() which is required after
'commit 88a7c26af8da ("perf: Move task_pt_regs sampling into arch code")'.]

[yangtiezhu@loongson.cn: Fix build error about perf_get_regs_user() after
commit 76a4efa80900 ("perf/arch: Remove perf_sample_data::regs_user_copy"),
and also separate the original patches into two parts (MIPS kernel and perf
tools) to merge easily.]

The original patches:
https://lore.kernel.org/patchwork/patch/1126521/
https://lore.kernel.org/patchwork/patch/1126520/

Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Archer Yan <ayan@wavecomp.com>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>

authored by

Tiezhu Yang and committed by
Thomas Bogendoerfer
1ddc96bd c87bc737

+111 -1
+2
arch/mips/Kconfig
··· 77 77 select HAVE_NMI 78 78 select HAVE_OPROFILE 79 79 select HAVE_PERF_EVENTS 80 + select HAVE_PERF_REGS 81 + select HAVE_PERF_USER_STACK_DUMP 80 82 select HAVE_REGS_AND_STACK_ACCESS_API 81 83 select HAVE_RSEQ 82 84 select HAVE_SPARSE_SYSCALL_NR
+40
arch/mips/include/uapi/asm/perf_regs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + #ifndef _ASM_MIPS_PERF_REGS_H 3 + #define _ASM_MIPS_PERF_REGS_H 4 + 5 + enum perf_event_mips_regs { 6 + PERF_REG_MIPS_PC, 7 + PERF_REG_MIPS_R1, 8 + PERF_REG_MIPS_R2, 9 + PERF_REG_MIPS_R3, 10 + PERF_REG_MIPS_R4, 11 + PERF_REG_MIPS_R5, 12 + PERF_REG_MIPS_R6, 13 + PERF_REG_MIPS_R7, 14 + PERF_REG_MIPS_R8, 15 + PERF_REG_MIPS_R9, 16 + PERF_REG_MIPS_R10, 17 + PERF_REG_MIPS_R11, 18 + PERF_REG_MIPS_R12, 19 + PERF_REG_MIPS_R13, 20 + PERF_REG_MIPS_R14, 21 + PERF_REG_MIPS_R15, 22 + PERF_REG_MIPS_R16, 23 + PERF_REG_MIPS_R17, 24 + PERF_REG_MIPS_R18, 25 + PERF_REG_MIPS_R19, 26 + PERF_REG_MIPS_R20, 27 + PERF_REG_MIPS_R21, 28 + PERF_REG_MIPS_R22, 29 + PERF_REG_MIPS_R23, 30 + PERF_REG_MIPS_R24, 31 + PERF_REG_MIPS_R25, 32 + PERF_REG_MIPS_R26, 33 + PERF_REG_MIPS_R27, 34 + PERF_REG_MIPS_R28, 35 + PERF_REG_MIPS_R29, 36 + PERF_REG_MIPS_R30, 37 + PERF_REG_MIPS_R31, 38 + PERF_REG_MIPS_MAX = PERF_REG_MIPS_R31 + 1, 39 + }; 40 + #endif /* _ASM_MIPS_PERF_REGS_H */
+1 -1
arch/mips/kernel/Makefile
··· 103 103 104 104 CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -x c /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) 105 105 106 - obj-$(CONFIG_PERF_EVENTS) += perf_event.o 106 + obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o 107 107 obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o 108 108 109 109 obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+68
arch/mips/kernel/perf_regs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * This file is subject to the terms and conditions of the GNU General Public 4 + * License. See the file "COPYING" in the main directory of this archive 5 + * for more details. 6 + * 7 + * Some parts derived from x86 version of this file. 8 + * 9 + * Copyright (C) 2013 Cavium, Inc. 10 + */ 11 + 12 + #include <linux/perf_event.h> 13 + 14 + #include <asm/ptrace.h> 15 + 16 + #ifdef CONFIG_32BIT 17 + u64 perf_reg_abi(struct task_struct *tsk) 18 + { 19 + return PERF_SAMPLE_REGS_ABI_32; 20 + } 21 + #else /* Must be CONFIG_64BIT */ 22 + u64 perf_reg_abi(struct task_struct *tsk) 23 + { 24 + if (test_tsk_thread_flag(tsk, TIF_32BIT_REGS)) 25 + return PERF_SAMPLE_REGS_ABI_32; 26 + else 27 + return PERF_SAMPLE_REGS_ABI_64; 28 + } 29 + #endif /* CONFIG_32BIT */ 30 + 31 + int perf_reg_validate(u64 mask) 32 + { 33 + if (!mask) 34 + return -EINVAL; 35 + if (mask & ~((1ull << PERF_REG_MIPS_MAX) - 1)) 36 + return -EINVAL; 37 + return 0; 38 + } 39 + 40 + u64 perf_reg_value(struct pt_regs *regs, int idx) 41 + { 42 + long v; 43 + 44 + switch (idx) { 45 + case PERF_REG_MIPS_PC: 46 + v = regs->cp0_epc; 47 + break; 48 + case PERF_REG_MIPS_R1 ... PERF_REG_MIPS_R25: 49 + v = regs->regs[idx - PERF_REG_MIPS_R1 + 1]; 50 + break; 51 + case PERF_REG_MIPS_R28 ... PERF_REG_MIPS_R31: 52 + v = regs->regs[idx - PERF_REG_MIPS_R28 + 28]; 53 + break; 54 + 55 + default: 56 + WARN_ON_ONCE(1); 57 + return 0; 58 + } 59 + 60 + return (s64)v; /* Sign extend if 32-bit. */ 61 + } 62 + 63 + void perf_get_regs_user(struct perf_regs *regs_user, 64 + struct pt_regs *regs) 65 + { 66 + regs_user->regs = task_pt_regs(current); 67 + regs_user->abi = perf_reg_abi(current); 68 + }