Change unnecessary list_for_each_entry_safe to list_for_each_entry.
[ksplice.git] / kmodsrc / helper.c
blob2fe29e3cc6fc8870b73ebef99e104ec10e2b02c3
1 /* Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License, version 2.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
14 * 02110-1301, USA.
17 #include "modcommon.h"
18 #include "helper.h"
19 #include "jumps.h"
20 #include "nops.h"
21 #include <linux/kthread.h>
23 /* defined by modcommon.c */
24 extern int debug;
26 /* defined by ksplice-create */
27 extern struct ksplice_size ksplice_sizes;
29 #undef max
30 #define max(a, b) ((a) > (b) ? (a) : (b))
32 int
33 init_module(void)
35 printk("ksplice_h: Preparing and checking %s\n", ksplice_name);
37 if (ksplice_do_helper() != 0)
38 return -1;
40 if (ksplice_do_primary() != 0)
41 return -1;
43 return 0;
46 void
47 cleanup_module(void)
49 /* These pointers should always be NULL when no helper module is loaded */
50 release_list((struct starts_with_next *) reloc_namevals);
51 release_list((struct starts_with_next *) reloc_addrmaps);
52 release_list((struct starts_with_next *) safety_records);
55 int
56 ksplice_do_helper(void)
58 struct ksplice_size *s;
59 int i, record_count = 0, ret;
60 char *finished;
61 int numfinished, oldfinished = 0;
62 int restart_count = 0, stage = 1;
64 if (process_ksplice_relocs(1) != 0)
65 return -1;
67 for (s = &ksplice_sizes; s->name != NULL; s++) {
68 record_count++;
71 /* old kernels do not have kcalloc */
72 finished = ksplice_kcalloc(record_count);
74 start:
75 for (s = &ksplice_sizes, i = 0; s->name != NULL; s++, i++) {
76 if (s->size == 0)
77 finished[i] = 1;
78 if (finished[i])
79 continue;
81 ret = search_for_match(s, &stage);
82 if (ret < 0) {
83 kfree(finished);
84 return ret;
85 } else if (ret == 0) {
86 finished[i] = 1;
90 numfinished = 0;
91 for (i = 0; i < record_count; i++) {
92 if (finished[i])
93 numfinished++;
95 if (numfinished == record_count) {
96 kfree(finished);
97 return 0;
100 if (oldfinished == numfinished) {
101 if (stage < 3) {
102 stage++;
103 goto start;
105 print_abort("run-pre: could not match some sections");
106 kfree(finished);
107 return -1;
109 oldfinished = numfinished;
111 if (restart_count < 20) {
112 restart_count++;
113 goto start;
115 print_abort("run-pre: restart limit exceeded");
116 kfree(finished);
117 return -1;
120 /* old kernels do not have kcalloc */
121 void *
122 ksplice_kcalloc(int size)
124 char *mem = kmalloc(size, GFP_KERNEL);
125 int i;
126 for (i = 0; i < size; i++) {
127 mem[i] = 0;
129 return mem;
133 search_for_match(struct ksplice_size *s, int *stage)
135 int i, saved_debug;
136 long run_addr;
137 struct ansglob *glob = NULL, *g;
139 for (i = 0; i < s->num_sym_addrs; i++) {
140 add2glob(&glob, s->sym_addrs[i]);
143 compute_address(s->name, &glob);
144 if (*stage <= 1 && !singular(glob)) {
145 release(&glob);
146 return 1;
149 if (debug >= 3) {
150 printk("ksplice_h: run-pre: starting sect search for %s\n",
151 s->name);
154 for (g = glob; g != NULL; g = g->next) {
155 run_addr = g->val;
157 yield();
158 if (try_addr(s, run_addr, s->thismod_addr, !singular(glob))) {
159 release(&glob);
160 return 0;
163 release(&glob);
165 if (*stage <= 2)
166 return 1;
168 saved_debug = debug;
169 debug = 0;
170 brute_search_all_mods(s);
171 debug = saved_debug;
172 return 1;
176 try_addr(struct ksplice_size *s, long run_addr, long pre_addr,
177 int create_nameval)
179 struct safety_record *tmp;
181 if (run_pre_cmp(run_addr, pre_addr, s->size, 0) != 0) {
182 set_temp_myst_relocs(NOVAL);
183 if (debug >= 1) {
184 printk("ksplice_h: run-pre: sect %s does not match ",
185 s->name);
186 printk("(r_a=%08lx p_a=%08lx s=%ld)\n",
187 run_addr, pre_addr, s->size);
188 printk("ksplice_h: run-pre: ");
189 run_pre_cmp(run_addr, pre_addr, s->size, 1);
190 printk("\n");
192 } else {
193 set_temp_myst_relocs(VAL);
195 if (debug >= 3) {
196 printk("ksplice_h: run-pre: found sect %s=%08lx\n",
197 s->name, run_addr);
200 tmp = kmalloc(sizeof (*tmp), GFP_KERNEL);
201 tmp->addr = run_addr;
202 tmp->size = s->size;
203 tmp->next = safety_records;
204 tmp->care = 0;
205 safety_records = tmp;
207 if (create_nameval) {
208 struct reloc_nameval *nv = find_nameval(s->name, 1);
209 nv->val = run_addr;
210 nv->status = VAL;
213 return 1;
215 return 0;
219 run_pre_cmp(long run_addr, long pre_addr, int size, int rerun)
221 int run_o, pre_o, lenient = 0, prev_c3 = 0, recent_5b = 0;
222 unsigned char run, pre;
223 struct reloc_addrmap *map;
225 if (size == 0)
226 return 1;
228 for (run_o = 0, pre_o = 0; run_o < size && pre_o < size;
229 pre_o++, run_o++) {
230 if (lenient > 0)
231 lenient--;
232 if (prev_c3 > 0)
233 prev_c3--;
234 if (recent_5b > 0)
235 recent_5b--;
237 if (!virtual_address_mapped(run_addr + run_o))
238 return 1;
239 run = *(unsigned char *) (run_addr + run_o);
240 pre = *(unsigned char *) (pre_addr + pre_o);
242 if (rerun)
243 printk("%02x/%02x ", run, pre);
245 if (run == pre) {
246 if ((map = find_addrmap(pre_addr + pre_o)) != NULL) {
247 if (handle_myst_reloc
248 (pre_addr, &pre_o, run_addr, &run_o,
249 map, rerun) == 1)
250 return 1;
251 continue;
253 if (pre == 0xc3)
254 prev_c3 = 1 + 1;
255 if (pre == 0x5b)
256 recent_5b = 10 + 1;
257 if (jumplen[pre])
258 lenient = max(jumplen[pre] + 1, lenient);
259 if (match_nop(run_addr, &run_o, &pre_o) ||
260 match_nop(pre_addr, &pre_o, &run_o))
261 continue;
262 continue;
265 if ((map = find_addrmap(pre_addr + pre_o)) != NULL) {
266 if (handle_myst_reloc
267 (pre_addr, &pre_o, run_addr, &run_o, map,
268 rerun) == 1)
269 return 1;
270 continue;
272 if (prev_c3 && recent_5b)
273 return 0;
274 if (match_nop(run_addr, &run_o, &pre_o) ||
275 match_nop(pre_addr, &pre_o, &run_o))
276 continue;
277 if (jumplen[run] && jumplen[pre]) {
278 run_o += jumplen[run];
279 pre_o += jumplen[pre];
280 continue;
282 if (lenient)
283 continue;
284 if (rerun) {
285 printk("[p_o=%08x] ! %02x/%02x %02x/%02x",
286 pre_o,
287 *(unsigned char *) (run_addr + run_o + 1),
288 *(unsigned char *) (pre_addr + pre_o + 1),
289 *(unsigned char *) (run_addr + run_o + 2),
290 *(unsigned char *) (pre_addr + pre_o + 2));
292 return 1;
294 return 0;
298 handle_myst_reloc(long pre_addr, int *pre_o, long run_addr,
299 int *run_o, struct reloc_addrmap *map, int rerun)
301 int expected;
302 int offset = (int) (pre_addr + *pre_o - map->addr);
303 int run_reloc = *(int *) (run_addr + *run_o - offset);
305 if (debug >= 3 && !rerun) {
306 printk("ksplice_h: run-pre: reloc at r_a=%08lx p_o=%08x: ",
307 run_addr, *pre_o);
308 printk("%s=%08lx (A=%08lx *r=%08x)\n",
309 map->nameval->name, map->nameval->val,
310 map->addend, run_reloc);
313 if (!starts_with(map->nameval->name, ".rodata.str")) {
314 expected = run_reloc - map->addend;
315 if (run_reloc == 0x77777777)
316 return 1;
317 if (map->flags & PCREL)
318 expected += run_addr + *run_o - offset;
319 if (map->nameval->status == NOVAL) {
320 map->nameval->val = expected;
321 map->nameval->status = TEMP;
322 } else if (map->nameval->val != expected) {
323 if (rerun)
324 return 1;
325 printk("ksplice_h: pre-run reloc: Expected %s=%08x!\n",
326 map->nameval->name, expected);
327 return 1;
331 *pre_o += 4 - offset - 1;
332 *run_o += 4 - offset - 1;
333 return 0;
336 /* TODO: The recommended way to pad 64bit code is to use NOPs preceded by
337 maximally four 0x66 prefixes. */
339 match_nop(long addr, int *o, int *other_o)
341 int i, j;
342 for (i = NUM_NOPS - 1; i >= 0; i--) {
343 for (j = 0; j < i + 1; j++) {
344 if (!virtual_address_mapped(addr + *o + j))
345 break;
346 if (*(unsigned char *) (addr + *o + j) != nops[i][j])
347 break;
349 if (j == i + 1) {
350 *o += i;
351 (*other_o)--;
352 return 1;
356 return 0;
359 void
360 brute_search_all_mods(struct ksplice_size *s)
362 struct module *m;
363 list_for_each_entry(m, &(THIS_MODULE->list), list) {
364 if (!starts_with(m->name, ksplice_name)
365 && !ends_with(m->name, "_helper")) {
366 if (brute_search(s, m->module_core, m->core_size) == 0)
367 return;
368 if (brute_search(s, m->module_init, m->init_size) == 0)
369 return;