* callback.c (os_stat): Make 3rd arg a host struct stat ptr.
[binutils-gdb.git] / sim / common / syscall.c
1 /* Remote target system call support.
2 Copyright 1997 Free Software Foundation, Inc.
3 Contributed by Cygnus Solutions.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 /* This interface isn't intended to be specific to any particular kind
22 of remote (hardware, simulator, whatever). As such, support for it
23 (e.g. sim/common/callback.c) should *not* live in the simulator source
24 tree, nor should it live in the gdb source tree. K&R C must be
25 supported. */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 #include "ansidecl.h"
31 #include "libiberty.h"
32 #ifdef ANSI_PROTOTYPES
33 #include <stdarg.h>
34 #else
35 #include <varargs.h>
36 #endif
37 #include <stdio.h>
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <time.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include "callback.h"
50 #include "targ-vals.h"
51
52 #ifndef ENOSYS
53 #define ENOSYS EINVAL
54 #endif
55 #ifndef ENAMETOOLONG
56 #define ENAMETOOLONG EINVAL
57 #endif
58
59 /* Maximum length of a path name. */
60 #ifndef MAX_PATH_LEN
61 #define MAX_PATH_LEN 1024
62 #endif
63
64 /* When doing file read/writes, do this many bytes at a time. */
65 #define FILE_XFR_SIZE 4096
66
67 /* FIXME: for now */
68 #define TWORD unsigned long
69 #define TADDR unsigned long
70
71 /* Utility of cb_syscall to fetch a path name or other string from the target.
72 The result is 0 for success or a host errno value. */
73
74 static int
75 get_string (cb, sc, buf, buflen, addr)
76 host_callback *cb;
77 CB_SYSCALL *sc;
78 char *buf;
79 int buflen;
80 TADDR addr;
81 {
82 char *p, *pend;
83
84 for (p = buf, pend = buf + buflen; p < pend; ++p, ++addr)
85 {
86 /* No, it isn't expected that this would cause one transaction with
87 the remote target for each byte. The target could send the
88 path name along with the syscall request, and cache the file
89 name somewhere (or otherwise tweak this as desired). */
90 unsigned int count = (*sc->read_mem) (cb, sc, addr, p, 1);
91
92 if (count != 1)
93 return EINVAL;
94 if (*p == 0)
95 break;
96 }
97 if (p == pend)
98 return ENAMETOOLONG;
99 return 0;
100 }
101
102 /* Utility of cb_syscall to fetch a path name.
103 The buffer is malloc'd and the address is stored in BUFP.
104 The result is that of get_string.
105 If an error occurs, no buffer is left malloc'd. */
106
107 static int
108 get_path (cb, sc, addr, bufp)
109 host_callback *cb;
110 CB_SYSCALL *sc;
111 TADDR addr;
112 char **bufp;
113 {
114 char *buf = xmalloc (MAX_PATH_LEN);
115 int result;
116
117 result = get_string (cb, sc, buf, MAX_PATH_LEN, addr);
118 if (result == 0)
119 *bufp = buf;
120 else
121 free (buf);
122 return result;
123 }
124
125 /* Perform a system call on behalf of the target. */
126
127 CB_RC
128 cb_syscall (cb, sc)
129 host_callback *cb;
130 CB_SYSCALL *sc;
131 {
132 /* ??? Need to consider target word size. */
133 long result = 0, errcode = 0;
134
135 switch (cb_target_to_host_syscall (cb, sc->func))
136 {
137 #if 0 /* FIXME: wip */
138 case CB_SYS_argvlen :
139 {
140 /* Compute how much space is required to store the argv,envp
141 strings so that the program can allocate the space and then
142 call SYS_argv to fetch the values. */
143 int addr_size = cb->addr_size;
144 int argc,envc,arglen,envlen;
145 const char **argv = cb->init_argv;
146 const char **envp = cb->init_envp;
147
148 argc = arglen = 0;
149 if (argv)
150 {
151 for ( ; argv[argc]; ++argc)
152 arglen += strlen (argv[argc]) + 1;
153 }
154 envc = envlen = 0;
155 if (envp)
156 {
157 for ( ; envp[envc]; ++envc)
158 envlen += strlen (envp[envc]) + 1;
159 }
160 result = arglen + envlen;
161 break;
162 }
163
164 case CB_SYS_argv :
165 {
166 /* Pointer to target's buffer. */
167 TADDR tbuf = sc->arg1;
168 /* Buffer size. */
169 int bufsize = sc->arg2;
170 /* Q is the target address of where all the strings go. */
171 TADDR q;
172 int word_size = cb->word_size;
173 int i,argc,envc,len;
174 const char **argv = cb->init_argv;
175 const char **envp = cb->init_envp;
176
177 argc = 0;
178 if (argv)
179 {
180 for ( ; argv[argc]; ++argc)
181 {
182 int len = strlen (argv[argc]);
183 int written = (*sc->write_mem) (cb, sc, tbuf, argv[argc], len + 1);
184 if (written != len)
185 {
186 result = -1;
187 errcode = EINVAL;
188 goto FinishSyscall;
189 }
190 tbuf = len + 1;
191 }
192 }
193 if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
194 {
195 result = -1;
196 errcode = EINVAL;
197 goto FinishSyscall;
198 }
199 tbuf++;
200 envc = 0;
201 if (envp)
202 {
203 for ( ; envp[envc]; ++envc)
204 {
205 int len = strlen (envp[envc]);
206 int written = (*sc->write_mem) (cb, sc, tbuf, envp[envc], len + 1);
207 if (written != len)
208 {
209 result = -1;
210 errcode = EINVAL;
211 goto FinishSyscall;
212 }
213 tbuf = len + 1;
214 }
215 }
216 if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
217 {
218 result = -1;
219 errcode = EINVAL;
220 goto FinishSyscall;
221 }
222 result = argc;
223 sc->result2 = envc;
224 break;
225 }
226 #endif /* wip */
227
228 case CB_SYS_exit :
229 /* Caller must catch and handle. */
230 break;
231
232 case CB_SYS_open :
233 {
234 char *path;
235
236 errcode = get_path (cb, sc, sc->arg1, &path);
237 if (errcode != 0)
238 {
239 result = -1;
240 goto FinishSyscall;
241 }
242 result = (*cb->open) (cb, path, sc->arg2 /*, sc->arg3*/);
243 free (path);
244 if (result < 0)
245 goto ErrorFinish;
246 }
247 break;
248
249 case CB_SYS_close :
250 result = (*cb->close) (cb, sc->arg1);
251 if (result < 0)
252 goto ErrorFinish;
253 break;
254
255 case CB_SYS_read :
256 {
257 /* ??? Perfect handling of error conditions may require only one
258 call to cb->read. One can't assume all the data is
259 contiguously stored in host memory so that would require
260 malloc'ing/free'ing the space. Maybe later. */
261 char buf[FILE_XFR_SIZE];
262 int fd = sc->arg1;
263 TADDR addr = sc->arg2;
264 size_t count = sc->arg3;
265 size_t bytes_read = 0;
266 int bytes_written;
267
268 while (count > 0)
269 {
270 if (fd == 0)
271 result = (int) (*cb->read_stdin) (cb, buf,
272 (count < FILE_XFR_SIZE
273 ? count : FILE_XFR_SIZE));
274 else
275 result = (int) (*cb->read) (cb, fd, buf,
276 (count < FILE_XFR_SIZE
277 ? count : FILE_XFR_SIZE));
278 if (result == -1)
279 goto ErrorFinish;
280 bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result);
281 if (bytes_written != result)
282 {
283 result = -1;
284 errcode = EINVAL;
285 goto FinishSyscall;
286 }
287 bytes_read += result;
288 count -= result;
289 addr += result;
290 }
291 result = bytes_read;
292 }
293 break;
294
295 case CB_SYS_write :
296 {
297 /* ??? Perfect handling of error conditions may require only one
298 call to cb->write. One can't assume all the data is
299 contiguously stored in host memory so that would require
300 malloc'ing/free'ing the space. Maybe later. */
301 char buf[FILE_XFR_SIZE];
302 int fd = sc->arg1;
303 TADDR addr = sc->arg2;
304 size_t count = sc->arg3;
305 int bytes_read;
306 size_t bytes_written = 0;
307
308 while (count > 0)
309 {
310 int bytes_to_read = count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE;
311 bytes_read = (*sc->read_mem) (cb, sc, addr, buf, bytes_to_read);
312 if (bytes_read != bytes_to_read)
313 {
314 result = -1;
315 errcode = EINVAL;
316 goto FinishSyscall;
317 }
318 if (fd == 1)
319 result = (int) (*cb->write_stdout) (cb, buf, bytes_read);
320 if (fd == 2)
321 result = (int) (*cb->write_stderr) (cb, buf, bytes_read);
322 else
323 result = (int) (*cb->write) (cb, fd, buf, bytes_read);
324 if (result == -1)
325 goto ErrorFinish;
326 bytes_written += result;
327 count -= result;
328 addr += result;
329 }
330 result = bytes_written;
331 }
332 break;
333
334 case CB_SYS_lseek :
335 {
336 int fd = sc->arg1;
337 unsigned long offset = sc->arg2;
338 int whence = sc->arg3;
339
340 result = (*cb->lseek) (cb, fd, offset, whence);
341 if (result < 0)
342 goto ErrorFinish;
343 }
344 break;
345
346 case CB_SYS_unlink :
347 {
348 char *path;
349
350 errcode = get_path (cb, sc, sc->arg1, &path);
351 if (errcode != 0)
352 {
353 result = -1;
354 goto FinishSyscall;
355 }
356 result = (*cb->unlink) (cb, path);
357 free (path);
358 if (result < 0)
359 goto ErrorFinish;
360 }
361 break;
362
363 case CB_SYS_stat :
364 {
365 char *path,*buf;
366 int buflen;
367 struct stat statbuf;
368 TADDR addr = sc->arg2;
369
370 errcode = get_path (cb, sc, sc->arg1, &path);
371 if (errcode != 0)
372 {
373 result = -1;
374 goto FinishSyscall;
375 }
376 result = (*cb->stat) (cb, path, &statbuf);
377 free (path);
378 if (result < 0)
379 goto ErrorFinish;
380 buflen = cb_host_to_target_stat (cb, NULL, NULL);
381 buf = xmalloc (buflen);
382 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
383 {
384 /* The translation failed. This is due to an internal
385 host program error, not the target's fault. */
386 free (buf);
387 errcode = ENOSYS;
388 result = -1;
389 goto FinishSyscall;
390 }
391 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
392 {
393 free (buf);
394 errcode = EINVAL;
395 result = -1;
396 goto FinishSyscall;
397 }
398 free (buf);
399 }
400 break;
401
402 case CB_SYS_fstat :
403 {
404 char *buf;
405 int buflen;
406 struct stat statbuf;
407 TADDR addr = sc->arg2;
408
409 result = (*cb->fstat) (cb, sc->arg1, &statbuf);
410 if (result < 0)
411 goto ErrorFinish;
412 buflen = cb_host_to_target_stat (cb, NULL, NULL);
413 buf = xmalloc (buflen);
414 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
415 {
416 /* The translation failed. This is due to an internal
417 host program error, not the target's fault. */
418 free (buf);
419 errcode = ENOSYS;
420 result = -1;
421 goto FinishSyscall;
422 }
423 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
424 {
425 free (buf);
426 errcode = EINVAL;
427 result = -1;
428 goto FinishSyscall;
429 }
430 free (buf);
431 }
432 break;
433
434 case CB_SYS_time :
435 {
436 /* FIXME: May wish to change CB_SYS_time to something else.
437 We might also want gettimeofday or times, but if system calls
438 can be built on others, we can keep the number we have to support
439 here down. */
440 time_t t = (*cb->time) (cb, (time_t *) 0);
441 result = t;
442 /* It is up to target code to process the argument to time(). */
443 }
444 break;
445
446 case CB_SYS_chdir :
447 case CB_SYS_chmod :
448 case CB_SYS_utime :
449 /* fall through for now */
450
451 default :
452 result = -1;
453 errcode = ENOSYS;
454 break;
455 }
456
457 FinishSyscall:
458 sc->result = result;
459 if (errcode == 0)
460 sc->errcode = 0;
461 else
462 sc->errcode = cb_host_to_target_errno (cb, errcode);
463 return CB_RC_OK;
464
465 ErrorFinish:
466 sc->result = result;
467 sc->errcode = (*cb->get_errno) (cb);
468 return CB_RC_OK;
469 }