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