mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
objtool: Allow multiple pv_ops arrays
Having a single large pv_ops array has the main disadvantage of needing all prototypes of the single array members in one header file. This is adding up to the need to include lots of otherwise unrelated headers. In order to allow multiple smaller pv_ops arrays dedicated to one area of the kernel each, allow multiple arrays in objtool. For better performance limit the possible names of the arrays to start with "pv_ops". Signed-off-by: Juergen Gross <jgross@suse.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://patch.msgid.link/20260105110520.21356-19-jgross@suse.com
This commit is contained in:
parent
7aef17f367
commit
f88dc319fc
3 changed files with 65 additions and 18 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue