static bool dead_end_function(struct objtool_file *file, struct symbol *func)
{
int i;
- struct instruction *insn;
+ struct instruction *insn, *func_insn;
bool empty = true;
/*
if (!func->sec)
return false;
- insn = find_instruction(file, func->sec, func->offset);
- if (!insn)
+ func_insn = find_instruction(file, func->sec, func->offset);
+ if (!func_insn)
return false;
+ insn = func_insn;
list_for_each_entry_from(insn, &file->insns, list) {
if (insn->sec != func->sec ||
insn->offset >= func->offset + func->len)
if (insn->type == INSN_RETURN)
return false;
+ }
+
+ if (empty)
+ return false;
+
+ /*
+ * A function can have a sibling call instead of a return. In that
+ * case, the function's dead-end status depends on whether the target
+ * of the sibling call returns.
+ */
+ insn = func_insn;
+ list_for_each_entry_from(insn, &file->insns, list) {
+ if (insn->sec != func->sec ||
+ insn->offset >= func->offset + func->len)
+ break;
if (insn->type == INSN_JUMP_UNCONDITIONAL) {
struct instruction *dest = insn->jump_dest;
return false;
}
- return !empty;
+ return true;
}
/*