Skip to content

Commit

Permalink
[ARM] 5384/1: unwind: Add stack unwinding support for loadable modules
Browse files Browse the repository at this point in the history
This patch adds ELF section parsing for the unwinding tables in loadable
modules together with the PREL31 relocation symbol resolving.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Catalin Marinas authored and Russell King committed Feb 19, 2009
1 parent bff595c commit 2e1926e
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 5 deletions.
1 change: 1 addition & 0 deletions arch/arm/include/asm/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
22 changes: 17 additions & 5 deletions arch/arm/include/asm/module.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
#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.
*/
Expand Down
64 changes: 64 additions & 0 deletions arch/arm/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

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

#ifdef CONFIG_XIP_KERNEL
/*
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand All @@ -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);
}

0 comments on commit 2e1926e

Please sign in to comment.