diff options
Diffstat (limited to 'arch/s390/mm/extable.c')
| -rw-r--r-- | arch/s390/mm/extable.c | 81 | 
1 files changed, 81 insertions, 0 deletions
diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c new file mode 100644 index 00000000000..4d1ee88864e --- /dev/null +++ b/arch/s390/mm/extable.c @@ -0,0 +1,81 @@ +#include <linux/module.h> +#include <linux/sort.h> +#include <asm/uaccess.h> + +/* + * Search one exception table for an entry corresponding to the + * given instruction address, and return the address of the entry, + * or NULL if none is found. + * We use a binary search, and thus we assume that the table is + * already sorted. + */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, +	       const struct exception_table_entry *last, +	       unsigned long value) +{ +	const struct exception_table_entry *mid; +	unsigned long addr; + +	while (first <= last) { +		mid = ((last - first) >> 1) + first; +		addr = extable_insn(mid); +		if (addr < value) +			first = mid + 1; +		else if (addr > value) +			last = mid - 1; +		else +			return mid; +	} +	return NULL; +} + +/* + * The exception table needs to be sorted so that the binary + * search that we use to find entries in it works properly. + * This is used both for the kernel exception table and for + * the exception tables of modules that get loaded. + * + */ +static int cmp_ex(const void *a, const void *b) +{ +	const struct exception_table_entry *x = a, *y = b; + +	/* This compare is only valid after normalization. */ +	return x->insn - y->insn; +} + +void sort_extable(struct exception_table_entry *start, +		  struct exception_table_entry *finish) +{ +	struct exception_table_entry *p; +	int i; + +	/* Normalize entries to being relative to the start of the section */ +	for (p = start, i = 0; p < finish; p++, i += 8) +		p->insn += i; +	sort(start, finish - start, sizeof(*start), cmp_ex, NULL); +	/* Denormalize all entries */ +	for (p = start, i = 0; p < finish; p++, i += 8) +		p->insn -= i; +} + +#ifdef CONFIG_MODULES +/* + * If the exception table is sorted, any referring to the module init + * will be at the beginning or the end. + */ +void trim_init_extable(struct module *m) +{ +	/* Trim the beginning */ +	while (m->num_exentries && +	       within_module_init(extable_insn(&m->extable[0]), m)) { +		m->extable++; +		m->num_exentries--; +	} +	/* Trim the end */ +	while (m->num_exentries && +	       within_module_init(extable_insn(&m->extable[m->num_exentries-1]), m)) +		m->num_exentries--; +} +#endif /* CONFIG_MODULES */  | 
