History

LoongArch: Add ORC stack unwinder support

The kernel CONFIG_UNWINDER_ORC option enables the ORC unwinder, which is similar in concept to a DWARF unwinder. The difference is that the format of the ORC data is much simpler than DWARF, which in turn allows the ORC unwinder to be much simpler and faster. The ORC data consists of unwind tables which are generated by objtool. After analyzing all the code paths of a .o file, it determines information about the stack state at each instruction address in the file and outputs that information to the .orc_unwind and .orc_unwind_ip sections. The per-object ORC sections are combined at link time and are sorted and post-processed at boot time. The unwinder uses the resulting data to correlate instruction addresses with their stack states at run time. Most of the logic are similar with x86, in order to get ra info before ra is saved into stack, add ra_reg and ra_offset into orc_entry. At the same time, modify some arch-specific code to silence the objtool warnings.

Tiezhu Yang committed 2 years ago

Commit cb8a2ef1 parent e91c5e437 files · +875 −42Browse files

Unified · Split

37 files
  1. arch/loongarch/Kconfig +2 −0
  2. arch/loongarch/Kconfig.debug +11 −0
  3. arch/loongarch/Makefile +21 −2
  4. arch/loongarch/include/asm/Kbuild +2 −0
  5. arch/loongarch/include/asm/bug.h +1 −0
  6. arch/loongarch/include/asm/exception.h +2 −0
  7. arch/loongarch/include/asm/module.h +7 −0
  8. arch/loongarch/include/asm/orc_header.h +18 −0
  9. arch/loongarch/include/asm/orc_lookup.h +31 −0
  10. arch/loongarch/include/asm/orc_types.h +58 −0
  11. arch/loongarch/include/asm/stackframe.h +3 −0
  12. arch/loongarch/include/asm/unwind.h +18 −2
  13. arch/loongarch/include/asm/unwind_hints.h +28 −0
  14. arch/loongarch/kernel/Makefile +4 −0
  15. arch/loongarch/kernel/entry.S +5 −0
  16. arch/loongarch/kernel/fpu.S +7 −0
  17. arch/loongarch/kernel/genex.S +6 −0
  18. arch/loongarch/kernel/lbt.S +3 −0
  19. arch/loongarch/kernel/mcount_dyn.S +6 −0
  20. arch/loongarch/kernel/module.c +18 −4
  21. arch/loongarch/kernel/relocate_kernel.S +4 −3
  22. arch/loongarch/kernel/rethook_trampoline.S +1 −0
  23. arch/loongarch/kernel/setup.c +2 −0
  24. arch/loongarch/kernel/stacktrace.c +1 −0
  25. arch/loongarch/kernel/traps.c +29 −13
  26. arch/loongarch/kernel/unwind_orc.c +528 −0
  27. arch/loongarch/kernel/vmlinux.lds.S +3 −0
  28. arch/loongarch/kvm/switch.S +8 −1
  29. arch/loongarch/lib/clear_user.S +3 −0
  30. arch/loongarch/lib/copy_user.S +3 −0
  31. arch/loongarch/lib/memcpy.S +3 −0
  32. arch/loongarch/lib/memset.S +3 −0
  33. arch/loongarch/mm/tlb.c +12 −15
  34. arch/loongarch/mm/tlbex.S +9 −0
  35. arch/loongarch/vdso/Makefile +1 −0
  36. include/linux/compiler.h +9 −0
  37. scripts/Makefile +5 −2
