Blame ksymtab.c

Packit Service 80a84b
/*
Packit Service 80a84b
	Copyright(C) 2016, Red Hat, Inc., Stanislav Kozina
Packit Service 80a84b
Packit Service 80a84b
	This program is free software: you can redistribute it and/or modify
Packit Service 80a84b
	it under the terms of the GNU General Public License as published by
Packit Service 80a84b
	the Free Software Foundation, either version 3 of the License, or
Packit Service 80a84b
	(at your option) any later version.
Packit Service 80a84b
Packit Service 80a84b
	This program is distributed in the hope that it will be useful,
Packit Service 80a84b
	but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 80a84b
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 80a84b
	GNU General Public License for more details.
Packit Service 80a84b
Packit Service 80a84b
	You should have received a copy of the GNU General Public License
Packit Service 80a84b
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 80a84b
*/
Packit Service 80a84b
Packit Service 80a84b
/*
Packit Service 80a84b
 * This file contains the code which reads the __ksymtab section of the kernel
Packit Service 80a84b
 * binaries to ensure that the symbol we parse is actually exported using the
Packit Service 80a84b
 * EXPORT_SYMBOL() macro.
Packit Service 80a84b
 */
Packit Service 80a84b
Packit Service 80a84b
#include <stdlib.h>
Packit Service 80a84b
#include <unistd.h>
Packit Service 80a84b
#include <stdio.h>
Packit Service 80a84b
#include <sys/types.h>
Packit Service 80a84b
#include <sys/stat.h>
Packit Service 80a84b
#include <stdbool.h>
Packit Service 80a84b
#include <fcntl.h>
Packit Service 80a84b
#include <string.h>
Packit Service 80a84b
#include <errno.h>
Packit Service 80a84b
#include <assert.h>
Packit Service 80a84b
Packit Service 80a84b
#include <libelf.h>
Packit Service 80a84b
#include <gelf.h>
Packit Service 80a84b
#include "main.h"
Packit Service 80a84b
#include "utils.h"
Packit Service 80a84b
#include "hash.h"
Packit Service 80a84b
#include "ksymtab.h"
Packit Service 80a84b
Packit Service 80a84b
#define	KSYMTAB_STRINGS	"__ksymtab_strings"
Packit Service 80a84b
#define SYMTAB		".symtab"
Packit Service 80a84b
#define STRTAB		".strtab"
Packit Service 80a84b
Packit Service 80a84b
#define KSYMTAB_SIZE 8192
Packit Service 80a84b
Packit Service 80a84b
struct ksymtab {
Packit Service 80a84b
	struct hash *hash;
Packit Service 80a84b
	size_t mark_count;
Packit Service 80a84b
};
Packit Service 80a84b
Packit Service 80a84b
struct ksym;
Packit Service 80a84b
Packit Service 80a84b
static int elf_get_section(Elf *elf,
Packit Service 80a84b
			   size_t shstrndx,
Packit Service 80a84b
			   const char *section,
Packit Service 80a84b
			   const char **d_data,
Packit Service 80a84b
			   size_t *size)
