blob: d6348e71917a725833d682e8c2122b9b6660985c [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*/
cerion85665ca2005-06-20 15:51:07 +0000108static UWord do_syscall_WRK (
109 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(
114"do_syscall_WRK:\n"
115" push %esi\n"
116" push %edi\n"
117" push %ebx\n"
118" push %ebp\n"
119" movl 16+ 4(%esp),%eax\n"
120" movl 16+ 8(%esp),%ebx\n"
121" movl 16+12(%esp),%ecx\n"
122" movl 16+16(%esp),%edx\n"
123" movl 16+20(%esp),%esi\n"
124" movl 16+24(%esp),%edi\n"
125" movl 16+28(%esp),%ebp\n"
126" int $0x80\n"
127" popl %ebp\n"
128" popl %ebx\n"
129" popl %edi\n"
130" popl %esi\n"
131" ret\n"
132);
133#elif defined(VGP_amd64_linux)
134/* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
135 %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
136 calling convention).
137
138 The syscall number goes in %rax. The args are passed to the syscall in
139 the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
140 ie. the kernel's syscall calling convention.
141
142 %rax gets the return value. %rcx and %r11 are clobbered by the syscall;
143 no matter, they are caller-save (the syscall clobbers no callee-save
144 regs, so we don't have to do any register saving/restoring).
145*/
cerion85665ca2005-06-20 15:51:07 +0000146static UWord do_syscall_WRK (
147 UWord syscall_no,
148 UWord a1, UWord a2, UWord a3,
149 UWord a4, UWord a5, UWord a6
150 );
njn9abd6082005-06-17 21:31:45 +0000151asm(
152"do_syscall_WRK:\n"
153 /* Convert function calling convention --> syscall calling
154 convention */
155" movq %rdi, %rax\n"
156" movq %rsi, %rdi\n"
157" movq %rdx, %rsi\n"
158" movq %rcx, %rdx\n"
159" movq %r8, %r10\n"
160" movq %r9, %r8\n"
161" movq 8(%rsp), %r9\n" /* last arg from stack */
162" syscall\n"
163" ret\n"
164);
cerion85665ca2005-06-20 15:51:07 +0000165#elif defined(VGP_ppc32_linux)
166/* Incoming args (syscall number + up to 6 args) come in %r0, %r3:%r8
167
168 The syscall number goes in %r0. The args are passed to the syscall in
169 the regs %r3:%r8, i.e. the kernel's syscall calling convention.
170
171 The %cr0.so bit flags an error.
172 We return the syscall return value in %r3, and the %cr in %r4.
173 We return a ULong, of which %r3 is the high word, and %r4 the low.
174 No callee-save regs are clobbered, so no saving/restoring is needed.
175*/
176static ULong do_syscall_WRK (
177 UWord syscall_no,
178 UWord a1, UWord a2, UWord a3,
179 UWord a4, UWord a5, UWord a6
180 );
181asm(
182"do_syscall_WRK:\n"
183" mr 0,3\n"
184" mr 3,4\n"
185" mr 4,5\n"
186" mr 5,6\n"
187" mr 6,7\n"
188" mr 7,8\n"
189" mr 8,9\n"
190" sc\n" /* syscall: sets %cr0.so on error */
191" mfcr 4\n" /* %cr -> low word of return var */
192" rlwinm 4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
193" blr\n" /* and return */
194);
njn9abd6082005-06-17 21:31:45 +0000195#else
196# error Unknown platform
197#endif
198
199SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
200 UWord a4, UWord a5, UWord a6 )
201{
cerion85665ca2005-06-20 15:51:07 +0000202#if defined(VGP_x86_linux)
203 UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
204 return VG_(mk_SysRes_x86_linux)( val );
205#elif defined(VGP_amd64_linux)
206 UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
207 return VG_(mk_SysRes_amd64_linux)( val );
208#elif defined(VGP_ppc32_linux)
209 ULong ret = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
210 UInt val = (UInt)(ret>>32);
211 UInt errflag = (UInt)(ret);
212 return VG_(mk_SysRes_ppc32_linux)( val, errflag );
213#else
214# error Unknown platform
215#endif
njn9abd6082005-06-17 21:31:45 +0000216}
217
218/*--------------------------------------------------------------------*/
219/*--- end ---*/
220/*--------------------------------------------------------------------*/