* syscall.c (cb_syscall) <case CB_SYS_lstat>: New case.
[deliverable/binutils-gdb.git] / sim / common / syscall.c
1 /* Remote target system call support.
2 Copyright 1997, 1998, 2002, 2004 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 "cconfig.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_STRING_H
42 #include <string.h>
43 #elif defined (HAVE_STRINGS_H)
44 #include <strings.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <time.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include "gdb/callback.h"
55 #include "targ-vals.h"
56
57 #ifndef ENOSYS
58 #define ENOSYS EINVAL
59 #endif
60 #ifndef ENAMETOOLONG
61 #define ENAMETOOLONG EINVAL
62 #endif
63
64 /* Maximum length of a path name. */
65 #ifndef MAX_PATH_LEN
66 #define MAX_PATH_LEN 1024
67 #endif
68
69 /* When doing file read/writes, do this many bytes at a time. */
70 #define FILE_XFR_SIZE 4096
71
72 /* FIXME: for now, need to consider target word size. */
73 #define TWORD long
74 #define TADDR unsigned long
75
76 /* Path to be prepended to syscalls with absolute paths, and to be
77 chdir:ed at startup, if not empty. */
78 char *simulator_sysroot = "";
79
80 /* Utility of cb_syscall to fetch a path name or other string from the target.
81 The result is 0 for success or a host errno value. */
82
83 static int
84 get_string (cb, sc, buf, buflen, addr)
85 host_callback *cb;
86 CB_SYSCALL *sc;
87 char *buf;
88 int buflen;
89 TADDR addr;
90 {
91 char *p, *pend;
92
93 for (p = buf, pend = buf + buflen; p < pend; ++p, ++addr)
94 {
95 /* No, it isn't expected that this would cause one transaction with
96 the remote target for each byte. The target could send the
97 path name along with the syscall request, and cache the file
98 name somewhere (or otherwise tweak this as desired). */
99 unsigned int count = (*sc->read_mem) (cb, sc, addr, p, 1);
100
101 if (count != 1)
102 return EINVAL;
103 if (*p == 0)
104 break;
105 }
106 if (p == pend)
107 return ENAMETOOLONG;
108 return 0;
109 }
110
111 /* Utility of cb_syscall to fetch a path name.
112 The buffer is malloc'd and the address is stored in BUFP.
113 The result is that of get_string, but prepended with
114 simulator_sysroot if the string starts with '/'.
115 If an error occurs, no buffer is left malloc'd. */
116
117 static int
118 get_path (cb, sc, addr, bufp)
119 host_callback *cb;
120 CB_SYSCALL *sc;
121 TADDR addr;
122 char **bufp;
123 {
124 char *buf = xmalloc (MAX_PATH_LEN);
125 int result;
126 int sysroot_len = strlen (simulator_sysroot);
127
128 result = get_string (cb, sc, buf, MAX_PATH_LEN - sysroot_len, addr);
129 if (result == 0)
130 {
131 /* Prepend absolute paths with simulator_sysroot. Relative paths
132 are supposed to be relative to a chdir within that path, but at
133 this point unknown where. */
134 if (simulator_sysroot[0] != '\0' && *buf == '/')
135 {
136 /* Considering expected rareness of syscalls with absolute
137 file paths (compared to relative file paths and insn
138 execution), it does not seem worthwhile to rearrange things
139 to get rid of the string moves here; we'd need at least an
140 extra call to check the initial '/' in the path. */
141 memmove (buf + sysroot_len, buf, sysroot_len);
142 memcpy (buf, simulator_sysroot, sysroot_len);
143 }
144
145 *bufp = buf;
146 }
147 else
148 free (buf);
149 return result;
150 }
151
152 /* Perform a system call on behalf of the target. */
153
154 CB_RC
155 cb_syscall (cb, sc)
156 host_callback *cb;
157 CB_SYSCALL *sc;
158 {
159 TWORD result = 0, errcode = 0;
160
161 if (sc->magic != CB_SYSCALL_MAGIC)
162 abort ();
163
164 switch (cb_target_to_host_syscall (cb, sc->func))
165 {
166 #if 0 /* FIXME: wip */
167 case CB_SYS_argvlen :
168 {
169 /* Compute how much space is required to store the argv,envp
170 strings so that the program can allocate the space and then
171 call SYS_argv to fetch the values. */
172 int addr_size = cb->addr_size;
173 int argc,envc,arglen,envlen;
174 const char **argv = cb->init_argv;
175 const char **envp = cb->init_envp;
176
177 argc = arglen = 0;
178 if (argv)
179 {
180 for ( ; argv[argc]; ++argc)
181 arglen += strlen (argv[argc]) + 1;
182 }
183 envc = envlen = 0;
184 if (envp)
185 {
186 for ( ; envp[envc]; ++envc)
187 envlen += strlen (envp[envc]) + 1;
188 }
189 result = arglen + envlen;
190 break;
191 }
192
193 case CB_SYS_argv :
194 {
195 /* Pointer to target's buffer. */
196 TADDR tbuf = sc->arg1;
197 /* Buffer size. */
198 int bufsize = sc->arg2;
199 /* Q is the target address of where all the strings go. */
200 TADDR q;
201 int word_size = cb->word_size;
202 int i,argc,envc,len;
203 const char **argv = cb->init_argv;
204 const char **envp = cb->init_envp;
205
206 argc = 0;
207 if (argv)
208 {
209 for ( ; argv[argc]; ++argc)
210 {
211 int len = strlen (argv[argc]);
212 int written = (*sc->write_mem) (cb, sc, tbuf, argv[argc], len + 1);
213 if (written != len)
214 {
215 result = -1;
216 errcode = EINVAL;
217 goto FinishSyscall;
218 }
219 tbuf = len + 1;
220 }
221 }
222 if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
223 {
224 result = -1;
225 errcode = EINVAL;
226 goto FinishSyscall;
227 }
228 tbuf++;
229 envc = 0;
230 if (envp)
231 {
232 for ( ; envp[envc]; ++envc)
233 {
234 int len = strlen (envp[envc]);
235 int written = (*sc->write_mem) (cb, sc, tbuf, envp[envc], len + 1);
236 if (written != len)
237 {
238 result = -1;
239 errcode = EINVAL;
240 goto FinishSyscall;
241 }
242 tbuf = len + 1;
243 }
244 }
245 if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
246 {
247 result = -1;
248 errcode = EINVAL;
249 goto FinishSyscall;
250 }
251 result = argc;
252 sc->result2 = envc;
253 break;
254 }
255 #endif /* wip */
256
257 case CB_SYS_exit :
258 /* Caller must catch and handle. */
259 break;
260
261 case CB_SYS_open :
262 {
263 char *path;
264
265 errcode = get_path (cb, sc, sc->arg1, &path);
266 if (errcode != 0)
267 {
268 result = -1;
269 goto FinishSyscall;
270 }
271 result = (*cb->open) (cb, path, sc->arg2 /*, sc->arg3*/);
272 free (path);
273 if (result < 0)
274 goto ErrorFinish;
275 }
276 break;
277
278 case CB_SYS_close :
279 result = (*cb->close) (cb, sc->arg1);
280 if (result < 0)
281 goto ErrorFinish;
282 break;
283
284 case CB_SYS_read :
285 {
286 /* ??? Perfect handling of error conditions may require only one
287 call to cb->read. One can't assume all the data is
288 contiguously stored in host memory so that would require
289 malloc'ing/free'ing the space. Maybe later. */
290 char buf[FILE_XFR_SIZE];
291 int fd = sc->arg1;
292 TADDR addr = sc->arg2;
293 size_t count = sc->arg3;
294 size_t bytes_read = 0;
295 int bytes_written;
296
297 while (count > 0)
298 {
299 if (fd == 0)
300 result = (int) (*cb->read_stdin) (cb, buf,
301 (count < FILE_XFR_SIZE
302 ? count : FILE_XFR_SIZE));
303 else
304 result = (int) (*cb->read) (cb, fd, buf,
305 (count < FILE_XFR_SIZE
306 ? count : FILE_XFR_SIZE));
307 if (result == -1)
308 goto ErrorFinish;
309 if (result == 0) /* EOF */
310 break;
311 bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result);
312 if (bytes_written != result)
313 {
314 result = -1;
315 errcode = EINVAL;
316 goto FinishSyscall;
317 }
318 bytes_read += result;
319 count -= result;
320 addr += result;
321 /* If this is a short read, don't go back for more */
322 if (result != FILE_XFR_SIZE)
323 break;
324 }
325 result = bytes_read;
326 }
327 break;
328
329 case CB_SYS_write :
330 {
331 /* ??? Perfect handling of error conditions may require only one
332 call to cb->write. One can't assume all the data is
333 contiguously stored in host memory so that would require
334 malloc'ing/free'ing the space. Maybe later. */
335 char buf[FILE_XFR_SIZE];
336 int fd = sc->arg1;
337 TADDR addr = sc->arg2;
338 size_t count = sc->arg3;
339 int bytes_read;
340 size_t bytes_written = 0;
341
342 while (count > 0)
343 {
344 int bytes_to_read = count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE;
345 bytes_read = (*sc->read_mem) (cb, sc, addr, buf, bytes_to_read);
346 if (bytes_read != bytes_to_read)
347 {
348 result = -1;
349 errcode = EINVAL;
350 goto FinishSyscall;
351 }
352 if (fd == 1)
353 {
354 result = (int) (*cb->write_stdout) (cb, buf, bytes_read);
355 (*cb->flush_stdout) (cb);
356 }
357 else if (fd == 2)
358 {
359 result = (int) (*cb->write_stderr) (cb, buf, bytes_read);
360 (*cb->flush_stderr) (cb);
361 }
362 else
363 result = (int) (*cb->write) (cb, fd, buf, bytes_read);
364 if (result == -1)
365 goto ErrorFinish;
366 bytes_written += result;
367 count -= result;
368 addr += result;
369 }
370 result = bytes_written;
371 }
372 break;
373
374 case CB_SYS_lseek :
375 {
376 int fd = sc->arg1;
377 unsigned long offset = sc->arg2;
378 int whence = sc->arg3;
379
380 result = (*cb->lseek) (cb, fd, offset, whence);
381 if (result < 0)
382 goto ErrorFinish;
383 }
384 break;
385
386 case CB_SYS_unlink :
387 {
388 char *path;
389
390 errcode = get_path (cb, sc, sc->arg1, &path);
391 if (errcode != 0)
392 {
393 result = -1;
394 goto FinishSyscall;
395 }
396 result = (*cb->unlink) (cb, path);
397 free (path);
398 if (result < 0)
399 goto ErrorFinish;
400 }
401 break;
402
403 case CB_SYS_stat :
404 {
405 char *path,*buf;
406 int buflen;
407 struct stat statbuf;
408 TADDR addr = sc->arg2;
409
410 errcode = get_path (cb, sc, sc->arg1, &path);
411 if (errcode != 0)
412 {
413 result = -1;
414 goto FinishSyscall;
415 }
416 result = (*cb->stat) (cb, path, &statbuf);
417 free (path);
418 if (result < 0)
419 goto ErrorFinish;
420 buflen = cb_host_to_target_stat (cb, NULL, NULL);
421 buf = xmalloc (buflen);
422 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
423 {
424 /* The translation failed. This is due to an internal
425 host program error, not the target's fault. */
426 free (buf);
427 errcode = ENOSYS;
428 result = -1;
429 goto FinishSyscall;
430 }
431 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
432 {
433 free (buf);
434 errcode = EINVAL;
435 result = -1;
436 goto FinishSyscall;
437 }
438 free (buf);
439 }
440 break;
441
442 case CB_SYS_fstat :
443 {
444 char *buf;
445 int buflen;
446 struct stat statbuf;
447 TADDR addr = sc->arg2;
448
449 result = (*cb->fstat) (cb, sc->arg1, &statbuf);
450 if (result < 0)
451 goto ErrorFinish;
452 buflen = cb_host_to_target_stat (cb, NULL, NULL);
453 buf = xmalloc (buflen);
454 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
455 {
456 /* The translation failed. This is due to an internal
457 host program error, not the target's fault. */
458 free (buf);
459 errcode = ENOSYS;
460 result = -1;
461 goto FinishSyscall;
462 }
463 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
464 {
465 free (buf);
466 errcode = EINVAL;
467 result = -1;
468 goto FinishSyscall;
469 }
470 free (buf);
471 }
472 break;
473
474 case CB_SYS_lstat :
475 {
476 char *path, *buf;
477 int buflen;
478 struct stat statbuf;
479 TADDR addr = sc->arg2;
480
481 errcode = get_path (cb, sc, sc->arg1, &path);
482 if (errcode != 0)
483 {
484 result = -1;
485 goto FinishSyscall;
486 }
487 result = (*cb->lstat) (cb, path, &statbuf);
488 free (path);
489 if (result < 0)
490 goto ErrorFinish;
491
492 buflen = cb_host_to_target_stat (cb, NULL, NULL);
493 buf = xmalloc (buflen);
494 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
495 {
496 /* The translation failed. This is due to an internal
497 host program error, not the target's fault.
498 Unfortunately, it's hard to test this case, so there's no
499 test-case for this execution path. */
500 free (buf);
501 errcode = ENOSYS;
502 result = -1;
503 goto FinishSyscall;
504 }
505
506 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
507 {
508 free (buf);
509 errcode = EINVAL;
510 result = -1;
511 goto FinishSyscall;
512 }
513
514 free (buf);
515 }
516 break;
517
518 case CB_SYS_time :
519 {
520 /* FIXME: May wish to change CB_SYS_time to something else.
521 We might also want gettimeofday or times, but if system calls
522 can be built on others, we can keep the number we have to support
523 here down. */
524 time_t t = (*cb->time) (cb, (time_t *) 0);
525 result = t;
526 /* It is up to target code to process the argument to time(). */
527 }
528 break;
529
530 case CB_SYS_chdir :
531 case CB_SYS_chmod :
532 case CB_SYS_utime :
533 /* fall through for now */
534
535 default :
536 result = -1;
537 errcode = ENOSYS;
538 break;
539 }
540
541 FinishSyscall:
542 sc->result = result;
543 if (errcode == 0)
544 sc->errcode = 0;
545 else
546 sc->errcode = cb_host_to_target_errno (cb, errcode);
547 return CB_RC_OK;
548
549 ErrorFinish:
550 sc->result = result;
551 sc->errcode = (*cb->get_errno) (cb);
552 return CB_RC_OK;
553 }
This page took 0.061249 seconds and 5 git commands to generate.