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