Merge 5.18-rc5 into tty-next
[linux-2.6-microblaze.git] / tools / objtool / check.c
index bd0c2c8..ca5b746 100644 (file)
@@ -184,6 +184,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
                "do_group_exit",
                "stop_this_cpu",
                "__invalid_creds",
+               "cpu_startup_entry",
        };
 
        if (!func)
@@ -559,12 +560,12 @@ static int add_dead_ends(struct objtool_file *file)
                else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
                        insn = find_last_insn(file, reloc->sym->sec);
                        if (!insn) {
-                               WARN("can't find unreachable insn at %s+0x%x",
+                               WARN("can't find unreachable insn at %s+0x%lx",
                                     reloc->sym->sec->name, reloc->addend);
                                return -1;
                        }
                } else {
-                       WARN("can't find unreachable insn at %s+0x%x",
+                       WARN("can't find unreachable insn at %s+0x%lx",
                             reloc->sym->sec->name, reloc->addend);
                        return -1;
                }
@@ -594,12 +595,12 @@ reachable:
                else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
                        insn = find_last_insn(file, reloc->sym->sec);
                        if (!insn) {
-                               WARN("can't find reachable insn at %s+0x%x",
+                               WARN("can't find reachable insn at %s+0x%lx",
                                     reloc->sym->sec->name, reloc->addend);
                                return -1;
                        }
                } else {
-                       WARN("can't find reachable insn at %s+0x%x",
+                       WARN("can't find reachable insn at %s+0x%lx",
                             reloc->sym->sec->name, reloc->addend);
                        return -1;
                }
@@ -1271,12 +1272,19 @@ static bool is_first_func_insn(struct objtool_file *file, struct instruction *in
  */
 static int add_jump_destinations(struct objtool_file *file)
 {
-       struct instruction *insn;
+       struct instruction *insn, *jump_dest;
        struct reloc *reloc;
        struct section *dest_sec;
        unsigned long dest_off;
 
        for_each_insn(file, insn) {
+               if (insn->jump_dest) {
+                       /*
+                        * handle_group_alt() may have previously set
+                        * 'jump_dest' for some alternatives.
+                        */
+                       continue;
+               }
                if (!is_static_jump(insn))
                        continue;
 
@@ -1291,7 +1299,10 @@ static int add_jump_destinations(struct objtool_file *file)
                        add_retpoline_call(file, insn);
                        continue;
                } else if (insn->func) {
-                       /* internal or external sibling call (with reloc) */
+                       /*
+                        * External sibling call or internal sibling call with
+                        * STT_FUNC reloc.
+                        */
                        add_call_dest(file, insn, reloc->sym, true);
                        continue;
                } else if (reloc->sym->sec->idx) {
@@ -1303,17 +1314,8 @@ static int add_jump_destinations(struct objtool_file *file)
                        continue;
                }
 
-               insn->jump_dest = find_insn(file, dest_sec, dest_off);
-               if (!insn->jump_dest) {
-
-                       /*
-                        * This is a special case where an alt instruction
-                        * jumps past the end of the section.  These are
-                        * handled later in handle_group_alt().
-                        */
-                       if (!strcmp(insn->sec->name, ".altinstr_replacement"))
-                               continue;
-
+               jump_dest = find_insn(file, dest_sec, dest_off);
+               if (!jump_dest) {
                        WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
                                  insn->sec, insn->offset, dest_sec->name,
                                  dest_off);
@@ -1323,8 +1325,8 @@ static int add_jump_destinations(struct objtool_file *file)
                /*
                 * Cross-function jump.
                 */
-               if (insn->func && insn->jump_dest->func &&
-                   insn->func != insn->jump_dest->func) {
+               if (insn->func && jump_dest->func &&
+                   insn->func != jump_dest->func) {
 
                        /*
                         * For GCC 8+, create parent/child links for any cold
@@ -1342,16 +1344,22 @@ static int add_jump_destinations(struct objtool_file *file)
                         * subfunction is through a jump table.
                         */
                        if (!strstr(insn->func->name, ".cold") &&
-                           strstr(insn->jump_dest->func->name, ".cold")) {
-                               insn->func->cfunc = insn->jump_dest->func;
-                               insn->jump_dest->func->pfunc = insn->func;
+                           strstr(jump_dest->func->name, ".cold")) {
+                               insn->func->cfunc = jump_dest->func;
+                               jump_dest->func->pfunc = insn->func;
 
-                       } else if (!same_function(insn, insn->jump_dest) &&
-                                  is_first_func_insn(file, insn->jump_dest)) {
-                               /* internal sibling call (without reloc) */
-                               add_call_dest(file, insn, insn->jump_dest->func, true);
+                       } else if (!same_function(insn, jump_dest) &&
+                                  is_first_func_insn(file, jump_dest)) {
+                               /*
+                                * Internal sibling call without reloc or with
+                                * STT_SECTION reloc.
+                                */
+                               add_call_dest(file, insn, jump_dest->func, true);
+                               continue;
                        }
                }
+
+               insn->jump_dest = jump_dest;
        }
 
        return 0;
@@ -1540,13 +1548,13 @@ static int handle_group_alt(struct objtool_file *file,
                        continue;
 
                dest_off = arch_jump_destination(insn);
-               if (dest_off == special_alt->new_off + special_alt->new_len)
+               if (dest_off == special_alt->new_off + special_alt->new_len) {
                        insn->jump_dest = next_insn_same_sec(file, last_orig_insn);
-
-               if (!insn->jump_dest) {
-                       WARN_FUNC("can't find alternative jump destination",
-                                 insn->sec, insn->offset);
-                       return -1;
+                       if (!insn->jump_dest) {
+                               WARN_FUNC("can't find alternative jump destination",
+                                         insn->sec, insn->offset);
+                               return -1;
+                       }
                }
        }
 
@@ -2245,14 +2253,14 @@ static int decode_sections(struct objtool_file *file)
                return ret;
 
        /*
-        * Must be before add_special_section_alts() as that depends on
-        * jump_dest being set.
+        * Must be before add_jump_destinations(), which depends on 'func'
+        * being set for alternatives, to enable proper sibling call detection.
         */
-       ret = add_jump_destinations(file);
+       ret = add_special_section_alts(file);
        if (ret)
                return ret;
 
-       ret = add_special_section_alts(file);
+       ret = add_jump_destinations(file);
        if (ret)
                return ret;
 
@@ -3210,9 +3218,8 @@ validate_ibt_reloc(struct objtool_file *file, struct reloc *reloc)
 static void warn_noendbr(const char *msg, struct section *sec, unsigned long offset,
                         struct instruction *dest)
 {
-       WARN_FUNC("%srelocation to !ENDBR: %s+0x%lx", sec, offset, msg,
-                 dest->func ? dest->func->name : dest->sec->name,
-                 dest->func ? dest->offset - dest->func->offset : dest->offset);
+       WARN_FUNC("%srelocation to !ENDBR: %s", sec, offset, msg,
+                 offstr(dest->sec, dest->offset));
 }
 
 static void validate_ibt_dest(struct objtool_file *file, struct instruction *insn,
@@ -3303,7 +3310,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
        while (1) {
                next_insn = next_insn_to_validate(file, insn);
 
-               if (file->c_file && func && insn->func && func != insn->func->pfunc) {
+               if (func && insn->func && func != insn->func->pfunc) {
                        WARN("%s() falls through to next function %s()",
                             func->name, insn->func->name);
                        return 1;
@@ -3816,11 +3823,8 @@ static int validate_ibt(struct objtool_file *file)
                        struct instruction *dest;
 
                        dest = validate_ibt_reloc(file, reloc);
-                       if (is_data && dest && !dest->noendbr) {
-                               warn_noendbr("data ", reloc->sym->sec,
-                                            reloc->sym->offset + reloc->addend,
-                                            dest);
-                       }
+                       if (is_data && dest && !dest->noendbr)
+                               warn_noendbr("data ", sec, reloc->offset, dest);
                }
        }