Blame kpatch-build/create-klp-module.c

Packit c71e3f
/*
Packit c71e3f
 * create-klp-module.c
Packit c71e3f
 *
Packit c71e3f
 * This program is free software; you can redistribute it and/or
Packit c71e3f
 * modify it under the terms of the GNU General Public License
Packit c71e3f
 * as published by the Free Software Foundation; either version 2
Packit c71e3f
 * of the License, or (at your option) any later version.
Packit c71e3f
 *
Packit c71e3f
 * This program is distributed in the hope that it will be useful,
Packit c71e3f
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit c71e3f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit c71e3f
 * GNU General Public License for more details.
Packit c71e3f
 *
Packit c71e3f
 * You should have received a copy of the GNU General Public License
Packit c71e3f
 * along with this program; if not, write to the Free Software
Packit c71e3f
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA,
Packit c71e3f
 * 02110-1301, USA.
Packit c71e3f
 */
Packit c71e3f
Packit c71e3f
#include <string.h>
Packit c71e3f
#include <stdlib.h>
Packit c71e3f
#include <libgen.h>
Packit c71e3f
#include <argp.h>
Packit c71e3f
Packit c71e3f
#include "log.h"
Packit c71e3f
#include "kpatch-elf.h"
Packit c71e3f
#include "kpatch-intermediate.h"
Packit c71e3f
Packit c71e3f
/* For log.h */
Packit c71e3f
char *childobj;
Packit c71e3f
enum loglevel loglevel = NORMAL;
Packit c71e3f
Packit c71e3f
/*
Packit c71e3f
 * Add a symbol from .kpatch.symbols to the symbol table
Packit c71e3f
 *
Packit c71e3f
 * If a symbol matching the .kpatch.symbols entry already
Packit c71e3f
 * exists, return it.
Packit c71e3f
 */
Packit c71e3f
static struct symbol *find_or_add_ksym_to_symbols(struct kpatch_elf *kelf,
Packit c71e3f
						  struct section *ksymsec,
Packit c71e3f
						  char *strings, int offset)
