new file mode 100644
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Based on arch/x86/include/asm/trace/common.h
+ *
+ */
+
+#ifndef _ASM_TRACE_COMMON_H
+#define _ASM_TRACE_COMMON_H
+
+#ifdef CONFIG_TRACING
+DECLARE_STATIC_KEY_FALSE(trace_memabort_key);
+#define trace_memabort_enabled() \
+ static_branch_unlikely(&trace_memabort_key)
+#else
+static inline bool trace_memabort_enabled(void) { return false; }
+#endif
+
+#endif
new file mode 100644
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Based on arch/x86/include/asm/trace/exceptions.h
+ *
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM exceptions
+
+#if !defined(_TRACE_MEM_ABORT_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MEM_ABORT_H
+
+#include <linux/tracepoint.h>
+#include <asm/trace/common.h>
+
+extern int trace_memabort_reg(void);
+extern void trace_memabort_unreg(void);
+
+DECLARE_EVENT_CLASS(arm64_exceptions,
+
+ TP_PROTO(unsigned long address, struct pt_regs *regs,
+ unsigned long error_code),
+
+ TP_ARGS(address, regs, error_code),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, address )
+ __field( unsigned long, ip )
+ __field( unsigned long, error_code )
+ ),
+
+ TP_fast_assign(
+ __entry->address = address;
+ __entry->ip = regs->pc;
+ __entry->error_code = error_code;
+ ),
+
+ TP_printk("address=%ps ip=%ps error_code=0x%lx",
+ (void *)__entry->address, (void *)__entry->ip,
+ __entry->error_code) );
+
+#define DEFINE_MEM_ABORT_EVENT(name) \
+DEFINE_EVENT_FN(arm64_exceptions, name, \
+ TP_PROTO(unsigned long address, struct pt_regs *regs, \
+ unsigned long error_code), \
+ TP_ARGS(address, regs, error_code), \
+ trace_memabort_reg, trace_memabort_unreg);
+
+DEFINE_MEM_ABORT_EVENT(mem_abort_user);
+DEFINE_MEM_ABORT_EVENT(mem_abort_kernel);
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH asm/trace
+#define TRACE_INCLUDE_FILE exceptions
+#endif /* _TRACE_MEM_ABORT_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
@@ -43,6 +43,7 @@ obj-$(CONFIG_KUSER_HELPERS) += kuser32.o
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
obj-$(CONFIG_MODULES) += module.o module-plts.o
obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
+obj-$(CONFIG_TRACING) += tracepoint.o
obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF) += watchdog_hld.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
new file mode 100644
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Based on arch/x86/kernel/tracepoint.c
+ *
+ */
+
+#include <linux/jump_label.h>
+#include <linux/atomic.h>
+
+#include <asm/trace/exceptions.h>
+
+DEFINE_STATIC_KEY_FALSE(trace_memabort_key);
+
+int trace_memabort_reg(void)
+{
+ static_branch_inc(&trace_memabort_key);
+ return 0;
+}
+
+void trace_memabort_unreg(void)
+{
+ static_branch_dec(&trace_memabort_key);
+}
@@ -43,6 +43,9 @@
#include <asm/tlbflush.h>
#include <asm/traps.h>
+#define CREATE_TRACE_POINTS
+#include <asm/trace/exceptions.h>
+
struct fault_info {
int (*fn)(unsigned long far, unsigned long esr,
struct pt_regs *regs);
@@ -818,11 +821,26 @@ static const struct fault_info fault_info[] = {
{ do_bad, SIGKILL, SI_KERNEL, "unknown 63" },
};
+static __always_inline void
+trace_mem_abort_entries(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ if (!trace_memabort_enabled())
+ return;
+
+ if (user_mode(regs))
+ trace_mem_abort_user(address, regs, error_code);
+ else
+ trace_mem_abort_kernel(address, regs, error_code);
+}
+
void do_mem_abort(unsigned long far, unsigned long esr, struct pt_regs *regs)
{
const struct fault_info *inf = esr_to_fault_info(esr);
unsigned long addr = untagged_addr(far);
+ trace_mem_abort_entries(regs, esr, addr);
+
if (!inf->fn(far, esr, regs))
return;
Introduce an event to trace the occurrence of memory abort exceptions. The event can be useful if you only want to trace the page fault exception when accessing a specific virtual address range, and it can also help in locating the userspace code that triggers the fault. I have referred to the trace_page_fault_user/trace_page_fault_kernel on the x86 platform. For example: $ sudo perf record -e exceptions:mem_abort_user \ --filter 'address >= 0xffff8fe00010 && address <= 0xffff90e00010' \ -g -p 596 -- sleep 10 $ sudo perf script fault 596 [000] 1218.765001: exceptions:mem_abort_user: address=0xffff9010e010 ip=0xaaaad8c90a6c error_code=0x9200000b ffff800080028e78 do_mem_abort+0xd0 ([kernel.kallsyms]) ffff800080028e78 do_mem_abort+0xd0 ([kernel.kallsyms]) ffff800080c89a38 el0_da+0x38 ([kernel.kallsyms]) ffff800080c8ac54 el0t_64_sync_handler+0x8c ([kernel.kallsyms]) ffff80008001148c el0t_64_sync+0x14c ([kernel.kallsyms]) aaaad8c90a6c func_three+0xf0 (/home/pengdl/demo/pagefault/fault) aaaad8c90ae4 func_two+0x20 (/home/pengdl/demo/pagefault/fault) aaaad8c90b0c func_one+0x20 (/home/pengdl/demo/pagefault/fault) aaaad8c90c54 main+0x140 (/home/pengdl/demo/pagefault/fault) ffff90fece10 __libc_start_main+0xe8 (/usr/lib/aarch64-linux-gnu/libc-2.31.so) aaaad8c908a4 _start+0x34 (/home/pengdl/demo/pagefault/fault) Signed-off-by: Donglin Peng <dolinux.peng@gmail.com> --- arch/arm64/include/asm/trace/common.h | 18 +++++++ arch/arm64/include/asm/trace/exceptions.h | 59 +++++++++++++++++++++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/tracepoint.c | 23 +++++++++ arch/arm64/mm/fault.c | 18 +++++++ 5 files changed, 119 insertions(+) create mode 100644 arch/arm64/include/asm/trace/common.h create mode 100644 arch/arm64/include/asm/trace/exceptions.h create mode 100644 arch/arm64/kernel/tracepoint.c