blob: 084604c9974749fbdb4c7eedcc9d0070a253bb8b [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"
133);
134#elif defined(VGP_amd64_linux)
135/* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
136 %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
137 calling convention).
138
139 The syscall number goes in %rax. The args are passed to the syscall in
140 the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
141 ie. the kernel's syscall calling convention.
142
143 %rax gets the return value. %rcx and %r11 are clobbered by the syscall;
144 no matter, they are caller-save (the syscall clobbers no callee-save
145 regs, so we don't have to do any register saving/restoring).
146*/
sewardj03d8aa82005-10-14 11:25:49 +0000147extern UWord do_syscall_WRK (
cerion85665ca2005-06-20 15:51:07 +0000148 UWord syscall_no,
149 UWord a1, UWord a2, UWord a3,
150 UWord a4, UWord a5, UWord a6
151 );
njn9abd6082005-06-17 21:31:45 +0000152asm(
sewardjd9fc3822005-11-18 23:50:43 +0000153".text\n"
njn9abd6082005-06-17 21:31:45 +0000154"do_syscall_WRK:\n"
155 /* Convert function calling convention --> syscall calling
156 convention */
157" movq %rdi, %rax\n"
158" movq %rsi, %rdi\n"
159" movq %rdx, %rsi\n"
160" movq %rcx, %rdx\n"
161" movq %r8, %r10\n"
162" movq %r9, %r8\n"
163" movq 8(%rsp), %r9\n" /* last arg from stack */
164" syscall\n"
165" ret\n"
166);
cerion85665ca2005-06-20 15:51:07 +0000167#elif defined(VGP_ppc32_linux)
168/* Incoming args (syscall number + up to 6 args) come in %r0, %r3:%r8
169
170 The syscall number goes in %r0. The args are passed to the syscall in
171 the regs %r3:%r8, i.e. the kernel's syscall calling convention.
172
173 The %cr0.so bit flags an error.
174 We return the syscall return value in %r3, and the %cr in %r4.
175 We return a ULong, of which %r3 is the high word, and %r4 the low.
176 No callee-save regs are clobbered, so no saving/restoring is needed.
177*/
sewardj03d8aa82005-10-14 11:25:49 +0000178extern ULong do_syscall_WRK (
cerion85665ca2005-06-20 15:51:07 +0000179 UWord syscall_no,
180 UWord a1, UWord a2, UWord a3,
181 UWord a4, UWord a5, UWord a6
182 );
183asm(
sewardjd9fc3822005-11-18 23:50:43 +0000184".text\n"
cerion85665ca2005-06-20 15:51:07 +0000185"do_syscall_WRK:\n"
186" mr 0,3\n"
187" mr 3,4\n"
188" mr 4,5\n"
189" mr 5,6\n"
190" mr 6,7\n"
191" mr 7,8\n"
192" mr 8,9\n"
193" sc\n" /* syscall: sets %cr0.so on error */
194" mfcr 4\n" /* %cr -> low word of return var */
195" rlwinm 4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
196" blr\n" /* and return */
197);
njn9abd6082005-06-17 21:31:45 +0000198#else
199# error Unknown platform
200#endif
201
202SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
203 UWord a4, UWord a5, UWord a6 )
204{
cerion85665ca2005-06-20 15:51:07 +0000205#if defined(VGP_x86_linux)
206 UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
207 return VG_(mk_SysRes_x86_linux)( val );
208#elif defined(VGP_amd64_linux)
209 UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
210 return VG_(mk_SysRes_amd64_linux)( val );
211#elif defined(VGP_ppc32_linux)
212 ULong ret = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
213 UInt val = (UInt)(ret>>32);
214 UInt errflag = (UInt)(ret);
215 return VG_(mk_SysRes_ppc32_linux)( val, errflag );
216#else
217# error Unknown platform
218#endif
njn9abd6082005-06-17 21:31:45 +0000219}
220
sewardj45f4e7c2005-09-27 19:20:21 +0000221/* ---------------------------------------------------------------------
222 Names of errors.
223 ------------------------------------------------------------------ */
224
225/* Return a string which gives the name of an error value. Note,
226 unlike the standard C syserror fn, the returned string is not
227 malloc-allocated or writable -- treat it as a constant.
228 TODO: implement this properly. */
229
230const HChar* VG_(strerror) ( UWord errnum )
231{
232 switch (errnum) {
233 case VKI_EPERM: return "Operation not permitted";
234 case VKI_ENOENT: return "No such file or directory";
235 case VKI_ESRCH: return "No such process";
236 case VKI_EINTR: return "Interrupted system call";
237 case VKI_EBADF: return "Bad file number";
238 case VKI_EAGAIN: return "Try again";
239 case VKI_ENOMEM: return "Out of memory";
240 case VKI_EACCES: return "Permission denied";
241 case VKI_EFAULT: return "Bad address";
242 case VKI_EEXIST: return "File exists";
243 case VKI_EINVAL: return "Invalid argument";
244 case VKI_EMFILE: return "Too many open files";
245 case VKI_ENOSYS: return "Function not implemented";
246 case VKI_ERESTARTSYS: return "ERESTARTSYS";
247 default: return "VG_(strerror): unknown error";
248 }
249}
250
251
njn9abd6082005-06-17 21:31:45 +0000252/*--------------------------------------------------------------------*/
253/*--- end ---*/
254/*--------------------------------------------------------------------*/