Packit c71e3f
{
Packit c71e3f
	struct kpatch_symbol *ksyms, *ksym;
Packit c71e3f
	struct symbol *sym;
Packit c71e3f
	struct rela *rela;
Packit c71e3f
	char *objname, *name;
Packit c71e3f
	char pos[32], buf[256];
Packit c71e3f
	int index;
Packit c71e3f
Packit c71e3f
	ksyms = ksymsec->data->d_buf;
Packit c71e3f
	index = offset / sizeof(*ksyms);
Packit c71e3f
	ksym = &ksyms[index];
Packit c71e3f
Packit c71e3f
	/* Get name of ksym */
Packit c71e3f
	rela = find_rela_by_offset(ksymsec->rela,
Packit c71e3f
				   offset + offsetof(struct kpatch_symbol, name));
Packit c71e3f
	if (!rela)
Packit c71e3f
		ERROR("name of ksym not found?");
Packit c71e3f
Packit c71e3f
	name = strdup(strings + rela->addend);
Packit c71e3f
	if (!name)
Packit c71e3f
		ERROR("strdup");
Packit c71e3f
Packit c71e3f
	/* Get objname of ksym */
Packit c71e3f
	rela = find_rela_by_offset(ksymsec->rela,
Packit c71e3f
				   offset + offsetof(struct kpatch_symbol, objname));
Packit c71e3f
	if (!rela)
Packit c71e3f
		ERROR("objname of ksym not found?");
Packit c71e3f
Packit c71e3f
	objname = strdup(strings + rela->addend);
Packit c71e3f
	if (!objname)
Packit c71e3f
		ERROR("strdup");
Packit c71e3f
Packit c71e3f
	snprintf(pos, 32, "%lu", ksym->pos);
Packit c71e3f
	/* .klp.sym.objname.name,pos */
Packit c71e3f
	snprintf(buf, 256, KLP_SYM_PREFIX "%s.%s,%s", objname, name, pos);
Packit c71e3f
Packit c71e3f
	/* Look for an already allocated symbol */
Packit c71e3f
	list_for_each_entry(sym, &kelf->symbols, list) {
Packit c71e3f
		if (!strcmp(buf, sym->name))
Packit c71e3f
			return sym;
Packit c71e3f
	}
Packit c71e3f
Packit c71e3f
	ALLOC_LINK(sym, NULL);
Packit c71e3f
	sym->name = strdup(buf);
Packit c71e3f
	if (!sym->name)
Packit c71e3f
		ERROR("strdup");
Packit c71e3f
	sym->type = ksym->type;
Packit c71e3f
	sym->bind = ksym->bind;
Packit c71e3f
	/*
Packit c71e3f
	 * Note that st_name will be set in kpatch_create_strtab(),
Packit c71e3f
	 * and sym->index is set in kpatch_reindex_elements()
Packit c71e3f
	 */
Packit c71e3f
	sym->sym.st_shndx = SHN_LIVEPATCH;
Packit c71e3f
	sym->sym.st_info = GELF_ST_INFO(sym->bind, sym->type);
Packit c71e3f
	/*
Packit c71e3f
	 * Figure out where to put the new symbol:
Packit c71e3f
	 *   a) locals need to be grouped together, before globals
Packit c71e3f
	 *   b) globals can be tacked into the end of the list
Packit c71e3f
	 */
Packit c71e3f
	if (is_local_sym(sym)) {
Packit c71e3f
		struct list_head *head;
Packit c71e3f
		struct symbol *s;
Packit c71e3f
Packit c71e3f
		head = &kelf->symbols;
Packit c71e3f
		list_for_each_entry(s, &kelf->symbols, list) {
Packit c71e3f
			if (!is_local_sym(s))
Packit c71e3f
				break;
Packit c71e3f
			head = &s->list;
Packit c71e3f
		}
Packit c71e3f
		list_add_tail(&sym->list, head);
Packit c71e3f
	} else {
Packit c71e3f
		list_add_tail(&sym->list, &kelf->symbols);
Packit c71e3f
	}
Packit c71e3f
Packit c71e3f
	return sym;
Packit c71e3f
}
Packit c71e3f
Packit c71e3f
/*
Packit c71e3f
 * Create a klp rela section given the base section and objname
Packit c71e3f
 *
Packit c71e3f
 * If a klp rela section matching the base section and objname
Packit c71e3f
 * already exists, return it.
Packit c71e3f
 */
Packit c71e3f
static struct section *find_or_add_klp_relasec(struct kpatch_elf *kelf,
Packit c71e3f
					       struct section *base,
Packit c71e3f
					       char *objname)
Packit c71e3f
{
Packit c71e3f
	struct section  *sec;
Packit c71e3f
	char buf[256];
Packit c71e3f
Packit c71e3f
	/* .klp.rela.objname.secname */
Packit c71e3f
	snprintf(buf, 256, KLP_RELASEC_PREFIX "%s.%s", objname, base->name);
Packit c71e3f
Packit c71e3f
	list_for_each_entry(sec, &kelf->sections, list) {
Packit c71e3f
		if (!strcmp(sec->name, buf))
Packit c71e3f
			return sec;
Packit c71e3f
	}
Packit c71e3f
Packit c71e3f
	ALLOC_LINK(sec, &kelf->sections);
Packit c71e3f
	sec->name = strdup(buf);
Packit c71e3f
	if (!sec->name)
Packit c71e3f
		ERROR("strdup");
Packit c71e3f
	sec->base = base;
Packit c71e3f
Packit c71e3f
	INIT_LIST_HEAD(&sec->relas);
Packit c71e3f
Packit c71e3f
	sec->data = malloc(sizeof(*sec->data));
Packit c71e3f
	if (!sec->data)
Packit c71e3f
		ERROR("malloc");
Packit c71e3f
	sec->data->d_type = ELF_T_RELA;
Packit c71e3f
Packit c71e3f
	/* sh_info and sh_link are set when rebuilding rela sections */
Packit c71e3f
	sec->sh.sh_type = SHT_RELA;
Packit c71e3f
	sec->sh.sh_entsize = sizeof(GElf_Rela);
Packit c71e3f
	sec->sh.sh_addralign = 8;
Packit c71e3f
	sec->sh.sh_flags = SHF_RELA_LIVEPATCH | SHF_INFO_LINK | SHF_ALLOC;
Packit c71e3f
Packit c71e3f
	return sec;
Packit c71e3f
}
Packit c71e3f
Packit c71e3f
/*
Packit c71e3f
 * Create klp relocation sections and klp symbols from .kpatch.relocations
Packit c71e3f
 * and .kpatch.symbols sections
Packit c71e3f
 *
Packit c71e3f
 * For every entry in .kpatch.relocations:
Packit c71e3f
 *   1) Allocate a symbol for the corresponding .kpatch.symbols entry if
Packit c71e3f
 *      it doesn't already exist (find_or_add_ksym_to_symbols())
Packit c71e3f
 *      This is the symbol that the relocation points to (rela->sym)
Packit c71e3f
 *   2) Allocate a rela, and add it to the corresponding .klp.rela. section. If
Packit c71e3f
 *      the matching .klp.rela. section (given the base section and objname)
Packit c71e3f
 *      doesn't exist yet, create it (find_or_add_klp_relasec())
Packit c71e3f
 */
