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