Remove unused str2addr function.
[ksplice.git] / kmodsrc / modcommon.c
blobe16c352ed7cb2f967c23ea824dbac9dacec67c28
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 <linux/kallsyms.h>
19 #include <linux/stop_machine.h>
21 #ifdef CONFIG_KALLSYMS
22 static const int CONFIG_KALLSYMS_VAL = 1;
23 extern unsigned long kallsyms_addresses[], kallsyms_num_syms;
24 extern u8 kallsyms_names[];
25 #else
26 static const int CONFIG_KALLSYMS_VAL = 0;
27 #endif
29 /* defined by ksplice-create */
30 extern struct ksplice_reloc ksplice_init_relocs, ksplice_relocs;
32 static int safe = 0, helper = 0;
33 int debug;
34 module_param(debug, int, 0600);
36 int process_ksplice_relocs(int caller_is_helper)
38 struct ksplice_reloc *r;
39 helper = caller_is_helper;
40 for (r = &ksplice_init_relocs; r->sym_name != NULL; r++) {
41 if (process_reloc(r) != 0)
42 return -1;
44 safe = 1;
45 for (r = &ksplice_relocs; r->sym_name != NULL; r++) {
46 if (process_reloc(r) != 0)
47 return -1;
49 return 0;
52 int process_reloc(struct ksplice_reloc *r)
54 int i;
55 long sym_addr;
56 struct reloc_addrmap *map;
58 #define blank_addr (r->blank_sect_addr+r->blank_offset)
60 LIST_HEAD(vals);
61 if (CONFIG_KALLSYMS_VAL || !safe) {
62 for (i = 0; i < r->num_sym_addrs; i++) {
63 int adjustment = (long)printk - map_printk;
64 if (adjustment & 0xfffff) {
65 print_abort("System.map does not match kernel");
66 return -1;
68 add_candidate_val(&vals, r->sym_addrs[i] + adjustment);
72 if (*(int *)blank_addr == 0x77777777) {
73 r->flags |= SAFE;
75 if (!(r->flags & SAFE)) {
76 if (debug >= 4) {
77 printk
78 ("ksplice%s: reloc: skipped %s:%08lx (altinstr)\n",
79 (helper ? "_h" : ""), r->sym_name,
80 r->blank_offset);
82 release_vals(&vals);
83 return 0;
86 compute_address(r->sym_name, &vals);
87 if (!singular(&vals)) {
88 release_vals(&vals);
89 if (!(helper && safe)) {
90 failed_to_find(r->sym_name);
91 return -1;
94 if (debug >= 4) {
95 printk("ksplice: reloc: deferred %s:%08lx to run-pre\n",
96 r->sym_name, r->blank_offset);
99 map = kmalloc(sizeof(*map), GFP_KERNEL);
100 map->addr = blank_addr;
101 map->nameval = find_nameval(r->sym_name, 1);
102 map->addend = r->addend;
103 map->flags = r->flags;
104 list_add(&map->list, &reloc_addrmaps);
105 return 0;
107 sym_addr = list_entry(vals.next, struct candidate_val, list)->val;
108 release_vals(&vals);
110 if (debug >= 4) {
111 printk("ksplice%s: reloc: %s:%08lx ",
112 (helper ? "_h" : ""), r->sym_name, r->blank_offset);
113 printk("(S=%08lx A=%08lx ", sym_addr, r->addend);
116 if ((r->flags & PCREL) && (helper && safe)) {
117 map = kmalloc(sizeof(*map), GFP_KERNEL);
118 map->addr = blank_addr;
119 map->nameval = find_nameval("ksplice_zero", 1);
120 map->nameval->val = 0;
121 map->nameval->status = VAL;
122 map->addend = sym_addr + r->addend;
123 map->flags = r->flags;
124 list_add(&map->list, &reloc_addrmaps);
126 } else if ((r->flags & PCREL) && !(helper && safe)) {
127 *(int *)blank_addr =
128 sym_addr + r->addend - (unsigned long)blank_addr;
129 } else {
130 *(int *)blank_addr = sym_addr + r->addend;
132 if (debug >= 4)
133 printk("aft=%08x)\n", *(int *)blank_addr);
134 return 0;
137 void compute_address(char *sym_name, struct list_head *vals)
139 int i, have_added_val = 0;
140 const char *prefix[] = { ".text.", ".bss.", ".data.", NULL };
142 if (!safe)
143 return;
145 if (!(helper && safe)) {
146 struct reloc_nameval *nv = find_nameval(sym_name, 0);
147 if (nv != NULL && nv->status != NOVAL) {
148 if (!have_added_val)
149 release_vals(vals);
150 have_added_val = 1;
151 add_candidate_val(vals, nv->val);
153 if (debug >= 1) {
154 printk("ksplice: using detected sym %s=%08lx\n",
155 sym_name, nv->val);
159 if (have_added_val)
160 return;
162 #ifdef CONFIG_KALLSYMS
163 kernel_lookup(sym_name, vals);
164 other_module_lookup(sym_name, vals);
165 #endif
167 for (i = 0; prefix[i] != NULL; i++) {
168 if (starts_with(sym_name, prefix[i])) {
169 compute_address(sym_name + strlen(prefix[i]), vals);
174 #ifdef CONFIG_KALLSYMS
175 /* Modified version of Linux's kallsyms_lookup_name */
176 void kernel_lookup(const char *name_wlabel, struct list_head *vals)
178 char namebuf[KSYM_NAME_LEN + 1];
179 unsigned long i;
180 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
181 unsigned long off;
182 #endif
184 const char *name = dup_wolabel(name_wlabel);
186 /* kallsyms compression was added by 5648d78927ca65e74aadc88a2b1d6431e55e78ec
187 * 2.6.10 was the first release after this commit
189 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
190 for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
191 off = ksplice_kallsyms_expand_symbol(off, namebuf);
193 if (strcmp(namebuf, name) == 0) {
194 add_candidate_val(vals, kallsyms_addresses[i]);
197 #else
198 char *knames;
200 for (i = 0, knames = kallsyms_names; i < kallsyms_num_syms; i++) {
201 unsigned prefix = *knames++;
203 strlcpy(namebuf + prefix, knames, KSYM_NAME_LEN - prefix);
205 if (strcmp(namebuf, name) == 0) {
206 add_candidate_val(vals, kallsyms_addresses[i]);
209 knames += strlen(knames) + 1;
211 #endif
213 kfree(name);
216 /* kallsyms compression was added by 5648d78927ca65e74aadc88a2b1d6431e55e78ec
217 * 2.6.10 was the first release after this commit
219 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
220 extern u8 kallsyms_token_table[];
221 extern u16 kallsyms_token_index[];
222 /* Modified version of Linux's kallsyms_expand_symbol */
223 long ksplice_kallsyms_expand_symbol(unsigned long off, char *result)
225 long len, skipped_first = 0;
226 const u8 *tptr, *data;
228 data = &kallsyms_names[off];
229 len = *data;
230 data++;
232 off += len + 1;
234 while (len) {
235 tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
236 data++;
237 len--;
239 while (*tptr) {
240 if (skipped_first) {
241 *result = *tptr;
242 result++;
243 } else
244 skipped_first = 1;
245 tptr++;
249 *result = '\0';
251 return off;
253 #endif /* LINUX_VERSION_CODE */
255 void this_module_lookup(const char *name, struct list_head *vals)
257 ksplice_mod_find_sym(THIS_MODULE, name, vals);
258 if (list_empty(vals) && starts_with(name, ".text.")) {
259 ksplice_mod_find_sym(THIS_MODULE, name + strlen(".text."),
260 vals);
264 void other_module_lookup(const char *name_wlabel, struct list_head *vals)
266 struct module *m;
267 const char *name = dup_wolabel(name_wlabel);
269 list_for_each_entry(m, &(THIS_MODULE->list), list) {
270 if (!starts_with(m->name, ksplice_name)
271 && !ends_with(m->name, "_helper")) {
272 ksplice_mod_find_sym(m, name, vals);
276 kfree(name);
279 /* Modified version of Linux's mod_find_symname */
280 void
281 ksplice_mod_find_sym(struct module *m, const char *name, struct list_head *vals)
283 int i;
284 if (strlen(m->name) <= 1)
285 return;
287 for (i = 0; i < m->num_symtab; i++) {
288 const char *cursym_name = m->strtab + m->symtab[i].st_name;
289 if (strncmp(cursym_name, name, strlen(name)) != 0)
290 continue;
292 cursym_name = dup_wolabel(cursym_name);
293 if (strcmp(cursym_name, name) == 0 &&
294 m->symtab[i].st_value != 0) {
296 add_candidate_val(vals, m->symtab[i].st_value);
298 kfree(cursym_name);
301 #endif /* CONFIG_KALLSYMS */
303 void add_candidate_val(struct list_head *vals, long val)
305 struct candidate_val *tmp, *new;
307 list_for_each_entry(tmp, vals, list) {
308 if (tmp->val == val)
309 return;
311 new = kmalloc(sizeof(*new), GFP_KERNEL);
312 new->val = val;
313 list_add(&new->list, vals);
316 void release_vals(struct list_head *vals)
318 clear_list(vals, struct candidate_val, list);
321 struct reloc_nameval *find_nameval(char *name, int create)
323 struct list_head *pos;
324 struct reloc_nameval *nv, *new;
325 char *newname;
326 list_for_each(pos, &reloc_namevals) {
327 nv = list_entry(pos, struct reloc_nameval, list);
328 newname = nv->name;
329 if (starts_with(newname, ".text.")) {
330 newname += 6;
332 if (strcmp(newname, name) == 0) {
333 return nv;
336 if (!create)
337 return NULL;
339 new = kmalloc(sizeof(*new), GFP_KERNEL);
340 new->name = name;
341 new->val = 0;
342 new->status = NOVAL;
343 list_add(&new->list, &reloc_namevals);
344 return new;
347 struct reloc_addrmap *find_addrmap(long addr)
349 struct list_head *pos;
350 struct reloc_addrmap *map;
351 list_for_each(pos, &reloc_addrmaps) {
352 map = list_entry(pos, struct reloc_addrmap, list);
353 if (addr >= map->addr && addr <= map->addr + 3) {
354 return map;
357 return NULL;
360 void set_temp_myst_relocs(int status_val)
362 struct list_head *pos;
363 struct reloc_nameval *nv;
364 list_for_each(pos, &reloc_namevals) {
365 nv = list_entry(pos, struct reloc_nameval, list);
366 if (nv->status == TEMP) {
367 nv->status = status_val;