|
@@ -810,17 +810,28 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
|
|
|
struct rela *rela = table;
|
|
|
struct instruction *alt_insn;
|
|
|
struct alternative *alt;
|
|
|
+ struct symbol *pfunc = insn->func->pfunc;
|
|
|
+ unsigned int prev_offset = 0;
|
|
|
|
|
|
list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
|
|
|
if (rela == next_table)
|
|
|
break;
|
|
|
|
|
|
+ /* Make sure the switch table entries are consecutive: */
|
|
|
+ if (prev_offset && rela->offset != prev_offset + 8)
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* Detect function pointers from contiguous objects: */
|
|
|
+ if (rela->sym->sec == pfunc->sec &&
|
|
|
+ rela->addend == pfunc->offset)
|
|
|
+ break;
|
|
|
+
|
|
|
alt_insn = find_insn(file, rela->sym->sec, rela->addend);
|
|
|
if (!alt_insn)
|
|
|
break;
|
|
|
|
|
|
/* Make sure the jmp dest is in the function or subfunction: */
|
|
|
- if (alt_insn->func->pfunc != insn->func->pfunc)
|
|
|
+ if (alt_insn->func->pfunc != pfunc)
|
|
|
break;
|
|
|
|
|
|
alt = malloc(sizeof(*alt));
|
|
@@ -831,6 +842,13 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
|
|
|
|
|
|
alt->insn = alt_insn;
|
|
|
list_add_tail(&alt->list, &insn->alts);
|
|
|
+ prev_offset = rela->offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!prev_offset) {
|
|
|
+ WARN_FUNC("can't find switch jump table",
|
|
|
+ insn->sec, insn->offset);
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -887,7 +905,9 @@ static struct rela *find_switch_table(struct objtool_file *file,
|
|
|
struct instruction *orig_insn = insn;
|
|
|
|
|
|
text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
|
|
|
- if (text_rela && text_rela->sym == file->rodata->sym) {
|
|
|
+ if (text_rela && text_rela->sym == file->rodata->sym &&
|
|
|
+ !find_symbol_containing(file->rodata, text_rela->addend)) {
|
|
|
+
|
|
|
/* case 1 */
|
|
|
rodata_rela = find_rela_by_dest(file->rodata,
|
|
|
text_rela->addend);
|