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

objtool: Make unwind hint definitions available to other architectures

Unwind hints are useful to provide objtool with information about stack
states in non-standard functions/code.

While the type of information being provided might be very arch
specific, the mechanism to provide the information can be useful for
other architectures.

Move the relevant unwint hint definitions for all architectures to
see.

[ jpoimboe: REGS_IRET -> REGS_PARTIAL ]

Signed-off-by: Julien Thierry <jthierry@redhat.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>

authored by

Julien Thierry and committed by
Josh Poimboeuf
ee819aed 5567c6c3

+249 -125
-34
arch/x86/include/asm/orc_types.h
··· 39 39 #define ORC_REG_SP_INDIRECT 9 40 40 #define ORC_REG_MAX 15 41 41 42 - /* 43 - * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the 44 - * caller's SP right before it made the call). Used for all callable 45 - * functions, i.e. all C code and all callable asm functions. 46 - * 47 - * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points 48 - * to a fully populated pt_regs from a syscall, interrupt, or exception. 49 - * 50 - * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset 51 - * points to the iret return frame. 52 - * 53 - * The UNWIND_HINT macros are used only for the unwind_hint struct. They 54 - * aren't used in struct orc_entry due to size and complexity constraints. 55 - * Objtool converts them to real types when it converts the hints to orc 56 - * entries. 57 - */ 58 - #define ORC_TYPE_CALL 0 59 - #define ORC_TYPE_REGS 1 60 - #define ORC_TYPE_REGS_IRET 2 61 - #define UNWIND_HINT_TYPE_RET_OFFSET 3 62 - 63 42 #ifndef __ASSEMBLY__ 64 43 /* 65 44 * This struct is more or less a vastly simplified version of the DWARF Call ··· 57 78 unsigned end:1; 58 79 } __packed; 59 80 60 - /* 61 - * This struct is used by asm and inline asm code to manually annotate the 62 - * location of registers on the stack for the ORC unwinder. 63 - * 64 - * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. 65 - */ 66 - struct unwind_hint { 67 - u32 ip; 68 - s16 sp_offset; 69 - u8 sp_reg; 70 - u8 type; 71 - u8 end; 72 - }; 73 81 #endif /* __ASSEMBLY__ */ 74 82 75 83 #endif /* _ORC_TYPES_H */
+11 -45
arch/x86/include/asm/unwind_hints.h
··· 1 1 #ifndef _ASM_X86_UNWIND_HINTS_H 2 2 #define _ASM_X86_UNWIND_HINTS_H 3 3 4 + #include <linux/objtool.h> 5 + 4 6 #include "orc_types.h" 5 7 6 8 #ifdef __ASSEMBLY__ 7 9 8 - /* 9 - * In asm, there are two kinds of code: normal C-type callable functions and 10 - * the rest. The normal callable functions can be called by other code, and 11 - * don't do anything unusual with the stack. Such normal callable functions 12 - * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this 13 - * category. In this case, no special debugging annotations are needed because 14 - * objtool can automatically generate the ORC data for the ORC unwinder to read 15 - * at runtime. 16 - * 17 - * Anything which doesn't fall into the above category, such as syscall and 18 - * interrupt handlers, tends to not be called directly by other functions, and 19 - * often does unusual non-C-function-type things with the stack pointer. Such 20 - * code needs to be annotated such that objtool can understand it. The 21 - * following CFI hint macros are for this type of code. 22 - * 23 - * These macros provide hints to objtool about the state of the stack at each 24 - * instruction. Objtool starts from the hints and follows the code flow, 25 - * making automatic CFI adjustments when it sees pushes and pops, filling out 26 - * the debuginfo as necessary. It will also warn if it sees any 27 - * inconsistencies. 28 - */ 29 - .macro UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=0 type=ORC_TYPE_CALL end=0 30 - #ifdef CONFIG_STACK_VALIDATION 31 - .Lunwind_hint_ip_\@: 32 - .pushsection .discard.unwind_hints 33 - /* struct unwind_hint */ 34 - .long .Lunwind_hint_ip_\@ - . 35 - .short \sp_offset 36 - .byte \sp_reg 37 - .byte \type 38 - .byte \end 39 - .balign 4 40 - .popsection 41 - #endif 42 - .endm 43 - 44 10 .macro UNWIND_HINT_EMPTY 45 - UNWIND_HINT sp_reg=ORC_REG_UNDEFINED end=1 11 + UNWIND_HINT sp_reg=ORC_REG_UNDEFINED type=UNWIND_HINT_TYPE_CALL end=1 46 12 .endm 47 13 48 - .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 iret=0 14 + .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 49 15 .if \base == %rsp 50 16 .if \indirect 51 17 .set sp_reg, ORC_REG_SP_INDIRECT ··· 32 66 33 67 .set sp_offset, \offset 34 68 35 - .if \iret 36 - .set type, ORC_TYPE_REGS_IRET 69 + .if \partial 70 + .set type, UNWIND_HINT_TYPE_REGS_PARTIAL 37 71 .elseif \extra == 0 38 - .set type, ORC_TYPE_REGS_IRET 72 + .set type, UNWIND_HINT_TYPE_REGS_PARTIAL 39 73 .set sp_offset, \offset + (16*8) 40 74 .else 41 - .set type, ORC_TYPE_REGS 75 + .set type, UNWIND_HINT_TYPE_REGS 42 76 .endif 43 77 44 78 UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type 45 79 .endm 46 80 47 81 .macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 48 - UNWIND_HINT_REGS base=\base offset=\offset iret=1 82 + UNWIND_HINT_REGS base=\base offset=\offset partial=1 49 83 .endm 50 84 51 85 .macro UNWIND_HINT_FUNC sp_offset=8 52 - UNWIND_HINT sp_offset=\sp_offset 86 + UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=\sp_offset type=UNWIND_HINT_TYPE_CALL 53 87 .endm 54 88 55 89 /* ··· 58 92 * initial_func_cfi. 59 93 */ 60 94 .macro UNWIND_HINT_RET_OFFSET sp_offset=8 61 - UNWIND_HINT type=UNWIND_HINT_TYPE_RET_OFFSET sp_offset=\sp_offset 95 + UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_RET_OFFSET sp_offset=\sp_offset 62 96 .endm 63 97 64 98 #endif /* __ASSEMBLY__ */
+6 -5
arch/x86/kernel/unwind_orc.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 + #include <linux/objtool.h> 2 3 #include <linux/module.h> 3 4 #include <linux/sort.h> 4 5 #include <asm/ptrace.h> ··· 128 127 .sp_offset = sizeof(long), 129 128 .sp_reg = ORC_REG_SP, 130 129 .bp_reg = ORC_REG_UNDEFINED, 131 - .type = ORC_TYPE_CALL 130 + .type = UNWIND_HINT_TYPE_CALL 132 131 }; 133 132 134 133 /* Fake frame pointer entry -- used as a fallback for generated code */ 135 134 static struct orc_entry orc_fp_entry = { 136 - .type = ORC_TYPE_CALL, 135 + .type = UNWIND_HINT_TYPE_CALL, 137 136 .sp_reg = ORC_REG_BP, 138 137 .sp_offset = 16, 139 138 .bp_reg = ORC_REG_PREV_SP, ··· 532 531 533 532 /* Find IP, SP and possibly regs: */ 534 533 switch (orc->type) { 535 - case ORC_TYPE_CALL: 534 + case UNWIND_HINT_TYPE_CALL: 536 535 ip_p = sp - sizeof(long); 537 536 538 537 if (!deref_stack_reg(state, ip_p, &state->ip)) ··· 547 546 state->signal = false; 548 547 break; 549 548 550 - case ORC_TYPE_REGS: 549 + case UNWIND_HINT_TYPE_REGS: 551 550 if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) { 552 551 orc_warn_current("can't access registers at %pB\n", 553 552 (void *)orig_ip); ··· 560 559 state->signal = true; 561 560 break; 562 561 563 - case ORC_TYPE_REGS_IRET: 562 + case UNWIND_HINT_TYPE_REGS_PARTIAL: 564 563 if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) { 565 564 orc_warn_current("can't access iret registers at %pB\n", 566 565 (void *)orig_ip);
+88
include/linux/objtool.h
··· 2 2 #ifndef _LINUX_OBJTOOL_H 3 3 #define _LINUX_OBJTOOL_H 4 4 5 + #ifndef __ASSEMBLY__ 6 + 7 + #include <linux/types.h> 8 + 9 + /* 10 + * This struct is used by asm and inline asm code to manually annotate the 11 + * location of registers on the stack. 12 + */ 13 + struct unwind_hint { 14 + u32 ip; 15 + s16 sp_offset; 16 + u8 sp_reg; 17 + u8 type; 18 + u8 end; 19 + }; 20 + #endif 21 + 22 + /* 23 + * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP 24 + * (the caller's SP right before it made the call). Used for all callable 25 + * functions, i.e. all C code and all callable asm functions. 26 + * 27 + * UNWIND_HINT_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset 28 + * points to a fully populated pt_regs from a syscall, interrupt, or exception. 29 + * 30 + * UNWIND_HINT_TYPE_REGS_PARTIAL: Used in entry code to indicate that 31 + * sp_reg+sp_offset points to the iret return frame. 32 + */ 33 + #define UNWIND_HINT_TYPE_CALL 0 34 + #define UNWIND_HINT_TYPE_REGS 1 35 + #define UNWIND_HINT_TYPE_REGS_PARTIAL 2 36 + #define UNWIND_HINT_TYPE_RET_OFFSET 3 37 + 5 38 #ifdef CONFIG_STACK_VALIDATION 6 39 7 40 #ifndef __ASSEMBLY__ 41 + 42 + #define UNWIND_HINT(sp_reg, sp_offset, type, end) \ 43 + "987: \n\t" \ 44 + ".pushsection .discard.unwind_hints\n\t" \ 45 + /* struct unwind_hint */ \ 46 + ".long 987b - .\n\t" \ 47 + ".short " __stringify(sp_offset) "\n\t" \ 48 + ".byte " __stringify(sp_reg) "\n\t" \ 49 + ".byte " __stringify(type) "\n\t" \ 50 + ".byte " __stringify(end) "\n\t" \ 51 + ".balign 4 \n\t" \ 52 + ".popsection\n\t" 53 + 8 54 /* 9 55 * This macro marks the given function's stack frame as "non-standard", which 10 56 * tells objtool to ignore the function when doing stack metadata validation. ··· 75 29 .long 999b; \ 76 30 .popsection; 77 31 32 + /* 33 + * In asm, there are two kinds of code: normal C-type callable functions and 34 + * the rest. The normal callable functions can be called by other code, and 35 + * don't do anything unusual with the stack. Such normal callable functions 36 + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this 37 + * category. In this case, no special debugging annotations are needed because 38 + * objtool can automatically generate the ORC data for the ORC unwinder to read 39 + * at runtime. 40 + * 41 + * Anything which doesn't fall into the above category, such as syscall and 42 + * interrupt handlers, tends to not be called directly by other functions, and 43 + * often does unusual non-C-function-type things with the stack pointer. Such 44 + * code needs to be annotated such that objtool can understand it. The 45 + * following CFI hint macros are for this type of code. 46 + * 47 + * These macros provide hints to objtool about the state of the stack at each 48 + * instruction. Objtool starts from the hints and follows the code flow, 49 + * making automatic CFI adjustments when it sees pushes and pops, filling out 50 + * the debuginfo as necessary. It will also warn if it sees any 51 + * inconsistencies. 52 + */ 53 + .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0 54 + .Lunwind_hint_ip_\@: 55 + .pushsection .discard.unwind_hints 56 + /* struct unwind_hint */ 57 + .long .Lunwind_hint_ip_\@ - . 58 + .short \sp_offset 59 + .byte \sp_reg 60 + .byte \type 61 + .byte \end 62 + .balign 4 63 + .popsection 64 + .endm 65 + 78 66 #endif /* __ASSEMBLY__ */ 79 67 80 68 #else /* !CONFIG_STACK_VALIDATION */ 81 69 70 + #ifndef __ASSEMBLY__ 71 + 72 + #define UNWIND_HINT(sp_reg, sp_offset, type, end) \ 73 + "\n\t" 82 74 #define STACK_FRAME_NON_STANDARD(func) 75 + #else 83 76 #define ANNOTATE_INTRA_FUNCTION_CALL 77 + .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0 78 + .endm 79 + #endif 84 80 85 81 #endif /* CONFIG_STACK_VALIDATION */ 86 82
-34
tools/arch/x86/include/asm/orc_types.h
··· 39 39 #define ORC_REG_SP_INDIRECT 9 40 40 #define ORC_REG_MAX 15 41 41 42 - /* 43 - * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the 44 - * caller's SP right before it made the call). Used for all callable 45 - * functions, i.e. all C code and all callable asm functions. 46 - * 47 - * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points 48 - * to a fully populated pt_regs from a syscall, interrupt, or exception. 49 - * 50 - * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset 51 - * points to the iret return frame. 52 - * 53 - * The UNWIND_HINT macros are used only for the unwind_hint struct. They 54 - * aren't used in struct orc_entry due to size and complexity constraints. 55 - * Objtool converts them to real types when it converts the hints to orc 56 - * entries. 57 - */ 58 - #define ORC_TYPE_CALL 0 59 - #define ORC_TYPE_REGS 1 60 - #define ORC_TYPE_REGS_IRET 2 61 - #define UNWIND_HINT_TYPE_RET_OFFSET 3 62 - 63 42 #ifndef __ASSEMBLY__ 64 43 /* 65 44 * This struct is more or less a vastly simplified version of the DWARF Call ··· 57 78 unsigned end:1; 58 79 } __packed; 59 80 60 - /* 61 - * This struct is used by asm and inline asm code to manually annotate the 62 - * location of registers on the stack for the ORC unwinder. 63 - * 64 - * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. 65 - */ 66 - struct unwind_hint { 67 - u32 ip; 68 - s16 sp_offset; 69 - u8 sp_reg; 70 - u8 type; 71 - u8 end; 72 - }; 73 81 #endif /* __ASSEMBLY__ */ 74 82 75 83 #endif /* _ORC_TYPES_H */
+129
tools/include/linux/objtool.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _LINUX_OBJTOOL_H 3 + #define _LINUX_OBJTOOL_H 4 + 5 + #ifndef __ASSEMBLY__ 6 + 7 + #include <linux/types.h> 8 + 9 + /* 10 + * This struct is used by asm and inline asm code to manually annotate the 11 + * location of registers on the stack. 12 + */ 13 + struct unwind_hint { 14 + u32 ip; 15 + s16 sp_offset; 16 + u8 sp_reg; 17 + u8 type; 18 + u8 end; 19 + }; 20 + #endif 21 + 22 + /* 23 + * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP 24 + * (the caller's SP right before it made the call). Used for all callable 25 + * functions, i.e. all C code and all callable asm functions. 26 + * 27 + * UNWIND_HINT_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset 28 + * points to a fully populated pt_regs from a syscall, interrupt, or exception. 29 + * 30 + * UNWIND_HINT_TYPE_REGS_PARTIAL: Used in entry code to indicate that 31 + * sp_reg+sp_offset points to the iret return frame. 32 + */ 33 + #define UNWIND_HINT_TYPE_CALL 0 34 + #define UNWIND_HINT_TYPE_REGS 1 35 + #define UNWIND_HINT_TYPE_REGS_PARTIAL 2 36 + #define UNWIND_HINT_TYPE_RET_OFFSET 3 37 + 38 + #ifdef CONFIG_STACK_VALIDATION 39 + 40 + #ifndef __ASSEMBLY__ 41 + 42 + #define UNWIND_HINT(sp_reg, sp_offset, type, end) \ 43 + "987: \n\t" \ 44 + ".pushsection .discard.unwind_hints\n\t" \ 45 + /* struct unwind_hint */ \ 46 + ".long 987b - .\n\t" \ 47 + ".short " __stringify(sp_offset) "\n\t" \ 48 + ".byte " __stringify(sp_reg) "\n\t" \ 49 + ".byte " __stringify(type) "\n\t" \ 50 + ".byte " __stringify(end) "\n\t" \ 51 + ".balign 4 \n\t" \ 52 + ".popsection\n\t" 53 + 54 + /* 55 + * This macro marks the given function's stack frame as "non-standard", which 56 + * tells objtool to ignore the function when doing stack metadata validation. 57 + * It should only be used in special cases where you're 100% sure it won't 58 + * affect the reliability of frame pointers and kernel stack traces. 59 + * 60 + * For more information, see tools/objtool/Documentation/stack-validation.txt. 61 + */ 62 + #define STACK_FRAME_NON_STANDARD(func) \ 63 + static void __used __section(.discard.func_stack_frame_non_standard) \ 64 + *__func_stack_frame_non_standard_##func = func 65 + 66 + #else /* __ASSEMBLY__ */ 67 + 68 + /* 69 + * This macro indicates that the following intra-function call is valid. 70 + * Any non-annotated intra-function call will cause objtool to issue a warning. 71 + */ 72 + #define ANNOTATE_INTRA_FUNCTION_CALL \ 73 + 999: \ 74 + .pushsection .discard.intra_function_calls; \ 75 + .long 999b; \ 76 + .popsection; 77 + 78 + /* 79 + * In asm, there are two kinds of code: normal C-type callable functions and 80 + * the rest. The normal callable functions can be called by other code, and 81 + * don't do anything unusual with the stack. Such normal callable functions 82 + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this 83 + * category. In this case, no special debugging annotations are needed because 84 + * objtool can automatically generate the ORC data for the ORC unwinder to read 85 + * at runtime. 86 + * 87 + * Anything which doesn't fall into the above category, such as syscall and 88 + * interrupt handlers, tends to not be called directly by other functions, and 89 + * often does unusual non-C-function-type things with the stack pointer. Such 90 + * code needs to be annotated such that objtool can understand it. The 91 + * following CFI hint macros are for this type of code. 92 + * 93 + * These macros provide hints to objtool about the state of the stack at each 94 + * instruction. Objtool starts from the hints and follows the code flow, 95 + * making automatic CFI adjustments when it sees pushes and pops, filling out 96 + * the debuginfo as necessary. It will also warn if it sees any 97 + * inconsistencies. 98 + */ 99 + .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0 100 + .Lunwind_hint_ip_\@: 101 + .pushsection .discard.unwind_hints 102 + /* struct unwind_hint */ 103 + .long .Lunwind_hint_ip_\@ - . 104 + .short \sp_offset 105 + .byte \sp_reg 106 + .byte \type 107 + .byte \end 108 + .balign 4 109 + .popsection 110 + .endm 111 + 112 + #endif /* __ASSEMBLY__ */ 113 + 114 + #else /* !CONFIG_STACK_VALIDATION */ 115 + 116 + #ifndef __ASSEMBLY__ 117 + 118 + #define UNWIND_HINT(sp_reg, sp_offset, type, end) \ 119 + "\n\t" 120 + #define STACK_FRAME_NON_STANDARD(func) 121 + #else 122 + #define ANNOTATE_INTRA_FUNCTION_CALL 123 + .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0 124 + .endm 125 + #endif 126 + 127 + #endif /* CONFIG_STACK_VALIDATION */ 128 + 129 + #endif /* _LINUX_OBJTOOL_H */
+3 -1
tools/objtool/check.c
··· 14 14 #include "warn.h" 15 15 #include "arch_elf.h" 16 16 17 + #include <linux/objtool.h> 17 18 #include <linux/hashtable.h> 18 19 #include <linux/kernel.h> 19 20 #include <linux/static_call_types.h> ··· 1806 1805 return 0; 1807 1806 } 1808 1807 1809 - if (cfi->type == ORC_TYPE_REGS || cfi->type == ORC_TYPE_REGS_IRET) 1808 + if (cfi->type == UNWIND_HINT_TYPE_REGS || 1809 + cfi->type == UNWIND_HINT_TYPE_REGS_PARTIAL) 1810 1810 return update_cfi_state_regs(insn, cfi, op); 1811 1811 1812 1812 switch (op->dest.type) {
+5 -4
tools/objtool/orc_dump.c
··· 4 4 */ 5 5 6 6 #include <unistd.h> 7 + #include <linux/objtool.h> 7 8 #include <asm/orc_types.h> 8 9 #include "objtool.h" 9 10 #include "warn.h" ··· 38 37 static const char *orc_type_name(unsigned int type) 39 38 { 40 39 switch (type) { 41 - case ORC_TYPE_CALL: 40 + case UNWIND_HINT_TYPE_CALL: 42 41 return "call"; 43 - case ORC_TYPE_REGS: 42 + case UNWIND_HINT_TYPE_REGS: 44 43 return "regs"; 45 - case ORC_TYPE_REGS_IRET: 46 - return "iret"; 44 + case UNWIND_HINT_TYPE_REGS_PARTIAL: 45 + return "regs (partial)"; 47 46 default: 48 47 return "?"; 49 48 }
+4 -1
tools/objtool/orc_gen.c
··· 6 6 #include <stdlib.h> 7 7 #include <string.h> 8 8 9 + #include <linux/objtool.h> 10 + #include <asm/orc_types.h> 11 + 9 12 #include "check.h" 10 13 #include "warn.h" 11 14 ··· 149 146 struct orc_entry empty = { 150 147 .sp_reg = ORC_REG_UNDEFINED, 151 148 .bp_reg = ORC_REG_UNDEFINED, 152 - .type = ORC_TYPE_CALL, 149 + .type = UNWIND_HINT_TYPE_CALL, 153 150 }; 154 151 155 152 sec = find_section_by_name(file->elf, ".orc_unwind");
+3 -1
tools/objtool/sync-check.sh
··· 6 6 exit 1 7 7 fi 8 8 9 + FILES="include/linux/objtool.h" 10 + 9 11 if [ "$SRCARCH" = "x86" ]; then 10 - FILES=" 12 + FILES="$FILES 11 13 arch/x86/include/asm/inat_types.h 12 14 arch/x86/include/asm/orc_types.h 13 15 arch/x86/include/asm/emulate_prefix.h