diff options
author | Nicolas Pitre <nico@cam.org> | 2006-01-14 11:36:12 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-01-14 11:36:12 -0500 |
commit | dd35afc22b76766e827c9e67ebc4b7bf6e31ecab (patch) | |
tree | 3336355470c2d57a2b11a47f8d9bcc1e86546735 /arch/arm/kernel | |
parent | 687ad0191488a067b3b3cc94f670cc21f93811e1 (diff) |
[ARM] 3110/5: old ABI compat: multi-ABI syscall entry support
Patch from Nicolas Pitre
This patch adds the required code to support both user space ABIs at
the same time. A second syscall table is created to include legacy ABI
syscalls that need an ABI compat wrapper.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/calls.S | 55 | ||||
-rw-r--r-- | arch/arm/kernel/entry-common.S | 78 | ||||
-rw-r--r-- | arch/arm/kernel/sys_arm.c | 2 |
3 files changed, 100 insertions, 35 deletions
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 8c0bf04814b1..75e6f9a94713 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S | |||
@@ -13,7 +13,7 @@ | |||
13 | #define NR_syscalls 328 | 13 | #define NR_syscalls 328 |
14 | #else | 14 | #else |
15 | 15 | ||
16 | __syscall_start: | 16 | 100: |
17 | /* 0 */ .long sys_restart_syscall | 17 | /* 0 */ .long sys_restart_syscall |
18 | .long sys_exit | 18 | .long sys_exit |
19 | .long sys_fork_wrapper | 19 | .long sys_fork_wrapper |
@@ -27,7 +27,7 @@ __syscall_start: | |||
27 | /* 10 */ .long sys_unlink | 27 | /* 10 */ .long sys_unlink |
28 | .long sys_execve_wrapper | 28 | .long sys_execve_wrapper |
29 | .long sys_chdir | 29 | .long sys_chdir |
30 | .long sys_time /* used by libc4 */ | 30 | .long OBSOLETE(sys_time) /* used by libc4 */ |
31 | .long sys_mknod | 31 | .long sys_mknod |
32 | /* 15 */ .long sys_chmod | 32 | /* 15 */ .long sys_chmod |
33 | .long sys_lchown16 | 33 | .long sys_lchown16 |
@@ -36,15 +36,15 @@ __syscall_start: | |||
36 | .long sys_lseek | 36 | .long sys_lseek |
37 | /* 20 */ .long sys_getpid | 37 | /* 20 */ .long sys_getpid |
38 | .long sys_mount | 38 | .long sys_mount |
39 | .long sys_oldumount /* used by libc4 */ | 39 | .long OBSOLETE(sys_oldumount) /* used by libc4 */ |
40 | .long sys_setuid16 | 40 | .long sys_setuid16 |
41 | .long sys_getuid16 | 41 | .long sys_getuid16 |
42 | /* 25 */ .long sys_stime | 42 | /* 25 */ .long OBSOLETE(sys_stime) |
43 | .long sys_ptrace | 43 | .long sys_ptrace |
44 | .long sys_alarm /* used by libc4 */ | 44 | .long OBSOLETE(sys_alarm) /* used by libc4 */ |
45 | .long sys_ni_syscall /* was sys_fstat */ | 45 | .long sys_ni_syscall /* was sys_fstat */ |
46 | .long sys_pause | 46 | .long sys_pause |
47 | /* 30 */ .long sys_utime /* used by libc4 */ | 47 | /* 30 */ .long OBSOLETE(sys_utime) /* used by libc4 */ |
48 | .long sys_ni_syscall /* was sys_stty */ | 48 | .long sys_ni_syscall /* was sys_stty */ |
49 | .long sys_ni_syscall /* was sys_getty */ | 49 | .long sys_ni_syscall /* was sys_getty */ |
50 | .long sys_access | 50 | .long sys_access |
@@ -90,21 +90,21 @@ __syscall_start: | |||
90 | .long sys_sigpending | 90 | .long sys_sigpending |
91 | .long sys_sethostname | 91 | .long sys_sethostname |
92 | /* 75 */ .long sys_setrlimit | 92 | /* 75 */ .long sys_setrlimit |
93 | .long sys_old_getrlimit /* used by libc4 */ | 93 | .long OBSOLETE(sys_old_getrlimit) /* used by libc4 */ |
94 | .long sys_getrusage | 94 | .long sys_getrusage |
95 | .long sys_gettimeofday | 95 | .long sys_gettimeofday |
96 | .long sys_settimeofday | 96 | .long sys_settimeofday |
97 | /* 80 */ .long sys_getgroups16 | 97 | /* 80 */ .long sys_getgroups16 |
98 | .long sys_setgroups16 | 98 | .long sys_setgroups16 |
99 | .long old_select /* used by libc4 */ | 99 | .long OBSOLETE(old_select) /* used by libc4 */ |
100 | .long sys_symlink | 100 | .long sys_symlink |
101 | .long sys_ni_syscall /* was sys_lstat */ | 101 | .long sys_ni_syscall /* was sys_lstat */ |
102 | /* 85 */ .long sys_readlink | 102 | /* 85 */ .long sys_readlink |
103 | .long sys_uselib | 103 | .long sys_uselib |
104 | .long sys_swapon | 104 | .long sys_swapon |
105 | .long sys_reboot | 105 | .long sys_reboot |
106 | .long old_readdir /* used by libc4 */ | 106 | .long OBSOLETE(old_readdir) /* used by libc4 */ |
107 | /* 90 */ .long old_mmap /* used by libc4 */ | 107 | /* 90 */ .long OBSOLETE(old_mmap) /* used by libc4 */ |
108 | .long sys_munmap | 108 | .long sys_munmap |
109 | .long sys_truncate | 109 | .long sys_truncate |
110 | .long sys_ftruncate | 110 | .long sys_ftruncate |
@@ -116,7 +116,7 @@ __syscall_start: | |||
116 | .long sys_statfs | 116 | .long sys_statfs |
117 | /* 100 */ .long sys_fstatfs | 117 | /* 100 */ .long sys_fstatfs |
118 | .long sys_ni_syscall | 118 | .long sys_ni_syscall |
119 | .long sys_socketcall | 119 | .long OBSOLETE(sys_socketcall) |
120 | .long sys_syslog | 120 | .long sys_syslog |
121 | .long sys_setitimer | 121 | .long sys_setitimer |
122 | /* 105 */ .long sys_getitimer | 122 | /* 105 */ .long sys_getitimer |
@@ -127,11 +127,11 @@ __syscall_start: | |||
127 | /* 110 */ .long sys_ni_syscall /* was sys_iopl */ | 127 | /* 110 */ .long sys_ni_syscall /* was sys_iopl */ |
128 | .long sys_vhangup | 128 | .long sys_vhangup |
129 | .long sys_ni_syscall | 129 | .long sys_ni_syscall |
130 | .long sys_syscall /* call a syscall */ | 130 | .long OBSOLETE(sys_syscall) /* call a syscall */ |
131 | .long sys_wait4 | 131 | .long sys_wait4 |
132 | /* 115 */ .long sys_swapoff | 132 | /* 115 */ .long sys_swapoff |
133 | .long sys_sysinfo | 133 | .long sys_sysinfo |
134 | .long sys_ipc | 134 | .long OBSOLETE(ABI(sys_ipc, sys_oabi_ipc)) |
135 | .long sys_fsync | 135 | .long sys_fsync |
136 | .long sys_sigreturn_wrapper | 136 | .long sys_sigreturn_wrapper |
137 | /* 120 */ .long sys_clone_wrapper | 137 | /* 120 */ .long sys_clone_wrapper |
@@ -194,8 +194,8 @@ __syscall_start: | |||
194 | .long sys_rt_sigtimedwait | 194 | .long sys_rt_sigtimedwait |
195 | .long sys_rt_sigqueueinfo | 195 | .long sys_rt_sigqueueinfo |
196 | .long sys_rt_sigsuspend_wrapper | 196 | .long sys_rt_sigsuspend_wrapper |
197 | /* 180 */ .long sys_pread64 | 197 | /* 180 */ .long ABI(sys_pread64, sys_oabi_pread64) |
198 | .long sys_pwrite64 | 198 | .long ABI(sys_pwrite64, sys_oabi_pwrite64) |
199 | .long sys_chown16 | 199 | .long sys_chown16 |
200 | .long sys_getcwd | 200 | .long sys_getcwd |
201 | .long sys_capget | 201 | .long sys_capget |
@@ -207,11 +207,11 @@ __syscall_start: | |||
207 | /* 190 */ .long sys_vfork_wrapper | 207 | /* 190 */ .long sys_vfork_wrapper |
208 | .long sys_getrlimit | 208 | .long sys_getrlimit |
209 | .long sys_mmap2 | 209 | .long sys_mmap2 |
210 | .long sys_truncate64 | 210 | .long ABI(sys_truncate64, sys_oabi_truncate64) |
211 | .long sys_ftruncate64 | 211 | .long ABI(sys_ftruncate64, sys_oabi_ftruncate64) |
212 | /* 195 */ .long sys_stat64 | 212 | /* 195 */ .long ABI(sys_stat64, sys_oabi_stat64) |
213 | .long sys_lstat64 | 213 | .long ABI(sys_lstat64, sys_oabi_lstat64) |
214 | .long sys_fstat64 | 214 | .long ABI(sys_fstat64, sys_oabi_fstat64) |
215 | .long sys_lchown | 215 | .long sys_lchown |
216 | .long sys_getuid | 216 | .long sys_getuid |
217 | /* 200 */ .long sys_getgid | 217 | /* 200 */ .long sys_getgid |
@@ -235,11 +235,11 @@ __syscall_start: | |||
235 | .long sys_pivot_root | 235 | .long sys_pivot_root |
236 | .long sys_mincore | 236 | .long sys_mincore |
237 | /* 220 */ .long sys_madvise | 237 | /* 220 */ .long sys_madvise |
238 | .long sys_fcntl64 | 238 | .long ABI(sys_fcntl64, sys_oabi_fcntl64) |
239 | .long sys_ni_syscall /* TUX */ | 239 | .long sys_ni_syscall /* TUX */ |
240 | .long sys_ni_syscall | 240 | .long sys_ni_syscall |
241 | .long sys_gettid | 241 | .long sys_gettid |
242 | /* 225 */ .long sys_readahead | 242 | /* 225 */ .long ABI(sys_readahead, sys_oabi_readahead) |
243 | .long sys_setxattr | 243 | .long sys_setxattr |
244 | .long sys_lsetxattr | 244 | .long sys_lsetxattr |
245 | .long sys_fsetxattr | 245 | .long sys_fsetxattr |
@@ -265,8 +265,8 @@ __syscall_start: | |||
265 | .long sys_exit_group | 265 | .long sys_exit_group |
266 | .long sys_lookup_dcookie | 266 | .long sys_lookup_dcookie |
267 | /* 250 */ .long sys_epoll_create | 267 | /* 250 */ .long sys_epoll_create |
268 | .long sys_epoll_ctl | 268 | .long ABI(sys_epoll_ctl, sys_oabi_epoll_ctl) |
269 | .long sys_epoll_wait | 269 | .long ABI(sys_epoll_wait, sys_oabi_epoll_wait) |
270 | .long sys_remap_file_pages | 270 | .long sys_remap_file_pages |
271 | .long sys_ni_syscall /* sys_set_thread_area */ | 271 | .long sys_ni_syscall /* sys_set_thread_area */ |
272 | /* 255 */ .long sys_ni_syscall /* sys_get_thread_area */ | 272 | /* 255 */ .long sys_ni_syscall /* sys_get_thread_area */ |
@@ -312,7 +312,7 @@ __syscall_start: | |||
312 | /* 295 */ .long sys_getsockopt | 312 | /* 295 */ .long sys_getsockopt |
313 | .long sys_sendmsg | 313 | .long sys_sendmsg |
314 | .long sys_recvmsg | 314 | .long sys_recvmsg |
315 | .long sys_semop | 315 | .long ABI(sys_semop, sys_oabi_semop) |
316 | .long sys_semget | 316 | .long sys_semget |
317 | /* 300 */ .long sys_semctl | 317 | /* 300 */ .long sys_semctl |
318 | .long sys_msgsnd | 318 | .long sys_msgsnd |
@@ -326,7 +326,7 @@ __syscall_start: | |||
326 | .long sys_add_key | 326 | .long sys_add_key |
327 | /* 310 */ .long sys_request_key | 327 | /* 310 */ .long sys_request_key |
328 | .long sys_keyctl | 328 | .long sys_keyctl |
329 | .long sys_semtimedop | 329 | .long ABI(sys_semtimedop, sys_oabi_semtimedop) |
330 | /* vserver */ .long sys_ni_syscall | 330 | /* vserver */ .long sys_ni_syscall |
331 | .long sys_ioprio_set | 331 | .long sys_ioprio_set |
332 | /* 315 */ .long sys_ioprio_get | 332 | /* 315 */ .long sys_ioprio_get |
@@ -336,9 +336,8 @@ __syscall_start: | |||
336 | .long sys_mbind | 336 | .long sys_mbind |
337 | /* 320 */ .long sys_get_mempolicy | 337 | /* 320 */ .long sys_get_mempolicy |
338 | .long sys_set_mempolicy | 338 | .long sys_set_mempolicy |
339 | __syscall_end: | ||
340 | 339 | ||
341 | .rept NR_syscalls - (__syscall_end - __syscall_start) / 4 | 340 | .rept NR_syscalls - (. - 100b) / 4 |
342 | .long sys_ni_syscall | 341 | .long sys_ni_syscall |
343 | .endr | 342 | .endr |
344 | #endif | 343 | #endif |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 59ce1bcec42b..8826d9803aeb 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -123,23 +123,49 @@ ENTRY(vector_swi) | |||
123 | /* | 123 | /* |
124 | * Get the system call number. | 124 | * Get the system call number. |
125 | */ | 125 | */ |
126 | #if defined(CONFIG_AEABI) | ||
127 | 126 | ||
128 | @ syscall number is in scno (r7) already. | 127 | #if defined(CONFIG_OABI_COMPAT) |
129 | 128 | ||
129 | /* | ||
130 | * If we have CONFIG_OABI_COMPAT then we need to look at the swi | ||
131 | * value to determine if it is an EABI or an old ABI call. | ||
132 | */ | ||
133 | #ifdef CONFIG_ARM_THUMB | ||
134 | tst r8, #PSR_T_BIT | ||
135 | movne r10, #0 @ no thumb OABI emulation | ||
136 | ldreq r10, [lr, #-4] @ get SWI instruction | ||
137 | #else | ||
138 | ldr r10, [lr, #-4] @ get SWI instruction | ||
139 | A710( and ip, r10, #0x0f000000 @ check for SWI ) | ||
140 | A710( teq ip, #0x0f000000 ) | ||
141 | A710( bne .Larm710bug ) | ||
142 | #endif | ||
143 | |||
144 | #elif defined(CONFIG_AEABI) | ||
145 | |||
146 | /* | ||
147 | * Pure EABI user space always put syscall number into scno (r7). | ||
148 | */ | ||
130 | A710( ldr ip, [lr, #-4] @ get SWI instruction ) | 149 | A710( ldr ip, [lr, #-4] @ get SWI instruction ) |
131 | A710( and ip, ip, #0x0f000000 @ check for SWI ) | 150 | A710( and ip, ip, #0x0f000000 @ check for SWI ) |
132 | A710( teq ip, #0x0f000000 ) | 151 | A710( teq ip, #0x0f000000 ) |
133 | A710( bne .Larm710bug ) | 152 | A710( bne .Larm710bug ) |
153 | |||
134 | #elif defined(CONFIG_ARM_THUMB) | 154 | #elif defined(CONFIG_ARM_THUMB) |
155 | |||
156 | /* Legacy ABI only, possibly thumb mode. */ | ||
135 | tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs | 157 | tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs |
136 | addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in | 158 | addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in |
137 | ldreq scno, [lr, #-4] | 159 | ldreq scno, [lr, #-4] |
160 | |||
138 | #else | 161 | #else |
162 | |||
163 | /* Legacy ABI only. */ | ||
139 | ldr scno, [lr, #-4] @ get SWI instruction | 164 | ldr scno, [lr, #-4] @ get SWI instruction |
140 | A710( and ip, scno, #0x0f000000 @ check for SWI ) | 165 | A710( and ip, scno, #0x0f000000 @ check for SWI ) |
141 | A710( teq ip, #0x0f000000 ) | 166 | A710( teq ip, #0x0f000000 ) |
142 | A710( bne .Larm710bug ) | 167 | A710( bne .Larm710bug ) |
168 | |||
143 | #endif | 169 | #endif |
144 | 170 | ||
145 | #ifdef CONFIG_ALIGNMENT_TRAP | 171 | #ifdef CONFIG_ALIGNMENT_TRAP |
@@ -150,12 +176,24 @@ ENTRY(vector_swi) | |||
150 | enable_irq | 176 | enable_irq |
151 | 177 | ||
152 | get_thread_info tsk | 178 | get_thread_info tsk |
179 | adr tbl, sys_call_table @ load syscall table pointer | ||
153 | ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing | 180 | ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing |
154 | #ifndef CONFIG_AEABI | 181 | |
182 | #if defined(CONFIG_OABI_COMPAT) | ||
183 | /* | ||
184 | * If the swi argument is zero, this is an EABI call and we do nothing. | ||
185 | * | ||
186 | * If this is an old ABI call, get the syscall number into scno and | ||
187 | * get the old ABI syscall table address. | ||
188 | */ | ||
189 | bics r10, r10, #0xff000000 | ||
190 | eorne scno, r10, #__NR_OABI_SYSCALL_BASE | ||
191 | ldrne tbl, =sys_oabi_call_table | ||
192 | #elif !defined(CONFIG_AEABI) | ||
155 | bic scno, scno, #0xff000000 @ mask off SWI op-code | 193 | bic scno, scno, #0xff000000 @ mask off SWI op-code |
156 | eor scno, scno, #__NR_SYSCALL_BASE @ check OS number | 194 | eor scno, scno, #__NR_SYSCALL_BASE @ check OS number |
157 | #endif | 195 | #endif |
158 | adr tbl, sys_call_table @ load syscall table pointer | 196 | |
159 | stmdb sp!, {r4, r5} @ push fifth and sixth args | 197 | stmdb sp!, {r4, r5} @ push fifth and sixth args |
160 | tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? | 198 | tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? |
161 | bne __sys_trace | 199 | bne __sys_trace |
@@ -200,10 +238,24 @@ __sys_trace_return: | |||
200 | __cr_alignment: | 238 | __cr_alignment: |
201 | .word cr_alignment | 239 | .word cr_alignment |
202 | #endif | 240 | #endif |
241 | .ltorg | ||
242 | |||
243 | /* | ||
244 | * This is the syscall table declaration for native ABI syscalls. | ||
245 | * With EABI a couple syscalls are obsolete and defined as sys_ni_syscall. | ||
246 | */ | ||
247 | #define ABI(native, compat) native | ||
248 | #ifdef CONFIG_AEABI | ||
249 | #define OBSOLETE(syscall) sys_ni_syscall | ||
250 | #else | ||
251 | #define OBSOLETE(syscall) syscall | ||
252 | #endif | ||
203 | 253 | ||
204 | .type sys_call_table, #object | 254 | .type sys_call_table, #object |
205 | ENTRY(sys_call_table) | 255 | ENTRY(sys_call_table) |
206 | #include "calls.S" | 256 | #include "calls.S" |
257 | #undef ABI | ||
258 | #undef OBSOLETE | ||
207 | 259 | ||
208 | /*============================================================================ | 260 | /*============================================================================ |
209 | * Special system call wrappers | 261 | * Special system call wrappers |
@@ -212,8 +264,7 @@ ENTRY(sys_call_table) | |||
212 | @ r8 = syscall table | 264 | @ r8 = syscall table |
213 | .type sys_syscall, #function | 265 | .type sys_syscall, #function |
214 | sys_syscall: | 266 | sys_syscall: |
215 | #ifndef CONFIG_AEABI | 267 | eor scno, r0, #__NR_OABI_SYSCALL_BASE |
216 | eor scno, r0, #__NR_SYSCALL_BASE | ||
217 | cmp scno, #__NR_syscall - __NR_SYSCALL_BASE | 268 | cmp scno, #__NR_syscall - __NR_SYSCALL_BASE |
218 | cmpne scno, #NR_syscalls @ check range | 269 | cmpne scno, #NR_syscalls @ check range |
219 | stmloia sp, {r5, r6} @ shuffle args | 270 | stmloia sp, {r5, r6} @ shuffle args |
@@ -222,7 +273,6 @@ sys_syscall: | |||
222 | movlo r2, r3 | 273 | movlo r2, r3 |
223 | movlo r3, r4 | 274 | movlo r3, r4 |
224 | ldrlo pc, [tbl, scno, lsl #2] | 275 | ldrlo pc, [tbl, scno, lsl #2] |
225 | #endif | ||
226 | b sys_ni_syscall | 276 | b sys_ni_syscall |
227 | 277 | ||
228 | sys_fork_wrapper: | 278 | sys_fork_wrapper: |
@@ -290,6 +340,7 @@ sys_mmap2: | |||
290 | #endif | 340 | #endif |
291 | 341 | ||
292 | #ifdef CONFIG_OABI_COMPAT | 342 | #ifdef CONFIG_OABI_COMPAT |
343 | |||
293 | /* | 344 | /* |
294 | * These are syscalls with argument register differences | 345 | * These are syscalls with argument register differences |
295 | */ | 346 | */ |
@@ -318,5 +369,18 @@ sys_oabi_readahead: | |||
318 | mov r2, r1 | 369 | mov r2, r1 |
319 | b sys_readahead | 370 | b sys_readahead |
320 | 371 | ||
372 | /* | ||
373 | * Let's declare a second syscall table for old ABI binaries | ||
374 | * using the compatibility syscall entries. | ||
375 | */ | ||
376 | #define ABI(native, compat) compat | ||
377 | #define OBSOLETE(syscall) syscall | ||
378 | |||
379 | .type sys_oabi_call_table, #object | ||
380 | ENTRY(sys_oabi_call_table) | ||
381 | #include "calls.S" | ||
382 | #undef ABI | ||
383 | #undef OBSOLETE | ||
384 | |||
321 | #endif | 385 | #endif |
322 | 386 | ||
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index ea569ba482b1..a491de2d9024 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c | |||
@@ -147,6 +147,7 @@ asmlinkage int old_select(struct sel_arg_struct __user *arg) | |||
147 | return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); | 147 | return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); |
148 | } | 148 | } |
149 | 149 | ||
150 | #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT) | ||
150 | /* | 151 | /* |
151 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. | 152 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. |
152 | * | 153 | * |
@@ -226,6 +227,7 @@ asmlinkage int sys_ipc(uint call, int first, int second, int third, | |||
226 | return -ENOSYS; | 227 | return -ENOSYS; |
227 | } | 228 | } |
228 | } | 229 | } |
230 | #endif | ||
229 | 231 | ||
230 | /* Fork a new task - this creates a new program thread. | 232 | /* Fork a new task - this creates a new program thread. |
231 | * This is called indirectly via a small wrapper | 233 | * This is called indirectly via a small wrapper |