Packit Service 80a84b
{
Packit Service 80a84b
	Elf_Scn *scn;
Packit Service 80a84b
	GElf_Shdr shdr;
Packit Service 80a84b
	char *name;
Packit Service 80a84b
	Elf_Data *data;
Packit Service 80a84b
Packit Service 80a84b
	scn = elf_nextscn(elf, NULL);
Packit Service 80a84b
	for (; scn != NULL; scn = elf_nextscn(elf, scn)) {
Packit Service 80a84b
		if (gelf_getshdr(scn, &shdr) != &shdr)
Packit Service 80a84b
			fail("getshdr() failed: %s\n", elf_errmsg(-1));
Packit Service 80a84b
		name = elf_strptr(elf, shstrndx, shdr.sh_name);
Packit Service 80a84b
		if (name == NULL)
Packit Service 80a84b
			fail("elf_strptr() failed: %s\n", elf_errmsg(-1));
Packit Service 80a84b
Packit Service 80a84b
		if (strcmp(name, section) == 0)
Packit Service 80a84b
			break;
Packit Service 80a84b
	}
Packit Service 80a84b
Packit Service 80a84b
	if (scn == NULL) /* no suitable section */
Packit Service 80a84b
		return -1;
Packit Service 80a84b
Packit Service 80a84b
	/*
Packit Service 80a84b
	 * This is unlucky. Fedora/EL builds -debuginfo packages by running
Packit Service 80a84b
	 * eu-strip --reloc-debug-sections which places only standard .debug*
Packit Service 80a84b
	 * sections into the -debuginfo modules. The sections which cannot
Packit Service 80a84b
	 * be stripped completely (because they are allocated) are changed
Packit Service 80a84b
	 * to SHT_NOBITS type to indicate you need to look in the original
Packit Service 80a84b
	 * (non-debug) module for them. But those are xzipped.
Packit Service 80a84b
	 * So we reject such stuff. We only support fresh output from the
Packit Service 80a84b
	 * kernel build.
Packit Service 80a84b
	 */
Packit Service 80a84b
	if (shdr.sh_type == SHT_NOBITS) {
Packit Service 80a84b
		printf("The %s section has type SHT_NOBITS. Most likely you're "
Packit Service 80a84b
		    "running this tool on modules coming from kernel-debuginfo "
Packit Service 80a84b
		    "packages. They don't contain the %s section, you need to "
Packit Service 80a84b
		    "use the raw modules before they are stripped\n", section,
Packit Service 80a84b
		    section);
Packit Service 80a84b
		exit(1);
Packit Service 80a84b
	}
Packit Service 80a84b
Packit Service 80a84b
	if (gelf_getshdr(scn, &shdr) != &shdr)
Packit Service 80a84b
		fail("getshdr() failed: %s\n", elf_errmsg(-1));
Packit Service 80a84b
Packit Service 80a84b
	data = elf_getdata(scn, NULL);
Packit Service 80a84b
	if (data == NULL || data->d_size == 0)
Packit Service 80a84b
		fail("%s section empty!\n", section);
Packit Service 80a84b
Packit Service 80a84b
	*d_data = data->d_buf;
Packit Service 80a84b
	*size = data->d_size;
Packit Service 80a84b
Packit Service 80a84b
	return 0;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
struct elf_data *elf_open(const char *filename)
Packit Service 80a84b
{
Packit Service 80a84b
	Elf *elf;
Packit Service 80a84b
	int fd;
Packit Service 80a84b
	int class;
Packit Service 80a84b
	GElf_Ehdr *ehdr;
Packit Service 80a84b
	size_t shstrndx;
Packit Service 80a84b
	struct elf_data *data = NULL;
Packit Service 80a84b
Packit Service 80a84b
	if (elf_version(EV_CURRENT) == EV_NONE)
Packit Service 80a84b
		fail("elf_version() failed: %s\n", elf_errmsg(-1));
Packit Service 80a84b
Packit Service 80a84b
	fd = open(filename, O_RDONLY, 0);
Packit Service 80a84b
	if (fd < 0)
Packit Service 80a84b
		fail("Failed to open file %s: %s\n", filename,
Packit Service 80a84b
		     strerror(errno));
Packit Service 80a84b
Packit Service 80a84b
	elf = elf_begin(fd, ELF_C_READ, NULL);
Packit Service 80a84b
	if (elf == NULL)
Packit Service 80a84b
		fail("elf_begin() failed: %s\n", elf_errmsg(-1));
Packit Service 80a84b
Packit Service 80a84b
	if (elf_kind(elf) != ELF_K_ELF) {
Packit Service 80a84b
		printf("Doesn't look like an ELF file, ignoring: %s\n",
Packit Service 80a84b
		       filename);
Packit Service 80a84b
		(void) elf_end(elf);
Packit Service 80a84b
		(void) close(fd);
Packit Service 80a84b
		goto out;
Packit Service 80a84b
	}
Packit Service 80a84b
Packit Service 80a84b
	ehdr = safe_zmalloc(sizeof(*ehdr));
Packit Service 80a84b
Packit Service 80a84b
	if (gelf_getehdr(elf, ehdr) == NULL)
Packit Service 80a84b
		fail("getehdr() failed: %s\n", elf_errmsg(-1));
Packit Service 80a84b
Packit Service 80a84b
	class = gelf_getclass(elf);
Packit Service 80a84b
	if (class != ELFCLASS64) {
Packit Service 80a84b
		printf("Unsupported elf class of %s: %d\n", filename, class);
Packit Service 80a84b
		free(ehdr);
Packit Service 80a84b
		(void) elf_end(elf);
Packit Service 80a84b
		(void) close(fd);
Packit Service 80a84b
		goto out;
Packit Service 80a84b
	}
Packit Service 80a84b
Packit Service 80a84b
	/*
Packit Service 80a84b
	 * Get section index of the string table associated with the section
Packit Service 80a84b
	 * headers in the ELF file.
Packit Service 80a84b
	 * Required by elf_get_section calls.
Packit Service 80a84b
	 */
Packit Service 80a84b
	if (elf_getshdrstrndx(elf, &shstrndx) != 0)
Packit Service 80a84b
		fail("elf_getshdrstrndx() failed: %s\n", elf_errmsg(-1))
Packit Service 80a84b
Packit Service 80a84b
	data = safe_zmalloc(sizeof(*data));
Packit Service 80a84b
Packit Service 80a84b
	data->fd = fd;
Packit Service 80a84b
	data->elf = elf;
Packit Service 80a84b
	data->ehdr = ehdr;
Packit Service 80a84b
	data->shstrndx = shstrndx;
Packit Service 80a84b
out:
Packit Service 80a84b
	return data;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
void elf_close(struct elf_data *ed)
Packit Service 80a84b
{
Packit Service 80a84b
	if (ed == NULL)
Packit Service 80a84b
		return;
Packit Service 80a84b
	(void) elf_end(ed->elf);
Packit Service 80a84b
	(void) close(ed->fd);
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
static void elf_for_each_global_sym(struct elf_data *ed,
Packit Service 80a84b
				    void (*fn)(const char *name,
Packit Service 80a84b
					       uint64_t value,
Packit Service 80a84b
					       int binding,
Packit Service 80a84b
					       void *ctx),
Packit Service 80a84b
				    void *ctx)
Packit Service 80a84b
{
Packit Service 80a84b
	const Elf64_Sym *end;
Packit Service 80a84b
	Elf64_Sym *sym;
Packit Service 80a84b
	int binding;
Packit Service 80a84b
	const char *name;
Packit Service 80a84b
	const char *data;
Packit Service 80a84b
	size_t size;
Packit Service 80a84b
Packit Service 80a84b
	if (elf_get_section(ed->elf, ed->shstrndx, SYMTAB, &data, &size) < 0)
Packit Service 80a84b
		return;
Packit Service 80a84b
Packit Service 80a84b
	sym = (Elf64_Sym *)data;
Packit Service 80a84b
	end = (Elf64_Sym *)(data + size);
Packit Service 80a84b
Packit Service 80a84b
	sym++; /* skip first zero record */
Packit Service 80a84b
	for (; sym < end; sym++) {
Packit Service 80a84b
Packit Service 80a84b
		binding = ELF64_ST_BIND(sym->st_info);
Packit Service 80a84b
		if (!(binding == STB_GLOBAL ||
Packit Service 80a84b
		       binding == STB_WEAK))
Packit Service 80a84b
			continue;
Packit Service 80a84b
Packit Service 80a84b
		if (sym->st_name == 0)
Packit Service 80a84b
			continue;
Packit Service 80a84b
Packit Service 80a84b
		if (sym->st_name > ed->strtab_size)
Packit Service 80a84b
			fail("Symbol name index %d out of range %ld\n",
Packit Service 80a84b
			    sym->st_name, ed->strtab_size);
Packit Service 80a84b
Packit Service 80a84b
		name = ed->strtab + sym->st_name;
Packit Service 80a84b
		if (name == NULL)
Packit Service 80a84b
			fail("Could not find symbol name\n");
Packit Service 80a84b
Packit Service 80a84b
		fn(name, sym->st_value, binding, ctx);
Packit Service 80a84b
	}
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
void ksymtab_ksym_mark(struct ksym *ksym)
Packit Service 80a84b
{
Packit Service 80a84b
	if (!ksym->mark)
Packit Service 80a84b
		ksym->ksymtab->mark_count++;
Packit Service 80a84b
	ksym->mark = true;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
static void ksymtab_ksym_free(void *arg)
Packit Service 80a84b
{
Packit Service 80a84b
	struct ksym *ksym = arg;
Packit Service 80a84b
Packit Service 80a84b
	free(ksym->link);
Packit Service 80a84b
	free(ksym);
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
void ksymtab_free(struct ksymtab *ksymtab)
Packit Service 80a84b
{
Packit Service 80a84b
	struct hash *h;
Packit Service 80a84b
Packit Service 80a84b
	if (ksymtab == NULL)
Packit Service 80a84b
		return;
Packit Service 80a84b
Packit Service 80a84b
	h = ksymtab->hash;
Packit Service 80a84b
Packit Service 80a84b
	hash_free(h);
Packit Service 80a84b
	free(ksymtab);
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
struct ksymtab *ksymtab_new(size_t size)
Packit Service 80a84b
{
Packit Service 80a84b
	struct hash *h;
Packit Service 80a84b
	struct ksymtab *ksymtab;
Packit Service 80a84b
Packit Service 80a84b
	h = hash_new(size, ksymtab_ksym_free);
Packit Service 80a84b
	assert(h != NULL);
Packit Service 80a84b
Packit Service 80a84b
	ksymtab = safe_zmalloc(sizeof(*ksymtab));
Packit Service 80a84b
	ksymtab->hash = h;
Packit Service 80a84b
	/* ksymtab->mark_count is zeroed by the allocator */
Packit Service 80a84b
Packit Service 80a84b
	return ksymtab;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
struct ksym *ksymtab_add_sym(struct ksymtab *ksymtab,
Packit Service 80a84b
			     const char *str,
Packit Service 80a84b
			     size_t len,
Packit Service 80a84b
			     uint64_t value)
Packit Service 80a84b
{
Packit Service 80a84b
	struct hash *h = ksymtab->hash;
Packit Service 80a84b
	struct ksym *ksym;
Packit Service 80a84b
Packit Service 80a84b
	ksym = safe_zmalloc(sizeof(*ksym) + len + 1);
Packit Service 80a84b
	memcpy(ksym->key, str, len);
Packit Service 80a84b
	ksym->key[len] = '\0';
Packit Service 80a84b
	ksym->value = value;
Packit Service 80a84b
	ksym->ksymtab = ksymtab;
Packit Service 80a84b
	/* ksym->link is zeroed by the allocator */
Packit Service 80a84b
	hash_add(h, ksym->key, ksym);
Packit Service 80a84b
Packit Service 80a84b
	return ksym;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
struct ksym *ksymtab_copy_sym(struct ksymtab *ksymtab, struct ksym *ksym)
Packit Service 80a84b
{
Packit Service 80a84b
	const char *name = ksymtab_ksym_get_name(ksym);
Packit Service 80a84b
	uint64_t value = ksymtab_ksym_get_value(ksym);
Packit Service 80a84b
	char *link = ksymtab_ksym_get_link(ksym);
Packit Service 80a84b
	struct ksym *new;
Packit Service 80a84b
Packit Service 80a84b
	new = ksymtab_add_sym(ksymtab, name, strlen(name), value);
Packit Service 80a84b
	ksymtab_ksym_set_link(new, link);
Packit Service 80a84b
Packit Service 80a84b
	return new;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
struct ksym *ksymtab_find(struct ksymtab *ksymtab, const char *name)
Packit Service 80a84b
{
Packit Service 80a84b
	struct ksym *v;
Packit Service 80a84b
	struct hash *h = ksymtab->hash;
Packit Service 80a84b
Packit Service 80a84b
	if (name == NULL)
Packit Service 80a84b
		return NULL;
Packit Service 80a84b
Packit Service 80a84b
	v = hash_find(h, name);
Packit Service 80a84b
	if (v == NULL)
Packit Service 80a84b
		return NULL;
Packit Service 80a84b
Packit Service 80a84b
	return v;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
size_t ksymtab_len(struct ksymtab *ksymtab)
Packit Service 80a84b
{
Packit Service 80a84b
	struct hash *h;
Packit Service 80a84b
Packit Service 80a84b
	if (ksymtab == NULL)
Packit Service 80a84b
		return 0;
Packit Service 80a84b
Packit Service 80a84b
	h = ksymtab->hash;
Packit Service 80a84b
	return hash_get_count(h);
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
size_t ksymtab_mark_count(struct ksymtab *ksymtab)
Packit Service 80a84b
{
Packit Service 80a84b
	return ksymtab->mark_count;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
void ksymtab_for_each(struct ksymtab *ksymtab,
Packit Service 80a84b
		      void (*f)(struct ksym *, void *),
Packit Service 80a84b
		      void *ctx)
Packit Service 80a84b
{
Packit Service 80a84b
	struct hash *h;
Packit Service 80a84b
	struct hash_iter iter;
Packit Service 80a84b
	const void *v;
Packit Service 80a84b
	struct ksym *vv;
Packit Service 80a84b
Packit Service 80a84b
	if (ksymtab == NULL)
Packit Service 80a84b
		return;
Packit Service 80a84b
Packit Service 80a84b
	h = ksymtab->hash;
Packit Service 80a84b
Packit Service 80a84b
	hash_iter_init(h, &iter);
Packit Service 80a84b
	while (hash_iter_next(&iter, NULL, &v)) {
Packit Service 80a84b
		vv = (struct ksym *)v;
Packit Service 80a84b
		f(vv, ctx);
Packit Service 80a84b
	}
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
/* Parses raw content of  __ksymtab_strings section to a ksymtab */
Packit Service 80a84b
static struct ksymtab *parse_ksymtab_strings(const char *d_buf, size_t d_size)
Packit Service 80a84b
{
Packit Service 80a84b
	char *p, *oldp;
Packit Service 80a84b
	size_t size = 0;
Packit Service 80a84b
	size_t i = 0;
Packit Service 80a84b
	struct ksymtab *res;
Packit Service 80a84b
Packit Service 80a84b
	res = ksymtab_new(KSYMTAB_SIZE);
Packit Service 80a84b
Packit Service 80a84b
	p = oldp = (char *)d_buf;
Packit Service 80a84b
Packit Service 80a84b
	/* Make sure we have the final '\0' */
Packit Service 80a84b
	if (p[d_size - 1] != '\0')
Packit Service 80a84b
		fail("Mallformed " KSYMTAB_STRINGS " section: %s\n", p);
Packit Service 80a84b
Packit Service 80a84b
	for (size = 0; size < d_size; size++, p++) {
Packit Service 80a84b
		/* End of symbol? */
Packit Service 80a84b
		if (*p == '\0') {
Packit Service 80a84b
			size_t len = p - oldp;
Packit Service 80a84b
Packit Service 80a84b
			/* Skip empty strings */
Packit Service 80a84b
			if (len == 0) {
Packit Service 80a84b
				oldp = p + 1;
Packit Service 80a84b
				continue;
Packit Service 80a84b
			}
Packit Service 80a84b
Packit Service 80a84b
			ksymtab_add_sym(res, oldp, len, i);
Packit Service 80a84b
			i++;
Packit Service 80a84b
			oldp = p + 1;
Packit Service 80a84b
		}
Packit Service 80a84b
	}
Packit Service 80a84b
Packit Service 80a84b
	return res;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
/*
Packit Service 80a84b
 * An entry for address -> symbol mapping.
Packit Service 80a84b
 * The key will be "value".
Packit Service 80a84b
 * We can use name pointer directly from the elf,
Packit Service 80a84b
 * it will be freed later.
Packit Service 80a84b
 */
Packit Service 80a84b
struct map_entry {
Packit Service 80a84b
	uint64_t value;
Packit Service 80a84b
	const char *name;
Packit Service 80a84b
};
Packit Service 80a84b
Packit Service 80a84b
static struct map_entry *map_entry_new(uint64_t value, const char *name)
Packit Service 80a84b
{
Packit Service 80a84b
	struct map_entry *res;
Packit Service 80a84b
Packit Service 80a84b
	res = safe_zmalloc(sizeof(*res));
Packit Service 80a84b
	res->value = value;
Packit Service 80a84b
	res->name = name;
Packit Service 80a84b
Packit Service 80a84b
	return res;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
struct weak_filter_ctx {
Packit Service 80a84b
	struct ksymtab *ksymtab;
Packit Service 80a84b
	struct ksymtab *weaks;
Packit Service 80a84b
	struct hash *map;
Packit Service 80a84b
};
Packit Service 80a84b
Packit Service 80a84b
/*
Packit Service 80a84b
 * Does two things in one pass on the symbol table:
Packit Service 80a84b
 * 1) makes address -> symbol map for GLOBAL symbols;
Packit Service 80a84b
 * 2) collecs subset of EXPORTed symbol, which have WEAK binding.
Packit Service 80a84b
 */
Packit Service 80a84b
static void weak_filter(const char *name, uint64_t value, int bind, void *_ctx)
Packit Service 80a84b
{
Packit Service 80a84b
	struct weak_filter_ctx *ctx = _ctx;
Packit Service 80a84b
	struct map_entry *m;
Packit Service 80a84b
	struct ksym *ksym;
Packit Service 80a84b
Packit Service 80a84b
	if (bind == STB_GLOBAL) {
Packit Service 80a84b
		m = map_entry_new(value, name);
Packit Service 80a84b
		hash_add_bin(ctx->map,
Packit Service 80a84b
			     (const char *)&m->value, sizeof(m->value), m);
Packit Service 80a84b
		return;
Packit Service 80a84b
	}
Packit Service 80a84b
Packit Service 80a84b
	/* WEAK handling */
Packit Service 80a84b
Packit Service 80a84b
	ksym = ksymtab_find(ctx->ksymtab, name);
Packit Service 80a84b
	if (ksym == NULL)
Packit Service 80a84b
		/* skip non-exported aliases */
Packit Service 80a84b
		return;
Packit Service 80a84b
Packit Service 80a84b
	ksymtab_add_sym(ctx->weaks, name, strlen(name), value);
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
struct weak_to_alias_ctx {
Packit Service 80a84b
	struct ksymtab *aliases;
Packit Service 80a84b
	struct hash *map;
Packit Service 80a84b
};
Packit Service 80a84b
Packit Service 80a84b
static void weak_to_alias(struct ksym *ksym, void *_ctx)
Packit Service 80a84b
{
Packit Service 80a84b
	struct weak_to_alias_ctx *ctx = _ctx;
Packit Service 80a84b
	struct map_entry *m;
Packit Service 80a84b
	uint64_t value = ksymtab_ksym_get_value(ksym);
Packit Service 80a84b
	const char *name = ksymtab_ksym_get_name(ksym);
Packit Service 80a84b
	struct ksym *alias;
Packit Service 80a84b
Packit Service 80a84b
	m = hash_find_bin(ctx->map, (const char *)&value, sizeof(value));
Packit Service 80a84b
	if (m == NULL)
Packit Service 80a84b
		/* there is no GLOBAL alias for the WEAK exported symbol */
Packit Service 80a84b
		return;
Packit Service 80a84b
Packit Service 80a84b
	alias = ksymtab_add_sym(ctx->aliases, m->name, strlen(m->name), 0);
Packit Service 80a84b
	ksymtab_ksym_set_link(alias, name);
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
static struct ksymtab *ksymtab_weaks_to_aliases(struct ksymtab *weaks,
Packit Service 80a84b
						struct hash *map)
Packit Service 80a84b
{
Packit Service 80a84b
	struct ksymtab *aliases;
Packit Service 80a84b
	struct weak_to_alias_ctx ctx;
Packit Service 80a84b
Packit Service 80a84b
	aliases = ksymtab_new(KSYMTAB_SIZE);
Packit Service 80a84b
	if (aliases == NULL)
Packit Service 80a84b
		fail("Cannot create ksymtab\n");
Packit Service 80a84b
Packit Service 80a84b
	ctx.aliases = aliases;
Packit Service 80a84b
	ctx.map = map;
Packit Service 80a84b
Packit Service 80a84b
	ksymtab_for_each(weaks, weak_to_alias, &ctx;;
Packit Service 80a84b
Packit Service 80a84b
	return aliases;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
/*
Packit Service 80a84b
 * Generate weak aliases for the symbols, found in the list of exported.
Packit Service 80a84b
 * It will work correctly for one alias only.
Packit Service 80a84b
 */
Packit Service 80a84b
static struct ksymtab *ksymtab_find_aliases(struct ksymtab *ksymtab,
Packit Service 80a84b
					    struct elf_data *elf)
Packit Service 80a84b
{
Packit Service 80a84b
	struct ksymtab *aliases;
Packit Service 80a84b
	struct ksymtab *weaks;
Packit Service 80a84b
	struct hash *map; /* address to name mapping */
Packit Service 80a84b
	struct weak_filter_ctx ctx;
Packit Service 80a84b
Packit Service 80a84b
	weaks = ksymtab_new(KSYMTAB_SIZE);
Packit Service 80a84b
	if (weaks == NULL)
Packit Service 80a84b
		fail("Cannot create weaks symtab\n");
Packit Service 80a84b
Packit Service 80a84b
	map = hash_new(KSYMTAB_SIZE, free);
Packit Service 80a84b
	if (map == NULL)
Packit Service 80a84b
		fail("Cannot create address->symbol mapping hash\n");
Packit Service 80a84b
Packit Service 80a84b
	ctx.ksymtab = ksymtab;
Packit Service 80a84b
	ctx.weaks = weaks;
Packit Service 80a84b
	ctx.map = map;
Packit Service 80a84b
	/*
Packit Service 80a84b
	 * If there's a weak symbol on the whitelist,
Packit Service 80a84b
	 * we need to find the proper global
Packit Service 80a84b
	 * symbol to generate the type for it.
Packit Service 80a84b
	 *
Packit Service 80a84b
	 * It is done in two steps below:
Packit Service 80a84b
	 * 1) create address -> global symbol mapping and
Packit Service 80a84b
	 *    suitable weak symbol list;
Packit Service 80a84b
	 * 2) for all weak symbols find its alias with the mapping.
Packit Service 80a84b
	 */
Packit Service 80a84b
	elf_for_each_global_sym(elf, weak_filter, &ctx;;
Packit Service 80a84b
	aliases = ksymtab_weaks_to_aliases(weaks, map);
Packit Service 80a84b
Packit Service 80a84b
	hash_free(map);
Packit Service 80a84b
	ksymtab_free(weaks);
Packit Service 80a84b
Packit Service 80a84b
	return aliases;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
int elf_get_endianness(struct elf_data *data, unsigned int *endianness)
Packit Service 80a84b
{
Packit Service 80a84b
	if (data->ehdr->e_ident[EI_DATA] != ELFDATA2LSB &&
Packit Service 80a84b
	     data->ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
Packit Service 80a84b
		printf("Unsupported ELF endianness (EI_DATA) found: %d.\n",
Packit Service 80a84b
		     data->ehdr->e_ident[EI_DATA]);
Packit Service 80a84b
		return 1;
Packit Service 80a84b
	}
Packit Service 80a84b
Packit Service 80a84b
	*endianness = data->ehdr->e_ident[EI_DATA];
Packit Service 80a84b
	return 0;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
static inline int elf_get_strtab(struct elf_data *data)
Packit Service 80a84b
{
Packit Service 80a84b
	const char *strtab;
Packit Service 80a84b
	size_t strtab_size;
Packit Service 80a84b
Packit Service 80a84b
	if (elf_get_section(data->elf, data->shstrndx, STRTAB, &strtab,
Packit Service 80a84b
			   &strtab_size) < 0) {
Packit Service 80a84b
		return 1;
Packit Service 80a84b
	}
Packit Service 80a84b
Packit Service 80a84b
	data->strtab = strtab;
Packit Service 80a84b
	data->strtab_size = strtab_size;
Packit Service 80a84b
Packit Service 80a84b
	return 0;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
/*
Packit Service 80a84b
 * Build list of exported symbols, ie. read seciton __ksymtab_strings,
Packit Service 80a84b
 * analyze symbol table and create table of aliases -- list of global symbols,
Packit Service 80a84b
 * which have the same addresses, as weak symbols,
Packit Service 80a84b
 * mentioned by __ksymtab_strings
Packit Service 80a84b
 */
Packit Service 80a84b
int elf_get_exported(struct elf_data *data, struct ksymtab **ksymtab,
Packit Service 80a84b
		     struct ksymtab **aliases)
Packit Service 80a84b
{
Packit Service 80a84b
	const char *ksymtab_raw;
Packit Service 80a84b
	size_t ksymtab_sz;
Packit Service 80a84b
Packit Service 80a84b
	if (elf_get_strtab(data) > 0)
Packit Service 80a84b
		return 1;
Packit Service 80a84b
Packit Service 80a84b
	if (elf_get_section(data->elf, data->shstrndx, KSYMTAB_STRINGS,
Packit Service 80a84b
			   &ksymtab_raw, &ksymtab_sz) < 0)
Packit Service 80a84b
		return 1;
Packit Service 80a84b
Packit Service 80a84b
	*ksymtab = parse_ksymtab_strings(ksymtab_raw, ksymtab_sz);
Packit Service 80a84b
	*aliases = ksymtab_find_aliases(*ksymtab, data);
Packit Service 80a84b
Packit Service 80a84b
	return 0;
Packit Service 80a84b
}
Packit Service 80a84b
Packit Service 80a84b
Packit Service 80a84b