2 * vi:set cin noet sw=4 tw=70:
3 * Copyright 2004, International Business Machines Corporation and others.
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
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.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
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.
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.
30 * Alternatively, this software may be distributed under the terms of the
31 * GNU General Public License ("GPL").
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
46 /* Code to find the Linux syscall table */
48 #ifdef OSI_PROBE_STANDALONE
49 #define OSI_PROBE_DEBUG
51 #ifndef OSI_PROBE_STANDALONE
52 #include <afsconfig.h>
53 #include "afs/param.h"
55 #include <linux/module.h> /* early to avoid printf->printk mapping */
56 #ifndef OSI_PROBE_STANDALONE
57 #include "afs/sysincludes.h"
58 #include "afsincludes.h"
60 #include <linux/version.h>
61 #include <linux/config.h>
62 #include <linux/linkage.h>
63 #include <linux/init.h>
64 #include <linux/unistd.h>
67 #ifdef AFS_AMD64_LINUX20_ENV
68 #include <asm/ia32_unistd.h>
71 /* number of syscalls */
72 /* NB: on MIPS we care about the 4xxx range */
74 #define NR_syscalls 222
77 /* lower bound of valid kernel text pointers */
78 #ifdef AFS_IA64_LINUX20_ENV
79 #define ktxt_lower_bound (((unsigned long)&kernel_thread ) & 0xfff00000L)
81 #define ktxt_lower_bound (((unsigned long)&kernel_thread ) & ~0xfffffL)
84 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
85 * even though pointers are 64 bit quantities.
87 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
88 #define SYSCALLTYPE unsigned int
91 #define SYSCALLTYPE void *
92 #define PROBETYPE long
95 #if defined(AFS_S390X_LINUX20_ENV) && !defined(AFS_S390X_LINUX26_ENV)
96 #define _SS(x) ((x) << 1)
97 #define _SX(x) ((x) &~ 1)
104 /* Allow the user to specify sys_call_table addresses */
105 static unsigned long sys_call_table_addr[4] = { 0,0,0,0 };
106 MODULE_PARM(sys_call_table_addr, "1-4l");
107 MODULE_PARM_DESC(sys_call_table_addr, "Location of system call tables");
109 /* If this is set, we are more careful about avoiding duplicate matches */
110 static int probe_carefully = 1;
111 MODULE_PARM(probe_carefully, "i");
112 MODULE_PARM_DESC(probe_carefully, "Probe for system call tables carefully");
114 static int probe_ignore_syscalls[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
115 MODULE_PARM(probe_ignore_syscalls, "1-8i");
116 MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
118 #ifdef OSI_PROBE_DEBUG
121 * 0x0001 - General debugging
122 * 0x0002 - detail - try
123 * 0x0004 - detail - try_harder
124 * 0x0008 - detail - check_table
125 * 0x0010 - detail - check_harder
126 * 0x0020 - detail - check_harder/zapped
127 * 0x0040 - automatically ignore setgroups and afs_syscall
129 static int probe_debug = 0x41;
130 MODULE_PARM(probe_debug, "i");
131 MODULE_PARM_DESC(probe_debug, "Debugging level");
133 static unsigned long probe_debug_addr[4] = { 0,0,0,0 };
134 MODULE_PARM(probe_debug_addr, "1-4l");
135 MODULE_PARM_DESC(probe_debug_addr, "Debug range starting locations");
137 static unsigned long probe_debug_range = 0;
138 MODULE_PARM(probe_debug_range, "l");
139 MODULE_PARM_DESC(probe_debug_range, "Debug range length");
141 static unsigned long probe_debug_tag = 0;
142 MODULE_PARM(probe_debug_tag, "l");
143 MODULE_PARM_DESC(probe_debug_tag, "Debugging output start tag");
147 /* Weak references are our friends. They are supported by the in-kernel
148 * linker in Linux 2.6 and by all versions of modutils back to 2.2pre1.
149 * A weak reference not satisified by the kernel will have value zero.
151 * Unfortunately, weak references to functions don't work right on
152 * IA64; specifically, if you actually try to make a call through
153 * such a reference, and the symbol doesn't exist in the kernel, then
154 * the module relocation code will oops. A workaround for this is
155 * probably possible, but the use of kallsyms_* is of limited value,
156 * so I'm not bothing with the effort for now.
157 * -- jhutz, 10-Feb-2005
159 #ifdef OSI_PROBE_KALLSYMS
160 extern int kallsyms_symbol_to_address(char *name, unsigned long *token,
162 unsigned long *mod_start,
163 unsigned long *mod_end,
165 unsigned long *sec_start,
166 unsigned long *sec_end,
168 unsigned long *sym_start,
169 unsigned long *sym_end
170 ) __attribute__((weak));
172 extern int kallsyms_address_to_symbol(unsigned long address,
174 unsigned long *mod_start,
175 unsigned long *mod_end,
177 unsigned long *sec_start,
178 unsigned long *sec_end,
180 unsigned long *sym_start,
181 unsigned long *sym_end
182 ) __attribute__((weak));
185 extern SYSCALLTYPE sys_call_table[] __attribute__((weak));
186 extern SYSCALLTYPE ia32_sys_call_table[] __attribute__((weak));
187 extern SYSCALLTYPE sys_call_table32[] __attribute__((weak));
188 extern SYSCALLTYPE sys_call_table_emu[] __attribute__((weak));
190 extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
191 extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
192 extern asmlinkage ssize_t sys_write(unsigned int, const char *, size_t) __attribute__((weak));
193 #ifdef AFS_LINUX26_ENV
194 extern asmlinkage long sys_wait4(pid_t, int *, int, struct rusage *) __attribute__((weak));
196 extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *) __attribute__((weak));
198 extern asmlinkage long sys_exit (int) __attribute__((weak));
199 extern asmlinkage long sys_open (const char *, int, int) __attribute__((weak));
200 extern asmlinkage long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak));
203 /* Structures used to control probing. We put all the details of which
204 * symbols we're interested in, what syscall functions to look for, etc
205 * into tables, so we can then have a single copy of the functions that
206 * actually do the work.
219 char *symbol; /* symbol name */
220 char *desc; /* description for messages */
221 int offset; /* first syscall number in table */
223 void *weak_answer; /* weak symbol ref */
224 void *parm_answer; /* module parameter answer */
225 void *debug_answer; /* module parameter answer */
226 unsigned long given_answer; /* compiled-in answer, if any */
228 tryctl *trylist; /* array of combinations to try */
230 unsigned long try_sect_sym; /* symbol in section to try scanning */
231 unsigned long try_base; /* default base address for scan */
232 unsigned long try_base_mask; /* base address bits to force to zero */
233 unsigned long try_length; /* default length for scan */
235 int n_zapped_syscalls; /* number of unimplemented system calls */
236 int *zapped_syscalls; /* list of unimplemented system calls */
238 int n_unique_syscalls; /* number of unique system calls */
239 int *unique_syscalls; /* list of unimplemented system calls */
241 int verifyNR; /* syscall number to verify match */
242 void *verify_fn; /* syscall pointer to verify match */
244 int debug_ignore_NR[4]; /* syscalls to ignore for debugging */
249 /********** Probing Configuration: sys_call_table **********/
251 /* syscall pairs/triplets to probe */
252 /* On PPC64 and SPARC64, we need to omit the ones that might match both tables */
253 static tryctl main_try[] = {
254 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
255 { "scan: close+chdir+write", __NR_close, &sys_close, __NR_chdir, &sys_chdir, __NR_write, &sys_write },
257 { "scan: close+wait4", __NR_close, &sys_close, __NR_wait4, &sys_wait4, -1, 0 },
258 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
259 { "scan: close+chdir", __NR_close, &sys_close, __NR_chdir, &sys_chdir, -1, 0 },
261 { "scan: close+ioctl", __NR_close, &sys_close, __NR_ioctl, &sys_ioctl, -1, 0 },
262 { "scan: exit+open", __NR_exit, &sys_exit, __NR_open, &sys_open, -1, 0 },
266 /* zapped syscalls for try_harder */
267 /* this list is based on the table in 'zapped_syscalls' */
269 static int main_zapped_syscalls[] = {
271 * SPARC-Linux uses syscall number mappings chosen to be compatible
272 * with SunOS. So, it doesn't have any of the traditional calls or
273 * the new STREAMS ones. However, there are a number of syscalls
274 * which are SunOS-specific (not implemented on Linux), i386-specific
275 * (not implemented on SPARC-Linux), or implemented only on one of
276 * sparc32 or sparc64. Of course, there are no __NR macros for most
279 * Note that the calls we list here are implemented by sys_nis_syscall,
280 * not by sys_ni_syscall. That means we have to exclude all of the
281 * other entries, or we might get a sys_ni_syscall into the list and
282 * the test would no longer work.
284 #if defined(AFS_SPARC64_LINUX20_ENV)
285 /* mmap2, fstat64, getmsg, putmsg, modify_ldt */
286 56, 63, 151, 152, 218,
287 #elif defined(AFS_SPARC_LINUX20_ENV)
288 /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
289 52, 151, 152, 164, 218,
290 #else /* !AFS_SPARC_LINUX20_ENV */
293 * These 7 syscalls are present in the syscall table on most "older"
294 * platforms that use the traditional syscall number mappings. They
295 * are not implemented on any platform.
319 * On s390 and arm (but not arm26), the seven traditional unimplemented
320 * system calls are indeed present and unimplemented. However, the
321 * corresponding __NR macros are not defined, so the tests above fail.
322 * Instead, we just have to know the numbers for these.
324 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
325 /* break, stty, gtty, ftime, prof, lock, mpx */
326 17, 31, 32, 35, 44, 53, 56,
330 * Sadly, some newer platforms like IA64, amd64, and PA-RISC don't have
331 * the traditional numbers, so the list above are not helpful. They
332 * do have entries for getpmsg/putpmsg, which are always unimplemented.
342 * The module-loading mechanism changed in Linux 2.6, and insmod's
343 * loss is our gain: three new unimplemented system calls!
345 #if defined(AFS_LINUX26_ENV)
349 #ifdef __NR_query_module
352 #ifdef __NR_get_kernel_syms
353 __NR_get_kernel_syms,
355 #endif /* AFS_LINUX26_ENV */
358 * On IA64, the old module-loading calls are indeed present and
359 * unimplemented, but the __NR macros are not defined. Again,
360 * we simply have to know their numbers.
362 #ifdef AFS_IA64_LINUX26_ENV
363 /* create_module, query_module, get_kernel_sysms */
367 /* And the same deal for arm (not arm26), if we ever support that. */
369 /* create_module, query_module, get_kernel_sysms */
374 * Alpha-Linux uses syscall number mappings chosen to be compatible
375 * with OSF/1. So, it doesn't have any of the traditional calls or
376 * the new STREAMS ones, but it does have several OSF/1-specific
377 * syscalls which are not implemented on Linux. These don't exist on
378 * any other platform.
380 #ifdef __NR_osf_syscall
383 #ifdef __NR_osf_profil
386 #ifdef __NR_osf_reboot
389 #ifdef __NR_osf_kmodcall
392 #ifdef __NR_osf_old_vtrace
397 * On PPC64, we need a couple more entries to distinguish the two
398 * tables, since the system call numbers are the same and the sets of
399 * unimplemented calls are very similar.
400 * mmap2 and fstat64 are implemented only for 32-bit calls
402 #ifdef AFS_PPC64_LINUX20_ENV
403 /* _mmap2, _fstat64 */
405 #endif /* AFS_PPC64_LINUX20_ENV */
407 /* Similarly for S390X, with lcown16 and fstat64 */
408 #ifdef AFS_S390X_LINUX20_ENV
409 /* lchown16, fstat64 */
412 #endif /* !AFS_SPARC_LINUX20_ENV */
416 /* unique syscalls for try_harder */
417 static int main_unique_syscalls[] = {
418 #if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
420 * On SPARC, we need some additional unique calls to make sure
421 * we don't match the SunOS-compatibility table.
423 __NR_sgetmask, __NR_ssetmask,
425 __NR_exit, __NR_mount, __NR_read, __NR_write,
426 __NR_open, __NR_close, __NR_unlink
429 /* probe control structure */
430 static probectl main_probe = {
431 /* symbol name and description */
435 /* syscall number of first entry in table */
436 #ifdef AFS_IA64_LINUX20_ENV
442 sys_call_table, /* weak symbol ref */
443 0, 0, /* module parameter answers */
444 #ifdef AFS_LINUX_sys_call_table
445 AFS_LINUX_sys_call_table, /* compiled-in answer, if any */
450 main_try, /* array of combinations to try */
452 /* symbol in section to try scanning */
453 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
454 (unsigned long)&sys_close,
455 #elif defined(AFS_AMD64_LINUX20_ENV)
456 /* On this platform, it's in a different section! */
457 (unsigned long)&tasklist_lock,
459 (unsigned long)&init_mm,
462 /* default base address for scan */
463 /* base address bits to force to zero */
464 /* default length for scan */
465 #if defined(AFS_SPARC64_LINUX20_ENV)
466 (unsigned long)(&sys_close),
469 #elif defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
470 /* bleah; this is so suboptimal */
471 (unsigned long)(&sys_close),
474 #elif defined(AFS_IA64_LINUX20_ENV)
475 (unsigned long)(&init_mm),
478 #elif defined(AFS_AMD64_LINUX20_ENV)
479 (unsigned long)(&tasklist_lock) - 0x30000,
482 #elif defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC_LINUX20_ENV)
483 (unsigned long)&init_mm,
487 (unsigned long)&init_mm,
492 /* number and list of unimplemented system calls */
493 ((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1),
494 main_zapped_syscalls,
496 /* number and list of unique system calls */
497 (sizeof(main_unique_syscalls)/sizeof(main_unique_syscalls[0])),
498 main_unique_syscalls,
500 /* syscall number and pointer to verify match */
501 __NR_close, &sys_close,
503 /* syscalls to ignore for debugging */
505 #if defined(AFS_ALPHA_LINUX20_ENV)
507 #elif defined(AFS_AMD64_LINUX20_ENV)
509 #elif defined(AFS_IA64_LINUX20_ENV)
511 #elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
517 #ifdef __NR_setgroups32
527 /********** Probing Configuration: amd64 ia32_sys_call_table **********/
528 #if defined(AFS_AMD64_LINUX20_ENV)
530 /* syscall pairs/triplets to probe */
531 static tryctl ia32_try[] = {
532 { "scan: close+chdir+write", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir, __NR_ia32_write, &sys_write },
533 { "scan: close+chdir", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir, -1, 0 },
537 /* zapped syscalls for try_harder */
538 static int ia32_zapped_syscalls[] = {
539 __NR_ia32_break, __NR_ia32_stty, __NR_ia32_gtty, __NR_ia32_ftime,
540 __NR_ia32_prof, __NR_ia32_lock, __NR_ia32_mpx,
544 /* unique syscalls for try_harder */
545 static int ia32_unique_syscalls[] = {
546 __NR_ia32_exit, __NR_ia32_mount, __NR_ia32_read, __NR_ia32_write,
547 __NR_ia32_open, __NR_ia32_close, __NR_ia32_unlink
550 /* probe control structure */
551 static probectl ia32_probe = {
552 /* symbol name and description */
553 "ia32_sys_call_table",
554 "32-bit system call table",
556 /* syscall number of first entry in table */
559 ia32_sys_call_table, /* weak symbol ref */
560 0, 0, /* module parameter answers */
561 #ifdef AFS_LINUX_ia32_sys_call_table
562 AFS_LINUX_ia32_sys_call_table,/* compiled-in answer, if any */
567 ia32_try, /* array of combinations to try */
569 /* symbol in section to try scanning */
570 (unsigned long)&init_mm,
572 /* default base address for scan */
573 /* base address bits to force to zero */
574 /* default length for scan */
575 (unsigned long)&init_mm,
577 (0x180000 / sizeof(unsigned long *)),
579 /* number and list of unimplemented system calls */
580 ((sizeof(ia32_zapped_syscalls)/sizeof(ia32_zapped_syscalls[0])) - 1),
581 ia32_zapped_syscalls,
583 /* number and list of unique system calls */
584 (sizeof(ia32_unique_syscalls)/sizeof(ia32_unique_syscalls[0])),
585 ia32_unique_syscalls,
587 /* syscall number and pointer to verify match */
588 __NR_ia32_close, &sys_close,
590 /* syscalls to ignore for debugging */
594 __NR_ia32_setgroups32,
599 static probectl *probe_list[] = {
600 &main_probe, &ia32_probe
604 /********** Probing Configuration: IA64 **********/
605 #elif defined(AFS_IA64_LINUX20_ENV)
611 /* no 32-bit support on IA64 for now */
612 static probectl *probe_list[] = {
617 /********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
618 #elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
621 * syscall pairs/triplets to probe
622 * This has to be empty, because anything that would work will
623 * also match the main table, and that's no good.
625 static tryctl sct32_try[] = {
629 /* zapped syscalls for try_harder */
630 static int sct32_zapped_syscalls[] = {
631 #ifdef AFS_PPC64_LINUX20_ENV
632 /* These should be sufficient */
633 __NR_break, __NR_stty, __NR_gtty, __NR_ftime,
634 __NR_prof, __NR_lock, __NR_mpx,
636 #ifdef AFS_SPARC64_LINUX20_ENV
637 /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
638 52, 151, 152, 164, 218,
643 /* unique syscalls for try_harder */
644 /* mmap2 and fstat64 are implemented only for 32-bit calls */
645 static int sct32_unique_syscalls[] = {
646 #ifdef AFS_PPC64_LINUX20_ENV
647 /* _mmap2, _fstat64 */
650 #ifdef AFS_SPARC64_LINUX24_ENV
652 * On SPARC, we need some additional unique calls to make sure
653 * we don't match the SunOS-compatibility table.
655 __NR_sgetmask, __NR_ssetmask,
657 __NR_exit, __NR_mount, __NR_read, __NR_write,
658 __NR_open, __NR_close, __NR_unlink
661 /* probe control structure */
662 static probectl sct32_probe = {
663 /* symbol name and description */
665 "32-bit system call table",
667 /* syscall number of first entry in table */
670 sys_call_table32, /* weak symbol ref */
671 0, 0, /* module parameter answers */
672 #ifdef AFS_LINUX_sys_call_table32
673 AFS_LINUX_sys_call_table32, /* compiled-in answer, if any */
678 sct32_try, /* array of combinations to try */
680 /* symbol in section to try scanning */
681 #if defined(AFS_SPARC64_LINUX20_ENV)
682 (unsigned long)&sys_close,
684 (unsigned long)&init_mm,
687 /* default base address for scan */
688 /* base address bits to force to zero */
689 /* default length for scan */
690 #if defined(AFS_SPARC64_LINUX20_ENV)
691 (unsigned long)(&sys_close),
695 (unsigned long)&init_mm,
700 /* number and list of unimplemented system calls */
701 ((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1),
702 sct32_zapped_syscalls,
704 /* number and list of unique system calls */
705 (sizeof(sct32_unique_syscalls)/sizeof(sct32_unique_syscalls[0])),
706 sct32_unique_syscalls,
708 /* syscall number and pointer to verify match */
709 __NR_close, &sys_close,
711 /* syscalls to ignore for debugging */
713 #if defined(AFS_SPARC64_LINUX20_ENV)
724 static probectl *probe_list[] = {
725 &main_probe, &sct32_probe
729 /********** Probing Configuration: s390x sys_call_table_emu **********/
730 /* We only actually need to do this on s390x_linux26 and later.
731 * On earlier versions, the two tables were interleaved and so
732 * have related base addresses.
734 #elif defined(AFS_S390X_LINUX26_ENV)
736 /* syscall pairs/triplets to probe */
737 /* nothing worthwhile is exported, so this is empty */
738 static tryctl emu_try[] = {
742 /* zapped syscalls for try_harder */
743 static int emu_zapped_syscalls[] = {
744 /* break, stty, gtty, ftime, prof, lock, mpx */
745 17, 31, 32, 35, 44, 53, 56,
749 /* unique syscalls for try_harder */
750 static int emu_unique_syscalls[] = {
751 /* lchown16, fstat64 */
753 __NR_exit, __NR_mount, __NR_read, __NR_write,
754 __NR_open, __NR_close, __NR_unlink
757 /* probe control structure */
758 static probectl emu_probe = {
759 /* symbol name and description */
760 "sys_call_table_emu",
761 "32-bit system call table",
763 /* syscall number of first entry in table */
766 sys_call_table_emu, /* weak symbol ref */
767 0, 0, /* module parameter answers */
768 #ifdef AFS_LINUX_sys_call_table_emu
769 AFS_LINUX_sys_call_table_emu, /* compiled-in answer, if any */
774 emu_try, /* array of combinations to try */
776 /* symbol in section to try scanning */
777 (unsigned long)&sys_close,
779 /* default base address for scan */
780 /* base address bits to force to zero */
781 /* default length for scan */
782 (unsigned long)&sys_close,
786 /* number and list of unimplemented system calls */
787 ((sizeof(emu_zapped_syscalls)/sizeof(emu_zapped_syscalls[0])) - 1),
790 /* number and list of unique system calls */
791 (sizeof(emu_unique_syscalls)/sizeof(emu_unique_syscalls[0])),
794 /* syscall number and pointer to verify match */
795 __NR_close, &sys_close,
797 /* syscalls to ignore for debugging */
806 static probectl *probe_list[] = {
807 &main_probe, &emu_probe
811 /********** End of Probing Configuration **********/
813 #else /* no per-platform probe control, so use the default list */
814 static probectl *probe_list[] = {
819 #define N_PROBE_LIST (sizeof(probe_list) / sizeof(*probe_list))
820 #define DEBUG_IN_RANGE(P,x) (!probe_debug_range || \
821 (P->debug_answer && \
822 (unsigned long)(x) >= (unsigned long)P->debug_answer && \
823 (unsigned long)(x) < (unsigned long)P->debug_answer + probe_debug_range))
827 static int check_table(probectl *P, PROBETYPE *ptr)
832 for (x = ptr, i = 0; i < _SS(NR_syscalls); i++, x++) {
833 #ifdef OSI_PROBE_DEBUG
834 if (probe_debug & 0x0040) {
835 for (j = 0; j < 4; j++) {
836 if (_SS(P->debug_ignore_NR[j]) == _SX(i + P->offset)) break;
841 for (j = 0; j < 8; j++) {
842 if (_SS(probe_ignore_syscalls[j]) == _SX(i) + P->offset) break;
845 if (*x <= ktxt_lower_bound) {
846 #ifdef OSI_PROBE_DEBUG
847 if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
848 printk("<7>check 0x%lx -> %d [0x%lx]\n",
849 (unsigned long)ptr, i, (unsigned long)*x);
854 #ifdef OSI_PROBE_DEBUG
855 if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
856 printk("<7>check 0x%lx -> ok\n", (unsigned long)ptr);
861 static void *try(probectl *P, tryctl *T, PROBETYPE *ptr,
862 unsigned long datalen)
864 #ifdef OSI_PROBE_KALLSYMS
865 char *mod_name, *sec_name, *sym_name;
866 unsigned long mod_start, mod_end;
867 unsigned long sec_start, sec_end;
868 unsigned long sym_start, sym_end;
870 unsigned long offset, ip1, ip2, ip3;
873 #ifdef AFS_IA64_LINUX20_ENV
874 ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
875 ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
876 ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
878 ip1 = (unsigned long)T->fn1;
879 ip2 = (unsigned long)T->fn2;
880 ip3 = (unsigned long)T->fn3;
883 #ifdef OSI_PROBE_DEBUG
884 if (probe_debug & 0x0001)
885 printk("<7>osi_probe: %s %s (%d->0x%lx, %d->0x%lx, %d->0x%lx)\n",
886 P->symbol, T->name, T->NR1, ip1, T->NR2, ip2, T->NR3, ip3);
889 if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3))
892 for (offset = 0; offset < datalen; offset++, ptr++) {
893 ret = check_table(P, ptr);
895 /* return value is number of entries to skip */
901 #ifdef OSI_PROBE_DEBUG
902 if ((probe_debug & 0x0002) && DEBUG_IN_RANGE(P,ptr))
903 printk("<7>try 0x%lx\n", (unsigned long)ptr);
905 if (ptr[_SS(T->NR1 - P->offset)] != ip1) continue;
906 if (ptr[_SS(T->NR2 - P->offset)] != ip2) continue;
907 if (ip3 && ptr[_SS(T->NR3 - P->offset)] != ip3) continue;
909 #ifdef OSI_PROBE_DEBUG
910 if (probe_debug & 0x0002)
911 printk("<7>try found 0x%lx\n", (unsigned long)ptr);
913 #ifdef OSI_PROBE_KALLSYMS
914 if (kallsyms_address_to_symbol) {
915 ret = kallsyms_address_to_symbol((unsigned long)ptr,
916 &mod_name, &mod_start, &mod_end,
917 &sec_name, &sec_start, &sec_end,
918 &sym_name, &sym_start, &sym_end);
919 if (!ret || strcmp(sym_name, P->symbol)) continue;
922 /* XXX should we make sure there is only one match? */
929 static int check_harder(probectl *P, PROBETYPE *p)
934 /* Check zapped syscalls */
935 for (i = 1; i < P->n_zapped_syscalls; i++) {
936 if (p[_SS(P->zapped_syscalls[i])] != p[_SS(P->zapped_syscalls[0])]) {
937 #ifdef OSI_PROBE_DEBUG
938 if ((probe_debug & 0x0020) && DEBUG_IN_RANGE(P,p))
939 printk("<7>check_harder 0x%lx zapped failed i=%d\n", (unsigned long)p, i);
945 /* Check unique syscalls */
946 for (i = 0; i < P->n_unique_syscalls; i++) {
947 for (s = 0; s < NR_syscalls; s++) {
948 if (p[_SS(s)] == p[_SS(P->unique_syscalls[i])]
949 && s != P->unique_syscalls[i]) {
950 #ifdef OSI_PROBE_DEBUG
951 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
952 printk("<7>check_harder 0x%lx unique failed i=%d s=%d\n", (unsigned long)p, i, s);
959 #ifdef AFS_IA64_LINUX20_ENV
960 ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
962 ip1 = (unsigned long)(P->verify_fn);
965 if (ip1 && p[_SS(P->verifyNR - P->offset)] != ip1) {
966 #ifdef OSI_PROBE_DEBUG
967 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
968 printk("<7>check_harder 0x%lx verify failed\n", (unsigned long)p);
973 #ifdef OSI_PROBE_DEBUG
974 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
975 printk("<7>check_harder 0x%lx success!\n", (unsigned long)p);
980 static void *try_harder(probectl *P, PROBETYPE *ptr, unsigned long datalen)
982 #ifdef OSI_PROBE_KALLSYMS
983 char *mod_name, *sec_name, *sym_name;
984 unsigned long mod_start, mod_end;
985 unsigned long sec_start, sec_end;
986 unsigned long sym_start, sym_end;
988 unsigned long offset;
992 #ifdef OSI_PROBE_DEBUG
993 if (probe_debug & 0x0001)
994 printk("<7>osi_probe: %s try_harder\n", P->symbol);
996 for (offset = 0; offset < datalen; offset++, ptr++) {
997 ret = check_table(P, ptr);
999 /* return value is number of entries to skip */
1005 #ifdef OSI_PROBE_DEBUG
1006 if ((probe_debug & 0x0004) && DEBUG_IN_RANGE(P,ptr))
1007 printk("<7>try_harder 0x%lx\n", (unsigned long)ptr);
1009 if (!check_harder(P, ptr))
1012 #ifdef OSI_PROBE_DEBUG
1013 if (probe_debug & 0x0004)
1014 printk("<7>try_harder found 0x%lx\n", (unsigned long)ptr);
1017 #ifdef OSI_PROBE_KALLSYMS
1018 if (kallsyms_address_to_symbol) {
1019 ret = kallsyms_address_to_symbol((unsigned long)ptr,
1020 &mod_name, &mod_start, &mod_end,
1021 &sec_name, &sec_start, &sec_end,
1022 &sym_name, &sym_start, &sym_end);
1023 if (!ret || strcmp(sym_name, P->symbol)) continue;
1028 #ifdef OSI_PROBE_DEBUG
1029 if (probe_debug & 0x0005)
1030 printk("<7>%s: try_harder found multiple matches!\n", P->symbol);
1035 match = (void *)ptr;
1036 if (!probe_carefully)
1043 #ifdef OSI_PROBE_DEBUG
1044 #define check_result(x,m) do { \
1045 if (probe_debug & 0x0001) { \
1046 printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
1050 final_answer = (void *)(x); \
1054 #define check_result(x,m) do { \
1057 return (void *)(x); \
1061 static void *do_find_syscall_table(probectl *P, char **method)
1063 #ifdef OSI_PROBE_KALLSYMS
1064 char *mod_name, *sec_name, *sym_name;
1065 unsigned long mod_start, mod_end;
1066 unsigned long sec_start, sec_end;
1067 unsigned long sym_start, sym_end;
1068 unsigned long token;
1075 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1078 #ifdef OSI_PROBE_DEBUG
1079 void *final_answer = 0;
1082 *method = "not found";
1084 /* if it's exported, there's nothing to do */
1085 check_result(P->weak_answer, "exported");
1087 /* ask the kernel to do the name lookup, if it's willing */
1088 #ifdef OSI_PROBE_KALLSYMS
1089 if (kallsyms_symbol_to_address) {
1093 ret = kallsyms_symbol_to_address(P->symbol, &token,
1094 &mod_name, &mod_start, &mod_end,
1095 &sec_name, &sec_start, &sec_end,
1096 &sym_name, &sym_start, &sym_end);
1097 if (ret && !strcmp(mod_name, "kernel") && sym_start)
1101 check_result(sym_start, "kallsyms_symbol_to_address");
1105 /* Maybe a little birdie told us */
1106 check_result(P->parm_answer, "module parameter");
1107 check_result(P->given_answer, "compiled-in");
1109 /* OK, so we have to scan. */
1110 B = (PROBETYPE *)((P->try_base) & ~(P->try_base_mask));
1112 /* Now, see if the kernel will tell us something better than the default */
1113 #ifdef OSI_PROBE_KALLSYMS
1114 if (kallsyms_address_to_symbol) {
1115 ret = kallsyms_address_to_symbol(P->try_sect_sym,
1116 &mod_name, &mod_start, &mod_end,
1117 &sec_name, &sec_start, &sec_end,
1118 &sym_name, &sym_start, &sym_end);
1120 B = (PROBETYPE *)sec_start;
1121 L = (sec_end - sec_start) / sizeof(unsigned long);
1126 #ifdef OSI_PROBE_DEBUG
1127 if (probe_debug & 0x0007)
1128 printk("<7>osi_probe: %s base=0x%lx, len=0x%lx\n",
1129 P->symbol, (unsigned long)B, L);
1130 if (probe_debug & 0x0009) {
1131 printk("<7>osi_probe: %s ktxt_lower_bound=0x%lx\n",
1132 P->symbol, ktxt_lower_bound);
1133 printk("<7>osi_probe: %s NR_syscalls=%d\n",
1134 P->symbol, NR_syscalls);
1138 for (T = P->trylist; T->name; T++) {
1139 answer = try(P, T, B, L);
1140 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1141 answer2 = try(P, T, (PROBETYPE *)(2 + (void *)B), L);
1142 #ifdef OSI_PROBE_DEBUG
1143 if (probe_debug & 0x0003) {
1144 printk("<7>osi_probe: %s = 0x%016lx %s (even)\n",
1145 P->symbol, (unsigned long)(answer), T->name);
1146 printk("<7>osi_probe: %s = 0x%016lx %s (odd)\n",
1147 P->symbol, (unsigned long)(answer2), T->name);
1150 if (answer && answer2) answer = 0;
1151 else if (answer2) answer = answer2;
1153 check_result(answer, T->name);
1156 /* XXX more checks here */
1158 answer = try_harder(P, B, L);
1159 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1160 answer2 = try_harder(P, (PROBETYPE *)(2 + (void *)B), L);
1161 #ifdef OSI_PROBE_DEBUG
1162 if (probe_debug & 0x0005) {
1163 printk("<7>osi_probe: %s = 0x%016lx pattern scan (even)\n",
1164 P->symbol, (unsigned long)(answer));
1165 printk("<7>osi_probe: %s = 0x%016lx pattern scan (odd)\n",
1166 P->symbol, (unsigned long)(answer2));
1169 if (answer && answer2) answer = 0;
1170 else if (answer2) answer = answer2;
1172 check_result(answer, "pattern scan");
1174 #ifdef OSI_PROBE_DEBUG
1175 return final_answer;
1181 void *osi_find_syscall_table(int which)
1187 if (which < 0 || which >= N_PROBE_LIST) {
1188 printk("error - afs_find_syscall_table called with invalid index!\n");
1191 P = probe_list[which];
1193 P->parm_answer = (void *)sys_call_table_addr[which];
1194 #ifdef OSI_PROBE_DEBUG
1195 P->debug_answer = (void *)probe_debug_addr[which];
1198 answer = do_find_syscall_table(P, &method);
1200 printk("Warning: failed to find address of %s\n", P->desc);
1201 printk("System call hooks will not be installed; proceeding anyway\n");
1204 printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
1209 #ifdef OSI_PROBE_STANDALONE
1210 int __init osi_probe_init(void)
1214 if (!probe_debug_tag) probe_debug_tag = jiffies;
1215 printk("*** osi_probe %ld debug = 0x%04x ***\n",
1216 probe_debug_tag, probe_debug);
1217 for (i = 0; i < N_PROBE_LIST; i++)
1218 (void)osi_find_syscall_table(i);
1222 void osi_probe_exit(void) { }
1224 module_init(osi_probe_init);
1225 module_exit(osi_probe_exit);