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