Packit c71e3f
static void create_klp_relasecs_and_syms(struct kpatch_elf *kelf, struct section *krelasec,
Packit c71e3f
					 struct section *ksymsec, char *strings)
Packit c71e3f
{
Packit c71e3f
	struct section *klp_relasec;
Packit c71e3f
	struct kpatch_relocation *krelas;
Packit c71e3f
	struct symbol *sym, *dest;
Packit c71e3f
	struct rela *rela;
Packit c71e3f
	char *objname;
Packit c71e3f
	int nr, index, offset, dest_off;
Packit c71e3f
Packit c71e3f
	krelas = krelasec->data->d_buf;
Packit c71e3f
	nr = krelasec->data->d_size / sizeof(*krelas);
Packit c71e3f
Packit c71e3f
	for (index = 0; index < nr; index++) {
Packit c71e3f
		offset = index * sizeof(*krelas);
Packit c71e3f
Packit c71e3f
		/* Get the rela dest sym + offset */
Packit c71e3f
		rela = find_rela_by_offset(krelasec->rela,
Packit c71e3f
					   offset + offsetof(struct kpatch_relocation, dest));
Packit c71e3f
		if (!rela)
Packit c71e3f
			ERROR("find_rela_by_offset");
Packit c71e3f
Packit c71e3f
		dest = rela->sym;
Packit c71e3f
		dest_off = rela->addend;
Packit c71e3f
Packit c71e3f
		/* Get the name of the object the dest belongs to */
Packit c71e3f
		rela = find_rela_by_offset(krelasec->rela,
Packit c71e3f
					   offset + offsetof(struct kpatch_relocation, objname));
Packit c71e3f
		if (!rela)
Packit c71e3f
			ERROR("find_rela_by_offset");
Packit c71e3f
Packit c71e3f
		objname = strdup(strings + rela->addend);
Packit c71e3f
		if (!objname)
Packit c71e3f
			ERROR("strdup");
Packit c71e3f
Packit c71e3f
		/* Get the .kpatch.symbol entry for the rela src */
Packit c71e3f
		rela = find_rela_by_offset(krelasec->rela,
Packit c71e3f
					   offset + offsetof(struct kpatch_relocation, ksym));
Packit c71e3f
		if (!rela)
Packit c71e3f
			ERROR("find_rela_by_offset");
Packit c71e3f
Packit c71e3f
		/* Create (or find) a klp symbol from the rela src entry */
Packit c71e3f
		sym = find_or_add_ksym_to_symbols(kelf, ksymsec, strings, rela->addend);
Packit c71e3f
		if (!sym)
Packit c71e3f
			ERROR("error finding or adding ksym to symtab");
Packit c71e3f
Packit c71e3f
		/* Create (or find) the .klp.rela. section for the dest sec and object */
Packit c71e3f
		klp_relasec = find_or_add_klp_relasec(kelf, dest->sec, objname);
Packit c71e3f
		if (!klp_relasec)
Packit c71e3f
			ERROR("error finding or adding klp relasec");
Packit c71e3f
Packit c71e3f
		/* Add the klp rela to the .klp.rela. section */
Packit c71e3f
		ALLOC_LINK(rela, &klp_relasec->relas);
Packit c71e3f
		rela->offset = dest->sym.st_value + dest_off;
Packit c71e3f
		rela->type = krelas[index].type;
Packit c71e3f
		rela->sym = sym;
Packit c71e3f
		rela->addend = krelas[index].addend;
Packit c71e3f
	}
Packit c71e3f
}
Packit c71e3f
Packit c71e3f
/*
Packit c71e3f
 * Create .klp.arch. sections by iterating through the .kpatch.arch section
Packit c71e3f
 *
Packit c71e3f
 * A .kpatch.arch section is just an array of kpatch_arch structs:
Packit c71e3f
 *
Packit c71e3f
 * struct kpatch_arch {
Packit c71e3f
 *   unsigned long sec;
Packit c71e3f
 *   char *objname;
Packit c71e3f
 * };
Packit c71e3f
 *
Packit c71e3f
 * There are two relas associated with each kpatch arch entry, one that points
Packit c71e3f
 * to the section of interest (.parainstructions or .altinstructions), and one
Packit c71e3f
 * rela points to the name of the object the section belongs to in
Packit c71e3f
 * .kpatch.strings. This gives us the necessary information to create .klp.arch
Packit c71e3f
 * sections, which use the '.klp.arch.objname.secname' name format.
Packit c71e3f
 */