arch/loongarch/Kconfig+2−0
@@ -136,6 +136,7 @@ config LOONGARCH · 135 unmodified lines
136136 select HAVE_KVM
137137 select HAVE_MOD_ARCH_SPECIFIC
138138 select HAVE_NMI
139+ select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS
139140 select HAVE_PCI
140141 select HAVE_PERF_EVENTS
141142 select HAVE_PERF_REGS
@@ -148,6 +149,7 @@ config LOONGARCH · 6 unmodified lines
148149 select HAVE_SAMPLE_FTRACE_DIRECT
149150 select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
150151 select HAVE_SETUP_PER_CPU_AREA if NUMA
152+ select HAVE_STACK_VALIDATION if HAVE_OBJTOOL
151153 select HAVE_STACKPROTECTOR
152154 select HAVE_SYSCALL_TRACEPOINTS
153155 select HAVE_TIF_NOHZ
arch/loongarch/Kconfig.debug+11−0
@@ -26,4 +26,15 @@ config UNWINDER_PROLOGUE · 25 unmodified lines
2626 Some of the addresses it reports may be incorrect (but better than the
2727 Guess unwinder).
2828
29+config UNWINDER_ORC
30+ bool "ORC unwinder"
31+ select OBJTOOL
32+ help
33+ This option enables the ORC (Oops Rewind Capability) unwinder for
34+ unwinding kernel stack traces. It uses a custom data format which is
35+ a simplified version of the DWARF Call Frame Information standard.
36+
37+ Enabling this option will increase the kernel's runtime memory usage
38+ by roughly 2-4MB, depending on your kernel config.
39+
2940 endchoice
arch/loongarch/Makefile+21−2
@@ -26,6 +26,18 @@ endif · 25 unmodified lines
2626 32bit-emul = elf32loongarch
2727 64bit-emul = elf64loongarch
2828
29+ifdef CONFIG_UNWINDER_ORC
30+orc_hash_h := arch/$(SRCARCH)/include/generated/asm/orc_hash.h
31+orc_hash_sh := $(srctree)/scripts/orc_hash.sh
32+targets += $(orc_hash_h)
33+quiet_cmd_orc_hash = GEN $@
34+ cmd_orc_hash = mkdir -p $(dir $@); \
35+ $(CONFIG_SHELL) $(orc_hash_sh) < $< > $@
36+$(orc_hash_h): $(srctree)/arch/loongarch/include/asm/orc_types.h $(orc_hash_sh) FORCE
37+ $(call if_changed,orc_hash)
38+archprepare: $(orc_hash_h)
39+endif
40+
2941 ifdef CONFIG_DYNAMIC_FTRACE
3042 KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
3143 CC_FLAGS_FTRACE := -fpatchable-function-entry=2
@@ -72,8 +84,6 @@ KBUILD_CFLAGS_KERNEL += $(call cc-option,-mdirect-extern-access) · 40 unmodified lines
7284 KBUILD_CFLAGS_KERNEL += $(call cc-option,-fdirect-access-external-data)
7385 KBUILD_AFLAGS_MODULE += $(call cc-option,-fno-direct-access-external-data)
7486 KBUILD_CFLAGS_MODULE += $(call cc-option,-fno-direct-access-external-data)
75−KBUILD_AFLAGS_MODULE += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
76−KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
7787 else
7888 cflags-y += $(call cc-option,-mno-explicit-relocs)
7989 KBUILD_AFLAGS_KERNEL += -Wa,-mla-global-with-pcrel
@@ -82,6 +92,15 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs · 2 unmodified lines
8292 KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
8393 endif
8494
95+KBUILD_AFLAGS += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
96+KBUILD_CFLAGS += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
97+KBUILD_AFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub)
98+KBUILD_CFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub)
99+
100+ifdef CONFIG_OBJTOOL
101+KBUILD_CFLAGS += -fno-jump-tables
102+endif
103+
85104 KBUILD_RUSTFLAGS_MODULE += -Crelocation-model=pic
86105
87106 ifeq ($(CONFIG_RELOCATABLE),y)
arch/loongarch/include/asm/Kbuild+2−0
@@ -1,4 +1,6 @@
11 # SPDX-License-Identifier: GPL-2.0
2+generated-y += orc_hash.h
3+
24 generic-y += dma-contiguous.h
35 generic-y += mcs_spinlock.h
46 generic-y += parport.h
arch/loongarch/include/asm/bug.h+1−0
@@ -44,6 +44,7 @@ · 43 unmodified lines
4444 do { \
4545 instrumentation_begin(); \
4646 __BUG_FLAGS(BUGFLAG_WARNING|(flags)); \
47+ annotate_reachable(); \
4748 instrumentation_end(); \
4849 } while (0)
4950
arch/loongarch/include/asm/exception.h+2−0
@@ -6,6 +6,8 @@ · 5 unmodified lines
66 #include <asm/ptrace.h>
77 #include <linux/kprobes.h>
88
9+extern void *exception_table[];
10+
911 void show_registers(struct pt_regs *regs);
1012
1113 asmlinkage void cache_parity_error(void);
arch/loongarch/include/asm/module.h+7−0
@@ -6,6 +6,7 @@ · 5 unmodified lines
66 #define _ASM_MODULE_H
77
88 #include <asm/inst.h>
9+#include <asm/orc_types.h>
910 #include <asm-generic/module.h>
1011
1112 #define RELA_STACK_DEPTH 16
@@ -21,6 +22,12 @@ struct mod_arch_specific { · 9 unmodified lines
2122 struct mod_section plt;
2223 struct mod_section plt_idx;
2324
25+#ifdef CONFIG_UNWINDER_ORC
26+ unsigned int num_orcs;
27+ int *orc_unwind_ip;
28+ struct orc_entry *orc_unwind;
29+#endif
30+
2431 /* For CONFIG_DYNAMIC_FTRACE */
2532 struct plt_entry *ftrace_trampolines;
2633 };
arch/loongarch/include/asm/orc_header.h+18−0
@@ -0,0 +1,18 @@
1+/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
3+#ifndef _ORC_HEADER_H
4+#define _ORC_HEADER_H
5+
6+#include <linux/types.h>
7+#include <linux/compiler.h>
8+#include <asm/orc_hash.h>
9+
10+/*
11+ * The header is currently a 20-byte hash of the ORC entry definition; see
12+ * scripts/orc_hash.sh.
13+ */
14+#define ORC_HEADER \
15+ __used __section(".orc_header") __aligned(4) \
16+ static const u8 orc_header[] = { ORC_HASH }
17+
18+#endif /* _ORC_HEADER_H */
arch/loongarch/include/asm/orc_lookup.h+31−0
@@ -0,0 +1,31 @@
1+/* SPDX-License-Identifier: GPL-2.0-or-later */
2+#ifndef _ORC_LOOKUP_H
3+#define _ORC_LOOKUP_H
4+
5+/*
6+ * This is a lookup table for speeding up access to the .orc_unwind table.
7+ * Given an input address offset, the corresponding lookup table entry
8+ * specifies a subset of the .orc_unwind table to search.
9+ *
10+ * Each block represents the end of the previous range and the start of the
11+ * next range. An extra block is added to give the last range an end.
12+ *
13+ * The block size should be a power of 2 to avoid a costly 'div' instruction.
14+ *
15+ * A block size of 256 was chosen because it roughly doubles unwinder
16+ * performance while only adding ~5% to the ORC data footprint.
17+ */
18+#define LOOKUP_BLOCK_ORDER 8
19+#define LOOKUP_BLOCK_SIZE (1 << LOOKUP_BLOCK_ORDER)
20+
21+#ifndef LINKER_SCRIPT
22+
23+extern unsigned int orc_lookup[];
24+extern unsigned int orc_lookup_end[];
25+
26+#define LOOKUP_START_IP (unsigned long)_stext
27+#define LOOKUP_STOP_IP (unsigned long)_etext
28+
29+#endif /* LINKER_SCRIPT */
30+
31+#endif /* _ORC_LOOKUP_H */
arch/loongarch/include/asm/orc_types.h+58−0
@@ -0,0 +1,58 @@
1+/* SPDX-License-Identifier: GPL-2.0-or-later */
2+#ifndef _ORC_TYPES_H
3+#define _ORC_TYPES_H
4+
5+#include <linux/types.h>
6+
7+/*
8+ * The ORC_REG_* registers are base registers which are used to find other
9+ * registers on the stack.
10+ *
11+ * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the
12+ * address of the previous frame: the caller's SP before it called the current
13+ * function.
14+ *
15+ * ORC_REG_UNDEFINED means the corresponding register's value didn't change in
16+ * the current frame.
17+ *
18+ * The most commonly used base registers are SP and FP -- which the previous SP
19+ * is usually based on -- and PREV_SP and UNDEFINED -- which the previous FP is
20+ * usually based on.
21+ *
22+ * The rest of the base registers are needed for special cases like entry code
23+ * and GCC realigned stacks.
24+ */
25+#define ORC_REG_UNDEFINED 0
26+#define ORC_REG_PREV_SP 1
27+#define ORC_REG_SP 2
28+#define ORC_REG_FP 3
29+#define ORC_REG_MAX 4
30+
31+#define ORC_TYPE_UNDEFINED 0
32+#define ORC_TYPE_END_OF_STACK 1
33+#define ORC_TYPE_CALL 2
34+#define ORC_TYPE_REGS 3
35+#define ORC_TYPE_REGS_PARTIAL 4
36+
37+#ifndef __ASSEMBLY__
38+/*
39+ * This struct is more or less a vastly simplified version of the DWARF Call
40+ * Frame Information standard. It contains only the necessary parts of DWARF
41+ * CFI, simplified for ease of access by the in-kernel unwinder. It tells the
42+ * unwinder how to find the previous SP and FP (and sometimes entry regs) on
43+ * the stack for a given code address. Each instance of the struct corresponds
44+ * to one or more code locations.
45+ */
46+struct orc_entry {
47+ s16 sp_offset;
48+ s16 fp_offset;
49+ s16 ra_offset;
50+ unsigned int sp_reg:4;
51+ unsigned int fp_reg:4;
52+ unsigned int ra_reg:4;
53+ unsigned int type:3;
54+ unsigned int signal:1;
55+};
56+#endif /* __ASSEMBLY__ */
57+
58+#endif /* _ORC_TYPES_H */
arch/loongarch/include/asm/stackframe.h+3−0
@@ -13,6 +13,7 @@ · 12 unmodified lines
1313 #include <asm/asm-offsets.h>
1414 #include <asm/loongarch.h>
1515 #include <asm/thread_info.h>
16+#include <asm/unwind_hints.h>
1617
1718 /* Make the addition of cfi info a little easier. */
1819 .macro cfi_rel_offset reg offset=0 docfi=0
@@ -162,6 +163,7 @@ · 143 unmodified lines
162163 li.w t0, CSR_CRMD_WE
163164 csrxchg t0, t0, LOONGARCH_CSR_CRMD
164165 #endif
166+ UNWIND_HINT_REGS
165167 .endm
166168
167169 .macro SAVE_ALL docfi=0
@@ -219,6 +221,7 @@ · 51 unmodified lines
219221
220222 .macro RESTORE_SP_AND_RET docfi=0
221223 cfi_ld sp, PT_R3, \docfi
224+ UNWIND_HINT_FUNC
222225 ertn
223226 .endm
224227
arch/loongarch/include/asm/unwind.h+18−2
@@ -16,6 +16,7 @@ · 15 unmodified lines
1616 enum unwinder_type {
1717 UNWINDER_GUESS,
1818 UNWINDER_PROLOGUE,
19+ UNWINDER_ORC,
1920 };
2021
2122 struct unwind_state {
@@ -24,7 +25,7 @@ struct unwind_state { · 2 unmodified lines
2425 struct task_struct *task;
2526 bool first, error, reset;
2627 int graph_idx;
27− unsigned long sp, pc, ra;
28+ unsigned long sp, fp, pc, ra;
2829 };
2930
3031 bool default_next_frame(struct unwind_state *state);
@@ -61,14 +62,17 @@ static __always_inline void __unwind_start(struct unwind_state *state, · 30 unmodified lines
6162 state->sp = regs->regs[3];
6263 state->pc = regs->csr_era;
6364 state->ra = regs->regs[1];
65+ state->fp = regs->regs[22];
6466 } else if (task && task != current) {
6567 state->sp = thread_saved_fp(task);
6668 state->pc = thread_saved_ra(task);
6769 state->ra = 0;
70+ state->fp = 0;
6871 } else {
6972 state->sp = (unsigned long)__builtin_frame_address(0);
7073 state->pc = (unsigned long)__builtin_return_address(0);
7174 state->ra = 0;
75+ state->fp = 0;
7276 }
7377 state->task = task;
7478 get_stack_info(state->sp, state->task, &state->stack_info);
@@ -77,6 +81,18 @@ static __always_inline void __unwind_start(struct unwind_state *state, · 2 unmodified lines
7781
7882 static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
7983 {
80− return unwind_done(state) ? 0 : state->pc;
84+ if (unwind_done(state))
85+ return 0;
86+
87+ return __kernel_text_address(state->pc) ? state->pc : 0;
8188 }
89+
90+#ifdef CONFIG_UNWINDER_ORC
91+void unwind_init(void);
92+void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size);
93+#else
94+static inline void unwind_init(void) {}
95+static inline void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size) {}
96+#endif
97+
8298 #endif /* _ASM_UNWIND_H */
arch/loongarch/include/asm/unwind_hints.h+28−0
@@ -0,0 +1,28 @@
1+/* SPDX-License-Identifier: GPL-2.0 */
2+#ifndef _ASM_LOONGARCH_UNWIND_HINTS_H
3+#define _ASM_LOONGARCH_UNWIND_HINTS_H
4+
5+#include <linux/objtool.h>
6+#include <asm/orc_types.h>
7+
8+#ifdef __ASSEMBLY__
9+
10+.macro UNWIND_HINT_UNDEFINED
11+ UNWIND_HINT type=UNWIND_HINT_TYPE_UNDEFINED
12+.endm
13+
14+.macro UNWIND_HINT_END_OF_STACK
15+ UNWIND_HINT type=UNWIND_HINT_TYPE_END_OF_STACK
16+.endm
17+
18+.macro UNWIND_HINT_REGS
19+ UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_REGS
20+.endm
21+
22+.macro UNWIND_HINT_FUNC
23+ UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL
24+.endm
25+
26+#endif /* __ASSEMBLY__ */
27+
28+#endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */
arch/loongarch/kernel/Makefile+4−0
@@ -3,6 +3,8 @@ · 2 unmodified lines
33 # Makefile for the Linux/LoongArch kernel.
44 #
55
6+OBJECT_FILES_NON_STANDARD_head.o := y
7+
68 extra-y := vmlinux.lds
79
810 obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
@@ -21,6 +23,7 @@ obj-$(CONFIG_ARCH_STRICT_ALIGN) += unaligned.o · 12 unmodified lines
2123
2224 CFLAGS_module.o += $(call cc-option,-Wno-override-init,)
2325 CFLAGS_syscall.o += $(call cc-option,-Wno-override-init,)
26+CFLAGS_traps.o += $(call cc-option,-Wno-override-init,)
2427 CFLAGS_perf_event.o += $(call cc-option,-Wno-override-init,)
2528
2629 ifdef CONFIG_FUNCTION_TRACER
@@ -62,6 +65,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o · 35 unmodified lines
6265
6366 obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
6467 obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o
68+obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o
6569
6670 obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o
6771 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
arch/loongarch/kernel/entry.S+5−0
@@ -14,11 +14,13 @@ · 13 unmodified lines
1414 #include <asm/regdef.h>
1515 #include <asm/stackframe.h>
1616 #include <asm/thread_info.h>
17+#include <asm/unwind_hints.h>
1718
1819 .text
1920 .cfi_sections .debug_frame
2021 .align 5
2122 SYM_CODE_START(handle_syscall)
23+ UNWIND_HINT_UNDEFINED
2224 csrrd t0, PERCPU_BASE_KS
2325 la.pcrel t1, kernelsp
2426 add.d t1, t1, t0
@@ -57,6 +59,7 @@ SYM_CODE_START(handle_syscall) · 32 unmodified lines
5759 cfi_st fp, PT_R22
5860
5961 SAVE_STATIC
62+ UNWIND_HINT_REGS
6063
6164 #ifdef CONFIG_KGDB
6265 li.w t1, CSR_CRMD_WE
@@ -75,6 +78,7 @@ SYM_CODE_END(handle_syscall) · 12 unmodified lines
7578 _ASM_NOKPROBE(handle_syscall)
7679
7780 SYM_CODE_START(ret_from_fork)
81+ UNWIND_HINT_REGS
7882 bl schedule_tail # a0 = struct task_struct *prev
7983 move a0, sp
8084 bl syscall_exit_to_user_mode
@@ -84,6 +88,7 @@ SYM_CODE_START(ret_from_fork) · 3 unmodified lines
8488 SYM_CODE_END(ret_from_fork)
8589
8690 SYM_CODE_START(ret_from_kernel_thread)
91+ UNWIND_HINT_REGS
8792 bl schedule_tail # a0 = struct task_struct *prev
8893 move a0, s1
8994 jirl ra, s0, 0
arch/loongarch/kernel/fpu.S+7−0
@@ -15,6 +15,7 @@ · 14 unmodified lines
1515 #include <asm/fpregdef.h>
1616 #include <asm/loongarch.h>
1717 #include <asm/regdef.h>
18+#include <asm/unwind_hints.h>
1819
1920 #define FPU_REG_WIDTH 8
2021 #define LSX_REG_WIDTH 16
@@ -526,3 +527,9 @@ SYM_FUNC_END(_restore_lasx_context) · 505 unmodified lines
526527 .L_fpu_fault:
527528 li.w a0, -EFAULT # failure
528529 jr ra
530+
531+#ifdef CONFIG_CPU_HAS_LBT
532+STACK_FRAME_NON_STANDARD _restore_fp
533+STACK_FRAME_NON_STANDARD _restore_lsx
534+STACK_FRAME_NON_STANDARD _restore_lasx
535+#endif
arch/loongarch/kernel/genex.S+6−0
@@ -32,6 +32,7 @@ SYM_FUNC_START(__arch_cpu_idle) · 31 unmodified lines
3232 SYM_FUNC_END(__arch_cpu_idle)
3333
3434 SYM_CODE_START(handle_vint)
35+ UNWIND_HINT_UNDEFINED
3536 BACKUP_T0T1
3637 SAVE_ALL
3738 la_abs t1, __arch_cpu_idle
@@ -49,6 +50,7 @@ SYM_CODE_START(handle_vint) · 11 unmodified lines
4950 SYM_CODE_END(handle_vint)
5051
5152 SYM_CODE_START(except_vec_cex)
53+ UNWIND_HINT_UNDEFINED
5254 b cache_parity_error
5355 SYM_CODE_END(except_vec_cex)
5456
@@ -67,6 +69,7 @@ SYM_CODE_END(except_vec_cex) · 12 unmodified lines
6769 .macro BUILD_HANDLER exception handler prep
6870 .align 5
6971 SYM_CODE_START(handle_\exception)
72+ UNWIND_HINT_UNDEFINED
7073 666:
7174 BACKUP_T0T1
7275 SAVE_ALL
@@ -77,7 +80,9 @@ SYM_CODE_END(except_vec_cex) · 4 unmodified lines
7780 668:
7881 RESTORE_ALL_AND_RET
7982 SYM_CODE_END(handle_\exception)
83+ .pushsection ".data", "aw", %progbits
8084 SYM_DATA(unwind_hint_\exception, .word 668b - 666b)
85+ .popsection
8186 .endm
8287
8388 BUILD_HANDLER ade ade badv
@@ -94,6 +99,7 @@ SYM_CODE_END(except_vec_cex) · 10 unmodified lines
9499 BUILD_HANDLER reserved reserved none /* others */
95100
96101 SYM_CODE_START(handle_sys)
102+ UNWIND_HINT_UNDEFINED
97103 la_abs t0, handle_syscall
98104 jr t0
99105 SYM_CODE_END(handle_sys)
arch/loongarch/kernel/lbt.S+3−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #include <asm/asm-offsets.h>
1212 #include <asm/errno.h>
1313 #include <asm/regdef.h>
14+#include <asm/unwind_hints.h>
1415
1516 #define SCR_REG_WIDTH 8
1617
@@ -153,3 +154,5 @@ SYM_FUNC_END(_restore_ftop_context) · 136 unmodified lines
153154 .L_lbt_fault:
154155 li.w a0, -EFAULT # failure
155156 jr ra
157+
158+STACK_FRAME_NON_STANDARD _restore_ftop_context
arch/loongarch/kernel/mcount_dyn.S+6−0
@@ -73,6 +73,7 @@ SYM_FUNC_START(ftrace_stub) · 72 unmodified lines
7373 SYM_FUNC_END(ftrace_stub)
7474
7575 SYM_CODE_START(ftrace_common)
76+ UNWIND_HINT_UNDEFINED
7677 PTR_ADDI a0, ra, -8 /* arg0: ip */
7778 move a1, t0 /* arg1: parent_ip */
7879 la.pcrel t1, function_trace_op
@@ -113,12 +114,14 @@ ftrace_common_return: · 34 unmodified lines
113114 SYM_CODE_END(ftrace_common)
114115
115116 SYM_CODE_START(ftrace_caller)
117+ UNWIND_HINT_UNDEFINED
116118 ftrace_regs_entry allregs=0
117119 b ftrace_common
118120 SYM_CODE_END(ftrace_caller)
119121
120122 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
121123 SYM_CODE_START(ftrace_regs_caller)
124+ UNWIND_HINT_UNDEFINED
122125 ftrace_regs_entry allregs=1
123126 b ftrace_common
124127 SYM_CODE_END(ftrace_regs_caller)
@@ -126,6 +129,7 @@ SYM_CODE_END(ftrace_regs_caller) · 1 unmodified line
126129
127130 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
128131 SYM_CODE_START(ftrace_graph_caller)
132+ UNWIND_HINT_UNDEFINED
129133 PTR_L a0, sp, PT_ERA
130134 PTR_ADDI a0, a0, -8 /* arg0: self_addr */
131135 PTR_ADDI a1, sp, PT_R1 /* arg1: parent */
@@ -134,6 +138,7 @@ SYM_CODE_START(ftrace_graph_caller) · 2 unmodified lines
134138 SYM_CODE_END(ftrace_graph_caller)
135139
136140 SYM_CODE_START(return_to_handler)
141+ UNWIND_HINT_UNDEFINED
137142 /* Save return value regs */
138143 PTR_ADDI sp, sp, -FGRET_REGS_SIZE
139144 PTR_S a0, sp, FGRET_REGS_A0
@@ -155,6 +160,7 @@ SYM_CODE_END(return_to_handler) · 15 unmodified lines
155160
156161 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
157162 SYM_CODE_START(ftrace_stub_direct_tramp)
163+ UNWIND_HINT_UNDEFINED
158164 jr t0
159165 SYM_CODE_END(ftrace_stub_direct_tramp)
160166 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
arch/loongarch/kernel/module.c+18−4
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include <linux/kernel.h>
2121 #include <asm/alternative.h>
2222 #include <asm/inst.h>
23+#include <asm/unwind.h>
2324
2425 static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top)
2526 {
@@ -515,15 +516,28 @@ static void module_init_ftrace_plt(const Elf_Ehdr *hdr, · 489 unmodified lines
515516 int module_finalize(const Elf_Ehdr *hdr,
516517 const Elf_Shdr *sechdrs, struct module *mod)
517518 {
518− const Elf_Shdr *s, *se;
519519 const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
520+ const Elf_Shdr *s, *alt = NULL, *orc = NULL, *orc_ip = NULL, *ftrace = NULL;
520521
521− for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
522+ for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
522523 if (!strcmp(".altinstructions", secstrs + s->sh_name))
523− apply_alternatives((void *)s->sh_addr, (void *)s->sh_addr + s->sh_size);
524+ alt = s;
525+ if (!strcmp(".orc_unwind", secstrs + s->sh_name))
526+ orc = s;
527+ if (!strcmp(".orc_unwind_ip", secstrs + s->sh_name))
528+ orc_ip = s;
524529 if (!strcmp(".ftrace_trampoline", secstrs + s->sh_name))
525− module_init_ftrace_plt(hdr, s, mod);
530+ ftrace = s;
526531 }
527532
533+ if (alt)
534+ apply_alternatives((void *)alt->sh_addr, (void *)alt->sh_addr + alt->sh_size);
535+
536+ if (orc && orc_ip)
537+ unwind_module_init(mod, (void *)orc_ip->sh_addr, orc_ip->sh_size, (void *)orc->sh_addr, orc->sh_size);
538+
539+ if (ftrace)
540+ module_init_ftrace_plt(hdr, ftrace, mod);
541+
528542 return 0;
529543 }
arch/loongarch/kernel/relocate_kernel.S+4−3
@@ -15,6 +15,7 @@ · 14 unmodified lines
1515 #include <asm/addrspace.h>
1616
1717 SYM_CODE_START(relocate_new_kernel)
18+ UNWIND_HINT_UNDEFINED
1819 /*
1920 * a0: EFI boot flag for the new kernel
2021 * a1: Command line pointer for the new kernel
@@ -90,6 +91,7 @@ SYM_CODE_END(relocate_new_kernel) · 69 unmodified lines
9091 * then start at the entry point from LOONGARCH_IOCSR_MBUF0.
9192 */
9293 SYM_CODE_START(kexec_smp_wait)
94+ UNWIND_HINT_UNDEFINED
9395 1: li.w t0, 0x100 /* wait for init loop */
9496 2: addi.w t0, t0, -1 /* limit mailbox access */
9597 bnez t0, 2b
@@ -106,6 +108,5 @@ SYM_CODE_END(kexec_smp_wait) · 10 unmodified lines
106108
107109 relocate_new_kernel_end:
108110
109−SYM_DATA_START(relocate_new_kernel_size)
110− PTR relocate_new_kernel_end - relocate_new_kernel
111−SYM_DATA_END(relocate_new_kernel_size)
111+ .section ".data"
112+SYM_DATA(relocate_new_kernel_size, .long relocate_new_kernel_end - relocate_new_kernel)
arch/loongarch/kernel/rethook_trampoline.S+1−0
@@ -76,6 +76,7 @@ · 75 unmodified lines
7676 .endm
7777
7878 SYM_CODE_START(arch_rethook_trampoline)
79+ UNWIND_HINT_UNDEFINED
7980 addi.d sp, sp, -PT_SIZE
8081 save_all_base_regs
8182
arch/loongarch/kernel/setup.c+2−0
@@ -47,6 +47,7 @@ · 46 unmodified lines
4747 #include <asm/sections.h>
4848 #include <asm/setup.h>
4949 #include <asm/time.h>
50+#include <asm/unwind.h>
5051
5152 #define SMBIOS_BIOSSIZE_OFFSET 0x09
5253 #define SMBIOS_BIOSEXTERN_OFFSET 0x13
@@ -587,6 +588,7 @@ static void __init prefill_possible_map(void) · 534 unmodified lines
587588 void __init setup_arch(char **cmdline_p)
588589 {
589590 cpu_probe();
591+ unwind_init();
590592
591593 init_environ();
592594 efi_init();
arch/loongarch/kernel/stacktrace.c+1−0
@@ -29,6 +29,7 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, · 28 unmodified lines
2929 regs->csr_era = thread_saved_ra(task);
3030 }
3131 regs->regs[1] = 0;
32+ regs->regs[22] = 0;
3233 }
3334
3435 for (unwind_start(&state, task, regs);
arch/loongarch/kernel/traps.c+29−13
@@ -53,6 +53,32 @@ · 52 unmodified lines
5353
5454 #include "access-helper.h"
5555
56+void *exception_table[EXCCODE_INT_START] = {
57+ [0 ... EXCCODE_INT_START - 1] = handle_reserved,
58+
59+ [EXCCODE_TLBI] = handle_tlb_load,
60+ [EXCCODE_TLBL] = handle_tlb_load,
61+ [EXCCODE_TLBS] = handle_tlb_store,
62+ [EXCCODE_TLBM] = handle_tlb_modify,
63+ [EXCCODE_TLBNR] = handle_tlb_protect,
64+ [EXCCODE_TLBNX] = handle_tlb_protect,
65+ [EXCCODE_TLBPE] = handle_tlb_protect,
66+ [EXCCODE_ADE] = handle_ade,
67+ [EXCCODE_ALE] = handle_ale,
68+ [EXCCODE_BCE] = handle_bce,
69+ [EXCCODE_SYS] = handle_sys,
70+ [EXCCODE_BP] = handle_bp,
71+ [EXCCODE_INE] = handle_ri,
72+ [EXCCODE_IPE] = handle_ri,
73+ [EXCCODE_FPDIS] = handle_fpu,
74+ [EXCCODE_LSXDIS] = handle_lsx,
75+ [EXCCODE_LASXDIS] = handle_lasx,
76+ [EXCCODE_FPE] = handle_fpe,
77+ [EXCCODE_WATCH] = handle_watch,
78+ [EXCCODE_BTDIS] = handle_lbt,
79+};
80+EXPORT_SYMBOL_GPL(exception_table);
81+
5682 static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
5783 const char *loglvl, bool user)
5884 {
@@ -1150,19 +1176,9 @@ void __init trap_init(void) · 1091 unmodified lines
11501176 for (i = EXCCODE_INT_START; i <= EXCCODE_INT_END; i++)
11511177 set_handler(i * VECSIZE, handle_vint, VECSIZE);
11521178
1153− set_handler(EXCCODE_ADE * VECSIZE, handle_ade, VECSIZE);
1154− set_handler(EXCCODE_ALE * VECSIZE, handle_ale, VECSIZE);
1155− set_handler(EXCCODE_BCE * VECSIZE, handle_bce, VECSIZE);
1156− set_handler(EXCCODE_SYS * VECSIZE, handle_sys, VECSIZE);
1157− set_handler(EXCCODE_BP * VECSIZE, handle_bp, VECSIZE);
1158− set_handler(EXCCODE_INE * VECSIZE, handle_ri, VECSIZE);
1159− set_handler(EXCCODE_IPE * VECSIZE, handle_ri, VECSIZE);
1160− set_handler(EXCCODE_FPDIS * VECSIZE, handle_fpu, VECSIZE);
1161− set_handler(EXCCODE_LSXDIS * VECSIZE, handle_lsx, VECSIZE);
1162− set_handler(EXCCODE_LASXDIS * VECSIZE, handle_lasx, VECSIZE);
1163− set_handler(EXCCODE_FPE * VECSIZE, handle_fpe, VECSIZE);
1164− set_handler(EXCCODE_BTDIS * VECSIZE, handle_lbt, VECSIZE);
1165− set_handler(EXCCODE_WATCH * VECSIZE, handle_watch, VECSIZE);
1179+ /* Set exception vector handler */
1180+ for (i = EXCCODE_ADE; i <= EXCCODE_BTDIS; i++)
1181+ set_handler(i * VECSIZE, exception_table[i], VECSIZE);
11661182
11671183 cache_error_setup();
11681184
arch/loongarch/kernel/unwind_orc.c+528−0
@@ -0,0 +1,528 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+#include <linux/objtool.h>
3+#include <linux/module.h>
4+#include <linux/sort.h>
5+#include <asm/exception.h>
6+#include <asm/orc_header.h>
7+#include <asm/orc_lookup.h>
8+#include <asm/orc_types.h>
9+#include <asm/ptrace.h>
10+#include <asm/setup.h>
11+#include <asm/stacktrace.h>
12+#include <asm/tlb.h>
13+#include <asm/unwind.h>
14+
15+ORC_HEADER;
16+
17+#define orc_warn(fmt, ...) \
18+ printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
19+
20+extern int __start_orc_unwind_ip[];
21+extern int __stop_orc_unwind_ip[];
22+extern struct orc_entry __start_orc_unwind[];
23+extern struct orc_entry __stop_orc_unwind[];
24+
25+static bool orc_init __ro_after_init;
26+static unsigned int lookup_num_blocks __ro_after_init;
27+
28+/* Fake frame pointer entry -- used as a fallback for generated code */
29+static struct orc_entry orc_fp_entry = {
30+ .sp_reg = ORC_REG_FP,
31+ .sp_offset = 16,
32+ .fp_reg = ORC_REG_PREV_SP,
33+ .fp_offset = -16,
34+ .ra_reg = ORC_REG_PREV_SP,
35+ .ra_offset = -8,
36+ .type = ORC_TYPE_CALL
37+};
38+
39+/*
40+ * If we crash with IP==0, the last successfully executed instruction
41+ * was probably an indirect function call with a NULL function pointer,
42+ * and we don't have unwind information for NULL.
43+ * This hardcoded ORC entry for IP==0 allows us to unwind from a NULL function
44+ * pointer into its parent and then continue normally from there.
45+ */
46+static struct orc_entry orc_null_entry = {
47+ .sp_reg = ORC_REG_SP,
48+ .sp_offset = sizeof(long),
49+ .fp_reg = ORC_REG_UNDEFINED,
50+ .type = ORC_TYPE_CALL
51+};
52+
53+static inline unsigned long orc_ip(const int *ip)
54+{
55+ return (unsigned long)ip + *ip;
56+}
57+
58+static struct orc_entry *__orc_find(int *ip_table, struct orc_entry *u_table,
59+ unsigned int num_entries, unsigned long ip)
60+{
61+ int *first = ip_table;
62+ int *mid = first, *found = first;
63+ int *last = ip_table + num_entries - 1;
64+
65+ if (!num_entries)
66+ return NULL;
67+
68+ /*
69+ * Do a binary range search to find the rightmost duplicate of a given
70+ * starting address. Some entries are section terminators which are
71+ * "weak" entries for ensuring there are no gaps. They should be
72+ * ignored when they conflict with a real entry.
73+ */
74+ while (first <= last) {
75+ mid = first + ((last - first) / 2);
76+
77+ if (orc_ip(mid) <= ip) {
78+ found = mid;
79+ first = mid + 1;
80+ } else
81+ last = mid - 1;
82+ }
83+
84+ return u_table + (found - ip_table);
85+}
86+
87+#ifdef CONFIG_MODULES
88+static struct orc_entry *orc_module_find(unsigned long ip)
89+{
90+ struct module *mod;
91+
92+ mod = __module_address(ip);
93+ if (!mod || !mod->arch.orc_unwind || !mod->arch.orc_unwind_ip)
94+ return NULL;
95+
96+ return __orc_find(mod->arch.orc_unwind_ip, mod->arch.orc_unwind, mod->arch.num_orcs, ip);
97+}
98+#else
99+static struct orc_entry *orc_module_find(unsigned long ip)
100+{
101+ return NULL;
102+}
103+#endif
104+
105+#ifdef CONFIG_DYNAMIC_FTRACE
106+static struct orc_entry *orc_find(unsigned long ip);
107+
108+/*
109+ * Ftrace dynamic trampolines do not have orc entries of their own.
110+ * But they are copies of the ftrace entries that are static and
111+ * defined in ftrace_*.S, which do have orc entries.
112+ *
113+ * If the unwinder comes across a ftrace trampoline, then find the
114+ * ftrace function that was used to create it, and use that ftrace
115+ * function's orc entry, as the placement of the return code in
116+ * the stack will be identical.
117+ */
118+static struct orc_entry *orc_ftrace_find(unsigned long ip)
119+{
120+ struct ftrace_ops *ops;
121+ unsigned long tramp_addr, offset;
122+
123+ ops = ftrace_ops_trampoline(ip);
124+ if (!ops)
125+ return NULL;
126+
127+ /* Set tramp_addr to the start of the code copied by the trampoline */
128+ if (ops->flags & FTRACE_OPS_FL_SAVE_REGS)
129+ tramp_addr = (unsigned long)ftrace_regs_caller;
130+ else
131+ tramp_addr = (unsigned long)ftrace_caller;
132+
133+ /* Now place tramp_addr to the location within the trampoline ip is at */
134+ offset = ip - ops->trampoline;
135+ tramp_addr += offset;
136+
137+ /* Prevent unlikely recursion */
138+ if (ip == tramp_addr)
139+ return NULL;
140+
141+ return orc_find(tramp_addr);
142+}
143+#else
144+static struct orc_entry *orc_ftrace_find(unsigned long ip)
145+{
146+ return NULL;
147+}
148+#endif
149+
150+static struct orc_entry *orc_find(unsigned long ip)
151+{
152+ static struct orc_entry *orc;
153+
154+ if (ip == 0)
155+ return &orc_null_entry;
156+
157+ /* For non-init vmlinux addresses, use the fast lookup table: */
158+ if (ip >= LOOKUP_START_IP && ip < LOOKUP_STOP_IP) {
159+ unsigned int idx, start, stop;
160+
161+ idx = (ip - LOOKUP_START_IP) / LOOKUP_BLOCK_SIZE;
162+
163+ if (unlikely((idx >= lookup_num_blocks-1))) {
164+ orc_warn("WARNING: bad lookup idx: idx=%u num=%u ip=%pB\n",
165+ idx, lookup_num_blocks, (void *)ip);
166+ return NULL;
167+ }
168+
169+ start = orc_lookup[idx];
170+ stop = orc_lookup[idx + 1] + 1;
171+
172+ if (unlikely((__start_orc_unwind + start >= __stop_orc_unwind) ||
173+ (__start_orc_unwind + stop > __stop_orc_unwind))) {
174+ orc_warn("WARNING: bad lookup value: idx=%u num=%u start=%u stop=%u ip=%pB\n",
175+ idx, lookup_num_blocks, start, stop, (void *)ip);
176+ return NULL;
177+ }
178+
179+ return __orc_find(__start_orc_unwind_ip + start,
180+ __start_orc_unwind + start, stop - start, ip);
181+ }
182+
183+ /* vmlinux .init slow lookup: */
184+ if (is_kernel_inittext(ip))
185+ return __orc_find(__start_orc_unwind_ip, __start_orc_unwind,
186+ __stop_orc_unwind_ip - __start_orc_unwind_ip, ip);
187+
188+ /* Module lookup: */
189+ orc = orc_module_find(ip);
190+ if (orc)
191+ return orc;
192+
193+ return orc_ftrace_find(ip);
194+}
195+
196+#ifdef CONFIG_MODULES
197+
198+static DEFINE_MUTEX(sort_mutex);
199+static int *cur_orc_ip_table = __start_orc_unwind_ip;
200+static struct orc_entry *cur_orc_table = __start_orc_unwind;
201+
202+static void orc_sort_swap(void *_a, void *_b, int size)
203+{
204+ int delta = _b - _a;
205+ int *a = _a, *b = _b, tmp;
206+ struct orc_entry *orc_a, *orc_b;
207+
208+ /* Swap the .orc_unwind_ip entries: */
209+ tmp = *a;
210+ *a = *b + delta;
211+ *b = tmp - delta;
212+
213+ /* Swap the corresponding .orc_unwind entries: */
214+ orc_a = cur_orc_table + (a - cur_orc_ip_table);
215+ orc_b = cur_orc_table + (b - cur_orc_ip_table);
216+ swap(*orc_a, *orc_b);
217+}
218+
219+static int orc_sort_cmp(const void *_a, const void *_b)
220+{
221+ const int *a = _a, *b = _b;
222+ unsigned long a_val = orc_ip(a);
223+ unsigned long b_val = orc_ip(b);
224+ struct orc_entry *orc_a;
225+
226+ if (a_val > b_val)
227+ return 1;
228+ if (a_val < b_val)
229+ return -1;
230+
231+ /*
232+ * The "weak" section terminator entries need to always be first
233+ * to ensure the lookup code skips them in favor of real entries.
234+ * These terminator entries exist to handle any gaps created by
235+ * whitelisted .o files which didn't get objtool generation.
236+ */
237+ orc_a = cur_orc_table + (a - cur_orc_ip_table);
238+
239+ return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1;
240+}
241+
242+void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size,
243+ void *_orc, size_t orc_size)
244+{
245+ int *orc_ip = _orc_ip;
246+ struct orc_entry *orc = _orc;
247+ unsigned int num_entries = orc_ip_size / sizeof(int);
248+
249+ WARN_ON_ONCE(orc_ip_size % sizeof(int) != 0 ||
250+ orc_size % sizeof(*orc) != 0 ||
251+ num_entries != orc_size / sizeof(*orc));
252+
253+ /*
254+ * The 'cur_orc_*' globals allow the orc_sort_swap() callback to
255+ * associate an .orc_unwind_ip table entry with its corresponding
256+ * .orc_unwind entry so they can both be swapped.
257+ */
258+ mutex_lock(&sort_mutex);
259+ cur_orc_ip_table = orc_ip;
260+ cur_orc_table = orc;
261+ sort(orc_ip, num_entries, sizeof(int), orc_sort_cmp, orc_sort_swap);
262+ mutex_unlock(&sort_mutex);
263+
264+ mod->arch.orc_unwind_ip = orc_ip;
265+ mod->arch.orc_unwind = orc;
266+ mod->arch.num_orcs = num_entries;
267+}
268+#endif
269+
270+void __init unwind_init(void)
271+{
272+ int i;
273+ size_t orc_size = (void *)__stop_orc_unwind - (void *)__start_orc_unwind;
274+ size_t orc_ip_size = (void *)__stop_orc_unwind_ip - (void *)__start_orc_unwind_ip;
275+ size_t num_entries = orc_ip_size / sizeof(int);
276+ struct orc_entry *orc;
277+
278+ if (!num_entries || orc_ip_size % sizeof(int) != 0 ||
279+ orc_size % sizeof(struct orc_entry) != 0 ||
280+ num_entries != orc_size / sizeof(struct orc_entry)) {
281+ orc_warn("WARNING: Bad or missing .orc_unwind table. Disabling unwinder.\n");
282+ return;
283+ }
284+
285+ /*
286+ * Note, the orc_unwind and orc_unwind_ip tables were already
287+ * sorted at build time via the 'sorttable' tool.
288+ * It's ready for binary search straight away, no need to sort it.
289+ */
290+
291+ /* Initialize the fast lookup table: */
292+ lookup_num_blocks = orc_lookup_end - orc_lookup;
293+ for (i = 0; i < lookup_num_blocks-1; i++) {
294+ orc = __orc_find(__start_orc_unwind_ip, __start_orc_unwind,
295+ num_entries, LOOKUP_START_IP + (LOOKUP_BLOCK_SIZE * i));
296+ if (!orc) {
297+ orc_warn("WARNING: Corrupt .orc_unwind table. Disabling unwinder.\n");
298+ return;
299+ }
300+
301+ orc_lookup[i] = orc - __start_orc_unwind;
302+ }
303+
304+ /* Initialize the ending block: */
305+ orc = __orc_find(__start_orc_unwind_ip, __start_orc_unwind, num_entries, LOOKUP_STOP_IP);
306+ if (!orc) {
307+ orc_warn("WARNING: Corrupt .orc_unwind table. Disabling unwinder.\n");
308+ return;
309+ }
310+ orc_lookup[lookup_num_blocks-1] = orc - __start_orc_unwind;
311+
312+ orc_init = true;
313+}
314+
315+static inline bool on_stack(struct stack_info *info, unsigned long addr, size_t len)
316+{
317+ unsigned long begin = info->begin;
318+ unsigned long end = info->end;
319+
320+ return (info->type != STACK_TYPE_UNKNOWN &&
321+ addr >= begin && addr < end && addr + len > begin && addr + len <= end);
322+}
323+
324+static bool stack_access_ok(struct unwind_state *state, unsigned long addr, size_t len)
325+{
326+ struct stack_info *info = &state->stack_info;
327+
328+ if (on_stack(info, addr, len))
329+ return true;
330+
331+ return !get_stack_info(addr, state->task, info) && on_stack(info, addr, len);
332+}
333+
334+unsigned long unwind_get_return_address(struct unwind_state *state)
335+{
336+ return __unwind_get_return_address(state);
337+}
338+EXPORT_SYMBOL_GPL(unwind_get_return_address);
339+
340+void unwind_start(struct unwind_state *state, struct task_struct *task,
341+ struct pt_regs *regs)
342+{
343+ __unwind_start(state, task, regs);
344+ state->type = UNWINDER_ORC;
345+ if (!unwind_done(state) && !__kernel_text_address(state->pc))
346+ unwind_next_frame(state);
347+}
348+EXPORT_SYMBOL_GPL(unwind_start);
349+
350+static bool is_entry_func(unsigned long addr)
351+{
352+ extern u32 kernel_entry;
353+ extern u32 kernel_entry_end;
354+
355+ return addr >= (unsigned long)&kernel_entry && addr < (unsigned long)&kernel_entry_end;
356+}
357+
358+static inline unsigned long bt_address(unsigned long ra)
359+{
360+ extern unsigned long eentry;
361+
362+ if (__kernel_text_address(ra))
363+ return ra;
364+
365+ if (__module_text_address(ra))
366+ return ra;
367+
368+ if (ra >= eentry && ra < eentry + EXCCODE_INT_END * VECSIZE) {
369+ unsigned long func;
370+ unsigned long type = (ra - eentry) / VECSIZE;
371+ unsigned long offset = (ra - eentry) % VECSIZE;
372+
373+ switch (type) {
374+ case 0 ... EXCCODE_INT_START - 1:
375+ func = (unsigned long)exception_table[type];
376+ break;
377+ case EXCCODE_INT_START ... EXCCODE_INT_END:
378+ func = (unsigned long)handle_vint;
379+ break;
380+ default:
381+ func = (unsigned long)handle_reserved;
382+ break;
383+ }
384+
385+ return func + offset;
386+ }
387+
388+ return ra;
389+}
390+
391+bool unwind_next_frame(struct unwind_state *state)
392+{
393+ unsigned long *p, pc;
394+ struct pt_regs *regs;
395+ struct orc_entry *orc;
396+ struct stack_info *info = &state->stack_info;
397+
398+ if (unwind_done(state))
399+ return false;
400+
401+ /* Don't let modules unload while we're reading their ORC data. */
402+ preempt_disable();
403+
404+ if (is_entry_func(state->pc))
405+ goto end;
406+
407+ orc = orc_find(state->pc);
408+ if (!orc) {
409+ /*
410+ * As a fallback, try to assume this code uses a frame pointer.
411+ * This is useful for generated code, like BPF, which ORC
412+ * doesn't know about. This is just a guess, so the rest of
413+ * the unwind is no longer considered reliable.
414+ */
415+ orc = &orc_fp_entry;
416+ state->error = true;
417+ } else {
418+ if (orc->type == ORC_TYPE_UNDEFINED)
419+ goto err;
420+
421+ if (orc->type == ORC_TYPE_END_OF_STACK)
422+ goto end;
423+ }
424+
425+ switch (orc->sp_reg) {
426+ case ORC_REG_SP:
427+ if (info->type == STACK_TYPE_IRQ && state->sp == info->end)
428+ orc->type = ORC_TYPE_REGS;
429+ else
430+ state->sp = state->sp + orc->sp_offset;
431+ break;
432+ case ORC_REG_FP:
433+ state->sp = state->fp;
434+ break;
435+ default:
436+ orc_warn("unknown SP base reg %d at %pB\n", orc->sp_reg, (void *)state->pc);
437+ goto err;
438+ }
439+
440+ switch (orc->fp_reg) {
441+ case ORC_REG_PREV_SP:
442+ p = (unsigned long *)(state->sp + orc->fp_offset);
443+ if (!stack_access_ok(state, (unsigned long)p, sizeof(unsigned long)))
444+ goto err;
445+
446+ state->fp = *p;
447+ break;
448+ case ORC_REG_UNDEFINED:
449+ /* Nothing. */
450+ break;
451+ default:
452+ orc_warn("unknown FP base reg %d at %pB\n", orc->fp_reg, (void *)state->pc);
453+ goto err;
454+ }
455+
456+ switch (orc->type) {
457+ case ORC_TYPE_CALL:
458+ if (orc->ra_reg == ORC_REG_PREV_SP) {
459+ p = (unsigned long *)(state->sp + orc->ra_offset);
460+ if (!stack_access_ok(state, (unsigned long)p, sizeof(unsigned long)))
461+ goto err;
462+
463+ pc = unwind_graph_addr(state, *p, state->sp);
464+ pc -= LOONGARCH_INSN_SIZE;
465+ } else if (orc->ra_reg == ORC_REG_UNDEFINED) {
466+ if (!state->ra || state->ra == state->pc)
467+ goto err;
468+
469+ pc = unwind_graph_addr(state, state->ra, state->sp);
470+ pc -= LOONGARCH_INSN_SIZE;
471+ state->ra = 0;
472+ } else {
473+ orc_warn("unknown ra base reg %d at %pB\n", orc->ra_reg, (void *)state->pc);
474+ goto err;
475+ }
476+ break;
477+ case ORC_TYPE_REGS:
478+ if (info->type == STACK_TYPE_IRQ && state->sp == info->end)
479+ regs = (struct pt_regs *)info->next_sp;
480+ else
481+ regs = (struct pt_regs *)state->sp;
482+
483+ if (!stack_access_ok(state, (unsigned long)regs, sizeof(*regs)))
484+ goto err;
485+
486+ if ((info->end == (unsigned long)regs + sizeof(*regs)) &&
487+ !regs->regs[3] && !regs->regs[1])
488+ goto end;
489+
490+ if (user_mode(regs))
491+ goto end;
492+
493+ pc = regs->csr_era;
494+ if (!__kernel_text_address(pc))
495+ goto err;
496+
497+ state->sp = regs->regs[3];
498+ state->ra = regs->regs[1];
499+ state->fp = regs->regs[22];
500+ get_stack_info(state->sp, state->task, info);
501+
502+ break;
503+ default:
504+ orc_warn("unknown .orc_unwind entry type %d at %pB\n", orc->type, (void *)state->pc);
505+ goto err;
506+ }
507+
508+ state->pc = bt_address(pc);
509+ if (!state->pc) {
510+ pr_err("cannot find unwind pc at %pK\n", (void *)pc);
511+ goto err;
512+ }
513+
514+ if (!__kernel_text_address(state->pc))
515+ goto err;
516+
517+ preempt_enable();
518+ return true;
519+
520+err:
521+ state->error = true;
522+
523+end:
524+ preempt_enable();
525+ state->stack_info.type = STACK_TYPE_UNKNOWN;
526+ return false;
527+}
528+EXPORT_SYMBOL_GPL(unwind_next_frame);
arch/loongarch/kernel/vmlinux.lds.S+3−0
@@ -2,6 +2,7 @@ · 1 unmodified line
22 #include <linux/sizes.h>
33 #include <asm/asm-offsets.h>
44 #include <asm/thread_info.h>
5+#include <asm/orc_lookup.h>
56
67 #define PAGE_SIZE _PAGE_SIZE
78 #define RO_EXCEPTION_TABLE_ALIGN 4
@@ -122,6 +123,8 @@ SECTIONS · 114 unmodified lines
122123 }
123124 #endif
124125
126+ ORC_UNWIND_TABLE
127+
125128 .sdata : {
126129 *(.sdata)
127130 }
arch/loongarch/kvm/switch.S+8−1
@@ -8,7 +8,7 @@ · 7 unmodified lines
88 #include <asm/asmmacro.h>
99 #include <asm/loongarch.h>
1010 #include <asm/regdef.h>
11−#include <asm/stackframe.h>
11+#include <asm/unwind_hints.h>
1212
1313 #define HGPR_OFFSET(x) (PT_R0 + 8*x)
1414 #define GGPR_OFFSET(x) (KVM_ARCH_GGPR + 8*x)
@@ -112,6 +112,7 @@ · 97 unmodified lines
112112 .text
113113 .cfi_sections .debug_frame
114114 SYM_CODE_START(kvm_exc_entry)
115+ UNWIND_HINT_UNDEFINED
115116 csrwr a2, KVM_TEMP_KS
116117 csrrd a2, KVM_VCPU_KS
117118 addi.d a2, a2, KVM_VCPU_ARCH
@@ -279,3 +280,9 @@ SYM_FUNC_END(kvm_restore_lasx) · 161 unmodified lines
279280 .section ".rodata"
280281 SYM_DATA(kvm_exception_size, .quad kvm_exc_entry_end - kvm_exc_entry)
281282 SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest)
283+
284+#ifdef CONFIG_CPU_HAS_LBT
285+STACK_FRAME_NON_STANDARD kvm_restore_fpu
286+STACK_FRAME_NON_STANDARD kvm_restore_lsx
287+STACK_FRAME_NON_STANDARD kvm_restore_lasx
288+#endif
arch/loongarch/lib/clear_user.S+3−0
@@ -10,6 +10,7 @@ · 9 unmodified lines
1010 #include <asm/asm-extable.h>
1111 #include <asm/cpu.h>
1212 #include <asm/regdef.h>
13+#include <asm/unwind_hints.h>
1314
1415 SYM_FUNC_START(__clear_user)
1516 /*
@@ -204,3 +205,5 @@ SYM_FUNC_START(__clear_user_fast) · 188 unmodified lines
204205 _asm_extable 28b, .Lsmall_fixup
205206 _asm_extable 29b, .Lexit
206207 SYM_FUNC_END(__clear_user_fast)
208+
209+STACK_FRAME_NON_STANDARD __clear_user_fast
arch/loongarch/lib/copy_user.S+3−0
@@ -10,6 +10,7 @@ · 9 unmodified lines
1010 #include <asm/asm-extable.h>
1111 #include <asm/cpu.h>
1212 #include <asm/regdef.h>
13+#include <asm/unwind_hints.h>
1314
1415 SYM_FUNC_START(__copy_user)
1516 /*
@@ -278,3 +279,5 @@ SYM_FUNC_START(__copy_user_fast) · 262 unmodified lines
278279 _asm_extable 58b, .Lexit
279280 _asm_extable 59b, .Lexit
280281 SYM_FUNC_END(__copy_user_fast)
282+
283+STACK_FRAME_NON_STANDARD __copy_user_fast
arch/loongarch/lib/memcpy.S+3−0
@@ -9,6 +9,7 @@ · 8 unmodified lines
99 #include <asm/asmmacro.h>
1010 #include <asm/cpu.h>
1111 #include <asm/regdef.h>
12+#include <asm/unwind_hints.h>
1213
1314 .section .noinstr.text, "ax"
1415
@@ -197,3 +198,5 @@ SYM_FUNC_START(__memcpy_fast) · 182 unmodified lines
197198 jr ra
198199 SYM_FUNC_END(__memcpy_fast)
199200 _ASM_NOKPROBE(__memcpy_fast)
201+
202+STACK_FRAME_NON_STANDARD __memcpy_small
arch/loongarch/lib/memset.S+3−0
@@ -9,6 +9,7 @@ · 8 unmodified lines
99 #include <asm/asmmacro.h>
1010 #include <asm/cpu.h>
1111 #include <asm/regdef.h>
12+#include <asm/unwind_hints.h>
1213
1314 .macro fill_to_64 r0
1415 bstrins.d \r0, \r0, 15, 8
@@ -166,3 +167,5 @@ SYM_FUNC_START(__memset_fast) · 151 unmodified lines
166167 jr ra
167168 SYM_FUNC_END(__memset_fast)
168169 _ASM_NOKPROBE(__memset_fast)
170+
171+STACK_FRAME_NON_STANDARD __memset_fast
arch/loongarch/mm/tlb.c+12−15
@@ -9,8 +9,9 @@ · 8 unmodified lines
99 #include <linux/hugetlb.h>
1010 #include <linux/export.h>
1111
12−#include <asm/cpu.h>
1312 #include <asm/bootinfo.h>
13+#include <asm/cpu.h>
14+#include <asm/exception.h>
1415 #include <asm/mmu_context.h>
1516 #include <asm/pgtable.h>
1617 #include <asm/tlb.h>
@@ -266,24 +267,20 @@ static void setup_tlb_handler(int cpu) · 249 unmodified lines
266267 setup_ptwalker();
267268 local_flush_tlb_all();
268269
270+ if (cpu_has_ptw) {
271+ exception_table[EXCCODE_TLBI] = handle_tlb_load_ptw;
272+ exception_table[EXCCODE_TLBL] = handle_tlb_load_ptw;
273+ exception_table[EXCCODE_TLBS] = handle_tlb_store_ptw;
274+ exception_table[EXCCODE_TLBM] = handle_tlb_modify_ptw;
275+ }
276+
269277 /* The tlb handlers are generated only once */
270278 if (cpu == 0) {
271279 memcpy((void *)tlbrentry, handle_tlb_refill, 0x80);
272280 local_flush_icache_range(tlbrentry, tlbrentry + 0x80);
273− if (!cpu_has_ptw) {
274− set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load, VECSIZE);
275− set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load, VECSIZE);
276− set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store, VECSIZE);
277− set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify, VECSIZE);
278− } else {
279− set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load_ptw, VECSIZE);
280− set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load_ptw, VECSIZE);
281− set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store_ptw, VECSIZE);
282− set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify_ptw, VECSIZE);
283− }
284− set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE);
285− set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE);
286− set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE);
281+
282+ for (int i = EXCCODE_TLBL; i <= EXCCODE_TLBPE; i++)
283+ set_handler(i * VECSIZE, exception_table[i], VECSIZE);
287284 } else {
288285 int vec_sz __maybe_unused;
289286 void *addr __maybe_unused;
arch/loongarch/mm/tlbex.S+9−0
@@ -18,6 +18,7 @@ · 17 unmodified lines
1818
1919 .macro tlb_do_page_fault, write
2020 SYM_CODE_START(tlb_do_page_fault_\write)
21+ UNWIND_HINT_UNDEFINED
2122 SAVE_ALL
2223 csrrd a2, LOONGARCH_CSR_BADV
2324 move a0, sp
@@ -32,6 +33,7 @@ · 8 unmodified lines
3233 tlb_do_page_fault 1
3334
3435 SYM_CODE_START(handle_tlb_protect)
36+ UNWIND_HINT_UNDEFINED
3537 BACKUP_T0T1
3638 SAVE_ALL
3739 move a0, sp
@@ -44,6 +46,7 @@ SYM_CODE_START(handle_tlb_protect) · 6 unmodified lines
4446 SYM_CODE_END(handle_tlb_protect)
4547
4648 SYM_CODE_START(handle_tlb_load)
49+ UNWIND_HINT_UNDEFINED
4750 csrwr t0, EXCEPTION_KS0
4851 csrwr t1, EXCEPTION_KS1
4952 csrwr ra, EXCEPTION_KS2
@@ -190,6 +193,7 @@ nopage_tlb_load: · 140 unmodified lines
190193 SYM_CODE_END(handle_tlb_load)
191194
192195 SYM_CODE_START(handle_tlb_load_ptw)
196+ UNWIND_HINT_UNDEFINED
193197 csrwr t0, LOONGARCH_CSR_KS0
194198 csrwr t1, LOONGARCH_CSR_KS1
195199 la_abs t0, tlb_do_page_fault_0
@@ -197,6 +201,7 @@ SYM_CODE_START(handle_tlb_load_ptw) · 1 unmodified line
197201 SYM_CODE_END(handle_tlb_load_ptw)
198202
199203 SYM_CODE_START(handle_tlb_store)
204+ UNWIND_HINT_UNDEFINED
200205 csrwr t0, EXCEPTION_KS0
201206 csrwr t1, EXCEPTION_KS1
202207 csrwr ra, EXCEPTION_KS2
@@ -346,6 +351,7 @@ nopage_tlb_store: · 143 unmodified lines
346351 SYM_CODE_END(handle_tlb_store)
347352
348353 SYM_CODE_START(handle_tlb_store_ptw)
354+ UNWIND_HINT_UNDEFINED
349355 csrwr t0, LOONGARCH_CSR_KS0
350356 csrwr t1, LOONGARCH_CSR_KS1
351357 la_abs t0, tlb_do_page_fault_1
@@ -353,6 +359,7 @@ SYM_CODE_START(handle_tlb_store_ptw) · 1 unmodified line
353359 SYM_CODE_END(handle_tlb_store_ptw)
354360
355361 SYM_CODE_START(handle_tlb_modify)
362+ UNWIND_HINT_UNDEFINED
356363 csrwr t0, EXCEPTION_KS0
357364 csrwr t1, EXCEPTION_KS1
358365 csrwr ra, EXCEPTION_KS2
@@ -500,6 +507,7 @@ nopage_tlb_modify: · 141 unmodified lines
500507 SYM_CODE_END(handle_tlb_modify)
501508
502509 SYM_CODE_START(handle_tlb_modify_ptw)
510+ UNWIND_HINT_UNDEFINED
503511 csrwr t0, LOONGARCH_CSR_KS0
504512 csrwr t1, LOONGARCH_CSR_KS1
505513 la_abs t0, tlb_do_page_fault_1
@@ -507,6 +515,7 @@ SYM_CODE_START(handle_tlb_modify_ptw) · 1 unmodified line
507515 SYM_CODE_END(handle_tlb_modify_ptw)
508516
509517 SYM_CODE_START(handle_tlb_refill)
518+ UNWIND_HINT_UNDEFINED
510519 csrwr t0, LOONGARCH_CSR_TLBRSAVE
511520 csrrd t0, LOONGARCH_CSR_PGD
512521 lddir t0, t0, 3
arch/loongarch/vdso/Makefile+1−0
@@ -4,6 +4,7 @@ · 3 unmodified lines
44 KASAN_SANITIZE := n
55 UBSAN_SANITIZE := n
66 KCOV_INSTRUMENT := n
7+OBJECT_FILES_NON_STANDARD := y
78
89 # Include the generic Makefile to check the built vdso.
910 include $(srctree)/lib/vdso/Makefile
include/linux/compiler.h+9−0
@@ -116,6 +116,14 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, · 115 unmodified lines
116116 */
117117 #define __stringify_label(n) #n
118118
119+#define __annotate_reachable(c) ({ \
120+ asm volatile(__stringify_label(c) ":\n\t" \
121+ ".pushsection .discard.reachable\n\t" \
122+ ".long " __stringify_label(c) "b - .\n\t" \
123+ ".popsection\n\t"); \
124+})
125+#define annotate_reachable() __annotate_reachable(__COUNTER__)
126+
119127 #define __annotate_unreachable(c) ({ \
120128 asm volatile(__stringify_label(c) ":\n\t" \
121129 ".pushsection .discard.unreachable\n\t" \
@@ -128,6 +136,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, · 6 unmodified lines
128136 #define __annotate_jump_table __section(".rodata..c_jump_table")
129137
130138 #else /* !CONFIG_OBJTOOL */
139+#define annotate_reachable()
131140 #define annotate_unreachable()
132141 #define __annotate_jump_table
133142 #endif /* CONFIG_OBJTOOL */
scripts/Makefile+5−2
@@ -31,9 +31,12 @@ HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null | · 30 unmodified lines
3131
3232 ifdef CONFIG_UNWINDER_ORC
3333 ifeq ($(ARCH),x86_64)
34−ARCH := x86
34+SRCARCH := x86
3535 endif
36−HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include
36+ifeq ($(ARCH),loongarch)
37+SRCARCH := loongarch
38+endif
39+HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/$(SRCARCH)/include
3740 HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED
3841 endif
3942