1b670b3d2dd1d537f175972fadae242eea521dd5
[openafs.git] / src / afs / LINUX24 / 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 #if defined(ENABLE_LINUX_SYSCALL_PROBING) && defined(EXPORTED_INIT_MM)
56 #ifdef AFS_LINUX24_ENV
57 #include <linux/module.h> /* early to avoid printf->printk mapping */
58 #ifndef OSI_PROBE_STANDALONE
59 #include "afs/sysincludes.h"
60 #include "afsincludes.h"
61 #endif
62 #include <linux/version.h>
63 #include <linux/sched.h>
64 #ifdef CONFIG_H_EXISTS
65 #include <linux/config.h>
66 #endif
67 #include <linux/linkage.h>
68 #include <linux/init.h>
69 #include <linux/unistd.h>
70 #include <linux/mm.h>
71
72 #ifdef AFS_AMD64_LINUX20_ENV
73 #include <asm/ia32_unistd.h>
74 #endif
75
76 /* number of syscalls */
77 /* NB: on MIPS we care about the 4xxx range */
78 #ifndef NR_syscalls
79 #define NR_syscalls 222
80 #endif
81
82 /* lower bound of valid kernel text pointers */
83 #ifdef AFS_IA64_LINUX20_ENV
84 #define ktxt_lower_bound (((unsigned long)&kernel_thread )  & 0xfff00000L)
85 #elif defined(AFS_PPC64_LINUX20_ENV)
86 #define ktxt_lower_bound (KERNELBASE)
87 #else
88 #define ktxt_lower_bound (((unsigned long)&kernel_thread )  & ~0xfffffL)
89 #endif
90
91 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
92  * even though pointers are 64 bit quantities.
93  */
94 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
95 #define SYSCALLTYPE unsigned int
96 #define PROBETYPE int
97 #else
98 #define SYSCALLTYPE void *
99 #define PROBETYPE long
100 #endif
101
102 #if defined(AFS_S390X_LINUX20_ENV)
103 #define _SS(x) ((x) << 1)
104 #define _SX(x) ((x) &~ 1)
105 #else
106 #define _SS(x) (x)
107 #define _SX(x) (x)
108 #endif
109
110 /* Older Linux doesn't have __user. The sys_read prototype needs it. */
111 #ifndef __user
112 #define __user
113 #endif
114
115 /* Allow the user to specify sys_call_table addresses */
116 static unsigned long sys_call_table_addr[4] = { 0,0,0,0 };
117 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
118 module_param_array(sys_call_table_addr, long, NULL, 0);
119 #else
120 MODULE_PARM(sys_call_table_addr, "1-4l");
121 #endif
122 MODULE_PARM_DESC(sys_call_table_addr, "Location of system call tables");
123
124 /* If this is set, we are more careful about avoiding duplicate matches */
125 static int probe_carefully = 1;
126 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
127 module_param(probe_carefully, int, 0);
128 #else
129 MODULE_PARM(probe_carefully, "i");
130 #endif
131 MODULE_PARM_DESC(probe_carefully, "Probe for system call tables carefully");
132
133 static int probe_ignore_syscalls[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
134 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
135 module_param_array(probe_ignore_syscalls, int, NULL, 0);
136 #else
137 MODULE_PARM(probe_ignore_syscalls, "1-8i");
138 #endif
139 MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
140
141 #ifdef OSI_PROBE_DEBUG
142 /* 
143  * Debugging flags:
144  * 0x0001 - General debugging
145  * 0x0002 - detail - try
146  * 0x0004 - detail - try_harder
147  * 0x0008 - detail - check_table
148  * 0x0010 - detail - check_harder
149  * 0x0020 - detail - check_harder/zapped
150  * 0x0040 - automatically ignore setgroups and afs_syscall
151  * 0x0080 - detail - check_table_readable
152  */
153 static int probe_debug = 0x41;
154 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
155 module_param(probe_debug, int, 0);
156 #else
157 MODULE_PARM(probe_debug, "i");
158 #endif
159 MODULE_PARM_DESC(probe_debug, "Debugging level");
160
161 static unsigned long probe_debug_addr[4] = { 0,0,0,0 };
162 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
163 module_param_array(probe_debug_addr, long, NULL, 0);
164 #else
165 MODULE_PARM(probe_debug_addr, "1-4l");
166 #endif
167 MODULE_PARM_DESC(probe_debug_addr, "Debug range starting locations");
168
169 static unsigned long probe_debug_range = 0;
170 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
171 module_param(probe_debug_range, long, 0);
172 #else
173 MODULE_PARM(probe_debug_range, "l");
174 #endif
175 MODULE_PARM_DESC(probe_debug_range, "Debug range length");
176
177 static unsigned long probe_debug_tag = 0;
178 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
179 module_param(probe_debug_tag, long, 0);
180 #else
181 MODULE_PARM(probe_debug_tag, "l");
182 #endif
183 MODULE_PARM_DESC(probe_debug_tag, "Debugging output start tag");
184 #endif
185
186
187 /* Weak references are our friends.  They are supported by the in-kernel
188  * linker in Linux 2.6 and by all versions of modutils back to 2.2pre1.
189  * A weak reference not satisified by the kernel will have value zero.
190  *
191  * Unfortunately, weak references to functions don't work right on
192  * IA64; specifically, if you actually try to make a call through
193  * such a reference, and the symbol doesn't exist in the kernel, then
194  * the module relocation code will oops.  A workaround for this is
195  * probably possible, but the use of kallsyms_* is of limited value,
196  * so I'm not bothing with the effort for now.
197  * -- jhutz, 10-Feb-2005
198  */
199 #ifdef OSI_PROBE_KALLSYMS
200 extern int kallsyms_symbol_to_address(char *name, unsigned long *token,
201                                       char **mod_name,
202                                       unsigned long *mod_start,
203                                       unsigned long *mod_end,
204                                       char **sec_name,
205                                       unsigned long *sec_start,
206                                       unsigned long *sec_end,
207                                       char **sym_name,
208                                       unsigned long *sym_start,
209                                       unsigned long *sym_end
210                                      ) __attribute__((weak));
211
212 extern int kallsyms_address_to_symbol(unsigned long address,
213                                       char **mod_name,
214                                       unsigned long *mod_start,
215                                       unsigned long *mod_end,
216                                       char **sec_name,
217                                       unsigned long *sec_start,
218                                       unsigned long *sec_end,
219                                       char **sym_name,
220                                       unsigned long *sym_start,
221                                       unsigned long *sym_end
222                                      ) __attribute__((weak));
223 #endif
224
225 extern SYSCALLTYPE sys_call_table[] __attribute__((weak));
226 extern SYSCALLTYPE ia32_sys_call_table[] __attribute__((weak));
227 extern SYSCALLTYPE sys_call_table32[] __attribute__((weak));
228 extern SYSCALLTYPE sys_call_table_emu[] __attribute__((weak));
229
230 extern asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) __attribute__((weak));
231 extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
232 #if defined(EXPORTED_SYS_CHDIR)
233 extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
234 #endif
235 extern asmlinkage ssize_t sys_write(unsigned int, const char *, size_t) __attribute__((weak));
236 extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *) __attribute__((weak));
237 extern asmlinkage long sys_exit (int) __attribute__((weak));
238 #if defined(EXPORTED_SYS_OPEN)
239 extern asmlinkage long sys_open (const char *, int, int) __attribute__((weak));
240 #endif
241 extern asmlinkage long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak));
242
243
244 /* Structures used to control probing.  We put all the details of which
245  * symbols we're interested in, what syscall functions to look for, etc
246  * into tables, so we can then have a single copy of the functions that
247  * actually do the work.
248  */
249 typedef struct {
250     char *name;
251     int NR1;
252     void *fn1;
253     int NR2;
254     void *fn2;
255     int NR3;
256     void *fn3;
257 } tryctl;
258
259 typedef struct {
260     char *symbol;                   /* symbol name */
261     char *desc;                     /* description for messages */
262     int offset;                     /* first syscall number in table */
263
264     void *weak_answer;              /* weak symbol ref */
265     void *parm_answer;              /* module parameter answer */
266     void *debug_answer;             /* module parameter answer */
267     unsigned long given_answer;     /* compiled-in answer, if any */
268
269     tryctl *trylist;                /* array of combinations to try */
270
271     unsigned long try_sect_sym;     /* symbol in section to try scanning */
272     unsigned long try_base;         /* default base address for scan */
273     unsigned long try_base_mask;    /* base address bits to force to zero */
274     unsigned long try_length;       /* default length for scan */
275
276     unsigned long alt_try_sect_sym;     /* symbol in section to try scanning */
277     unsigned long alt_try_base;         /* default base address for scan */
278     unsigned long alt_try_base_mask;    /* base address bits to force to zero */
279     unsigned long alt_try_length;       /* default length for scan */
280
281     int n_zapped_syscalls;          /* number of unimplemented system calls */
282     int *zapped_syscalls;           /* list of unimplemented system calls */
283
284     int n_unique_syscalls;          /* number of unique system calls */
285     int *unique_syscalls;           /* list of unimplemented system calls */
286
287     int verifyNR;                   /* syscall number to verify match */
288     void *verify_fn;                /* syscall pointer to verify match */
289
290     int debug_ignore_NR[4];         /* syscalls to ignore for debugging */
291 } probectl;
292
293 /********** Probing Configuration: sys_call_table **********/
294
295 /* syscall pairs/triplets to probe */
296 /* On PPC64 and SPARC64, we need to omit the ones that might match both tables */
297 static tryctl main_try[] = {
298 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
299 #if defined(EXPORTED_SYS_CHDIR)
300     { "scan: close+chdir+write", __NR_close, &sys_close, __NR_chdir, &sys_chdir, __NR_write, &sys_write },
301 #endif
302 #endif
303     { "scan: close+wait4",       __NR_close, &sys_close, __NR_wait4, &sys_wait4, -1,         0          },
304 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
305 #if defined(EXPORTED_SYS_CHDIR)
306     { "scan: close+chdir",       __NR_close, &sys_close, __NR_chdir, &sys_chdir, -1,         0          },
307 #endif
308 #endif
309     { "scan: close+ioctl",       __NR_close, &sys_close, __NR_ioctl, &sys_ioctl, -1,         0          },
310 #if defined(EXPORTED_SYS_OPEN)
311     { "scan: exit+open",         __NR_exit,  &sys_exit,  __NR_open,  &sys_open,  -1,         0          },
312 #endif
313     { 0 }
314 };
315
316 /* zapped syscalls for try_harder */
317 /* this list is based on the table in 'zapped_syscalls' */
318
319 static int main_zapped_syscalls[] = {
320 /* 
321  * SPARC-Linux uses syscall number mappings chosen to be compatible
322  * with SunOS.  So, it doesn't have any of the traditional calls or
323  * the new STREAMS ones.  However, there are a number of syscalls
324  * which are SunOS-specific (not implemented on Linux), i386-specific
325  * (not implemented on SPARC-Linux), or implemented only on one of
326  * sparc32 or sparc64.  Of course, there are no __NR macros for most
327  * of these.
328  * 
329  * Note that the calls we list here are implemented by sys_nis_syscall,
330  * not by sys_ni_syscall.  That means we have to exclude all of the
331  * other entries, or we might get a sys_ni_syscall into the list and
332  * the test would no longer work.
333  */
334 #if defined(AFS_SPARC64_LINUX20_ENV)
335     /* mmap2, fstat64, getmsg, putmsg, modify_ldt */
336     56, 63, 151, 152, 218,
337 #elif defined(AFS_SPARC_LINUX20_ENV)
338     /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
339     52, 151, 152, 164, 218,
340 #else /* !AFS_SPARC_LINUX20_ENV */
341
342 /* 
343  * These 7 syscalls are present in the syscall table on most "older"
344  * platforms that use the traditional syscall number mappings.  They
345  * are not implemented on any platform.
346  */
347 #ifdef __NR_break
348     __NR_break,
349 #endif
350 #ifdef __NR_stty
351     __NR_stty,
352 #endif
353 #ifdef __NR_gtty
354     __NR_gtty,
355 #endif
356 #ifdef __NR_ftime
357     __NR_ftime,
358 #endif
359 #ifdef __NR_prof
360     __NR_prof,
361 #endif
362 #ifdef __NR_lock
363     __NR_lock,
364 #endif
365 #ifdef __NR_mpx
366     __NR_mpx,
367 #endif
368 /* 
369  * On s390 and arm (but not arm26), the seven traditional unimplemented
370  * system calls are indeed present and unimplemented.  However, the
371  * corresponding __NR macros are not defined, so the tests above fail.
372  * Instead, we just have to know the numbers for these.
373  */
374 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
375     /* break, stty, gtty, ftime, prof, lock, mpx */
376     17, 31, 32, 35, 44, 53, 56,
377 #endif
378
379 /* 
380  * Sadly, some newer platforms like IA64, amd64, and PA-RISC don't have
381  * the traditional numbers, so the list above are not helpful.  They
382  * do have entries for getpmsg/putpmsg, which are always unimplemented.
383  */
384 #ifdef __NR_getpmsg
385     __NR_getpmsg,
386 #endif
387 #ifdef __NR_putpmsg
388     __NR_putpmsg,
389 #endif
390
391 /*
392  * Alpha-Linux uses syscall number mappings chosen to be compatible
393  * with OSF/1.  So, it doesn't have any of the traditional calls or
394  * the new STREAMS ones, but it does have several OSF/1-specific
395  * syscalls which are not implemented on Linux.  These don't exist on
396  * any other platform.
397  */
398 #ifdef __NR_osf_syscall
399     __NR_osf_syscall,
400 #endif
401 #ifdef __NR_osf_profil
402     __NR_osf_profil,
403 #endif
404 #ifdef __NR_osf_reboot
405     __NR_osf_reboot,
406 #endif
407 #ifdef __NR_osf_kmodcall
408     __NR_osf_kmodcall,
409 #endif
410 #ifdef __NR_osf_old_vtrace
411     __NR_osf_old_vtrace,
412 #endif
413
414 /*
415  * On PPC64, we need a couple more entries to distinguish the two
416  * tables, since the system call numbers are the same and the sets of
417  * unimplemented calls are very similar.
418  * mmap2 and fstat64 are implemented only for 32-bit calls
419  */
420 #ifdef AFS_PPC64_LINUX20_ENV
421     /* _mmap2, _fstat64 */
422     192, 197,
423 #endif /* AFS_PPC64_LINUX20_ENV */
424
425 /* Similarly for S390X, with lcown16 and fstat64 */
426 #ifdef AFS_S390X_LINUX20_ENV
427     /* lchown16, fstat64 */
428     16, 197,
429 #endif
430 #endif /* !AFS_SPARC_LINUX20_ENV */
431     0
432 };
433
434 /* unique syscalls for try_harder */
435 static int main_unique_syscalls[] = {
436 #if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
437     /* 
438      * On SPARC, we need some additional unique calls to make sure
439      * we don't match the SunOS-compatibility table.
440      */
441     __NR_sgetmask, __NR_ssetmask,
442 #endif
443     __NR_exit, __NR_mount, __NR_read, __NR_write,
444     __NR_open, __NR_close, __NR_unlink
445 };
446
447 /* probe control structure */
448 static probectl main_probe = {
449     /* symbol name and description */
450     "sys_call_table",
451     "system call table",
452
453     /* syscall number of first entry in table */
454 #ifdef AFS_IA64_LINUX20_ENV
455     1024,
456 #else
457     0,
458 #endif
459
460     sys_call_table,               /* weak symbol ref */
461     0, 0,                         /* module parameter answers */
462 #ifdef AFS_LINUX_sys_call_table
463     AFS_LINUX_sys_call_table,     /* compiled-in answer, if any */
464 #else
465     0,
466 #endif
467
468     main_try,                     /* array of combinations to try */
469
470     /* symbol in section to try scanning */
471 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
472     (unsigned long)&sys_close,
473 #elif defined(AFS_AMD64_LINUX20_ENV)
474     /* On this platform, it's in a different section! */
475     (unsigned long)&tasklist_lock,
476 #else
477     (unsigned long)&init_mm,
478 #endif
479
480     /* default base address for scan */
481     /* base address bits to force to zero */
482     /* default length for scan */
483 #if   defined(AFS_SPARC64_LINUX20_ENV)
484     (unsigned long)(&sys_close),
485     0xfffff,
486     0x10000,
487 #elif   defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
488     /* bleah; this is so suboptimal */
489     (unsigned long)(&sys_close),
490     0xfffff,
491     0x20000,
492 #elif   defined(AFS_IA64_LINUX20_ENV)
493     (unsigned long)(&init_mm),
494     0x1fffff,
495     0x30000,
496 #elif defined(AFS_AMD64_LINUX20_ENV)
497     (unsigned long)(&tasklist_lock) - 0x30000,
498     0,
499     0x6000,
500 #elif defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC_LINUX20_ENV)
501     (unsigned long)&init_mm,
502     0xffff,
503     16384,
504 #else
505     (unsigned long)&init_mm,
506     0,
507     16384,
508 #endif
509
510     0, 0, 0, 0,
511
512     /* number and list of unimplemented system calls */
513     ((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1),
514     main_zapped_syscalls,
515
516     /* number and list of unique system calls */
517     (sizeof(main_unique_syscalls)/sizeof(main_unique_syscalls[0])),
518     main_unique_syscalls,
519
520     /* syscall number and pointer to verify match */
521     __NR_close, &sys_close,
522
523     /* syscalls to ignore for debugging */
524     {
525 #if   defined(AFS_ALPHA_LINUX20_ENV)
526         338,
527 #elif defined(AFS_AMD64_LINUX20_ENV)
528         183,
529 #elif defined(AFS_IA64_LINUX20_ENV)
530         1141,
531 #elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
532         227,
533 #else
534         137,
535 #endif
536         __NR_setgroups,
537 #ifdef __NR_setgroups32
538         __NR_setgroups32,
539 #else
540         -1,
541 #endif
542         -1,
543     }
544 };
545
546
547 /********** Probing Configuration: amd64 ia32_sys_call_table **********/
548 #if defined(AFS_AMD64_LINUX20_ENV)
549
550 /* syscall pairs/triplets to probe */
551 static tryctl ia32_try[] = {
552 #if defined(EXPORTED_SYS_CHDIR)
553     { "scan: close+chdir+write", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir,        __NR_ia32_write, &sys_write },
554     { "scan: close+chdir",       __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir,        -1,              0          },
555 #endif
556     { 0 }
557 };
558
559 /* zapped syscalls for try_harder */
560 static int ia32_zapped_syscalls[] = {
561     __NR_ia32_break, __NR_ia32_stty, __NR_ia32_gtty, __NR_ia32_ftime,
562     __NR_ia32_prof,  __NR_ia32_lock, __NR_ia32_mpx,
563     0
564 };
565
566 /* unique syscalls for try_harder */
567 static int ia32_unique_syscalls[] = {
568     __NR_ia32_exit, __NR_ia32_mount, __NR_ia32_read, __NR_ia32_write,
569     __NR_ia32_open, __NR_ia32_close, __NR_ia32_unlink
570 };
571
572 /* probe control structure */
573 static probectl ia32_probe = {
574     /* symbol name and description */
575     "ia32_sys_call_table",
576     "32-bit system call table",
577
578     /* syscall number of first entry in table */
579     0,
580
581     ia32_sys_call_table,          /* weak symbol ref */
582     0, 0,                         /* module parameter answers */
583 #ifdef AFS_LINUX_ia32_sys_call_table
584     AFS_LINUX_ia32_sys_call_table,/* compiled-in answer, if any */
585 #else
586     0,
587 #endif
588
589     ia32_try,                     /* array of combinations to try */
590
591     /* symbol in section to try scanning */
592     (unsigned long)&init_mm,
593
594     /* default base address for scan */
595     /* base address bits to force to zero */
596     /* default length for scan */
597     (unsigned long)&init_mm,
598     0,
599     (0x180000 / sizeof(unsigned long *)),
600
601     0, 0, 0, 0,
602
603
604     /* number and list of unimplemented system calls */
605     ((sizeof(ia32_zapped_syscalls)/sizeof(ia32_zapped_syscalls[0])) - 1),
606     ia32_zapped_syscalls,
607
608     /* number and list of unique system calls */
609     (sizeof(ia32_unique_syscalls)/sizeof(ia32_unique_syscalls[0])),
610     ia32_unique_syscalls,
611
612     /* syscall number and pointer to verify match */
613     __NR_ia32_close, &sys_close,
614
615     /* syscalls to ignore for debugging */
616     {
617         137,
618         __NR_ia32_setgroups,
619         __NR_ia32_setgroups32,
620         -1,
621     }
622 };
623
624 static probectl *probe_list[] = {
625     &main_probe, &ia32_probe
626 };
627
628
629 /********** Probing Configuration: IA64 **********/
630 #elif defined(AFS_IA64_LINUX20_ENV)
631 struct fptr {
632     void *ip;
633     unsigned long gp;
634 };
635
636 /* no 32-bit support on IA64 for now */
637 static probectl *probe_list[] = {
638     &main_probe
639 };
640
641
642 /********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
643 #elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
644 struct fptr {
645     void *ip;
646     unsigned long gp;
647 };
648
649 /* 
650  * syscall pairs/triplets to probe
651  * This has to be empty, because anything that would work will
652  * also match the main table, and that's no good.
653  */
654 static tryctl sct32_try[] = {
655     { 0 }
656 };
657
658 /* zapped syscalls for try_harder */
659 static int sct32_zapped_syscalls[] = {
660 #ifdef AFS_PPC64_LINUX20_ENV
661     /* These should be sufficient */
662     __NR_break, __NR_stty, __NR_gtty, __NR_ftime,
663     __NR_prof, __NR_lock, __NR_mpx,
664 #endif
665 #ifdef AFS_SPARC64_LINUX20_ENV
666     /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
667     52, 151, 152, 164, 218,
668 #endif
669     0
670 };
671
672 /* unique syscalls for try_harder */
673 /* mmap2 and fstat64 are implemented only for 32-bit calls */
674 static int sct32_unique_syscalls[] = {
675 #ifdef AFS_PPC64_LINUX20_ENV
676     /* _mmap2, _fstat64 */
677     192, 197,
678 #endif
679 #ifdef AFS_SPARC64_LINUX24_ENV
680     /* 
681      * On SPARC, we need some additional unique calls to make sure
682      * we don't match the SunOS-compatibility table.
683      */
684     __NR_sgetmask, __NR_ssetmask,
685 #endif
686     __NR_exit, __NR_mount, __NR_read, __NR_write,
687     __NR_open, __NR_close, __NR_unlink
688 };
689
690 /* probe control structure */
691 static probectl sct32_probe = {
692     /* symbol name and description */
693     "sys_call_table32",
694     "32-bit system call table",
695
696     /* syscall number of first entry in table */
697     0,
698
699     sys_call_table32,             /* weak symbol ref */
700     0, 0,                         /* module parameter answers */
701 #ifdef AFS_LINUX_sys_call_table32
702     AFS_LINUX_sys_call_table32,   /* compiled-in answer, if any */
703 #else
704     0,
705 #endif
706
707     sct32_try,                   /* array of combinations to try */
708
709     /* symbol in section to try scanning */
710 #if defined(AFS_SPARC64_LINUX20_ENV)
711     (unsigned long)&sys_close,
712 #else
713     (unsigned long)&init_mm,
714 #endif
715
716     /* default base address for scan */
717     /* base address bits to force to zero */
718     /* default length for scan */
719 #if   defined(AFS_SPARC64_LINUX20_ENV)
720     (unsigned long)(&sys_close),
721     0xfffff,
722     0x10000,
723 #else
724     (unsigned long)&init_mm,
725     0,
726     16384,
727 #endif
728
729     0, 0, 0, 0,
730
731     /* number and list of unimplemented system calls */
732     ((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1),
733     sct32_zapped_syscalls,
734
735     /* number and list of unique system calls */
736     (sizeof(sct32_unique_syscalls)/sizeof(sct32_unique_syscalls[0])),
737     sct32_unique_syscalls,
738
739     /* syscall number and pointer to verify match */
740     __NR_close, &sys_close,
741
742     /* syscalls to ignore for debugging */
743     {
744 #if defined(AFS_SPARC64_LINUX20_ENV)
745         227,
746 #else
747         137,
748 #endif
749         __NR_setgroups,
750         -1,
751         -1,
752     }
753 };
754
755 static probectl *probe_list[] = {
756     &main_probe, &sct32_probe
757 };
758
759
760 /********** End of Probing Configuration **********/
761
762 #else /* no per-platform probe control, so use the default list */
763 static probectl *probe_list[] = {
764     &main_probe
765 };
766 #endif
767
768 #define N_PROBE_LIST (sizeof(probe_list) / sizeof(*probe_list))
769 #define DEBUG_IN_RANGE(P,x) (!probe_debug_range ||                             \
770   (P->debug_answer &&                                                          \
771    (unsigned long)(x) >= (unsigned long)P->debug_answer &&                     \
772    (unsigned long)(x) <  (unsigned long)P->debug_answer + probe_debug_range))
773
774
775
776 static int check_table(probectl *P, PROBETYPE *ptr)
777 {
778     PROBETYPE *x;
779     int i, j;
780
781     for (x = ptr, i = 0; i < _SS(NR_syscalls); i++, x++) {
782 #ifdef OSI_PROBE_DEBUG
783         if (probe_debug & 0x0040) {
784             for (j = 0; j < 4; j++) {
785                 if (_SS(P->debug_ignore_NR[j]) == _SX(i + P->offset)) break;
786             }
787             if (j < 4) continue;
788         }
789 #endif
790         for (j = 0; j < 8; j++) {
791             if (_SS(probe_ignore_syscalls[j]) == _SX(i) + P->offset) break;
792         }
793         if (j < 8) continue;
794         if (*x <= ktxt_lower_bound) {
795 #ifdef OSI_PROBE_DEBUG
796             if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
797                 printk("<7>check 0x%lx -> %d [0x%lx]\n",
798                        (unsigned long)ptr, i, (unsigned long)*x);
799 #endif
800             return i;
801         }
802     }
803 #ifdef OSI_PROBE_DEBUG
804     if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
805         printk("<7>check 0x%lx -> ok\n", (unsigned long)ptr);
806 #endif
807     return -1;
808 }
809
810 static void *try(probectl *P, tryctl *T, PROBETYPE *aptr,
811                  unsigned long datalen)
812 {
813 #ifdef OSI_PROBE_KALLSYMS
814     char *mod_name, *sec_name, *sym_name;
815     unsigned long mod_start, mod_end;
816     unsigned long sec_start, sec_end;
817     unsigned long sym_start, sym_end;
818 #endif
819     unsigned long offset, ip1, ip2, ip3;
820     int ret;
821     PROBETYPE *ptr;
822
823 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
824     ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
825     ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
826     ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
827 #else
828     ip1 = (unsigned long)T->fn1;
829     ip2 = (unsigned long)T->fn2;
830     ip3 = (unsigned long)T->fn3;
831 #endif
832
833 #ifdef OSI_PROBE_DEBUG
834     if (probe_debug & 0x0001)
835         printk("<7>osi_probe: %s                      %s (%d->0x%lx, %d->0x%lx, %d->0x%lx)\n",
836                P->symbol, T->name, T->NR1, ip1, T->NR2, ip2, T->NR3, ip3);
837 #endif
838
839     if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3))
840         return 0;
841
842     for (offset = 0; offset < datalen; offset++, aptr++) {
843 #if defined(AFS_PPC64_LINUX20_ENV)
844         ptr = (PROBETYPE*)(*aptr);
845         if ((unsigned long)ptr <= KERNELBASE) {
846                 continue;
847         }
848 #else
849         ptr = aptr;
850 #endif
851         if ((unsigned long)ptr < init_mm.start_code ||
852 #if defined(AFS_AMD64_LINUX20_ENV)
853                 (unsigned long)ptr > init_mm.brk)
854 #else
855                 (unsigned long)ptr > init_mm.end_data)
856 #endif
857         {
858 /*           printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
859              continue;
860         }
861
862         ret = check_table(P, ptr);
863         if (ret >= 0) {
864             /* return value is number of entries to skip */
865             aptr    += ret;
866             offset += ret;
867             continue;
868         }
869
870 #ifdef OSI_PROBE_DEBUG
871         if ((probe_debug & 0x0002) && DEBUG_IN_RANGE(P,ptr))
872             printk("<7>try 0x%lx\n", (unsigned long)ptr);
873 #endif
874         if (ptr[_SS(T->NR1 - P->offset)] != ip1)        continue;
875         if (ptr[_SS(T->NR2 - P->offset)] != ip2)        continue;
876         if (ip3 && ptr[_SS(T->NR3 - P->offset)] != ip3) continue;
877
878 #ifdef OSI_PROBE_DEBUG
879         if (probe_debug & 0x0002)
880             printk("<7>try found 0x%lx\n", (unsigned long)ptr);
881 #endif
882 #ifdef OSI_PROBE_KALLSYMS
883         if (kallsyms_address_to_symbol) {
884             ret = kallsyms_address_to_symbol((unsigned long)ptr,
885                                              &mod_name, &mod_start, &mod_end,
886                                              &sec_name, &sec_start, &sec_end,
887                                              &sym_name, &sym_start, &sym_end);
888             if (!ret || strcmp(sym_name, P->symbol)) continue;
889         }
890 #endif
891         /* XXX should we make sure there is only one match? */
892         return (void *)ptr;
893     }
894     return 0;
895 }
896
897
898 static int check_harder(probectl *P, PROBETYPE *p)
899 {
900     unsigned long ip1;
901     int i, s;
902
903     /* Check zapped syscalls */
904     for (i = 1; i < P->n_zapped_syscalls; i++) {
905         if (p[_SS(P->zapped_syscalls[i])] != p[_SS(P->zapped_syscalls[0])]) {
906 #ifdef OSI_PROBE_DEBUG
907             if ((probe_debug & 0x0020) && DEBUG_IN_RANGE(P,p))
908                 printk("<7>check_harder 0x%lx zapped failed i=%d\n", (unsigned long)p, i);
909 #endif
910             return 0;
911         }
912     }
913
914     /* Check unique syscalls */
915     for (i = 0; i < P->n_unique_syscalls; i++) {
916         for (s = 0; s < NR_syscalls; s++) {
917             if (p[_SS(s)] == p[_SS(P->unique_syscalls[i])]
918                 && s != P->unique_syscalls[i]) {
919 #ifdef OSI_PROBE_DEBUG
920                 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
921                     printk("<7>check_harder 0x%lx unique failed i=%d s=%d\n", (unsigned long)p, i, s);
922 #endif
923                 return 0;
924             }
925         }
926     }
927
928 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
929     ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
930 #else
931     ip1 = (unsigned long)(P->verify_fn);
932 #endif
933
934     if (ip1 && p[_SS(P->verifyNR - P->offset)] != ip1) {
935 #ifdef OSI_PROBE_DEBUG
936         if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
937             printk("<7>check_harder 0x%lx verify failed\n", (unsigned long)p);
938 #endif
939         return 0;
940     }
941
942 #ifdef OSI_PROBE_DEBUG
943     if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
944         printk("<7>check_harder 0x%lx success!\n", (unsigned long)p);
945 #endif
946     return 1;
947 }
948
949 static void *try_harder(probectl *P, PROBETYPE *ptr, unsigned long datalen)
950 {
951 #ifdef OSI_PROBE_KALLSYMS
952     char *mod_name, *sec_name, *sym_name;
953     unsigned long mod_start, mod_end;
954     unsigned long sec_start, sec_end;
955     unsigned long sym_start, sym_end;
956 #endif
957     unsigned long offset;
958     void *match = 0;
959     int ret;
960
961 #ifdef OSI_PROBE_DEBUG
962     if (probe_debug & 0x0001)
963         printk("<7>osi_probe: %s                      try_harder\n", P->symbol);
964 #endif
965     for (offset = 0; offset < datalen; offset++, ptr++) {
966          if ((unsigned long)ptr < init_mm.start_code ||
967 #if defined(AFS_AMD64_LINUX20_ENV)
968                 (unsigned long)ptr > init_mm.brk)
969 #else
970                 (unsigned long)ptr > init_mm.end_data)
971 #endif
972         {
973 /*           printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
974              continue;
975         }
976         ret = check_table(P, ptr);
977         if (ret >= 0) {
978             /* return value is number of entries to skip */
979             ptr    += ret;
980             offset += ret;
981             continue;
982         }
983
984 #ifdef OSI_PROBE_DEBUG
985         if ((probe_debug & 0x0004) && DEBUG_IN_RANGE(P,ptr))
986             printk("<7>try_harder 0x%lx\n", (unsigned long)ptr);
987 #endif
988         if (!check_harder(P, ptr))
989             continue;
990
991 #ifdef OSI_PROBE_DEBUG
992         if (probe_debug & 0x0004)
993             printk("<7>try_harder found 0x%lx\n", (unsigned long)ptr);
994 #endif
995
996 #ifdef OSI_PROBE_KALLSYMS
997         if (kallsyms_address_to_symbol) {
998             ret = kallsyms_address_to_symbol((unsigned long)ptr,
999                                              &mod_name, &mod_start, &mod_end,
1000                                              &sec_name, &sec_start, &sec_end,
1001                                              &sym_name, &sym_start, &sym_end);
1002             if (!ret || strcmp(sym_name, P->symbol)) continue;
1003         }
1004 #endif
1005
1006         if (match) {
1007 #ifdef OSI_PROBE_DEBUG
1008             if (probe_debug & 0x0005)
1009                 printk("<7>%s: try_harder found multiple matches!\n", P->symbol);
1010 #endif
1011             return 0;
1012         }
1013
1014         match = (void *)ptr;
1015         if (!probe_carefully)
1016             break;
1017     }
1018     return match;
1019 }
1020
1021
1022 #ifdef OSI_PROBE_DEBUG
1023 #define check_result(x,m) do {                                                             \
1024     if (probe_debug & 0x0001) {                                                              \
1025         printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
1026     }                                                                                      \
1027     if ((x) && ((int)(x)) != -ENOENT) {                                                    \
1028         *method = (m);                                                                     \
1029         final_answer = (void *)(x);                                                        \
1030     }                                                                                      \
1031 } while (0)
1032 #else
1033 #define check_result(x,m) do {  \
1034     if ((x) && ((int)(x)) != -ENOENT) { \
1035         *method = (m);          \
1036         return (void *)(x);     \
1037     }                           \
1038 } while (0)
1039 #endif
1040 static void *scan_for_syscall_table(probectl *P, PROBETYPE *B, unsigned long L)
1041 {
1042     tryctl *T;
1043     void *answer;
1044 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1045     void *answer2;
1046 #endif
1047 #ifdef OSI_PROBE_DEBUG
1048     void *final_answer = 0;
1049 #endif
1050 #ifdef OSI_PROBE_DEBUG
1051     if (probe_debug & 0x0007)
1052         printk("<7>osi_probe: %s                      base=0x%lx, len=0x%lx\n",
1053                P->symbol, (unsigned long)B, L);
1054     if (probe_debug & 0x0009) {
1055         printk("<7>osi_probe: %s                      ktxt_lower_bound=0x%lx\n",
1056                P->symbol, ktxt_lower_bound);
1057         printk("<7>osi_probe: %s                      NR_syscalls=%d\n",
1058                P->symbol, NR_syscalls);
1059     }
1060 #endif
1061
1062     for (T = P->trylist; T->name; T++) {
1063         answer = try(P, T, B, L);
1064 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1065         answer2 = try(P, T, (PROBETYPE *)(2 + (void *)B), L);
1066 #ifdef OSI_PROBE_DEBUG
1067         if (probe_debug & 0x0003) {
1068             printk("<7>osi_probe: %s = 0x%016lx %s (even)\n",
1069                    P->symbol, (unsigned long)(answer), T->name);
1070             printk("<7>osi_probe: %s = 0x%016lx %s (odd)\n",
1071                    P->symbol, (unsigned long)(answer2), T->name);
1072         }
1073 #endif
1074         if (answer && answer2) answer = 0;
1075         else if (answer2) answer = answer2;
1076 #endif
1077         if (answer)
1078             return answer;
1079     }
1080
1081     /* XXX more checks here */
1082
1083     answer = try_harder(P, B, L);
1084 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1085     answer2 = try_harder(P, (PROBETYPE *)(2 + (void *)B), L);
1086 #ifdef OSI_PROBE_DEBUG
1087     if (probe_debug & 0x0005) {
1088         printk("<7>osi_probe: %s = 0x%016lx pattern scan (even)\n",
1089                P->symbol, (unsigned long)(answer));
1090         printk("<7>osi_probe: %s = 0x%016lx pattern scan (odd)\n",
1091                P->symbol, (unsigned long)(answer2));
1092     }
1093 #endif
1094     if (answer && answer2) answer = 0;
1095     else if (answer2) answer = answer2;
1096 #endif
1097     return answer;
1098 }
1099
1100 static void *do_find_syscall_table(probectl *P, char **method)
1101 {
1102 #ifdef OSI_PROBE_KALLSYMS
1103     char *mod_name, *sec_name, *sym_name;
1104     unsigned long mod_start, mod_end;
1105     unsigned long sec_start, sec_end;
1106     unsigned long sym_start, sym_end;
1107     unsigned long token;
1108     int ret;
1109 #endif
1110     PROBETYPE *B;
1111     unsigned long L;
1112     void *answer;
1113 #ifdef OSI_PROBE_DEBUG
1114     void *final_answer = 0;
1115 #endif
1116
1117     *method = "not found";
1118
1119     /* if it's exported, there's nothing to do */
1120     check_result(P->weak_answer, "exported");
1121
1122     /* ask the kernel to do the name lookup, if it's willing */
1123 #ifdef OSI_PROBE_KALLSYMS
1124     if (kallsyms_symbol_to_address) {
1125         token = 0;
1126         sym_start = 0;
1127         do {
1128             ret = kallsyms_symbol_to_address(P->symbol, &token,
1129                                              &mod_name, &mod_start, &mod_end,
1130                                              &sec_name, &sec_start, &sec_end,
1131                                              &sym_name, &sym_start, &sym_end);
1132             if (ret && !strcmp(mod_name, "kernel") && sym_start)
1133                 break;
1134             sym_start = 0;
1135         } while (ret);
1136         check_result(sym_start, "kallsyms_symbol_to_address");
1137     }
1138 #endif
1139
1140     /* Maybe a little birdie told us */
1141     check_result(P->parm_answer,  "module parameter");
1142     check_result(P->given_answer, "compiled-in");
1143
1144     /* OK, so we have to scan. */
1145     B = (PROBETYPE *)((P->try_base) & ~(P->try_base_mask));
1146     L = P->try_length;
1147     /* Now, see if the kernel will tell us something better than the default */
1148 #ifdef OSI_PROBE_KALLSYMS
1149     if (kallsyms_address_to_symbol) {
1150         ret = kallsyms_address_to_symbol(P->try_sect_sym,
1151                                          &mod_name, &mod_start, &mod_end,
1152                                          &sec_name, &sec_start, &sec_end,
1153                                          &sym_name, &sym_start, &sym_end);
1154         if (ret) {
1155             B = (PROBETYPE *)sec_start;
1156             L = (sec_end - sec_start) / sizeof(unsigned long);
1157         }
1158     }
1159 #endif
1160    
1161     answer = scan_for_syscall_table(P, B, L);
1162     check_result(answer, "pattern scan");
1163     B = (PROBETYPE *)((P->alt_try_base) & ~(P->alt_try_base_mask));
1164     L = P->alt_try_length;
1165     /* Now, see if the kernel will tell us something better than the default */
1166 #ifdef OSI_PROBE_KALLSYMS
1167     if (kallsyms_address_to_symbol && P->alt_try_sect_sym) {
1168         ret = kallsyms_address_to_symbol(P->alt_try_sect_sym,
1169                                          &mod_name, &mod_start, &mod_end,
1170                                          &sec_name, &sec_start, &sec_end,
1171                                          &sym_name, &sym_start, &sym_end);
1172         if (ret) {
1173             B = (PROBETYPE *)sec_start;
1174             L = (sec_end - sec_start) / sizeof(unsigned long);
1175         }
1176     }
1177 #endif
1178     if (B && L) {
1179         answer = scan_for_syscall_table(P, B, L);
1180         check_result(answer, "pattern scan");
1181     }
1182 #ifdef OSI_PROBE_DEBUG
1183     return final_answer;
1184 #else
1185     return 0;
1186 #endif
1187 }
1188
1189 void *osi_find_syscall_table(int which)
1190 {
1191     probectl *P;
1192     void *answer;
1193     char *method;
1194
1195     if (which < 0 || which >= N_PROBE_LIST) {
1196         printk("error - afs_find_syscall_table called with invalid index!\n");
1197         return 0;
1198     }
1199     P = probe_list[which];
1200     if (which < 4) {
1201         P->parm_answer = (void *)sys_call_table_addr[which];
1202 #ifdef OSI_PROBE_DEBUG
1203         P->debug_answer = (void *)probe_debug_addr[which];
1204 #endif
1205     }
1206     answer = do_find_syscall_table(P, &method);
1207     if (!answer) {
1208         printk("Warning: failed to find address of %s\n", P->desc);
1209         printk("System call hooks will not be installed; proceeding anyway\n");
1210         return 0;
1211     }
1212     printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
1213     return answer;
1214 }
1215
1216
1217 #ifdef OSI_PROBE_STANDALONE
1218 int __init osi_probe_init(void)
1219 {
1220     int i;
1221
1222     if (!probe_debug_tag) probe_debug_tag = jiffies;
1223     printk("*** osi_probe %ld debug = 0x%04x ***\n",
1224            probe_debug_tag, probe_debug);
1225     for (i = 0; i < N_PROBE_LIST; i++)
1226         (void)osi_find_syscall_table(i);
1227     return 0;
1228 }
1229
1230 void osi_probe_exit(void) { }
1231
1232 module_init(osi_probe_init);
1233 module_exit(osi_probe_exit);
1234 #endif
1235 #endif
1236 #else
1237 void *osi_find_syscall_table(int which)
1238 {
1239     return 0;
1240 }
1241 #endif /* EXPORTED_INIT_MM */