|
@@ -51,7 +51,7 @@ struct instruction {
|
|
|
unsigned int len, state;
|
|
|
unsigned char type;
|
|
|
unsigned long immediate;
|
|
|
- bool alt_group, visited;
|
|
|
+ bool alt_group, visited, dead_end;
|
|
|
struct symbol *call_dest;
|
|
|
struct instruction *jump_dest;
|
|
|
struct list_head alts;
|
|
@@ -329,6 +329,54 @@ static int decode_instructions(struct objtool_file *file)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Find all uses of the unreachable() macro, which are code path dead ends.
|
|
|
+ */
|
|
|
+static int add_dead_ends(struct objtool_file *file)
|
|
|
+{
|
|
|
+ struct section *sec;
|
|
|
+ struct rela *rela;
|
|
|
+ struct instruction *insn;
|
|
|
+ bool found;
|
|
|
+
|
|
|
+ sec = find_section_by_name(file->elf, ".rela__unreachable");
|
|
|
+ if (!sec)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ list_for_each_entry(rela, &sec->rela_list, list) {
|
|
|
+ if (rela->sym->type != STT_SECTION) {
|
|
|
+ WARN("unexpected relocation symbol type in .rela__unreachable");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ insn = find_insn(file, rela->sym->sec, rela->addend);
|
|
|
+ if (insn)
|
|
|
+ insn = list_prev_entry(insn, list);
|
|
|
+ else if (rela->addend == rela->sym->sec->len) {
|
|
|
+ found = false;
|
|
|
+ list_for_each_entry_reverse(insn, &file->insn_list, list) {
|
|
|
+ if (insn->sec == rela->sym->sec) {
|
|
|
+ found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!found) {
|
|
|
+ WARN("can't find unreachable insn at %s+0x%x",
|
|
|
+ rela->sym->sec->name, rela->addend);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ WARN("can't find unreachable insn at %s+0x%x",
|
|
|
+ rela->sym->sec->name, rela->addend);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ insn->dead_end = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Warnings shouldn't be reported for ignored functions.
|
|
|
*/
|
|
@@ -843,6 +891,10 @@ static int decode_sections(struct objtool_file *file)
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
+ ret = add_dead_ends(file);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
add_ignores(file);
|
|
|
|
|
|
ret = add_jump_destinations(file);
|
|
@@ -1037,13 +1089,13 @@ static int validate_branch(struct objtool_file *file,
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
- case INSN_BUG:
|
|
|
- return 0;
|
|
|
-
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ if (insn->dead_end)
|
|
|
+ return 0;
|
|
|
+
|
|
|
insn = next_insn_same_sec(file, insn);
|
|
|
if (!insn) {
|
|
|
WARN("%s: unexpected end of section", sec->name);
|