Skip to content

Commit cb8a2ef

Browse files
seehearfeelchenhuacai
authored andcommitted
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. Co-developed-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Jinyang He <hejinyang@loongson.cn> Co-developed-by: Youling Tang <tangyouling@loongson.cn> Signed-off-by: Youling Tang <tangyouling@loongson.cn> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
1 parent e91c5e4 commit cb8a2ef

37 files changed

+875
-42
lines changed

arch/loongarch/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ config LOONGARCH
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
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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,15 @@ config UNWINDER_PROLOGUE
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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ endif
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)
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
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
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 {
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
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */

0 commit comments

Comments
 (0)