linux-config-h-died-20061109
[openafs.git] / src / afs / LINUX / osi_probe.c
1 /*
2  * vi:set cin noet sw=4 tw=70:
3  * Copyright 2004, International Business Machines Corporation and others.
4  * All Rights Reserved.
5  * 
6  * This software has been released under the terms of the IBM Public
7  * License.  For details, see the LICENSE file in the top-level source
8  * directory or online at http://www.openafs.org/dl/license10.html
9  *
10  * Portions of this code borrowed from arla under the following terms:
11  * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan
12  * (Royal Institute of Technology, Stockholm, Sweden).
13  * All rights reserved.
14  * 
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 
26  * 3. Neither the name of the Institute nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  * 
30  * Alternatively, this software may be distributed under the terms of the
31  * GNU General Public License ("GPL").
32  * 
33  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
37  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  */
45
46 /* Code to find the Linux syscall table */
47
48 #ifdef OSI_PROBE_STANDALONE
49 #define OSI_PROBE_DEBUG
50 #endif
51 #ifndef OSI_PROBE_STANDALONE
52 #include <afsconfig.h>
53 #include "afs/param.h"
54 #endif
55 #ifdef AFS_LINUX24_ENV
56 #include <linux/module.h> /* early to avoid printf->printk mapping */
57 #ifndef OSI_PROBE_STANDALONE
58 #include "afs/sysincludes.h"
59 #include "afsincludes.h"
60 #endif
61 #include <linux/version.h>
62 #ifdef CONFIG_H_EXISTS
63 #include <linux/config.h>
64 #endif
65 #include <linux/linkage.h>
66 #include <linux/init.h>
67 #include <linux/unistd.h>
68 #include <linux/mm.h>
69 #ifdef AFS_LINUX26_ENV
70 #include <scsi/scsi.h> /* for scsi_command_size */
71 #endif
72
73 #if defined(AFS_PPC64_LINUX26_ENV)
74 #include <asm/abs_addr.h>
75 #endif
76
77 #ifdef AFS_AMD64_LINUX20_ENV
78 #include <asm/ia32_unistd.h>
79 #endif
80
81 /* number of syscalls */
82 /* NB: on MIPS we care about the 4xxx range */
83 #ifndef NR_syscalls
84 #define NR_syscalls 222
85 #endif
86
87 /* lower bound of valid kernel text pointers */
88 #ifdef AFS_IA64_LINUX20_ENV
89 #define ktxt_lower_bound (((unsigned long)&kernel_thread )  & 0xfff00000L)
90 #elif defined(AFS_PPC64_LINUX20_ENV)
91 #define ktxt_lower_bound (KERNELBASE)
92 #else
93 #define ktxt_lower_bound (((unsigned long)&kernel_thread )  & ~0xfffffL)
94 #endif
95
96 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
97  * even though pointers are 64 bit quantities.
98  */
99 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
100 #define SYSCALLTYPE unsigned int
101 #define PROBETYPE int
102 #else
103 #define SYSCALLTYPE void *
104 #define PROBETYPE long
105 #endif
106
107 #if defined(AFS_S390X_LINUX20_ENV) && !defined(AFS_S390X_LINUX26_ENV) 
108 #define _SS(x) ((x) << 1)
109 #define _SX(x) ((x) &~ 1)
110 #else
111 #define _SS(x) (x)
112 #define _SX(x) (x)
113 #endif
114
115 /* Older Linux doesn't have __user. The sys_read prototype needs it. */
116 #ifndef __user
117 #define __user
118 #endif
119
120 /* Allow the user to specify sys_call_table addresses */
121 static unsigned long sys_call_table_addr[4] = { 0,0,0,0 };
122 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
123 module_param_array(sys_call_table_addr, long, NULL, 0);
124 #else
125 MODULE_PARM(sys_call_table_addr, "1-4l");
126 #endif
127 MODULE_PARM_DESC(sys_call_table_addr, "Location of system call tables");
128
129 /* If this is set, we are more careful about avoiding duplicate matches */
130 static int probe_carefully = 1;
131 #ifdef module_param
132 module_param(probe_carefully, int, 0);
133 #else
134 MODULE_PARM(probe_carefully, "i");
135 #endif
136 MODULE_PARM_DESC(probe_carefully, "Probe for system call tables carefully");
137
138 static int probe_ignore_syscalls[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
139 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
140 module_param_array(probe_ignore_syscalls, int, NULL, 0);
141 #else
142 MODULE_PARM(probe_ignore_syscalls, "1-8i");
143 #endif
144 MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
145
146 #ifdef OSI_PROBE_DEBUG
147 /* 
148  * Debugging flags:
149  * 0x0001 - General debugging
150  * 0x0002 - detail - try
151  * 0x0004 - detail - try_harder
152  * 0x0008 - detail - check_table
153  * 0x0010 - detail - check_harder
154  * 0x0020 - detail - check_harder/zapped
155  * 0x0040 - automatically ignore setgroups and afs_syscall
156  */
157 static int probe_debug = 0x41;
158 #ifdef module_param
159 module_param(probe_debug, int, 0);
160 #else
161 MODULE_PARM(probe_debug, "i");
162 #endif
163 MODULE_PARM_DESC(probe_debug, "Debugging level");
164
165 static unsigned long probe_debug_addr[4] = { 0,0,0,0 };
166 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
167 module_param_array(probe_debug_addr, long, NULL, 0);
168 #else
169 MODULE_PARM(probe_debug_addr, "1-4l");
170 #endif
171 MODULE_PARM_DESC(probe_debug_addr, "Debug range starting locations");
172
173 static unsigned long probe_debug_range = 0;
174 #ifdef module_param
175 module_param(probe_debug_range, long, 0);
176 #else
177 MODULE_PARM(probe_debug_range, "l");
178 #endif
179 MODULE_PARM_DESC(probe_debug_range, "Debug range length");
180
181 static unsigned long probe_debug_tag = 0;
182 #ifdef module_param
183 module_param(probe_debug_tag, long, 0);
184 #else
185 MODULE_PARM(probe_debug_tag, "l");
186 #endif
187 MODULE_PARM_DESC(probe_debug_tag, "Debugging output start tag");
188 #endif
189
190
191 /* Weak references are our friends.  They are supported by the in-kernel
192  * linker in Linux 2.6 and by all versions of modutils back to 2.2pre1.
193  * A weak reference not satisified by the kernel will have value zero.
194  *
195  * Unfortunately, weak references to functions don't work right on
196  * IA64; specifically, if you actually try to make a call through
197  * such a reference, and the symbol doesn't exist in the kernel, then
198  * the module relocation code will oops.  A workaround for this is
199  * probably possible, but the use of kallsyms_* is of limited value,
200  * so I'm not bothing with the effort for now.
201  * -- jhutz, 10-Feb-2005
202  */
203 #ifdef OSI_PROBE_KALLSYMS
204 extern int kallsyms_symbol_to_address(char *name, unsigned long *token,
205                                       char **mod_name,
206                                       unsigned long *mod_start,
207                                       unsigned long *mod_end,
208                                       char **sec_name,
209                                       unsigned long *sec_start,
210                                       unsigned long *sec_end,
211                                       char **sym_name,
212                                       unsigned long *sym_start,
213                                       unsigned long *sym_end
214                                      ) __attribute__((weak));
215
216 extern int kallsyms_address_to_symbol(unsigned long address,
217                                       char **mod_name,
218                                       unsigned long *mod_start,
219                                       unsigned long *mod_end,
220                                       char **sec_name,
221                                       unsigned long *sec_start,
222                                       unsigned long *sec_end,
223                                       char **sym_name,
224                                       unsigned long *sym_start,
225                                       unsigned long *sym_end
226                                      ) __attribute__((weak));
227 #endif
228
229 extern SYSCALLTYPE sys_call_table[] __attribute__((weak));
230 extern SYSCALLTYPE ia32_sys_call_table[] __attribute__((weak));
231 extern SYSCALLTYPE sys_call_table32[] __attribute__((weak));
232 extern SYSCALLTYPE sys_call_table_emu[] __attribute__((weak));
233
234 extern asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) __attribute__((weak));
235 extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
236 #if defined(EXPORTED_SYS_CHDIR)
237 extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
238 #endif
239 extern asmlinkage ssize_t sys_write(unsigned int, const char *, size_t) __attribute__((weak));
240 #ifdef AFS_LINUX26_ENV
241 extern asmlinkage long sys_wait4(pid_t, int *, int, struct rusage *) __attribute__((weak));
242 #else
243 extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *) __attribute__((weak));
244 #endif
245 extern asmlinkage long sys_exit (int) __attribute__((weak));
246 #if defined(EXPORTED_SYS_OPEN)
247 extern asmlinkage long sys_open (const char *, int, int) __attribute__((weak));
248 #endif
249 extern asmlinkage long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak));
250 extern rwlock_t tasklist_lock __attribute__((weak));
251
252
253 /* Structures used to control probing.  We put all the details of which
254  * symbols we're interested in, what syscall functions to look for, etc
255  * into tables, so we can then have a single copy of the functions that
256  * actually do the work.
257  */
258 typedef struct {
259     char *name;
260     int NR1;
261     void *fn1;
262     int NR2;
263     void *fn2;
264     int NR3;
265     void *fn3;
266 } tryctl;
267
268 typedef struct {
269     char *symbol;                   /* symbol name */
270     char *desc;                     /* description for messages */
271     int offset;                     /* first syscall number in table */
272
273     void *weak_answer;              /* weak symbol ref */
274     void *parm_answer;              /* module parameter answer */
275     void *debug_answer;             /* module parameter answer */
276     unsigned long given_answer;     /* compiled-in answer, if any */
277
278     tryctl *trylist;                /* array of combinations to try */
279
280     unsigned long try_sect_sym;     /* symbol in section to try scanning */
281     unsigned long try_base;         /* default base address for scan */
282     unsigned long try_base_mask;    /* base address bits to force to zero */
283     unsigned long try_length;       /* default length for scan */
284
285     unsigned long alt_try_sect_sym;     /* symbol in section to try scanning */
286     unsigned long alt_try_base;         /* default base address for scan */
287     unsigned long alt_try_base_mask;    /* base address bits to force to zero */
288     unsigned long alt_try_length;       /* default length for scan */
289
290     int n_zapped_syscalls;          /* number of unimplemented system calls */
291     int *zapped_syscalls;           /* list of unimplemented system calls */
292
293     int n_unique_syscalls;          /* number of unique system calls */
294     int *unique_syscalls;           /* list of unimplemented system calls */
295
296     int verifyNR;                   /* syscall number to verify match */
297     void *verify_fn;                /* syscall pointer to verify match */
298
299     int debug_ignore_NR[4];         /* syscalls to ignore for debugging */
300 } probectl;
301
302
303
304 /********** Probing Configuration: sys_call_table **********/
305
306 /* syscall pairs/triplets to probe */
307 /* On PPC64 and SPARC64, we need to omit the ones that might match both tables */
308 static tryctl main_try[] = {
309 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
310 #if defined(EXPORTED_SYS_CHDIR)
311     { "scan: close+chdir+write", __NR_close, &sys_close, __NR_chdir, &sys_chdir, __NR_write, &sys_write },
312 #endif
313 #endif
314     { "scan: close+wait4",       __NR_close, &sys_close, __NR_wait4, &sys_wait4, -1,         0          },
315 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
316 #if defined(EXPORTED_SYS_CHDIR)
317     { "scan: close+chdir",       __NR_close, &sys_close, __NR_chdir, &sys_chdir, -1,         0          },
318 #endif
319 #endif
320     { "scan: close+ioctl",       __NR_close, &sys_close, __NR_ioctl, &sys_ioctl, -1,         0          },
321 #if defined(EXPORTED_SYS_OPEN)
322     { "scan: exit+open",         __NR_exit,  &sys_exit,  __NR_open,  &sys_open,  -1,         0          },
323 #endif
324     { 0 }
325 };
326
327 /* zapped syscalls for try_harder */
328 /* this list is based on the table in 'zapped_syscalls' */
329
330 static int main_zapped_syscalls[] = {
331 /* 
332  * SPARC-Linux uses syscall number mappings chosen to be compatible
333  * with SunOS.  So, it doesn't have any of the traditional calls or
334  * the new STREAMS ones.  However, there are a number of syscalls
335  * which are SunOS-specific (not implemented on Linux), i386-specific
336  * (not implemented on SPARC-Linux), or implemented only on one of
337  * sparc32 or sparc64.  Of course, there are no __NR macros for most
338  * of these.
339  * 
340  * Note that the calls we list here are implemented by sys_nis_syscall,
341  * not by sys_ni_syscall.  That means we have to exclude all of the
342  * other entries, or we might get a sys_ni_syscall into the list and
343  * the test would no longer work.
344  */
345 #if defined(AFS_SPARC64_LINUX20_ENV)
346     /* mmap2, fstat64, getmsg, putmsg, modify_ldt */
347     56, 63, 151, 152, 218,
348 #elif defined(AFS_SPARC_LINUX20_ENV)
349     /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
350     52, 151, 152, 164, 218,
351 #else /* !AFS_SPARC_LINUX20_ENV */
352
353 /* 
354  * These 7 syscalls are present in the syscall table on most "older"
355  * platforms that use the traditional syscall number mappings.  They
356  * are not implemented on any platform.
357  */
358 #ifdef __NR_break
359     __NR_break,
360 #endif
361 #ifdef __NR_stty
362     __NR_stty,
363 #endif
364 #ifdef __NR_gtty
365     __NR_gtty,
366 #endif
367 #ifdef __NR_ftime
368     __NR_ftime,
369 #endif
370 #ifdef __NR_prof
371     __NR_prof,
372 #endif
373 #ifdef __NR_lock
374     __NR_lock,
375 #endif
376 #ifdef __NR_mpx
377     __NR_mpx,
378 #endif
379 /* 
380  * On s390 and arm (but not arm26), the seven traditional unimplemented
381  * system calls are indeed present and unimplemented.  However, the
382  * corresponding __NR macros are not defined, so the tests above fail.
383  * Instead, we just have to know the numbers for these.
384  */
385 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
386     /* break, stty, gtty, ftime, prof, lock, mpx */
387     17, 31, 32, 35, 44, 53, 56,
388 #endif
389
390 /* 
391  * Sadly, some newer platforms like IA64, amd64, and PA-RISC don't have
392  * the traditional numbers, so the list above are not helpful.  They
393  * do have entries for getpmsg/putpmsg, which are always unimplemented.
394  */
395 #ifdef __NR_getpmsg
396     __NR_getpmsg,
397 #endif
398 #ifdef __NR_putpmsg
399     __NR_putpmsg,
400 #endif
401
402 /* 
403  * The module-loading mechanism changed in Linux 2.6, and insmod's
404  * loss is our gain: three new unimplemented system calls! 
405  */
406 #if defined(AFS_LINUX26_ENV)
407 #ifdef __NR_
408     __NR_create_module,
409 #endif
410 #ifdef __NR_query_module
411     __NR_query_module,
412 #endif
413 #ifdef __NR_get_kernel_syms
414     __NR_get_kernel_syms,
415 #endif
416 #endif /* AFS_LINUX26_ENV */
417
418 /* 
419  * On IA64, the old module-loading calls are indeed present and
420  * unimplemented, but the __NR macros are not defined.  Again,
421  * we simply have to know their numbers.
422  */
423 #ifdef AFS_IA64_LINUX26_ENV
424     /* create_module, query_module, get_kernel_sysms */
425     1132, 1136, 1135,
426 #endif
427
428 /* And the same deal for arm (not arm26), if we ever support that. */
429 #if 0
430     /* create_module, query_module, get_kernel_sysms */
431     127, 167, 130,
432 #endif
433
434 /*
435  * Alpha-Linux uses syscall number mappings chosen to be compatible
436  * with OSF/1.  So, it doesn't have any of the traditional calls or
437  * the new STREAMS ones, but it does have several OSF/1-specific
438  * syscalls which are not implemented on Linux.  These don't exist on
439  * any other platform.
440  */
441 #ifdef __NR_osf_syscall
442     __NR_osf_syscall,
443 #endif
444 #ifdef __NR_osf_profil
445     __NR_osf_profil,
446 #endif
447 #ifdef __NR_osf_reboot
448     __NR_osf_reboot,
449 #endif
450 #ifdef __NR_osf_kmodcall
451     __NR_osf_kmodcall,
452 #endif
453 #ifdef __NR_osf_old_vtrace
454     __NR_osf_old_vtrace,
455 #endif
456
457 /*
458  * On PPC64, we need a couple more entries to distinguish the two
459  * tables, since the system call numbers are the same and the sets of
460  * unimplemented calls are very similar.
461  * mmap2 and fstat64 are implemented only for 32-bit calls
462  */
463 #ifdef AFS_PPC64_LINUX20_ENV
464     /* _mmap2, _fstat64 */
465     192, 197,
466 #endif /* AFS_PPC64_LINUX20_ENV */
467
468 /* Similarly for S390X, with lcown16 and fstat64 */
469 #ifdef AFS_S390X_LINUX20_ENV
470     /* lchown16, fstat64 */
471     16, 197,
472 #endif
473 #endif /* !AFS_SPARC_LINUX20_ENV */
474     0
475 };
476
477 /* unique syscalls for try_harder */
478 static int main_unique_syscalls[] = {
479 #if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
480     /* 
481      * On SPARC, we need some additional unique calls to make sure
482      * we don't match the SunOS-compatibility table.
483      */
484     __NR_sgetmask, __NR_ssetmask,
485 #endif
486     __NR_exit, __NR_mount, __NR_read, __NR_write,
487     __NR_open, __NR_close, __NR_unlink
488 };
489
490 /* probe control structure */
491 static probectl main_probe = {
492     /* symbol name and description */
493     "sys_call_table",
494     "system call table",
495
496     /* syscall number of first entry in table */
497 #ifdef AFS_IA64_LINUX20_ENV
498     1024,
499 #else
500     0,
501 #endif
502
503     sys_call_table,               /* weak symbol ref */
504     0, 0,                         /* module parameter answers */
505 #ifdef AFS_LINUX_sys_call_table
506     AFS_LINUX_sys_call_table,     /* compiled-in answer, if any */
507 #else
508     0,
509 #endif
510
511     main_try,                     /* array of combinations to try */
512
513     /* symbol in section to try scanning */
514 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
515     (unsigned long)&sys_close,
516 #elif defined(AFS_AMD64_LINUX20_ENV)
517     /* On this platform, it's in a different section! */
518     (unsigned long)&tasklist_lock,
519 #else
520     (unsigned long)&init_mm,
521 #endif
522
523     /* default base address for scan */
524     /* base address bits to force to zero */
525     /* default length for scan */
526 #if   defined(AFS_SPARC64_LINUX20_ENV)
527     (unsigned long)(&sys_close),
528     0xfffff,
529     0x10000,
530 #elif   defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
531     /* bleah; this is so suboptimal */
532     (unsigned long)(&sys_close),
533     0xfffff,
534     0x20000,
535 #elif   defined(AFS_IA64_LINUX20_ENV)
536     (unsigned long)(&init_mm),
537     0x1fffff,
538     0x30000,
539 #elif defined(AFS_AMD64_LINUX20_ENV)
540     (unsigned long)(&tasklist_lock) - 0x30000,
541     0,
542     0x6000,
543 #elif defined(AFS_PPC64_LINUX26_ENV)
544     (unsigned long)(&do_signal),
545     0xfff,
546     0x400,
547 #elif defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC_LINUX20_ENV)
548     (unsigned long)&init_mm,
549     0xffff,
550     16384,
551 #else
552     (unsigned long)&init_mm,
553     0,
554     16384,
555 #endif
556
557 #ifdef AFS_LINUX26_ENV
558     (unsigned long)scsi_command_size,
559     (unsigned long)scsi_command_size,
560     0x3ffff,
561     0x30000,
562 #else
563     0, 0, 0, 0,
564 #endif
565
566     /* number and list of unimplemented system calls */
567     ((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1),
568     main_zapped_syscalls,
569
570     /* number and list of unique system calls */
571     (sizeof(main_unique_syscalls)/sizeof(main_unique_syscalls[0])),
572     main_unique_syscalls,
573
574     /* syscall number and pointer to verify match */
575     __NR_close, &sys_close,
576
577     /* syscalls to ignore for debugging */
578     {
579 #if   defined(AFS_ALPHA_LINUX20_ENV)
580         338,
581 #elif defined(AFS_AMD64_LINUX20_ENV)
582         183,
583 #elif defined(AFS_IA64_LINUX20_ENV)
584         1141,
585 #elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
586         227,
587 #else
588         137,
589 #endif
590         __NR_setgroups,
591 #ifdef __NR_setgroups32
592         __NR_setgroups32,
593 #else
594         -1,
595 #endif
596         -1,
597     }
598 };
599
600
601 /********** Probing Configuration: amd64 ia32_sys_call_table **********/
602 #if defined(AFS_AMD64_LINUX20_ENV)
603
604 /* syscall pairs/triplets to probe */
605 static tryctl ia32_try[] = {
606 #if defined(EXPORTED_SYS_CHDIR)
607     { "scan: close+chdir+write", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir,        __NR_ia32_write, &sys_write },
608     { "scan: close+chdir",       __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir,        -1,              0          },
609 #endif
610     { 0 }
611 };
612
613 /* zapped syscalls for try_harder */
614 static int ia32_zapped_syscalls[] = {
615     __NR_ia32_break, __NR_ia32_stty, __NR_ia32_gtty, __NR_ia32_ftime,
616     __NR_ia32_prof,  __NR_ia32_lock, __NR_ia32_mpx,
617     0
618 };
619
620 /* unique syscalls for try_harder */
621 static int ia32_unique_syscalls[] = {
622     __NR_ia32_exit, __NR_ia32_mount, __NR_ia32_read, __NR_ia32_write,
623     __NR_ia32_open, __NR_ia32_close, __NR_ia32_unlink
624 };
625
626 /* probe control structure */
627 static probectl ia32_probe = {
628     /* symbol name and description */
629     "ia32_sys_call_table",
630     "32-bit system call table",
631
632     /* syscall number of first entry in table */
633     0,
634
635     ia32_sys_call_table,          /* weak symbol ref */
636     0, 0,                         /* module parameter answers */
637 #ifdef AFS_LINUX_ia32_sys_call_table
638     AFS_LINUX_ia32_sys_call_table,/* compiled-in answer, if any */
639 #else
640     0,
641 #endif
642
643     ia32_try,                     /* array of combinations to try */
644
645     /* symbol in section to try scanning */
646     (unsigned long)&init_mm,
647
648     /* default base address for scan */
649     /* base address bits to force to zero */
650     /* default length for scan */
651     (unsigned long)&init_mm,
652     0,
653     (0x180000 / sizeof(unsigned long *)),
654
655 #ifdef AFS_LINUX26_ENV
656     (unsigned long)scsi_command_size,
657     (unsigned long)scsi_command_size,
658     0x3ffff,
659     0x30000,
660 #else
661     0, 0, 0, 0,
662 #endif
663
664
665     /* number and list of unimplemented system calls */
666     ((sizeof(ia32_zapped_syscalls)/sizeof(ia32_zapped_syscalls[0])) - 1),
667     ia32_zapped_syscalls,
668
669     /* number and list of unique system calls */
670     (sizeof(ia32_unique_syscalls)/sizeof(ia32_unique_syscalls[0])),
671     ia32_unique_syscalls,
672
673     /* syscall number and pointer to verify match */
674     __NR_ia32_close, &sys_close,
675
676     /* syscalls to ignore for debugging */
677     {
678         137,
679         __NR_ia32_setgroups,
680         __NR_ia32_setgroups32,
681         -1,
682     }
683 };
684
685 static probectl *probe_list[] = {
686     &main_probe, &ia32_probe
687 };
688
689
690 /********** Probing Configuration: IA64 **********/
691 #elif defined(AFS_IA64_LINUX20_ENV)
692 struct fptr {
693     void *ip;
694     unsigned long gp;
695 };
696
697 /* no 32-bit support on IA64 for now */
698 static probectl *probe_list[] = {
699     &main_probe
700 };
701
702
703 /********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
704 #elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
705 struct fptr {
706     void *ip;
707     unsigned long gp;
708 };
709
710 /* 
711  * syscall pairs/triplets to probe
712  * This has to be empty, because anything that would work will
713  * also match the main table, and that's no good.
714  */
715 static tryctl sct32_try[] = {
716     { 0 }
717 };
718
719 /* zapped syscalls for try_harder */
720 static int sct32_zapped_syscalls[] = {
721 #ifdef AFS_PPC64_LINUX20_ENV
722     /* These should be sufficient */
723     __NR_break, __NR_stty, __NR_gtty, __NR_ftime,
724     __NR_prof, __NR_lock, __NR_mpx,
725 #endif
726 #ifdef AFS_SPARC64_LINUX20_ENV
727     /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
728     52, 151, 152, 164, 218,
729 #endif
730     0
731 };
732
733 /* unique syscalls for try_harder */
734 /* mmap2 and fstat64 are implemented only for 32-bit calls */
735 static int sct32_unique_syscalls[] = {
736 #ifdef AFS_PPC64_LINUX20_ENV
737     /* _mmap2, _fstat64 */
738     192, 197,
739 #endif
740 #ifdef AFS_SPARC64_LINUX24_ENV
741     /* 
742      * On SPARC, we need some additional unique calls to make sure
743      * we don't match the SunOS-compatibility table.
744      */
745     __NR_sgetmask, __NR_ssetmask,
746 #endif
747     __NR_exit, __NR_mount, __NR_read, __NR_write,
748     __NR_open, __NR_close, __NR_unlink
749 };
750
751 /* probe control structure */
752 static probectl sct32_probe = {
753     /* symbol name and description */
754     "sys_call_table32",
755     "32-bit system call table",
756
757     /* syscall number of first entry in table */
758     0,
759
760     sys_call_table32,             /* weak symbol ref */
761     0, 0,                         /* module parameter answers */
762 #ifdef AFS_LINUX_sys_call_table32
763     AFS_LINUX_sys_call_table32,   /* compiled-in answer, if any */
764 #else
765     0,
766 #endif
767
768     sct32_try,                   /* array of combinations to try */
769
770     /* symbol in section to try scanning */
771 #if defined(AFS_SPARC64_LINUX20_ENV)
772     (unsigned long)&sys_close,
773 #else
774     (unsigned long)&init_mm,
775 #endif
776
777     /* default base address for scan */
778     /* base address bits to force to zero */
779     /* default length for scan */
780 #if   defined(AFS_SPARC64_LINUX20_ENV)
781     (unsigned long)(&sys_close),
782     0xfffff,
783     0x10000,
784 #elif defined(AFS_PPC64_LINUX26_ENV)
785     (unsigned long)(&do_signal),
786     0xfff,
787     0x400,
788 #else
789     (unsigned long)&init_mm,
790     0,
791     16384,
792 #endif
793
794 #ifdef AFS_LINUX26_ENV
795     (unsigned long)scsi_command_size,
796     (unsigned long)scsi_command_size,
797     0x3ffff,
798     0x30000,
799 #else
800     0, 0, 0, 0,
801 #endif
802
803     /* number and list of unimplemented system calls */
804     ((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1),
805     sct32_zapped_syscalls,
806
807     /* number and list of unique system calls */
808     (sizeof(sct32_unique_syscalls)/sizeof(sct32_unique_syscalls[0])),
809     sct32_unique_syscalls,
810
811     /* syscall number and pointer to verify match */
812     __NR_close, &sys_close,
813
814     /* syscalls to ignore for debugging */
815     {
816 #if defined(AFS_SPARC64_LINUX20_ENV)
817         227,
818 #else
819         137,
820 #endif
821         __NR_setgroups,
822         -1,
823         -1,
824     }
825 };
826
827 static probectl *probe_list[] = {
828     &main_probe, &sct32_probe
829 };
830
831
832 /********** Probing Configuration: s390x sys_call_table_emu **********/
833 /* We only actually need to do this on s390x_linux26 and later.
834  * On earlier versions, the two tables were interleaved and so
835  * have related base addresses.
836  */
837 #elif defined(AFS_S390X_LINUX26_ENV)
838
839 /* syscall pairs/triplets to probe */
840 /* nothing worthwhile is exported, so this is empty */
841 static tryctl emu_try[] = {
842     { 0 }
843 };
844
845 /* zapped syscalls for try_harder */
846 static int emu_zapped_syscalls[] = {
847     /* break, stty, gtty, ftime, prof, lock, mpx */
848     17, 31, 32, 35, 44, 53, 56,
849     0
850 };
851
852 /* unique syscalls for try_harder */
853 static int emu_unique_syscalls[] = {
854     /* lchown16, fstat64 */
855     16, 197,
856     __NR_exit, __NR_mount, __NR_read, __NR_write,
857     __NR_open, __NR_close, __NR_unlink
858 };
859
860 /* probe control structure */
861 static probectl emu_probe = {
862     /* symbol name and description */
863     "sys_call_table_emu",
864     "32-bit system call table",
865
866     /* syscall number of first entry in table */
867     0,
868
869     sys_call_table_emu,           /* weak symbol ref */
870     0, 0,                         /* module parameter answers */
871 #ifdef AFS_LINUX_sys_call_table_emu
872     AFS_LINUX_sys_call_table_emu, /* compiled-in answer, if any */
873 #else
874     0,
875 #endif
876
877     emu_try,                      /* array of combinations to try */
878
879     /* symbol in section to try scanning */
880     (unsigned long)&sys_close,
881
882     /* default base address for scan */
883     /* base address bits to force to zero */
884     /* default length for scan */
885     (unsigned long)&sys_close,
886     0xfffff,
887     0x20000,
888
889 #ifdef AFS_LINUX26_ENV
890     (unsigned long)scsi_command_size,
891     (unsigned long)scsi_command_size,
892     0x3ffff,
893     0x30000,
894 #else
895     0, 0, 0, 0,
896 #endif
897
898     /* number and list of unimplemented system calls */
899     ((sizeof(emu_zapped_syscalls)/sizeof(emu_zapped_syscalls[0])) - 1),
900     emu_zapped_syscalls,
901
902     /* number and list of unique system calls */
903     (sizeof(emu_unique_syscalls)/sizeof(emu_unique_syscalls[0])),
904     emu_unique_syscalls,
905
906     /* syscall number and pointer to verify match */
907     __NR_close, &sys_close,
908
909     /* syscalls to ignore for debugging */
910     {
911         137,
912         __NR_setgroups,
913         -1,
914         -1,
915     }
916 };
917
918 static probectl *probe_list[] = {
919     &main_probe, &emu_probe
920 };
921
922
923 /********** End of Probing Configuration **********/
924
925 #else /* no per-platform probe control, so use the default list */
926 static probectl *probe_list[] = {
927     &main_probe
928 };
929 #endif
930
931 #define N_PROBE_LIST (sizeof(probe_list) / sizeof(*probe_list))
932 #define DEBUG_IN_RANGE(P,x) (!probe_debug_range ||                             \
933   (P->debug_answer &&                                                          \
934    (unsigned long)(x) >= (unsigned long)P->debug_answer &&                     \
935    (unsigned long)(x) <  (unsigned long)P->debug_answer + probe_debug_range))
936
937
938
939 static int check_table(probectl *P, PROBETYPE *ptr)
940 {
941     PROBETYPE *x;
942     int i, j;
943
944     for (x = ptr, i = 0; i < _SS(NR_syscalls); i++, x++) {
945 #ifdef OSI_PROBE_DEBUG
946         if (probe_debug & 0x0040) {
947             for (j = 0; j < 4; j++) {
948                 if (_SS(P->debug_ignore_NR[j]) == _SX(i + P->offset)) break;
949             }
950             if (j < 4) continue;
951         }
952 #endif
953         for (j = 0; j < 8; j++) {
954             if (_SS(probe_ignore_syscalls[j]) == _SX(i) + P->offset) break;
955         }
956         if (j < 8) continue;
957         if (*x <= ktxt_lower_bound) {
958 #ifdef OSI_PROBE_DEBUG
959             if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
960                 printk("<7>check 0x%lx -> %d [0x%lx]\n",
961                        (unsigned long)ptr, i, (unsigned long)*x);
962 #endif
963             return i;
964         }
965     }
966 #ifdef OSI_PROBE_DEBUG
967     if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
968         printk("<7>check 0x%lx -> ok\n", (unsigned long)ptr);
969 #endif
970     return -1;
971 }
972
973 static void *try(probectl *P, tryctl *T, PROBETYPE *aptr,
974                  unsigned long datalen)
975 {
976 #ifdef OSI_PROBE_KALLSYMS
977     char *mod_name, *sec_name, *sym_name;
978     unsigned long mod_start, mod_end;
979     unsigned long sec_start, sec_end;
980     unsigned long sym_start, sym_end;
981 #endif
982     unsigned long offset, ip1, ip2, ip3;
983     int ret;
984     PROBETYPE *ptr;
985
986 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
987     ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
988     ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
989     ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
990 #else
991     ip1 = (unsigned long)T->fn1;
992     ip2 = (unsigned long)T->fn2;
993     ip3 = (unsigned long)T->fn3;
994 #endif
995
996 #ifdef OSI_PROBE_DEBUG
997     if (probe_debug & 0x0001)
998         printk("<7>osi_probe: %s                      %s (%d->0x%lx, %d->0x%lx, %d->0x%lx)\n",
999                P->symbol, T->name, T->NR1, ip1, T->NR2, ip2, T->NR3, ip3);
1000 #endif
1001
1002     if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3))
1003         return 0;
1004
1005     for (offset = 0; offset < datalen; offset++, aptr++) {
1006 #if defined(AFS_PPC64_LINUX20_ENV)
1007         ptr = (PROBETYPE*)(*aptr);
1008         if ((unsigned long)ptr <= KERNELBASE) {
1009                 continue;
1010         }
1011 #else
1012         ptr = aptr;
1013 #endif
1014         if ((unsigned long)ptr < init_mm.start_code ||
1015 #if defined(AFS_AMD64_LINUX20_ENV)
1016                 (unsigned long)ptr > init_mm.brk)
1017 #else
1018                 (unsigned long)ptr > init_mm.end_data)
1019 #endif
1020         {
1021 /*           printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
1022              continue;
1023         }
1024
1025         ret = check_table(P, ptr);
1026         if (ret >= 0) {
1027             /* return value is number of entries to skip */
1028             aptr    += ret;
1029             offset += ret;
1030             continue;
1031         }
1032
1033 #ifdef OSI_PROBE_DEBUG
1034         if ((probe_debug & 0x0002) && DEBUG_IN_RANGE(P,ptr))
1035             printk("<7>try 0x%lx\n", (unsigned long)ptr);
1036 #endif
1037         if (ptr[_SS(T->NR1 - P->offset)] != ip1)        continue;
1038         if (ptr[_SS(T->NR2 - P->offset)] != ip2)        continue;
1039         if (ip3 && ptr[_SS(T->NR3 - P->offset)] != ip3) continue;
1040
1041 #ifdef OSI_PROBE_DEBUG
1042         if (probe_debug & 0x0002)
1043             printk("<7>try found 0x%lx\n", (unsigned long)ptr);
1044 #endif
1045 #ifdef OSI_PROBE_KALLSYMS
1046         if (kallsyms_address_to_symbol) {
1047             ret = kallsyms_address_to_symbol((unsigned long)ptr,
1048                                              &mod_name, &mod_start, &mod_end,
1049                                              &sec_name, &sec_start, &sec_end,
1050                                              &sym_name, &sym_start, &sym_end);
1051             if (!ret || strcmp(sym_name, P->symbol)) continue;
1052         }
1053 #endif
1054         /* XXX should we make sure there is only one match? */
1055         return (void *)ptr;
1056     }
1057     return 0;
1058 }
1059
1060
1061 static int check_harder(probectl *P, PROBETYPE *p)
1062 {
1063     unsigned long ip1;
1064     int i, s;
1065
1066     /* Check zapped syscalls */
1067     for (i = 1; i < P->n_zapped_syscalls; i++) {
1068         if (p[_SS(P->zapped_syscalls[i])] != p[_SS(P->zapped_syscalls[0])]) {
1069 #ifdef OSI_PROBE_DEBUG
1070             if ((probe_debug & 0x0020) && DEBUG_IN_RANGE(P,p))
1071                 printk("<7>check_harder 0x%lx zapped failed i=%d\n", (unsigned long)p, i);
1072 #endif
1073             return 0;
1074         }
1075     }
1076
1077     /* Check unique syscalls */
1078     for (i = 0; i < P->n_unique_syscalls; i++) {
1079         for (s = 0; s < NR_syscalls; s++) {
1080             if (p[_SS(s)] == p[_SS(P->unique_syscalls[i])]
1081                 && s != P->unique_syscalls[i]) {
1082 #ifdef OSI_PROBE_DEBUG
1083                 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
1084                     printk("<7>check_harder 0x%lx unique failed i=%d s=%d\n", (unsigned long)p, i, s);
1085 #endif
1086                 return 0;
1087             }
1088         }
1089     }
1090
1091 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
1092     ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
1093 #else
1094     ip1 = (unsigned long)(P->verify_fn);
1095 #endif
1096
1097     if (ip1 && p[_SS(P->verifyNR - P->offset)] != ip1) {
1098 #ifdef OSI_PROBE_DEBUG
1099         if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
1100             printk("<7>check_harder 0x%lx verify failed\n", (unsigned long)p);
1101 #endif
1102         return 0;
1103     }
1104
1105 #ifdef OSI_PROBE_DEBUG
1106     if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
1107         printk("<7>check_harder 0x%lx success!\n", (unsigned long)p);
1108 #endif
1109     return 1;
1110 }
1111
1112 static void *try_harder(probectl *P, PROBETYPE *ptr, unsigned long datalen)
1113 {
1114 #ifdef OSI_PROBE_KALLSYMS
1115     char *mod_name, *sec_name, *sym_name;
1116     unsigned long mod_start, mod_end;
1117     unsigned long sec_start, sec_end;
1118     unsigned long sym_start, sym_end;
1119 #endif
1120     unsigned long offset;
1121     void *match = 0;
1122     int ret;
1123
1124 #ifdef OSI_PROBE_DEBUG
1125     if (probe_debug & 0x0001)
1126         printk("<7>osi_probe: %s                      try_harder\n", P->symbol);
1127 #endif
1128     for (offset = 0; offset < datalen; offset++, ptr++) {
1129          if ((unsigned long)ptr < init_mm.start_code ||
1130 #if defined(AFS_AMD64_LINUX20_ENV)
1131                 (unsigned long)ptr > init_mm.brk)
1132 #else
1133                 (unsigned long)ptr > init_mm.end_data)
1134 #endif
1135         {
1136 /*           printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
1137              continue;
1138         }
1139         ret = check_table(P, ptr);
1140         if (ret >= 0) {
1141             /* return value is number of entries to skip */
1142             ptr    += ret;
1143             offset += ret;
1144             continue;
1145         }
1146
1147 #ifdef OSI_PROBE_DEBUG
1148         if ((probe_debug & 0x0004) && DEBUG_IN_RANGE(P,ptr))
1149             printk("<7>try_harder 0x%lx\n", (unsigned long)ptr);
1150 #endif
1151         if (!check_harder(P, ptr))
1152             continue;
1153
1154 #ifdef OSI_PROBE_DEBUG
1155         if (probe_debug & 0x0004)
1156             printk("<7>try_harder found 0x%lx\n", (unsigned long)ptr);
1157 #endif
1158
1159 #ifdef OSI_PROBE_KALLSYMS
1160         if (kallsyms_address_to_symbol) {
1161             ret = kallsyms_address_to_symbol((unsigned long)ptr,
1162                                              &mod_name, &mod_start, &mod_end,
1163                                              &sec_name, &sec_start, &sec_end,
1164                                              &sym_name, &sym_start, &sym_end);
1165             if (!ret || strcmp(sym_name, P->symbol)) continue;
1166         }
1167 #endif
1168
1169         if (match) {
1170 #ifdef OSI_PROBE_DEBUG
1171             if (probe_debug & 0x0005)
1172                 printk("<7>%s: try_harder found multiple matches!\n", P->symbol);
1173 #endif
1174             return 0;
1175         }
1176
1177         match = (void *)ptr;
1178         if (!probe_carefully)
1179             break;
1180     }
1181     return match;
1182 }
1183
1184
1185 #ifdef OSI_PROBE_DEBUG
1186 #define check_result(x,m) do {                                                             \
1187     if (probe_debug & 0x0001) {                                                              \
1188         printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
1189     }                                                                                      \
1190     if ((x)) {                                                                             \
1191         *method = (m);                                                                     \
1192         final_answer = (void *)(x);                                                        \
1193     }                                                                                      \
1194 } while (0)
1195 #else
1196 #define check_result(x,m) do {  \
1197     if ((x)) {                  \
1198         *method = (m);          \
1199         return (void *)(x);     \
1200     }                           \
1201 } while (0)
1202 #endif
1203 static void *scan_for_syscall_table(probectl *P, PROBETYPE *B, unsigned long L)
1204 {
1205     tryctl *T;
1206     void *answer;
1207 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1208     void *answer2;
1209 #endif
1210 #ifdef OSI_PROBE_DEBUG
1211     void *final_answer = 0;
1212 #endif
1213 #ifdef OSI_PROBE_DEBUG
1214     if (probe_debug & 0x0007)
1215         printk("<7>osi_probe: %s                      base=0x%lx, len=0x%lx\n",
1216                P->symbol, (unsigned long)B, L);
1217     if (probe_debug & 0x0009) {
1218         printk("<7>osi_probe: %s                      ktxt_lower_bound=0x%lx\n",
1219                P->symbol, ktxt_lower_bound);
1220         printk("<7>osi_probe: %s                      NR_syscalls=%d\n",
1221                P->symbol, NR_syscalls);
1222     }
1223 #endif
1224
1225     for (T = P->trylist; T->name; T++) {
1226         answer = try(P, T, B, L);
1227 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1228         answer2 = try(P, T, (PROBETYPE *)(2 + (void *)B), L);
1229 #ifdef OSI_PROBE_DEBUG
1230         if (probe_debug & 0x0003) {
1231             printk("<7>osi_probe: %s = 0x%016lx %s (even)\n",
1232                    P->symbol, (unsigned long)(answer), T->name);
1233             printk("<7>osi_probe: %s = 0x%016lx %s (odd)\n",
1234                    P->symbol, (unsigned long)(answer2), T->name);
1235         }
1236 #endif
1237         if (answer && answer2) answer = 0;
1238         else if (answer2) answer = answer2;
1239 #endif
1240         if (answer)
1241             return answer;
1242     }
1243
1244     /* XXX more checks here */
1245
1246     answer = try_harder(P, B, L);
1247 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1248     answer2 = try_harder(P, (PROBETYPE *)(2 + (void *)B), L);
1249 #ifdef OSI_PROBE_DEBUG
1250     if (probe_debug & 0x0005) {
1251         printk("<7>osi_probe: %s = 0x%016lx pattern scan (even)\n",
1252                P->symbol, (unsigned long)(answer));
1253         printk("<7>osi_probe: %s = 0x%016lx pattern scan (odd)\n",
1254                P->symbol, (unsigned long)(answer2));
1255     }
1256 #endif
1257     if (answer && answer2) answer = 0;
1258     else if (answer2) answer = answer2;
1259 #endif
1260     return answer;
1261 }
1262
1263 static void *do_find_syscall_table(probectl *P, char **method)
1264 {
1265 #ifdef OSI_PROBE_KALLSYMS
1266     char *mod_name, *sec_name, *sym_name;
1267     unsigned long mod_start, mod_end;
1268     unsigned long sec_start, sec_end;
1269     unsigned long sym_start, sym_end;
1270     unsigned long token;
1271     int ret;
1272 #endif
1273     PROBETYPE *B;
1274     unsigned long L;
1275     void *answer;
1276 #ifdef OSI_PROBE_DEBUG
1277     void *final_answer = 0;
1278 #endif
1279
1280     *method = "not found";
1281
1282     /* if it's exported, there's nothing to do */
1283     check_result(P->weak_answer, "exported");
1284
1285     /* ask the kernel to do the name lookup, if it's willing */
1286 #ifdef OSI_PROBE_KALLSYMS
1287     if (kallsyms_symbol_to_address) {
1288         token = 0;
1289         sym_start = 0;
1290         do {
1291             ret = kallsyms_symbol_to_address(P->symbol, &token,
1292                                              &mod_name, &mod_start, &mod_end,
1293                                              &sec_name, &sec_start, &sec_end,
1294                                              &sym_name, &sym_start, &sym_end);
1295             if (ret && !strcmp(mod_name, "kernel") && sym_start)
1296                 break;
1297             sym_start = 0;
1298         } while (ret);
1299         check_result(sym_start, "kallsyms_symbol_to_address");
1300     }
1301 #endif
1302
1303     /* Maybe a little birdie told us */
1304     check_result(P->parm_answer,  "module parameter");
1305     check_result(P->given_answer, "compiled-in");
1306
1307     /* OK, so we have to scan. */
1308     B = (PROBETYPE *)((P->try_base) & ~(P->try_base_mask));
1309     L = P->try_length;
1310     /* Now, see if the kernel will tell us something better than the default */
1311 #ifdef OSI_PROBE_KALLSYMS
1312     if (kallsyms_address_to_symbol) {
1313         ret = kallsyms_address_to_symbol(P->try_sect_sym,
1314                                          &mod_name, &mod_start, &mod_end,
1315                                          &sec_name, &sec_start, &sec_end,
1316                                          &sym_name, &sym_start, &sym_end);
1317         if (ret) {
1318             B = (PROBETYPE *)sec_start;
1319             L = (sec_end - sec_start) / sizeof(unsigned long);
1320         }
1321     }
1322 #endif
1323    
1324     answer = scan_for_syscall_table(P, B, L);
1325     check_result(answer, "pattern scan");
1326     B = (PROBETYPE *)((P->alt_try_base) & ~(P->alt_try_base_mask));
1327     L = P->alt_try_length;
1328     /* Now, see if the kernel will tell us something better than the default */
1329 #ifdef OSI_PROBE_KALLSYMS
1330     if (kallsyms_address_to_symbol && P->alt_try_sect_sym) {
1331         ret = kallsyms_address_to_symbol(P->alt_try_sect_sym,
1332                                          &mod_name, &mod_start, &mod_end,
1333                                          &sec_name, &sec_start, &sec_end,
1334                                          &sym_name, &sym_start, &sym_end);
1335         if (ret) {
1336             B = (PROBETYPE *)sec_start;
1337             L = (sec_end - sec_start) / sizeof(unsigned long);
1338         }
1339     }
1340 #endif
1341     if (B && L) {
1342         answer = scan_for_syscall_table(P, B, L);
1343         check_result(answer, "pattern scan");
1344     }
1345 #ifdef OSI_PROBE_DEBUG
1346     return final_answer;
1347 #else
1348     return 0;
1349 #endif
1350 }
1351
1352 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
1353 static int check_writable(unsigned long address) 
1354
1355     pgd_t *pgd = pgd_offset_k(address);
1356 #ifdef PUD_SIZE
1357     pud_t *pud;
1358 #endif
1359     pmd_t *pmd;
1360     pte_t *pte;
1361
1362     if (pgd_none(*pgd))
1363         return 0;
1364 #ifdef PUD_SIZE
1365     pud = pud_offset(pgd, address);
1366     if (pud_none(*pud))
1367         return 0;
1368     pmd = pmd_offset(pud, address);
1369 #else
1370     pmd = pmd_offset(pgd, address);
1371 #endif
1372     if (pmd_none(*pmd))
1373         return 0;
1374     if (pmd_large(*pmd))
1375         pte = (pte_t *)pmd;
1376     else
1377         pte = pte_offset_kernel(pmd, address);
1378     if (pte_none(*pte) || !pte_present(*pte) || !pte_write(*pte))
1379         return 0;
1380     return 1;
1381 }
1382 #endif
1383
1384 void *osi_find_syscall_table(int which)
1385 {
1386     probectl *P;
1387     void *answer;
1388     char *method;
1389
1390     if (which < 0 || which >= N_PROBE_LIST) {
1391         printk("error - afs_find_syscall_table called with invalid index!\n");
1392         return 0;
1393     }
1394     P = probe_list[which];
1395     if (which < 4) {
1396         P->parm_answer = (void *)sys_call_table_addr[which];
1397 #ifdef OSI_PROBE_DEBUG
1398         P->debug_answer = (void *)probe_debug_addr[which];
1399 #endif
1400     }
1401     answer = do_find_syscall_table(P, &method);
1402     if (!answer) {
1403         printk("Warning: failed to find address of %s\n", P->desc);
1404         printk("System call hooks will not be installed; proceeding anyway\n");
1405         return 0;
1406     }
1407     printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
1408 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
1409     if (!check_writable((unsigned long)answer)) {
1410         printk("Address 0x%lx is not writable.\n", (unsigned long)answer);
1411         printk("System call hooks will not be installed; proceeding anyway\n");
1412         return 0;
1413     }
1414 #endif
1415     return answer;
1416 }
1417
1418
1419 #ifdef OSI_PROBE_STANDALONE
1420 int __init osi_probe_init(void)
1421 {
1422     int i;
1423
1424     if (!probe_debug_tag) probe_debug_tag = jiffies;
1425     printk("*** osi_probe %ld debug = 0x%04x ***\n",
1426            probe_debug_tag, probe_debug);
1427     for (i = 0; i < N_PROBE_LIST; i++)
1428         (void)osi_find_syscall_table(i);
1429     return 0;
1430 }
1431
1432 void osi_probe_exit(void) { }
1433
1434 module_init(osi_probe_init);
1435 module_exit(osi_probe_exit);
1436 #endif
1437 #endif