summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/objtool/arch/x86/decode.c8
-rw-r--r--tools/objtool/check.c74
-rw-r--r--tools/objtool/include/objtool/check.h1
3 files changed, 65 insertions, 18 deletions
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index f4af82508228..73bfea220d1b 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -711,10 +711,14 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
immr = find_reloc_by_dest(elf, (void *)sec, offset+3);
disp = find_reloc_by_dest(elf, (void *)sec, offset+7);
- if (!immr || strcmp(immr->sym->name, "pv_ops"))
+ if (!immr || strncmp(immr->sym->name, "pv_ops", 6))
break;
- idx = (reloc_addend(immr) + 8) / sizeof(void *);
+ idx = pv_ops_idx_off(immr->sym->name);
+ if (idx < 0)
+ break;
+
+ idx += (reloc_addend(immr) + 8) / sizeof(void *);
func = disp->sym;
if (disp->sym->type == STT_SECTION)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 61f3e0c48fcc..b3fec88d5bd3 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -520,21 +520,57 @@ static int decode_instructions(struct objtool_file *file)
}
/*
- * Read the pv_ops[] .data table to find the static initialized values.
+ * Known pv_ops*[] arrays.
*/
-static int add_pv_ops(struct objtool_file *file, const char *symname)
+static struct {
+ const char *name;
+ int idx_off;
+} pv_ops_tables[] = {
+ { .name = "pv_ops", },
+ { .name = NULL, .idx_off = -1 }
+};
+
+/*
+ * Get index offset for a pv_ops* array.
+ */
+int pv_ops_idx_off(const char *symname)
+{
+ int idx;
+
+ for (idx = 0; pv_ops_tables[idx].name; idx++) {
+ if (!strcmp(symname, pv_ops_tables[idx].name))
+ break;
+ }
+
+ return pv_ops_tables[idx].idx_off;
+}
+
+/*
+ * Read a pv_ops*[] .data table to find the static initialized values.
+ */
+static int add_pv_ops(struct objtool_file *file, int pv_ops_idx)
{
struct symbol *sym, *func;
unsigned long off, end;
struct reloc *reloc;
- int idx;
+ int idx, idx_off;
+ const char *symname;
+ symname = pv_ops_tables[pv_ops_idx].name;
sym = find_symbol_by_name(file->elf, symname);
- if (!sym)
- return 0;
+ if (!sym) {
+ ERROR("Unknown pv_ops array %s", symname);
+ return -1;
+ }
off = sym->offset;
end = off + sym->len;
+ idx_off = pv_ops_tables[pv_ops_idx].idx_off;
+ if (idx_off < 0) {
+ ERROR("pv_ops array %s has unknown index offset", symname);
+ return -1;
+ }
+
for (;;) {
reloc = find_reloc_by_dest_range(file->elf, sym->sec, off, end - off);
if (!reloc)
@@ -552,7 +588,7 @@ static int add_pv_ops(struct objtool_file *file, const char *symname)
return -1;
}
- if (objtool_pv_add(file, idx, func))
+ if (objtool_pv_add(file, idx + idx_off, func))
return -1;
off = reloc_offset(reloc) + 1;
@@ -568,11 +604,6 @@ static int add_pv_ops(struct objtool_file *file, const char *symname)
*/
static int init_pv_ops(struct objtool_file *file)
{
- static const char *pv_ops_tables[] = {
- "pv_ops",
- NULL,
- };
- const char *pv_ops;
struct symbol *sym;
int idx, nr;
@@ -581,11 +612,20 @@ static int init_pv_ops(struct objtool_file *file)
file->pv_ops = NULL;
- sym = find_symbol_by_name(file->elf, "pv_ops");
- if (!sym)
+ nr = 0;
+ for (idx = 0; pv_ops_tables[idx].name; idx++) {
+ sym = find_symbol_by_name(file->elf, pv_ops_tables[idx].name);
+ if (!sym) {
+ pv_ops_tables[idx].idx_off = -1;
+ continue;
+ }
+ pv_ops_tables[idx].idx_off = nr;
+ nr += sym->len / sizeof(unsigned long);
+ }
+
+ if (nr == 0)
return 0;
- nr = sym->len / sizeof(unsigned long);
file->pv_ops = calloc(nr, sizeof(struct pv_state));
if (!file->pv_ops) {
ERROR_GLIBC("calloc");
@@ -595,8 +635,10 @@ static int init_pv_ops(struct objtool_file *file)
for (idx = 0; idx < nr; idx++)
INIT_LIST_HEAD(&file->pv_ops[idx].targets);
- for (idx = 0; (pv_ops = pv_ops_tables[idx]); idx++) {
- if (add_pv_ops(file, pv_ops))
+ for (idx = 0; pv_ops_tables[idx].name; idx++) {
+ if (pv_ops_tables[idx].idx_off < 0)
+ continue;
+ if (add_pv_ops(file, idx))
return -1;
}
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index 2e1346ad5e92..5f2f77bd9b41 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -159,5 +159,6 @@ const char *objtool_disas_insn(struct instruction *insn);
extern size_t sym_name_max_len;
extern struct disas_context *objtool_disas_ctx;
+int pv_ops_idx_off(const char *symname);
#endif /* _CHECK_H */