Messages in this thread Patch in this message | | | From | Julien Thierry <> | Subject | [PATCH v2 9/9] objtool: Abstract unwind hint reading | Date | Thu, 30 Jul 2020 10:46:52 +0100 |
| |
The type of unwind hints and the semantics associated with them depend on the architecture. Let arch specific code convert unwind hints into objtool stack state descriptions.
Signed-off-by: Julien Thierry <jthierry@redhat.com> --- tools/objtool/arch.h | 5 +-- tools/objtool/arch/x86/decode.c | 54 ++++++++++++++++++++++++++++++ tools/objtool/cfi.h | 3 +- tools/objtool/check.c | 58 +++++---------------------------- tools/objtool/orc_gen.c | 4 ++- 5 files changed, 71 insertions(+), 53 deletions(-)
diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index 2e2ce089b0e9..44107e9aab71 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h @@ -7,12 +7,11 @@ #define _ARCH_H #include <stdbool.h> +#include <linux/frame.h> #include <linux/list.h> #include "objtool.h" #include "cfi.h" -#include <asm/orc_types.h> - enum insn_type { INSN_JUMP_CONDITIONAL, INSN_JUMP_UNCONDITIONAL, @@ -86,4 +85,6 @@ unsigned long arch_dest_reloc_offset(int addend); const char *arch_nop_insn(int len); +int arch_decode_insn_hint(struct instruction *insn, struct unwind_hint *hint); + #endif /* _ARCH_H */ diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 1967370440b3..2099809925af 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -6,6 +6,8 @@ #include <stdio.h> #include <stdlib.h> +#include <linux/frame.h> + #define unlikely(cond) (cond) #include <asm/insn.h> #include "../../../arch/x86/lib/inat.c" @@ -15,6 +17,7 @@ #include "../../elf.h" #include "../../arch.h" #include "../../warn.h" +#include <asm/orc_types.h> static unsigned char op_to_cfi_reg[][2] = { {CFI_AX, CFI_R8}, @@ -583,3 +586,54 @@ const char *arch_nop_insn(int len) return nops[len-1]; } + +int arch_decode_insn_hint(struct instruction *insn, struct unwind_hint *hint) +{ + struct cfi_reg *cfa = &insn->cfi.cfa; + + if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) { + insn->ret_offset = hint->sp_offset; + return 0; + } + + insn->hint = true; + + switch (hint->sp_reg) { + case ORC_REG_UNDEFINED: + cfa->base = CFI_UNDEFINED; + break; + case ORC_REG_SP: + cfa->base = CFI_SP; + break; + case ORC_REG_BP: + cfa->base = CFI_BP; + break; + case ORC_REG_SP_INDIRECT: + cfa->base = CFI_SP_INDIRECT; + break; + case ORC_REG_R10: + cfa->base = CFI_R10; + break; + case ORC_REG_R13: + cfa->base = CFI_R13; + break; + case ORC_REG_DI: + cfa->base = CFI_DI; + break; + case ORC_REG_DX: + cfa->base = CFI_DX; + break; + default: + WARN_FUNC("unsupported unwind_hint sp base reg %d", + insn->sec, insn->offset, hint->sp_reg); + return -1; + } + + cfa->offset = hint->sp_offset; + insn->cfi.hint_type = hint->type; + insn->cfi.end = hint->end; + + insn->cfi.sp_only = hint->type == ORC_TYPE_REGS || hint->type == ORC_TYPE_REGS_IRET; + + return 0; +} diff --git a/tools/objtool/cfi.h b/tools/objtool/cfi.h index c7c59c6a44ee..f5aeca023133 100644 --- a/tools/objtool/cfi.h +++ b/tools/objtool/cfi.h @@ -29,10 +29,11 @@ struct cfi_state { struct cfi_reg cfa; int stack_size; int drap_reg, drap_offset; - unsigned char type; + unsigned char hint_type; bool bp_scratch; bool drap; bool end; + bool sp_only; }; #endif /* _OBJTOOL_CFI_H */ diff --git a/tools/objtool/check.c b/tools/objtool/check.c index d6731e88259d..d856580369dd 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1217,7 +1217,6 @@ static int read_unwind_hints(struct objtool_file *file) struct reloc *reloc; struct unwind_hint *hint; struct instruction *insn; - struct cfi_reg *cfa; int i; sec = find_section_by_name(file->elf, ".discard.unwind_hints"); @@ -1252,49 +1251,10 @@ static int read_unwind_hints(struct objtool_file *file) return -1; } - cfa = &insn->cfi.cfa; - - if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) { - insn->ret_offset = hint->sp_offset; - continue; - } - - insn->hint = true; - - switch (hint->sp_reg) { - case ORC_REG_UNDEFINED: - cfa->base = CFI_UNDEFINED; - break; - case ORC_REG_SP: - cfa->base = CFI_SP; - break; - case ORC_REG_BP: - cfa->base = CFI_BP; - break; - case ORC_REG_SP_INDIRECT: - cfa->base = CFI_SP_INDIRECT; - break; - case ORC_REG_R10: - cfa->base = CFI_R10; - break; - case ORC_REG_R13: - cfa->base = CFI_R13; - break; - case ORC_REG_DI: - cfa->base = CFI_DI; - break; - case ORC_REG_DX: - cfa->base = CFI_DX; - break; - default: - WARN_FUNC("unsupported unwind_hint sp base reg %d", - insn->sec, insn->offset, hint->sp_reg); + if (arch_decode_insn_hint(insn, hint)) { + WARN_FUNC("Bad unwind hint", insn->sec, insn->offset); return -1; } - - cfa->offset = hint->sp_offset; - insn->cfi.type = hint->type; - insn->cfi.end = hint->end; } return 0; @@ -1571,9 +1531,9 @@ static bool has_valid_stack_frame(struct insn_state *state) return false; } -static int update_cfi_state_regs(struct instruction *insn, - struct cfi_state *cfi, - struct stack_op *op) +static int update_sp_only_cfi_state(struct instruction *insn, + struct cfi_state *cfi, + struct stack_op *op) { struct cfi_reg *cfa = &cfi->cfa; @@ -1679,8 +1639,8 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, return 0; } - if (cfi->type == ORC_TYPE_REGS || cfi->type == ORC_TYPE_REGS_IRET) - return update_cfi_state_regs(insn, cfi, op); + if (cfi->sp_only) + return update_sp_only_cfi_state(insn, cfi, op); switch (op->dest.type) { @@ -2084,10 +2044,10 @@ static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) break; } - } else if (cfi1->type != cfi2->type) { + } else if (cfi1->hint_type != cfi2->hint_type) { WARN_FUNC("stack state mismatch: type1=%d type2=%d", - insn->sec, insn->offset, cfi1->type, cfi2->type); + insn->sec, insn->offset, cfi1->hint_type, cfi2->hint_type); } else if (cfi1->drap != cfi2->drap || (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) || diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 00f1efd05653..a36aee98bed0 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -9,6 +9,8 @@ #include "check.h" #include "warn.h" +#include <asm/orc_types.h> + struct orc_data { struct list_head list; struct instruction *insn; @@ -92,7 +94,7 @@ int create_orc(struct objtool_file *file) orc->sp_offset = cfa->offset; orc->bp_offset = bp->offset; - orc->type = insn->cfi.type; + orc->type = insn->cfi.hint_type; } return 0; -- 2.21.3
| |