]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/sparc/mm/extable.c | |
3 | */ | |
4 | ||
1da177e4 | 5 | #include <linux/module.h> |
5437344c | 6 | #include <linux/extable.h> |
7c0f6ba6 | 7 | #include <linux/uaccess.h> |
1da177e4 LT |
8 | |
9 | void sort_extable(struct exception_table_entry *start, | |
10 | struct exception_table_entry *finish) | |
11 | { | |
12 | } | |
13 | ||
14 | /* Caller knows they are in a range if ret->fixup == 0 */ | |
15 | const struct exception_table_entry * | |
16 | search_extable(const struct exception_table_entry *start, | |
17 | const struct exception_table_entry *last, | |
18 | unsigned long value) | |
19 | { | |
20 | const struct exception_table_entry *walk; | |
21 | ||
22 | /* Single insn entries are encoded as: | |
23 | * word 1: insn address | |
24 | * word 2: fixup code address | |
25 | * | |
26 | * Range entries are encoded as: | |
27 | * word 1: first insn address | |
28 | * word 2: 0 | |
29 | * word 3: last insn address + 4 bytes | |
30 | * word 4: fixup code address | |
31 | * | |
ad6561df RR |
32 | * Deleted entries are encoded as: |
33 | * word 1: unused | |
34 | * word 2: -1 | |
35 | * | |
1da177e4 LT |
36 | * See asm/uaccess.h for more details. |
37 | */ | |
38 | ||
39 | /* 1. Try to find an exact match. */ | |
40 | for (walk = start; walk <= last; walk++) { | |
41 | if (walk->fixup == 0) { | |
42 | /* A range entry, skip both parts. */ | |
43 | walk++; | |
44 | continue; | |
45 | } | |
46 | ||
ad6561df RR |
47 | /* A deleted entry; see trim_init_extable */ |
48 | if (walk->fixup == -1) | |
49 | continue; | |
50 | ||
1da177e4 LT |
51 | if (walk->insn == value) |
52 | return walk; | |
53 | } | |
54 | ||
55 | /* 2. Try to find a range match. */ | |
56 | for (walk = start; walk <= (last - 1); walk++) { | |
57 | if (walk->fixup) | |
58 | continue; | |
59 | ||
60 | if (walk[0].insn <= value && walk[1].insn > value) | |
61 | return walk; | |
62 | ||
63 | walk++; | |
64 | } | |
65 | ||
66 | return NULL; | |
67 | } | |
68 | ||
ad6561df RR |
69 | #ifdef CONFIG_MODULES |
70 | /* We could memmove them around; easier to mark the trimmed ones. */ | |
71 | void trim_init_extable(struct module *m) | |
72 | { | |
73 | unsigned int i; | |
74 | bool range; | |
75 | ||
76 | for (i = 0; i < m->num_exentries; i += range ? 2 : 1) { | |
77 | range = m->extable[i].fixup == 0; | |
78 | ||
79 | if (within_module_init(m->extable[i].insn, m)) { | |
80 | m->extable[i].fixup = -1; | |
81 | if (range) | |
82 | m->extable[i+1].fixup = -1; | |
83 | } | |
84 | if (range) | |
85 | i++; | |
86 | } | |
87 | } | |
88 | #endif /* CONFIG_MODULES */ | |
89 | ||
1da177e4 LT |
90 | /* Special extable search, which handles ranges. Returns fixup */ |
91 | unsigned long search_extables_range(unsigned long addr, unsigned long *g2) | |
92 | { | |
93 | const struct exception_table_entry *entry; | |
94 | ||
95 | entry = search_exception_tables(addr); | |
96 | if (!entry) | |
97 | return 0; | |
98 | ||
99 | /* Inside range? Fix g2 and return correct fixup */ | |
100 | if (!entry->fixup) { | |
101 | *g2 = (addr - entry->insn) / 4; | |
102 | return (entry + 1)->fixup; | |
103 | } | |
104 | ||
105 | return entry->fixup; | |
106 | } |