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