Packit c71e3f
static void create_klp_arch_sections(struct kpatch_elf *kelf, char *strings)
Packit c71e3f
{
Packit c71e3f
	struct section *karch, *sec, *base = NULL;
Packit c71e3f
	struct kpatch_arch *entries;
Packit c71e3f
	struct rela *rela, *rela2;
Packit c71e3f
	char *secname, *objname = NULL;
Packit c71e3f
	char buf[256];
Packit c71e3f
	int nr, index, offset, old_size, new_size;
Packit c71e3f
Packit c71e3f
	karch = find_section_by_name(&kelf->sections, ".kpatch.arch");
Packit c71e3f
	if (!karch)
Packit c71e3f
		return;
Packit c71e3f
Packit c71e3f
	entries = karch->data->d_buf;
Packit c71e3f
	nr = karch->data->d_size / sizeof(*entries);
Packit c71e3f
Packit c71e3f
	for (index = 0; index < nr; index++) {
Packit c71e3f
		offset = index * sizeof(*entries);
Packit c71e3f
Packit c71e3f
		/* Get the base section (.parainstructions or .altinstructions) */
Packit c71e3f
		rela = find_rela_by_offset(karch->rela,
Packit c71e3f
					   offset + offsetof(struct kpatch_arch, sec));
Packit c71e3f
		if (!rela)
Packit c71e3f
			ERROR("find_rela_by_offset");
Packit c71e3f
Packit c71e3f
		base = rela->sym->sec;
Packit c71e3f
		if (!base)
Packit c71e3f
			ERROR("base sec of kpatch_arch entry not found");
Packit c71e3f
Packit c71e3f
		/* Get the name of the object the base section belongs to */
Packit c71e3f
		rela = find_rela_by_offset(karch->rela,
Packit c71e3f
					   offset + offsetof(struct kpatch_arch, objname));
Packit c71e3f
		if (!rela)
Packit c71e3f
			ERROR("find_rela_by_offset");
Packit c71e3f
Packit c71e3f
		objname = strdup(strings + rela->addend);
Packit c71e3f
		if (!objname)
Packit c71e3f
			ERROR("strdup");
Packit c71e3f
Packit c71e3f
		/* Example: .klp.arch.vmlinux..parainstructions */
Packit c71e3f
		snprintf(buf, 256, "%s%s.%s", KLP_ARCH_PREFIX, objname, base->name);
Packit c71e3f
Packit c71e3f
		/* Check if the .klp.arch. section already exists */
Packit c71e3f
		sec = find_section_by_name(&kelf->sections, buf);
Packit c71e3f
		if (!sec) {
Packit c71e3f
			secname = strdup(buf);
Packit c71e3f
			if (!secname)
Packit c71e3f
				ERROR("strdup");
Packit c71e3f
Packit c71e3f
			/* Start with a new section with size 0 first */
Packit c71e3f
			sec = create_section_pair(kelf, secname, 1, 0);
Packit c71e3f
		}
Packit c71e3f
Packit c71e3f
		/*
Packit c71e3f
		 * Merge .klp.arch. sections if necessary
Packit c71e3f
		 *
Packit c71e3f
		 * Example:
Packit c71e3f
		 * If there are multiple .parainstructions sections for vmlinux
Packit c71e3f
		 * (this can happen when, using the --unique option for ld,
Packit c71e3f
		 * we've linked together multiple .o's with .parainstructions
Packit c71e3f
		 * sections for the same object), they will be merged under a
Packit c71e3f
		 * single .klp.arch.vmlinux..parainstructions section
Packit c71e3f
		 */
Packit c71e3f
		old_size = sec->data->d_size;
Packit c71e3f
Packit c71e3f
		/*
Packit c71e3f
		 * Due to a quirk in how .parainstructions gets linked, the
Packit c71e3f
		 * section size doesn't encompass the last 4 bytes of the last
Packit c71e3f
		 * entry.  Align the old size properly before merging.
Packit c71e3f
		 */
Packit c71e3f
		if (!strcmp(base->name, ".parainstructions")) {
Packit c71e3f
			char *str;
Packit c71e3f
			static int align_mask = 0;
Packit c71e3f
Packit c71e3f
			if (!align_mask) {
Packit c71e3f
				str = getenv("PARA_STRUCT_SIZE");
Packit c71e3f
				if (!str)
Packit c71e3f
					ERROR("PARA_STRUCT_SIZE not set");
Packit c71e3f
Packit c71e3f
				align_mask = atoi(str) - 1;
Packit c71e3f
			}
Packit c71e3f
Packit c71e3f
			old_size = (old_size + align_mask) & ~align_mask;
Packit c71e3f
		}
Packit c71e3f
Packit c71e3f
		new_size = old_size + base->data->d_size;
Packit c71e3f
		sec->data->d_buf = realloc(sec->data->d_buf, new_size);
Packit c71e3f
		sec->data->d_size = new_size;
Packit c71e3f
		sec->sh.sh_size = sec->data->d_size;
Packit c71e3f
		memcpy(sec->data->d_buf + old_size,
Packit c71e3f
		       base->data->d_buf, base->data->d_size);
Packit c71e3f
Packit c71e3f
		list_for_each_entry(rela, &base->rela->relas, list) {
Packit c71e3f
			ALLOC_LINK(rela2, &sec->rela->relas);
Packit c71e3f
			rela2->sym = rela->sym;
Packit c71e3f
			rela2->type = rela->type;
Packit c71e3f
			rela2->addend = rela->addend;
Packit c71e3f
			rela2->offset = old_size + rela->offset;
Packit c71e3f
		}
Packit c71e3f
	}
Packit c71e3f
}
Packit c71e3f
Packit c71e3f
/*
Packit c71e3f
 * We can't keep these sections since the module loader will apply them before
Packit c71e3f
 * the patch module gets a chance to load (that's why we copied these sections
Packit c71e3f
 * into .klp.arch. sections. Hence we remove them here.
Packit c71e3f
 */
