From: "Madhavan T. Venkataraman" <madvenka@xxxxxxxxxxxxxxxxxxx> Unwind hint macros and struct unwind_hint are arch-specific. Move them into the arch-specific file asm/unwind_hints.h. But the unwind hint types are generic. Retain them in linux/objtool.h. Unwind hints can be used with static stack validation as well as other forms of validation such as dynamic FP validation. Move the function read_unwind_hints() from check.c to a new file unwind_hints.c so that it can be shared across validation schemes. Signed-off-by: Madhavan T. Venkataraman <madvenka@xxxxxxxxxxxxxxxxxxx> --- arch/x86/include/asm/unwind_hints.h | 86 ++++++++++++ arch/x86/kernel/unwind_orc.c | 2 +- include/linux/objtool.h | 70 ---------- tools/arch/x86/include/asm/unwind_hints.h | 160 ++++++++++++++++++++++ tools/include/linux/objtool.h | 70 ---------- tools/objtool/Build | 1 + tools/objtool/check.c | 97 ------------- tools/objtool/include/objtool/insn.h | 1 + tools/objtool/sync-check.sh | 1 + tools/objtool/unwind_hints.c | 107 +++++++++++++++ 10 files changed, 357 insertions(+), 238 deletions(-) create mode 100644 tools/arch/x86/include/asm/unwind_hints.h create mode 100644 tools/objtool/unwind_hints.c diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h index e7c71750b309..2570edfa8c35 100644 --- a/arch/x86/include/asm/unwind_hints.h +++ b/arch/x86/include/asm/unwind_hints.h @@ -1,10 +1,96 @@ #ifndef _ASM_X86_UNWIND_HINTS_H #define _ASM_X86_UNWIND_HINTS_H +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +/* + * This struct is used by asm and inline asm code to manually annotate the + * location of registers on the stack. + */ +struct unwind_hint { + u32 ip; + s16 sp_offset; + u8 sp_reg; + u8 type; + u8 signal; + u8 end; +}; +#endif + #include <linux/objtool.h> #include "orc_types.h" +#ifdef CONFIG_OBJTOOL + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \ + "987: \n\t" \ + ".pushsection .discard.unwind_hints\n\t" \ + /* struct unwind_hint */ \ + ".long 987b - .\n\t" \ + ".short " __stringify(sp_offset) "\n\t" \ + ".byte " __stringify(sp_reg) "\n\t" \ + ".byte " __stringify(type) "\n\t" \ + ".byte " __stringify(signal) "\n\t" \ + ".byte " __stringify(end) "\n\t" \ + ".balign 4 \n\t" \ + ".popsection\n\t" + +#else /* __ASSEMBLY__ */ + +/* + * In asm, there are two kinds of code: normal C-type callable functions and + * the rest. The normal callable functions can be called by other code, and + * don't do anything unusual with the stack. Such normal callable functions + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this + * category. In this case, no special debugging annotations are needed because + * objtool can automatically generate the ORC data for the ORC unwinder to read + * at runtime. + * + * Anything which doesn't fall into the above category, such as syscall and + * interrupt handlers, tends to not be called directly by other functions, and + * often does unusual non-C-function-type things with the stack pointer. Such + * code needs to be annotated such that objtool can understand it. The + * following CFI hint macros are for this type of code. + * + * These macros provide hints to objtool about the state of the stack at each + * instruction. Objtool starts from the hints and follows the code flow, + * making automatic CFI adjustments when it sees pushes and pops, filling out + * the debuginfo as necessary. It will also warn if it sees any + * inconsistencies. + */ +.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 +.Lunwind_hint_ip_\@: + .pushsection .discard.unwind_hints + /* struct unwind_hint */ + .long .Lunwind_hint_ip_\@ - . + .short \sp_offset + .byte \sp_reg + .byte \type + .byte \signal + .byte \end + .balign 4 + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#else /* !CONFIG_OBJTOOL */ + +#ifndef __ASSEMBLY__ +#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \ + "\n\t" +#else +.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 +.endm +#endif + +#endif /* CONFIG_OBJTOOL */ + #ifdef __ASSEMBLY__ .macro UNWIND_HINT_EMPTY diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 37307b40f8da..01b89f2039c3 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only -#include <linux/objtool.h> #include <linux/module.h> #include <linux/sort.h> #include <asm/ptrace.h> #include <asm/stacktrace.h> #include <asm/unwind.h> +#include <asm/unwind_hints.h> #include <asm/orc_types.h> #include <asm/orc_lookup.h> diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 9ac3df3fccf0..1af295efc12c 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -2,24 +2,6 @@ #ifndef _LINUX_OBJTOOL_H #define _LINUX_OBJTOOL_H -#ifndef __ASSEMBLY__ - -#include <linux/types.h> - -/* - * This struct is used by asm and inline asm code to manually annotate the - * location of registers on the stack. - */ -struct unwind_hint { - u32 ip; - s16 sp_offset; - u8 sp_reg; - u8 type; - u8 signal; - u8 end; -}; -#endif - /* * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP * (the caller's SP right before it made the call). Used for all callable @@ -50,19 +32,6 @@ struct unwind_hint { #ifndef __ASSEMBLY__ -#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \ - "987: \n\t" \ - ".pushsection .discard.unwind_hints\n\t" \ - /* struct unwind_hint */ \ - ".long 987b - .\n\t" \ - ".short " __stringify(sp_offset) "\n\t" \ - ".byte " __stringify(sp_reg) "\n\t" \ - ".byte " __stringify(type) "\n\t" \ - ".byte " __stringify(signal) "\n\t" \ - ".byte " __stringify(end) "\n\t" \ - ".balign 4 \n\t" \ - ".popsection\n\t" - /* * This macro marks the given function's stack frame as "non-standard", which * tells objtool to ignore the function when doing stack metadata validation. @@ -110,41 +79,6 @@ struct unwind_hint { .long 999b; \ .popsection; -/* - * In asm, there are two kinds of code: normal C-type callable functions and - * the rest. The normal callable functions can be called by other code, and - * don't do anything unusual with the stack. Such normal callable functions - * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this - * category. In this case, no special debugging annotations are needed because - * objtool can automatically generate the ORC data for the ORC unwinder to read - * at runtime. - * - * Anything which doesn't fall into the above category, such as syscall and - * interrupt handlers, tends to not be called directly by other functions, and - * often does unusual non-C-function-type things with the stack pointer. Such - * code needs to be annotated such that objtool can understand it. The - * following CFI hint macros are for this type of code. - * - * These macros provide hints to objtool about the state of the stack at each - * instruction. Objtool starts from the hints and follows the code flow, - * making automatic CFI adjustments when it sees pushes and pops, filling out - * the debuginfo as necessary. It will also warn if it sees any - * inconsistencies. - */ -.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 -.Lunwind_hint_ip_\@: - .pushsection .discard.unwind_hints - /* struct unwind_hint */ - .long .Lunwind_hint_ip_\@ - . - .short \sp_offset - .byte \sp_reg - .byte \type - .byte \signal - .byte \end - .balign 4 - .popsection -.endm - .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard, "aw" _ASM_PTR \func @@ -177,16 +111,12 @@ struct unwind_hint { #ifndef __ASSEMBLY__ -#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \ - "\n\t" #define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD_FP(func) #define ANNOTATE_NOENDBR #define ASM_REACHABLE #else #define ANNOTATE_INTRA_FUNCTION_CALL -.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 -.endm .macro STACK_FRAME_NON_STANDARD func:req .endm .macro ANNOTATE_NOENDBR diff --git a/tools/arch/x86/include/asm/unwind_hints.h b/tools/arch/x86/include/asm/unwind_hints.h new file mode 100644 index 000000000000..2570edfa8c35 --- /dev/null +++ b/tools/arch/x86/include/asm/unwind_hints.h @@ -0,0 +1,160 @@ +#ifndef _ASM_X86_UNWIND_HINTS_H +#define _ASM_X86_UNWIND_HINTS_H + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +/* + * This struct is used by asm and inline asm code to manually annotate the + * location of registers on the stack. + */ +struct unwind_hint { + u32 ip; + s16 sp_offset; + u8 sp_reg; + u8 type; + u8 signal; + u8 end; +}; +#endif + +#include <linux/objtool.h> + +#include "orc_types.h" + +#ifdef CONFIG_OBJTOOL + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \ + "987: \n\t" \ + ".pushsection .discard.unwind_hints\n\t" \ + /* struct unwind_hint */ \ + ".long 987b - .\n\t" \ + ".short " __stringify(sp_offset) "\n\t" \ + ".byte " __stringify(sp_reg) "\n\t" \ + ".byte " __stringify(type) "\n\t" \ + ".byte " __stringify(signal) "\n\t" \ + ".byte " __stringify(end) "\n\t" \ + ".balign 4 \n\t" \ + ".popsection\n\t" + +#else /* __ASSEMBLY__ */ + +/* + * In asm, there are two kinds of code: normal C-type callable functions and + * the rest. The normal callable functions can be called by other code, and + * don't do anything unusual with the stack. Such normal callable functions + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this + * category. In this case, no special debugging annotations are needed because + * objtool can automatically generate the ORC data for the ORC unwinder to read + * at runtime. + * + * Anything which doesn't fall into the above category, such as syscall and + * interrupt handlers, tends to not be called directly by other functions, and + * often does unusual non-C-function-type things with the stack pointer. Such + * code needs to be annotated such that objtool can understand it. The + * following CFI hint macros are for this type of code. + * + * These macros provide hints to objtool about the state of the stack at each + * instruction. Objtool starts from the hints and follows the code flow, + * making automatic CFI adjustments when it sees pushes and pops, filling out + * the debuginfo as necessary. It will also warn if it sees any + * inconsistencies. + */ +.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 +.Lunwind_hint_ip_\@: + .pushsection .discard.unwind_hints + /* struct unwind_hint */ + .long .Lunwind_hint_ip_\@ - . + .short \sp_offset + .byte \sp_reg + .byte \type + .byte \signal + .byte \end + .balign 4 + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#else /* !CONFIG_OBJTOOL */ + +#ifndef __ASSEMBLY__ +#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \ + "\n\t" +#else +.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 +.endm +#endif + +#endif /* CONFIG_OBJTOOL */ + +#ifdef __ASSEMBLY__ + +.macro UNWIND_HINT_EMPTY + UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1 +.endm + +.macro UNWIND_HINT_ENTRY + UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1 +.endm + +.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1 + .if \base == %rsp + .if \indirect + .set sp_reg, ORC_REG_SP_INDIRECT + .else + .set sp_reg, ORC_REG_SP + .endif + .elseif \base == %rbp + .set sp_reg, ORC_REG_BP + .elseif \base == %rdi + .set sp_reg, ORC_REG_DI + .elseif \base == %rdx + .set sp_reg, ORC_REG_DX + .elseif \base == %r10 + .set sp_reg, ORC_REG_R10 + .else + .error "UNWIND_HINT_REGS: bad base register" + .endif + + .set sp_offset, \offset + + .if \partial + .set type, UNWIND_HINT_TYPE_REGS_PARTIAL + .elseif \extra == 0 + .set type, UNWIND_HINT_TYPE_REGS_PARTIAL + .set sp_offset, \offset + (16*8) + .else + .set type, UNWIND_HINT_TYPE_REGS + .endif + + UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type signal=\signal +.endm + +.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 signal=1 + UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal +.endm + +.macro UNWIND_HINT_FUNC + UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC +.endm + +.macro UNWIND_HINT_SAVE + UNWIND_HINT type=UNWIND_HINT_TYPE_SAVE +.endm + +.macro UNWIND_HINT_RESTORE + UNWIND_HINT type=UNWIND_HINT_TYPE_RESTORE +.endm + +#else + +#define UNWIND_HINT_FUNC \ + UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0, 0) + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_X86_UNWIND_HINTS_H */ diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index 9ac3df3fccf0..1af295efc12c 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -2,24 +2,6 @@ #ifndef _LINUX_OBJTOOL_H #define _LINUX_OBJTOOL_H -#ifndef __ASSEMBLY__ - -#include <linux/types.h> - -/* - * This struct is used by asm and inline asm code to manually annotate the - * location of registers on the stack. - */ -struct unwind_hint { - u32 ip; - s16 sp_offset; - u8 sp_reg; - u8 type; - u8 signal; - u8 end; -}; -#endif - /* * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP * (the caller's SP right before it made the call). Used for all callable @@ -50,19 +32,6 @@ struct unwind_hint { #ifndef __ASSEMBLY__ -#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \ - "987: \n\t" \ - ".pushsection .discard.unwind_hints\n\t" \ - /* struct unwind_hint */ \ - ".long 987b - .\n\t" \ - ".short " __stringify(sp_offset) "\n\t" \ - ".byte " __stringify(sp_reg) "\n\t" \ - ".byte " __stringify(type) "\n\t" \ - ".byte " __stringify(signal) "\n\t" \ - ".byte " __stringify(end) "\n\t" \ - ".balign 4 \n\t" \ - ".popsection\n\t" - /* * This macro marks the given function's stack frame as "non-standard", which * tells objtool to ignore the function when doing stack metadata validation. @@ -110,41 +79,6 @@ struct unwind_hint { .long 999b; \ .popsection; -/* - * In asm, there are two kinds of code: normal C-type callable functions and - * the rest. The normal callable functions can be called by other code, and - * don't do anything unusual with the stack. Such normal callable functions - * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this - * category. In this case, no special debugging annotations are needed because - * objtool can automatically generate the ORC data for the ORC unwinder to read - * at runtime. - * - * Anything which doesn't fall into the above category, such as syscall and - * interrupt handlers, tends to not be called directly by other functions, and - * often does unusual non-C-function-type things with the stack pointer. Such - * code needs to be annotated such that objtool can understand it. The - * following CFI hint macros are for this type of code. - * - * These macros provide hints to objtool about the state of the stack at each - * instruction. Objtool starts from the hints and follows the code flow, - * making automatic CFI adjustments when it sees pushes and pops, filling out - * the debuginfo as necessary. It will also warn if it sees any - * inconsistencies. - */ -.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 -.Lunwind_hint_ip_\@: - .pushsection .discard.unwind_hints - /* struct unwind_hint */ - .long .Lunwind_hint_ip_\@ - . - .short \sp_offset - .byte \sp_reg - .byte \type - .byte \signal - .byte \end - .balign 4 - .popsection -.endm - .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard, "aw" _ASM_PTR \func @@ -177,16 +111,12 @@ struct unwind_hint { #ifndef __ASSEMBLY__ -#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \ - "\n\t" #define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD_FP(func) #define ANNOTATE_NOENDBR #define ASM_REACHABLE #else #define ANNOTATE_INTRA_FUNCTION_CALL -.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 -.endm .macro STACK_FRAME_NON_STANDARD func:req .endm .macro ANNOTATE_NOENDBR diff --git a/tools/objtool/Build b/tools/objtool/Build index 64ccae49cd5f..4e9ec210f134 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -8,6 +8,7 @@ objtool-y += builtin-check.o objtool-y += cfi.o objtool-y += insn.o objtool-y += decode.o +objtool-y += unwind_hints.o objtool-y += elf.o objtool-y += objtool.o diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 26ed9b0b8f49..f91723010d6b 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1842,103 +1842,6 @@ static int add_jump_table_alts(struct objtool_file *file) return 0; } -static int read_unwind_hints(struct objtool_file *file) -{ - struct cfi_state cfi = init_cfi; - struct section *sec, *relocsec; - struct unwind_hint *hint; - struct instruction *insn; - struct reloc *reloc; - int i; - - sec = find_section_by_name(file->elf, ".discard.unwind_hints"); - if (!sec) - return 0; - - relocsec = sec->reloc; - if (!relocsec) { - WARN("missing .rela.discard.unwind_hints section"); - return -1; - } - - if (sec->sh.sh_size % sizeof(struct unwind_hint)) { - WARN("struct unwind_hint size mismatch"); - return -1; - } - - file->hints = true; - - for (i = 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) { - hint = (struct unwind_hint *)sec->data->d_buf + i; - - reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint)); - if (!reloc) { - WARN("can't find reloc for unwind_hints[%d]", i); - return -1; - } - - insn = find_insn(file, reloc->sym->sec, reloc->addend); - if (!insn) { - WARN("can't find insn for unwind_hints[%d]", i); - return -1; - } - - insn->hint = true; - - if (hint->type == UNWIND_HINT_TYPE_SAVE) { - insn->hint = false; - insn->save = true; - continue; - } - - if (hint->type == UNWIND_HINT_TYPE_RESTORE) { - insn->restore = true; - continue; - } - - if (hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) { - struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); - - if (sym && sym->bind == STB_GLOBAL) { - if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { - WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR", - insn->sec, insn->offset); - } - - insn->entry = 1; - } - } - - if (hint->type == UNWIND_HINT_TYPE_ENTRY) { - hint->type = UNWIND_HINT_TYPE_CALL; - insn->entry = 1; - } - - if (hint->type == UNWIND_HINT_TYPE_FUNC) { - insn->cfi = &func_cfi; - continue; - } - - if (insn->cfi) - cfi = *(insn->cfi); - - if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) { - WARN_FUNC("unsupported unwind_hint sp base reg %d", - insn->sec, insn->offset, hint->sp_reg); - return -1; - } - - cfi.cfa.offset = bswap_if_needed(file->elf, hint->sp_offset); - cfi.type = hint->type; - cfi.signal = hint->signal; - cfi.end = hint->end; - - insn->cfi = cfi_hash_find_or_add(&cfi); - } - - return 0; -} - static int read_noendbr_hints(struct objtool_file *file) { struct section *sec; diff --git a/tools/objtool/include/objtool/insn.h b/tools/objtool/include/objtool/insn.h index 92f8f1ff6c09..0b37d72f06eb 100644 --- a/tools/objtool/include/objtool/insn.h +++ b/tools/objtool/include/objtool/insn.h @@ -128,6 +128,7 @@ bool is_first_func_insn(struct objtool_file *file, int decode_instructions(struct objtool_file *file); +int read_unwind_hints(struct objtool_file *file); #define for_each_insn(file, insn) \ for (struct section *__sec, *__fake = (struct section *)1; \ diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh index 105a291ff8e7..ee49b4e9e72c 100755 --- a/tools/objtool/sync-check.sh +++ b/tools/objtool/sync-check.sh @@ -14,6 +14,7 @@ arch/x86/include/asm/nops.h arch/x86/include/asm/inat_types.h arch/x86/include/asm/orc_types.h arch/x86/include/asm/emulate_prefix.h +arch/x86/include/asm/unwind_hints.h arch/x86/lib/x86-opcode-map.txt arch/x86/tools/gen-insn-attr-x86.awk include/linux/static_call_types.h diff --git a/tools/objtool/unwind_hints.c b/tools/objtool/unwind_hints.c new file mode 100644 index 000000000000..a5aaeaafc16e --- /dev/null +++ b/tools/objtool/unwind_hints.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@xxxxxxxxxx> + */ +#include <asm/unwind_hints.h> + +#include <objtool/builtin.h> +#include <objtool/endianness.h> +#include <objtool/insn.h> +#include <objtool/warn.h> + +int read_unwind_hints(struct objtool_file *file) +{ + struct cfi_state cfi = init_cfi; + struct section *sec, *relocsec; + struct unwind_hint *hint; + struct instruction *insn; + struct reloc *reloc; + int i; + + sec = find_section_by_name(file->elf, ".discard.unwind_hints"); + if (!sec) + return 0; + + relocsec = sec->reloc; + if (!relocsec) { + WARN("missing .rela.discard.unwind_hints section"); + return -1; + } + + if (sec->sh.sh_size % sizeof(struct unwind_hint)) { + WARN("struct unwind_hint size mismatch"); + return -1; + } + + file->hints = true; + + for (i = 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) { + hint = (struct unwind_hint *)sec->data->d_buf + i; + + reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint)); + if (!reloc) { + WARN("can't find reloc for unwind_hints[%d]", i); + return -1; + } + + insn = find_insn(file, reloc->sym->sec, reloc->addend); + if (!insn) { + WARN("can't find insn for unwind_hints[%d]", i); + return -1; + } + + insn->hint = true; + + if (hint->type == UNWIND_HINT_TYPE_SAVE) { + insn->hint = false; + insn->save = true; + continue; + } + + if (hint->type == UNWIND_HINT_TYPE_RESTORE) { + insn->restore = true; + continue; + } + + if (hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) { + struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); + + if (sym && sym->bind == STB_GLOBAL) { + if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { + WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR", + insn->sec, insn->offset); + } + + insn->entry = 1; + } + } + + if (hint->type == UNWIND_HINT_TYPE_ENTRY) { + hint->type = UNWIND_HINT_TYPE_CALL; + insn->entry = 1; + } + + if (hint->type == UNWIND_HINT_TYPE_FUNC) { + insn->cfi = &func_cfi; + continue; + } + + if (insn->cfi) + cfi = *(insn->cfi); + + if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) { + WARN_FUNC("unsupported unwind_hint sp base reg %d", + insn->sec, insn->offset, hint->sp_reg); + return -1; + } + + cfi.cfa.offset = bswap_if_needed(file->elf, hint->sp_offset); + cfi.type = hint->type; + cfi.signal = hint->signal; + cfi.end = hint->end; + + insn->cfi = cfi_hash_find_or_add(&cfi); + } + + return 0; +} -- 2.39.2