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