blob: af905172938891c5a0cc7b31cbeb5fe9b150d3c2 [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) */
sewardj39a7c1d2005-11-24 03:54:38 +000073/* Note this must be in the bottom bit of the second arg */
74SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ) {
cerion85665ca2005-06-20 15:51:07 +000075 SysRes res;
sewardj39a7c1d2005-11-24 03:54:38 +000076 res.isError = (cr0so & 1) != 0;
cerion85665ca2005-06-20 15:51:07 +000077 res.val = val;
78 return res;
79}
80
81
njn9abd6082005-06-17 21:31:45 +000082SysRes VG_(mk_SysRes_Error) ( UWord val ) {
83 SysRes r = { val, True };
84 return r;
85}
86
87SysRes VG_(mk_SysRes_Success) ( UWord val ) {
88 SysRes r = { val, False };
89 return r;
90}
91
92
93/* ---------------------------------------------------------------------
94 A function for doing syscalls.
95 ------------------------------------------------------------------ */
96
njn9abd6082005-06-17 21:31:45 +000097#if defined(VGP_x86_linux)
98/* Incoming args (syscall number + up to 6 args) come on the stack.
99 (ie. the C calling convention).
100
101 The syscall number goes in %eax. The args are passed to the syscall in
102 the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
103 calling convention.
104
105 %eax gets the return value. Not sure which registers the kernel
106 clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
107 %ebp).
108*/
sewardj03d8aa82005-10-14 11:25:49 +0000109extern UWord do_syscall_WRK (
cerion85665ca2005-06-20 15:51:07 +0000110 UWord syscall_no,
111 UWord a1, UWord a2, UWord a3,
112 UWord a4, UWord a5, UWord a6
113 );
njn9abd6082005-06-17 21:31:45 +0000114asm(
sewardjd9fc3822005-11-18 23:50:43 +0000115".text\n"
njn9abd6082005-06-17 21:31:45 +0000116"do_syscall_WRK:\n"
117" push %esi\n"
118" push %edi\n"
119" push %ebx\n"
120" push %ebp\n"
121" movl 16+ 4(%esp),%eax\n"
122" movl 16+ 8(%esp),%ebx\n"
123" movl 16+12(%esp),%ecx\n"
124" movl 16+16(%esp),%edx\n"
125" movl 16+20(%esp),%esi\n"
126" movl 16+24(%esp),%edi\n"
127" movl 16+28(%esp),%ebp\n"
128" int $0x80\n"
129" popl %ebp\n"
130" popl %ebx\n"
131" popl %edi\n"
132" popl %esi\n"
133" ret\n"
sewardj2fedc642005-11-19 02:02:57 +0000134".previous\n"
njn9abd6082005-06-17 21:31:45 +0000135);
136#elif defined(VGP_amd64_linux)
137/* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
138 %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
139 calling convention).
140
141 The syscall number goes in %rax. The args are passed to the syscall in
142 the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
143 ie. the kernel's syscall calling convention.
144
145 %rax gets the return value. %rcx and %r11 are clobbered by the syscall;
146 no matter, they are caller-save (the syscall clobbers no callee-save
147 regs, so we don't have to do any register saving/restoring).
148*/
sewardj03d8aa82005-10-14 11:25:49 +0000149extern UWord do_syscall_WRK (
cerion85665ca2005-06-20 15:51:07 +0000150 UWord syscall_no,
151 UWord a1, UWord a2, UWord a3,
152 UWord a4, UWord a5, UWord a6
153 );
njn9abd6082005-06-17 21:31:45 +0000154asm(
sewardjd9fc3822005-11-18 23:50:43 +0000155".text\n"
njn9abd6082005-06-17 21:31:45 +0000156"do_syscall_WRK:\n"
157 /* Convert function calling convention --> syscall calling
158 convention */
159" movq %rdi, %rax\n"
160" movq %rsi, %rdi\n"
161" movq %rdx, %rsi\n"
162" movq %rcx, %rdx\n"
163" movq %r8, %r10\n"
164" movq %r9, %r8\n"
165" movq 8(%rsp), %r9\n" /* last arg from stack */
166" syscall\n"
167" ret\n"
sewardj2fedc642005-11-19 02:02:57 +0000168".previous\n"
njn9abd6082005-06-17 21:31:45 +0000169);
cerion85665ca2005-06-20 15:51:07 +0000170#elif defined(VGP_ppc32_linux)
sewardj39a7c1d2005-11-24 03:54:38 +0000171/* Incoming args (syscall number + up to 6 args) come in %r3:%r9.
cerion85665ca2005-06-20 15:51:07 +0000172
173 The syscall number goes in %r0. The args are passed to the syscall in
174 the regs %r3:%r8, i.e. the kernel's syscall calling convention.
175
176 The %cr0.so bit flags an error.
sewardj39a7c1d2005-11-24 03:54:38 +0000177 We return the syscall return value in %r3, and the %cr0.so in
178 the lowest bit of %r4.
cerion85665ca2005-06-20 15:51:07 +0000179 We return a ULong, of which %r3 is the high word, and %r4 the low.
180 No callee-save regs are clobbered, so no saving/restoring is needed.
181*/
sewardj03d8aa82005-10-14 11:25:49 +0000182extern ULong do_syscall_WRK (
cerion85665ca2005-06-20 15:51:07 +0000183 UWord syscall_no,
184 UWord a1, UWord a2, UWord a3,
185 UWord a4, UWord a5, UWord a6
186 );
187asm(
sewardjd9fc3822005-11-18 23:50:43 +0000188".text\n"
cerion85665ca2005-06-20 15:51:07 +0000189"do_syscall_WRK:\n"
190" mr 0,3\n"
191" mr 3,4\n"
192" mr 4,5\n"
193" mr 5,6\n"
194" mr 6,7\n"
195" mr 7,8\n"
196" mr 8,9\n"
197" sc\n" /* syscall: sets %cr0.so on error */
198" mfcr 4\n" /* %cr -> low word of return var */
199" rlwinm 4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
200" blr\n" /* and return */
sewardj2fedc642005-11-19 02:02:57 +0000201".previous\n"
cerion85665ca2005-06-20 15:51:07 +0000202);
njn9abd6082005-06-17 21:31:45 +0000203#else
204# error Unknown platform
205#endif
206
207SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
208 UWord a4, UWord a5, UWord a6 )
209{
cerion85665ca2005-06-20 15:51:07 +0000210#if defined(VGP_x86_linux)
211 UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
212 return VG_(mk_SysRes_x86_linux)( val );
213#elif defined(VGP_amd64_linux)
214 UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
215 return VG_(mk_SysRes_amd64_linux)( val );
216#elif defined(VGP_ppc32_linux)
217 ULong ret = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
218 UInt val = (UInt)(ret>>32);
sewardj39a7c1d2005-11-24 03:54:38 +0000219 UInt cr0so = (UInt)(ret);
220 return VG_(mk_SysRes_ppc32_linux)( val, cr0so );
cerion85665ca2005-06-20 15:51:07 +0000221#else
222# error Unknown platform
223#endif
njn9abd6082005-06-17 21:31:45 +0000224}
225
sewardj45f4e7c2005-09-27 19:20:21 +0000226/* ---------------------------------------------------------------------
227 Names of errors.
228 ------------------------------------------------------------------ */
229
230/* Return a string which gives the name of an error value. Note,
231 unlike the standard C syserror fn, the returned string is not
232 malloc-allocated or writable -- treat it as a constant.
233 TODO: implement this properly. */
234
235const HChar* VG_(strerror) ( UWord errnum )
236{
237 switch (errnum) {
238 case VKI_EPERM: return "Operation not permitted";
239 case VKI_ENOENT: return "No such file or directory";
240 case VKI_ESRCH: return "No such process";
241 case VKI_EINTR: return "Interrupted system call";
242 case VKI_EBADF: return "Bad file number";
243 case VKI_EAGAIN: return "Try again";
244 case VKI_ENOMEM: return "Out of memory";
245 case VKI_EACCES: return "Permission denied";
246 case VKI_EFAULT: return "Bad address";
247 case VKI_EEXIST: return "File exists";
248 case VKI_EINVAL: return "Invalid argument";
249 case VKI_EMFILE: return "Too many open files";
250 case VKI_ENOSYS: return "Function not implemented";
251 case VKI_ERESTARTSYS: return "ERESTARTSYS";
252 default: return "VG_(strerror): unknown error";
253 }
254}
255
256
njn9abd6082005-06-17 21:31:45 +0000257/*--------------------------------------------------------------------*/
258/*--- end ---*/
259/*--------------------------------------------------------------------*/