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