Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e1926e7 authored by Catalin Marinas's avatar Catalin Marinas Committed by Russell King
Browse files

[ARM] 5384/1: unwind: Add stack unwinding support for loadable modules



This patch adds ELF section parsing for the unwinding tables in loadable
modules together with the PREL31 relocation symbol resolving.

Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent bff595c1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ typedef struct user_fp elf_fpregset_t;
#define R_ARM_ABS32	2
#define R_ARM_CALL	28
#define R_ARM_JUMP24	29
#define R_ARM_PREL31	42

/*
 * These are used to set parameters in the core dumps.
+17 −5
Original line number Diff line number Diff line
#ifndef _ASM_ARM_MODULE_H
#define _ASM_ARM_MODULE_H

struct mod_arch_specific
{
	int foo;
};

#define Elf_Shdr	Elf32_Shdr
#define Elf_Sym		Elf32_Sym
#define Elf_Ehdr	Elf32_Ehdr

struct unwind_table;

struct mod_arch_specific
{
#ifdef CONFIG_ARM_UNWIND
	Elf_Shdr *unw_sec_init;
	Elf_Shdr *unw_sec_devinit;
	Elf_Shdr *unw_sec_core;
	Elf_Shdr *sec_init_text;
	Elf_Shdr *sec_devinit_text;
	Elf_Shdr *sec_core_text;
	struct unwind_table *unwind_init;
	struct unwind_table *unwind_devinit;
	struct unwind_table *unwind_core;
#endif
};

/*
 * Include the ARM architecture version.
 */
+64 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include <asm/pgtable.h>
#include <asm/sections.h>
#include <asm/unwind.h>

#ifdef CONFIG_XIP_KERNEL
/*
@@ -66,6 +67,24 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
			      char *secstrings,
			      struct module *mod)
{
#ifdef CONFIG_ARM_UNWIND
	Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;

	for (s = sechdrs; s < sechdrs_end; s++) {
		if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0)
			mod->arch.unw_sec_init = s;
		else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0)
			mod->arch.unw_sec_devinit = s;
		else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0)
			mod->arch.unw_sec_core = s;
		else if (strcmp(".init.text", secstrings + s->sh_name) == 0)
			mod->arch.sec_init_text = s;
		else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0)
			mod->arch.sec_devinit_text = s;
		else if (strcmp(".text", secstrings + s->sh_name) == 0)
			mod->arch.sec_core_text = s;
	}
#endif
	return 0;
}

@@ -104,6 +123,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
		loc = dstsec->sh_addr + rel->r_offset;

		switch (ELF32_R_TYPE(rel->r_info)) {
		case R_ARM_NONE:
			/* ignore */
			break;

		case R_ARM_ABS32:
			*(u32 *)loc += sym->st_value;
			break;
@@ -132,6 +155,11 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
			*(u32 *)loc |= offset & 0x00ffffff;
			break;

		case R_ARM_PREL31:
			offset = *(u32 *)loc + sym->st_value - loc;
			*(u32 *)loc = offset & 0x7fffffff;
			break;

		default:
			printk(KERN_ERR "%s: unknown relocation: %u\n",
			       module->name, ELF32_R_TYPE(rel->r_info));
@@ -150,14 +178,50 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
	return -ENOEXEC;
}

#ifdef CONFIG_ARM_UNWIND
static void register_unwind_tables(struct module *mod)
{
	if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
		mod->arch.unwind_init =
			unwind_table_add(mod->arch.unw_sec_init->sh_addr,
					 mod->arch.unw_sec_init->sh_size,
					 mod->arch.sec_init_text->sh_addr,
					 mod->arch.sec_init_text->sh_size);
	if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
		mod->arch.unwind_devinit =
			unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
					 mod->arch.unw_sec_devinit->sh_size,
					 mod->arch.sec_devinit_text->sh_addr,
					 mod->arch.sec_devinit_text->sh_size);
	if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
		mod->arch.unwind_core =
			unwind_table_add(mod->arch.unw_sec_core->sh_addr,
					 mod->arch.unw_sec_core->sh_size,
					 mod->arch.sec_core_text->sh_addr,
					 mod->arch.sec_core_text->sh_size);
}

static void unregister_unwind_tables(struct module *mod)
{
	unwind_table_del(mod->arch.unwind_init);
	unwind_table_del(mod->arch.unwind_devinit);
	unwind_table_del(mod->arch.unwind_core);
}
#else
static inline void register_unwind_tables(struct module *mod) { }
static inline void unregister_unwind_tables(struct module *mod) { }
#endif

int
module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
		struct module *module)
{
	register_unwind_tables(module);
	return 0;
}

void
module_arch_cleanup(struct module *mod)
{
	unregister_unwind_tables(mod);
}