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