blob: fa94a4b8561542d3258992a507d22901ab3e9f65 [file] [log] [blame]
njn9abd6082005-06-17 21:31:45 +00001
2/*--------------------------------------------------------------------*/
3/*--- Doing syscalls. m_syscall.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2000-2005 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
njn9abd6082005-06-17 21:31:45 +000032#include "pub_core_syscall.h"
33
34/* ---------------------------------------------------------------------
35 Building syscall return values.
36 ------------------------------------------------------------------ */
37
38/* Make a SysRes value from an syscall return value. This is
39 Linux-specific.
40
41 From:
42 http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/sysdeps/unix/sysv/
43 linux/i386/sysdep.h?
44 rev=1.28&content-type=text/x-cvsweb-markup&cvsroot=glibc
45
46 Linux uses a negative return value to indicate syscall errors,
47 unlike most Unices, which use the condition codes' carry flag.
48
49 Since version 2.1 the return value of a system call might be
50 negative even if the call succeeded. E.g., the 'lseek' system call
51 might return a large offset. Therefore we must not anymore test
52 for < 0, but test for a real error by making sure the value in %eax
53 is a real error number. Linus said he will make sure the no
54 syscall returns a value in -1 .. -4095 as a valid result so we can
55 safely test with -4095.
56*/
sewardje5c600e2005-06-20 18:14:27 +000057SysRes VG_(mk_SysRes_x86_linux) ( Word val ) {
njn9abd6082005-06-17 21:31:45 +000058 SysRes res;
njn9abd6082005-06-17 21:31:45 +000059 res.isError = val >= -4095 && val <= -1;
60 res.val = res.isError ? -val : val;
njn9abd6082005-06-17 21:31:45 +000061 return res;
62}
63
cerion85665ca2005-06-20 15:51:07 +000064/* Similarly .. */
sewardje5c600e2005-06-20 18:14:27 +000065SysRes VG_(mk_SysRes_amd64_linux) ( Word val ) {
cerion85665ca2005-06-20 15:51:07 +000066 SysRes res;
67 res.isError = val >= -4095 && val <= -1;
68 res.val = res.isError ? -val : val;
69 return res;
70}
71
sewardje5c600e2005-06-20 18:14:27 +000072/* PPC uses the CR7.SO bit to flag an error (CR0 in IBM-speke) */
cerion85665ca2005-06-20 15:51:07 +000073SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt errflag ) {
74 SysRes res;
75 res.isError = errflag != 0;
76 res.val = val;
77 return res;
78}
79
80
njn9abd6082005-06-17 21:31:45 +000081SysRes VG_(mk_SysRes_Error) ( UWord val ) {
82 SysRes r = { val, True };
83 return r;
84}
85
86SysRes VG_(mk_SysRes_Success) ( UWord val ) {
87 SysRes r = { val, False };
88 return r;
89}
90
91
92/* ---------------------------------------------------------------------
93 A function for doing syscalls.
94 ------------------------------------------------------------------ */
95
njn9abd6082005-06-17 21:31:45 +000096#if defined(VGP_x86_linux)
97/* Incoming args (syscall number + up to 6 args) come on the stack.
98 (ie. the C calling convention).
99
100 The syscall number goes in %eax. The args are passed to the syscall in
101 the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
102 calling convention.
103
104 %eax gets the return value. Not sure which registers the kernel
105 clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
106 %ebp).
107*/
sewardj03d8aa82005-10-14 11:25:49 +0000108extern UWord do_syscall_WRK (
cerion85665ca2005-06-20 15:51:07 +0000109 UWord syscall_no,
110 UWord a1, UWord a2, UWord a3,
111 UWord a4, UWord a5, UWord a6
112 );
njn9abd6082005-06-17 21:31:45 +0000113asm(
sewardjd9fc3822005-11-18 23:50:43 +0000114".text\n"
njn9abd6082005-06-17 21:31:45 +0000115"do_syscall_WRK:\n"
116" push %esi\n"
117" push %edi\n"
118" push %ebx\n"
119" push %ebp\n"
120" movl 16+ 4(%esp),%eax\n"
121" movl 16+ 8(%esp),%ebx\n"
122" movl 16+12(%esp),%ecx\n"
123" movl 16+16(%esp),%edx\n"
124" movl 16+20(%esp),%esi\n"
125" movl 16+24(%esp),%edi\n"
126" movl 16+28(%esp),%ebp\n"
127" int $0x80\n"
128" popl %ebp\n"
129" popl %ebx\n"
130" popl %edi\n"
131" popl %esi\n"
132" ret\n"
sewardj2fedc642005-11-19 02:02:57 +0000133".previous\n"
njn9abd6082005-06-17 21:31:45 +0000134);
135#elif defined(VGP_amd64_linux)
136/* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
137 %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
138 calling convention).
139
140 The syscall number goes in %rax. The args are passed to the syscall in
141 the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
142 ie. the kernel's syscall calling convention.
143
144 %rax gets the return value. %rcx and %r11 are clobbered by the syscall;
145 no matter, they are caller-save (the syscall clobbers no callee-save
146 regs, so we don't have to do any register saving/restoring).
147*/
sewardj03d8aa82005-10-14 11:25:49 +0000148extern UWord do_syscall_WRK (
cerion85665ca2005-06-20 15:51:07 +0000149 UWord syscall_no,
150 UWord a1, UWord a2, UWord a3,
151 UWord a4, UWord a5, UWord a6
152 );
njn9abd6082005-06-17 21:31:45 +0000153asm(
sewardjd9fc3822005-11-18 23:50:43 +0000154".text\n"
njn9abd6082005-06-17 21:31:45 +0000155"do_syscall_WRK:\n"
156 /* Convert function calling convention --> syscall calling
157 convention */
158" movq %rdi, %rax\n"
159" movq %rsi, %rdi\n"
160" movq %rdx, %rsi\n"
161" movq %rcx, %rdx\n"
162" movq %r8, %r10\n"
163" movq %r9, %r8\n"
164" movq 8(%rsp), %r9\n" /* last arg from stack */
165" syscall\n"
166" ret\n"
sewardj2fedc642005-11-19 02:02:57 +0000167".previous\n"
njn9abd6082005-06-17 21:31:45 +0000168);
cerion85665ca2005-06-20 15:51:07 +0000169#elif defined(VGP_ppc32_linux)
170/* Incoming args (syscall number + up to 6 args) come in %r0, %r3:%r8
171
172 The syscall number goes in %r0. The args are passed to the syscall in
173 the regs %r3:%r8, i.e. the kernel's syscall calling convention.
174
175 The %cr0.so bit flags an error.
176 We return the syscall return value in %r3, and the %cr in %r4.
177 We return a ULong, of which %r3 is the high word, and %r4 the low.
178 No callee-save regs are clobbered, so no saving/restoring is needed.
179*/
sewardj03d8aa82005-10-14 11:25:49 +0000180extern ULong do_syscall_WRK (
cerion85665ca2005-06-20 15:51:07 +0000181 UWord syscall_no,
182 UWord a1, UWord a2, UWord a3,
183 UWord a4, UWord a5, UWord a6
184 );
185asm(
sewardjd9fc3822005-11-18 23:50:43 +0000186".text\n"
cerion85665ca2005-06-20 15:51:07 +0000187"do_syscall_WRK:\n"
188" mr 0,3\n"
189" mr 3,4\n"
190" mr 4,5\n"
191" mr 5,6\n"
192" mr 6,7\n"
193" mr 7,8\n"
194" mr 8,9\n"
195" sc\n" /* syscall: sets %cr0.so on error */
196" mfcr 4\n" /* %cr -> low word of return var */
197" rlwinm 4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
198" blr\n" /* and return */
sewardj2fedc642005-11-19 02:02:57 +0000199".previous\n"
cerion85665ca2005-06-20 15:51:07 +0000200);
njn9abd6082005-06-17 21:31:45 +0000201#else
202# error Unknown platform
203#endif
204
205SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
206 UWord a4, UWord a5, UWord a6 )
207{
cerion85665ca2005-06-20 15:51:07 +0000208#if defined(VGP_x86_linux)
209 UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
210 return VG_(mk_SysRes_x86_linux)( val );
211#elif defined(VGP_amd64_linux)
212 UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
213 return VG_(mk_SysRes_amd64_linux)( val );
214#elif defined(VGP_ppc32_linux)
215 ULong ret = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
216 UInt val = (UInt)(ret>>32);
217 UInt errflag = (UInt)(ret);
218 return VG_(mk_SysRes_ppc32_linux)( val, errflag );
219#else
220# error Unknown platform
221#endif
njn9abd6082005-06-17 21:31:45 +0000222}
223
sewardj45f4e7c2005-09-27 19:20:21 +0000224/* ---------------------------------------------------------------------
225 Names of errors.
226 ------------------------------------------------------------------ */
227
228/* Return a string which gives the name of an error value. Note,
229 unlike the standard C syserror fn, the returned string is not
230 malloc-allocated or writable -- treat it as a constant.
231 TODO: implement this properly. */
232
233const HChar* VG_(strerror) ( UWord errnum )
234{
235 switch (errnum) {
236 case VKI_EPERM: return "Operation not permitted";
237 case VKI_ENOENT: return "No such file or directory";
238 case VKI_ESRCH: return "No such process";
239 case VKI_EINTR: return "Interrupted system call";
240 case VKI_EBADF: return "Bad file number";
241 case VKI_EAGAIN: return "Try again";
242 case VKI_ENOMEM: return "Out of memory";
243 case VKI_EACCES: return "Permission denied";
244 case VKI_EFAULT: return "Bad address";
245 case VKI_EEXIST: return "File exists";
246 case VKI_EINVAL: return "Invalid argument";
247 case VKI_EMFILE: return "Too many open files";
248 case VKI_ENOSYS: return "Function not implemented";
249 case VKI_ERESTARTSYS: return "ERESTARTSYS";
250 default: return "VG_(strerror): unknown error";
251 }
252}
253
254
njn9abd6082005-06-17 21:31:45 +0000255/*--------------------------------------------------------------------*/
256/*--- end ---*/
257/*--------------------------------------------------------------------*/