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