// SPDX-License-Identifier: GPL-2.0-or-later
/*
* elf.c - ELF access library
*
* Adapted from kpatch (https://github.com/dynup/kpatch):
* Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com>
* Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <objtool/builtin.h>
#include <objtool/elf.h>
#include <objtool/warn.h>
#define MAX_NAME_LEN 128
static inline u32 str_hash(const char *str)
{
return jhash(str, strlen(str), 0);
}
#define __elf_table(name) (elf->name##_hash)
#define __elf_bits(name) (elf->name##_bits)
#define elf_hash_add(name, node, key) \
hlist_add_head(node, &__elf_table(name)[hash_min(key, __elf_bits(name))])
#define elf_hash_for_each_possible(name, obj, member, key) \
hlist_for_each_entry(obj, &__elf_table(name)[hash_min(key, __elf_bits(name))], member)
#define elf_alloc_hash(name, size) \
({ \
__elf_bits(name) = max(10, ilog2(size)); \
__elf_table(name) = mmap(NULL, sizeof(struct hlist_head) << __elf_bits(name), \
PROT_READ|PROT_WRITE, \
MAP_PRIVATE|MAP_ANON, -1, 0); \
if (__elf_table(name) == (void *)-1L) { \
WARN("mmap fail " #name); \
__elf_table(name) = NULL; \
} \
__elf_table(name); \
})
static bool symbol_to_offset(struct rb_node *a, const struct rb_node *b)
{
struct symbol *sa = rb_entry(a, struct symbol, node);
struct symbol *sb = rb_entry(b, struct symbol, node);
if (sa->offset < sb->offset)
return true;
if (sa->offset > sb->offset)
return false;
if (sa->len < sb->len)
return true;
if (sa->len > sb->len)
return false;
sa->alias = sb;
return false;
}
static int symbol_by_offset(const void *key, const struct rb_node *node)
{
const struct symbol *s = rb_entry(node, struct symbol, node);
const unsigned long *o = key;
if (*o < s->offset)
return -1;
if (*o >= s->offset + s->len)
return 1;
return 0;
}
struct symbol_hole {
unsigned long key;
const struct symbol *sym;
};
/*
* Find !section symbol where @offset is after it.
*/
static int symbol_hole_by_offset(const