82 lines
		
	
	
	
		
			2.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			82 lines
		
	
	
	
		
			2.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#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 */
							 |