Packit c71e3f
static void remove_arch_sections(struct kpatch_elf *kelf)
Packit c71e3f
{
Packit c71e3f
	size_t i;
Packit c71e3f
	char *arch_sections[] = {
Packit c71e3f
		".parainstructions",
Packit c71e3f
		".rela.parainstructions",
Packit c71e3f
		".altinstructions",
Packit c71e3f
		".rela.altinstructions"
Packit c71e3f
	};
Packit c71e3f
Packit c71e3f
	for (i = 0; i < sizeof(arch_sections)/sizeof(arch_sections[0]); i++)
Packit c71e3f
		kpatch_remove_and_free_section(kelf, arch_sections[i]);
Packit c71e3f
Packit c71e3f
}
Packit c71e3f
Packit c71e3f
static void remove_intermediate_sections(struct kpatch_elf *kelf)
Packit c71e3f
{
Packit c71e3f
	size_t i;
Packit c71e3f
	char *intermediate_sections[] = {
Packit c71e3f
		".kpatch.symbols",
Packit c71e3f
		".rela.kpatch.symbols",
Packit c71e3f
		".kpatch.relocations",
Packit c71e3f
		".rela.kpatch.relocations",
Packit c71e3f
		".kpatch.arch",
Packit c71e3f
		".rela.kpatch.arch"
Packit c71e3f
	};
Packit c71e3f
Packit c71e3f
	for (i = 0; i < sizeof(intermediate_sections)/sizeof(intermediate_sections[0]); i++)
Packit c71e3f
		kpatch_remove_and_free_section(kelf, intermediate_sections[i]);
Packit c71e3f
}
Packit c71e3f
Packit c71e3f
struct arguments {
Packit c71e3f
	char *args[2];
Packit c71e3f
	int debug;
Packit c71e3f
	int no_klp_arch;
Packit c71e3f
};
Packit c71e3f
Packit c71e3f
static char args_doc[] = "input.ko output.ko";
Packit c71e3f
Packit c71e3f
static struct argp_option options[] = {
Packit c71e3f
	{"debug", 'd', 0, 0, "Show debug output" },
Packit c71e3f
	{"no-klp-arch-sections", 'n', 0, 0, "Do not output .klp.arch.* sections" },
Packit c71e3f
	{ 0 }
Packit c71e3f
};
Packit c71e3f
Packit c71e3f
static error_t parse_opt (int key, char *arg, struct argp_state *state)
Packit c71e3f
{
Packit c71e3f
	/* Get the input argument from argp_parse, which we
Packit c71e3f
	   know is a pointer to our arguments structure. */
Packit c71e3f
	struct arguments *arguments = state->input;
Packit c71e3f
Packit c71e3f
	switch (key)
Packit c71e3f
	{
Packit c71e3f
		case 'd':
Packit c71e3f
			arguments->debug = 1;
Packit c71e3f
			break;
Packit c71e3f
		case 'n':
Packit c71e3f
			arguments->no_klp_arch = 1;
Packit c71e3f
			break;
Packit c71e3f
		case ARGP_KEY_ARG:
Packit c71e3f
			if (state->arg_num >= 2)
Packit c71e3f
				/* Too many arguments. */
Packit c71e3f
				argp_usage (state);
Packit c71e3f
			arguments->args[state->arg_num] = arg;
Packit c71e3f
			break;
Packit c71e3f
		case ARGP_KEY_END:
Packit c71e3f
			if (state->arg_num < 2)
Packit c71e3f
				/* Not enough arguments. */
Packit c71e3f
				argp_usage (state);
Packit c71e3f
			break;
Packit c71e3f
		default:
Packit c71e3f
			return ARGP_ERR_UNKNOWN;
Packit c71e3f
	}
Packit c71e3f
	return 0;
Packit c71e3f
}
Packit c71e3f
Packit c71e3f
static struct argp argp = { options, parse_opt, args_doc, 0 };
Packit c71e3f
Packit c71e3f
int main(int argc, char *argv[])
Packit c71e3f
{
Packit c71e3f
	struct kpatch_elf *kelf;
Packit c71e3f
	struct section *symtab, *sec;
Packit c71e3f
	struct section *ksymsec, *krelasec, *strsec;
Packit c71e3f
	struct arguments arguments;
Packit c71e3f
	char *strings;
Packit c71e3f
	int ksyms_nr, krelas_nr;
Packit c71e3f
Packit c71e3f
	memset(&arguments, 0, sizeof(arguments));
Packit c71e3f
	argp_parse (&argp, argc, argv, 0, 0, &arguments);
Packit c71e3f
	if (arguments.debug)
Packit c71e3f
		loglevel = DEBUG;
Packit c71e3f
Packit c71e3f
	elf_version(EV_CURRENT);
Packit c71e3f
Packit c71e3f
	childobj = basename(arguments.args[0]);
Packit c71e3f
Packit c71e3f
	kelf = kpatch_elf_open(arguments.args[0]);
Packit c71e3f
Packit c71e3f
	/*
Packit c71e3f
	 * Sanity checks:
Packit c71e3f
	 * - Make sure all the required sections exist
Packit c71e3f
	 * - Make sure that the number of entries in
Packit c71e3f
	 *   .kpatch.{symbols,relocations} match
Packit c71e3f
	 */
Packit c71e3f
	strsec = find_section_by_name(&kelf->sections, ".kpatch.strings");
Packit c71e3f
	if (!strsec)
Packit c71e3f
		ERROR("missing .kpatch.strings");
Packit c71e3f
	strings = strsec->data->d_buf;
Packit c71e3f
Packit c71e3f
	ksymsec = find_section_by_name(&kelf->sections, ".kpatch.symbols");
Packit c71e3f
	if (!ksymsec)
Packit c71e3f
		ERROR("missing .kpatch.symbols section");
Packit c71e3f
	ksyms_nr = ksymsec->data->d_size / sizeof(struct kpatch_symbol);
Packit c71e3f
Packit c71e3f
	krelasec = find_section_by_name(&kelf->sections, ".kpatch.relocations");
Packit c71e3f
	if (!krelasec)
Packit c71e3f
		ERROR("missing .kpatch.relocations section");
Packit c71e3f
	krelas_nr = krelasec->data->d_size / sizeof(struct kpatch_relocation);
Packit c71e3f
Packit c71e3f
	if (krelas_nr != ksyms_nr)
Packit c71e3f
		ERROR("number of krelas and ksyms do not match");
Packit c71e3f
Packit c71e3f
	/*
Packit c71e3f
	 * Create klp rela sections and klp symbols from
Packit c71e3f
	 * .kpatch.{relocations,symbols} sections
Packit c71e3f
	 */
Packit c71e3f
	create_klp_relasecs_and_syms(kelf, krelasec, ksymsec, strings);
Packit c71e3f
Packit c71e3f
	/*
Packit c71e3f
	 * If --no-klp-arch-sections wasn't set, additionally
Packit c71e3f
	 * create .klp.arch. sections
Packit c71e3f
	 */
Packit c71e3f
	if (!arguments.no_klp_arch) {
Packit c71e3f
		create_klp_arch_sections(kelf, strings);
Packit c71e3f
		remove_arch_sections(kelf);
Packit c71e3f
	}
Packit c71e3f
Packit c71e3f
	remove_intermediate_sections(kelf);
Packit c71e3f
	kpatch_reindex_elements(kelf);
Packit c71e3f
Packit c71e3f
	/* Rebuild rela sections, new klp rela sections will be rebuilt too. */
Packit c71e3f
	symtab = find_section_by_name(&kelf->sections, ".symtab");
Packit c71e3f
	list_for_each_entry(sec, &kelf->sections, list) {
Packit c71e3f
		if (!is_rela_section(sec))
Packit c71e3f
			continue;
Packit c71e3f
		sec->sh.sh_link = symtab->index;
Packit c71e3f
		sec->sh.sh_info = sec->base->index;
Packit c71e3f
		kpatch_rebuild_rela_section_data(sec);
Packit c71e3f
	}
Packit c71e3f
Packit c71e3f
	kpatch_create_shstrtab(kelf);
Packit c71e3f
	kpatch_create_strtab(kelf);
Packit c71e3f
	kpatch_create_symtab(kelf);
Packit c71e3f
Packit c71e3f
	kpatch_write_output_elf(kelf, kelf->elf, arguments.args[1]);
Packit c71e3f
	kpatch_elf_teardown(kelf);
Packit c71e3f
	kpatch_elf_free(kelf);
Packit c71e3f
Packit c71e3f
	return 0;
Packit c71e3f
}