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