objtool: Re-add UNWIND_HINT_{SAVE_RESTORE}
authorJosh Poimboeuf <jpoimboe@kernel.org>
Fri, 24 Jun 2022 10:52:40 +0000 (12:52 +0200)
committerBorislav Petkov <bp@suse.de>
Mon, 27 Jun 2022 08:34:00 +0000 (10:34 +0200)
Commit

  c536ed2fffd5 ("objtool: Remove SAVE/RESTORE hints")

removed the save/restore unwind hints because they were no longer
needed. Now they're going to be needed again so re-add them.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Borislav Petkov <bp@suse.de>
arch/x86/include/asm/unwind_hints.h
include/linux/objtool.h
tools/include/linux/objtool.h
tools/objtool/check.c
tools/objtool/include/objtool/check.h

index 6f70fe4c93f2619afd899def646b5c6b82ab4b0d..f66fbe6537dd7abac82b6bca5e6258f88a81d4b7 100644 (file)
@@ -8,11 +8,11 @@
 #ifdef __ASSEMBLY__
 
 .macro UNWIND_HINT_EMPTY
-       UNWIND_HINT sp_reg=ORC_REG_UNDEFINED type=UNWIND_HINT_TYPE_CALL end=1
+       UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1
 .endm
 
 .macro UNWIND_HINT_ENTRY
-       UNWIND_HINT sp_reg=ORC_REG_UNDEFINED type=UNWIND_HINT_TYPE_ENTRY end=1
+       UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1
 .endm
 
 .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0
        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 \
index b026f1ae39c6096c77f76986df64e61cf0a02b27..10bc88cc3bf6b8bc4865baf006151a4a25383795 100644 (file)
@@ -40,6 +40,8 @@ struct unwind_hint {
 #define UNWIND_HINT_TYPE_REGS_PARTIAL  2
 #define UNWIND_HINT_TYPE_FUNC          3
 #define UNWIND_HINT_TYPE_ENTRY         4
+#define UNWIND_HINT_TYPE_SAVE          5
+#define UNWIND_HINT_TYPE_RESTORE       6
 
 #ifdef CONFIG_OBJTOOL
 
@@ -127,7 +129,7 @@ struct unwind_hint {
  * the debuginfo as necessary.  It will also warn if it sees any
  * inconsistencies.
  */
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .Lunwind_hint_ip_\@:
        .pushsection .discard.unwind_hints
                /* struct unwind_hint */
@@ -180,7 +182,7 @@ struct unwind_hint {
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
index b026f1ae39c6096c77f76986df64e61cf0a02b27..10bc88cc3bf6b8bc4865baf006151a4a25383795 100644 (file)
@@ -40,6 +40,8 @@ struct unwind_hint {
 #define UNWIND_HINT_TYPE_REGS_PARTIAL  2
 #define UNWIND_HINT_TYPE_FUNC          3
 #define UNWIND_HINT_TYPE_ENTRY         4
+#define UNWIND_HINT_TYPE_SAVE          5
+#define UNWIND_HINT_TYPE_RESTORE       6
 
 #ifdef CONFIG_OBJTOOL
 
@@ -127,7 +129,7 @@ struct unwind_hint {
  * the debuginfo as necessary.  It will also warn if it sees any
  * inconsistencies.
  */
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .Lunwind_hint_ip_\@:
        .pushsection .discard.unwind_hints
                /* struct unwind_hint */
@@ -180,7 +182,7 @@ struct unwind_hint {
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
index 822a490e6d87d2f3c02ada52818ac39bf50436e7..ddfdd138cc2a3a58b56113943cb37c5fe3ff2320 100644 (file)
@@ -2032,6 +2032,17 @@ static int read_unwind_hints(struct objtool_file *file)
 
                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);
 
@@ -3329,6 +3340,35 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                        state.instr += insn->instr;
 
                if (insn->hint) {
+                       if (insn->restore) {
+                               struct instruction *save_insn, *i;
+
+                               i = insn;
+                               save_insn = NULL;
+
+                               sym_for_each_insn_continue_reverse(file, func, i) {
+                                       if (i->save) {
+                                               save_insn = i;
+                                               break;
+                                       }
+                               }
+
+                               if (!save_insn) {
+                                       WARN_FUNC("no corresponding CFI save for CFI restore",
+                                                 sec, insn->offset);
+                                       return 1;
+                               }
+
+                               if (!save_insn->visited) {
+                                       WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
+                                                 sec, insn->offset);
+                                       return 1;
+                               }
+
+                               insn->cfi = save_insn->cfi;
+                               nr_cfi_reused++;
+                       }
+
                        state.cfi = *insn->cfi;
                } else {
                        /* XXX track if we actually changed state.cfi */
index 0eeedeacbefb0c5cf049a095d897b82a15974140..036129cebeeefae3205e545ef837ae359cdc027e 100644 (file)
@@ -46,18 +46,19 @@ struct instruction {
        enum insn_type type;
        unsigned long immediate;
 
-       u8 dead_end     : 1,
-          ignore       : 1,
-          ignore_alts  : 1,
-          hint         : 1,
-          retpoline_safe : 1,
-          noendbr      : 1,
-          entry        : 1;
-               /* 1 bit hole */
+       u16 dead_end            : 1,
+          ignore               : 1,
+          ignore_alts          : 1,
+          hint                 : 1,
+          save                 : 1,
+          restore              : 1,
+          retpoline_safe       : 1,
+          noendbr              : 1,
+          entry                : 1;
+               /* 7 bit hole */
 
        s8 instr;
        u8 visited;
-       /* u8 hole */
 
        struct alt_group *alt_group;
        struct symbol *call_dest;