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