add chdir
[snitchaser:mainline.git] / src / arch / x86 / interp / syscalls / socketcall.c
1 /* 
2  * socketcall.c
3  * by WN @ Jul. 22, 2010
4  */
5
6 #include "syscall_handler.h"
7 #include <common/debug.h>
8 #include <xasm/string.h>
9
10 #define SYS_SOCKET      1               /* sys_socket(2)                */
11 #define SYS_BIND        2               /* sys_bind(2)                  */
12 #define SYS_CONNECT     3               /* sys_connect(2)               */
13 #define SYS_LISTEN      4               /* sys_listen(2)                */
14 #define SYS_ACCEPT      5               /* sys_accept(2)                */
15 #define SYS_GETSOCKNAME 6               /* sys_getsockname(2)           */
16 #define SYS_GETPEERNAME 7               /* sys_getpeername(2)           */
17 #define SYS_SOCKETPAIR  8               /* sys_socketpair(2)            */
18 #define SYS_SEND        9               /* sys_send(2)                  */
19 #define SYS_RECV        10              /* sys_recv(2)                  */
20 #define SYS_SENDTO      11              /* sys_sendto(2)                */
21 #define SYS_RECVFROM    12              /* sys_recvfrom(2)              */
22 #define SYS_SHUTDOWN    13              /* sys_shutdown(2)              */
23 #define SYS_SETSOCKOPT  14              /* sys_setsockopt(2)            */
24 #define SYS_GETSOCKOPT  15              /* sys_getsockopt(2)            */
25 #define SYS_SENDMSG     16              /* sys_sendmsg(2)               */
26 #define SYS_RECVMSG     17              /* sys_recvmsg(2)               */
27
28 #ifndef PRE_LIBRARY
29
30 #ifdef POST_LIBRARY
31 # define DEF_SUB_HANDLER(x)     static int post_##x
32 # define SUB_HANDLER(x) post_##x
33 #else
34 # define DEF_SUB_HANDLER(x)     static int replay_##x
35 # define SUB_HANDLER(x) replay_##x
36 #endif
37
38 /* Argument list sizes for sys_socketcall */
39 #define AL(x) ((x) * sizeof(unsigned long))
40 static const unsigned char nargs[18]={
41         AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
42         AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
43         AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)
44 };
45
46 DEF_SUB_HANDLER(getsockname)(int fd, uint32_t usockaddr,
47                 uint32_t usockaddr_len, int retval)
48 {
49         if (retval < 0)
50                 return 0;
51
52         BUFFER((void*)(usockaddr_len), sizeof(int));
53         int len = *((int*)(usockaddr_len));
54         assert((len > 0) && (len < 1000));
55
56         /* in fact this is incorrect. the size of buffer 'usockaddr'
57          * may smaller than output 'len' so the address may not be
58          * fully copied. However this is rare case in real programs. */
59         if (usockaddr != 0)
60                 BUFFER((void*)(usockaddr), len);
61
62         return 0;
63 }
64
65 DEF_SUB_HANDLER(recvfrom)(int fd, uint32_t ubuf, uint32_t size,
66                 uint32_t flags, uint32_t addr, uint32_t paddr_len, int retval)
67 {
68         if (retval < 0)
69                 return 0;
70         BUFFER((void*)(ubuf), retval);
71         if (addr != 0) {
72                 assert(paddr_len != 0);
73
74                 BUFFER((void*)paddr_len, sizeof(int));
75                 int len = *((int*)(paddr_len));
76
77                 BUFFER((void*)(addr), len);
78         }
79         return 0;
80 }
81
82 struct _iovec
83 {
84         uint32_t iov_base;
85         uint32_t iov_len;
86 };
87
88 struct _msghdr {
89         uint32_t msg_name;      /* Socket name                  */
90         uint32_t msg_namelen;   /* Length of name               */
91         uint32_t msg_iov;       /* Data blocks                  */
92         uint32_t msg_iovlen;    /* Number of blocks             */
93         uint32_t msg_control;   /* Per protocol magic (eg BSD file descriptor passing) */
94         uint32_t msg_controllen;        /* Length of cmsg list */
95         uint32_t msg_flags;
96 };
97
98 DEF_SUB_HANDLER(recvmsg)(int fd, uint32_t msg, uint32_t flags, int retval)
99 {
100         if (retval < 0)
101                 return 0;
102
103         struct _msghdr hdr;
104         BUFFER((void*)(msg), sizeof(hdr));
105         memcpy(&hdr, (void*)(msg), sizeof(hdr));
106
107         if (hdr.msg_name != 0)
108                 BUFFER((void*)(hdr.msg_name), hdr.msg_namelen);
109
110         int iov_len = hdr.msg_iovlen;
111         int sz_iovs = (sizeof(struct _iovec) * iov_len);
112
113         BUFFER((void*)(hdr.msg_iov), sz_iovs);
114         struct _iovec * vecs = (void*)(hdr.msg_iov);
115
116         for (int i = 0; i < iov_len; i++)
117                 BUFFER((void*)(vecs[i].iov_base), vecs[i].iov_len);
118         return 0;
119 }
120
121 DEF_SUB_HANDLER(recv)(int fd, uint32_t ubuf, uint32_t size,
122                 uint32_t flags, int retval)
123 {
124         /* this is incorrect: sometime even recv fails,
125          * the ubuf is still filled. */
126         if (retval <= 0)
127                 return 0;
128         BUFFER((void*)(ubuf), retval);
129         return 0;
130 }
131
132 DEF_SUB_HANDLER(getpeername)(int fd, uint32_t usockaddr,
133                 uint32_t usockaddr_len, int retval)
134 {
135         if (retval < 0)
136                 return 0;
137         if (usockaddr != 0) {
138                 assert(usockaddr_len != 0);
139                 BUFFER((void*)usockaddr_len, sizeof(int));
140                 BUFFER((void*)usockaddr, *(int*)(usockaddr_len));
141         }
142         return 0;
143 }
144
145 DEF_SUB_HANDLER(accept)(int fd, uintptr_t pupeer_sockaddr,
146                 uintptr_t pupeer_addrlen, int retval)
147 {
148         if (retval <= 0)
149                 return 0;
150         if (pupeer_sockaddr == 0)
151                 return 0;
152         assert(pupeer_addrlen != 0);
153         BUFFER((void*)pupeer_addrlen, sizeof(int));
154         int l = *((int*)(pupeer_addrlen));
155         BUFFER((void*)pupeer_sockaddr, l);
156         return 0;
157 }
158
159 DEF_SUB_HANDLER(socketpair)(int family, int type, int protocol,
160                 uintptr_t usockvec, int retval)
161 {
162         if (retval >= 0) {
163                 assert(usockvec != 0);
164                 BUFFER((void*)(usockvec), 2 * sizeof(int));
165         }
166         return 0;
167 }
168
169 DEF_SUB_HANDLER(getsockopt)(int fd, int level, int optname,
170                 uintptr_t optval, uintptr_t optlen, int retval)
171 {
172         if (retval >= 0) {
173                 assert(optlen != 0);
174                 BUFFER((int*)(optlen), sizeof(int));
175                 BUFFER((void*)(optval), *((int*)(optlen)));
176         }
177         return 0;
178 }
179
180 DEF_HANDLER(socketcall)
181 {
182         int call = regs->ebx;
183         uint32_t args = regs->ecx;
184
185         TRACE(LOG_SYSCALL, "socketcall, nr=0x%x\n", call);
186         assert((call >= 1) && (call <= SYS_RECVMSG));
187
188         unsigned long a0, a1, a2, a[6];
189         uint32_t retval = regs->eax;
190
191         if (nargs[call] > 0) {
192                 BUFFER((void*)args, nargs[call]);
193                 memcpy(a, (void*)(args), nargs[call]);
194         }
195
196         a0 = a[0];
197         a1 = a[1];
198         a2 = a[2];
199
200         switch (call) {
201         case SYS_GETSOCKNAME:
202                 return SUB_HANDLER(getsockname)(a0, a1, a2, retval);
203         case SYS_RECVFROM:
204                 return SUB_HANDLER(recvfrom)(a0, a1, a2, a[3], a[4], a[5], retval);
205         case SYS_RECVMSG:
206                 return SUB_HANDLER(recvmsg)(a0, a1, a2, retval);
207         case SYS_RECV:
208                 return SUB_HANDLER(recv)(a0, a1, a2, a[3], retval);
209         case SYS_GETPEERNAME:
210                 return SUB_HANDLER(getpeername)(a0, a1, a2, retval);
211         case SYS_ACCEPT:
212                 return SUB_HANDLER(accept)(a0, a1, a2, retval);
213         case SYS_SOCKETPAIR:
214                 return SUB_HANDLER(socketpair)(a0, a1, a2, a[3], retval);
215         case SYS_GETSOCKOPT:
216                 return SUB_HANDLER(getsockopt)(a0, a1, a2, a[3], a[4], retval);
217                 /* trivial sockcalls */
218         case SYS_CONNECT:
219         case SYS_SENDTO:
220         case SYS_SOCKET:
221         case SYS_BIND:
222         case SYS_SETSOCKOPT:
223         case SYS_LISTEN:
224         case SYS_SHUTDOWN:
225         case SYS_SEND:
226         case SYS_SENDMSG:
227                 return 0;
228         default:
229                 FATAL(LOG_SYSCALL, "Unknown socket call: %d\n", call);
230         }
231         return 0;
232 }
233 #endif
234
235 // vim:ts=4:sw=4
236