Blame ksymtab.c

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