]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/syscall.c
* callback.h (CB_SYS_truncate, CB_SYS_ftruncate): New macros.
[thirdparty/binutils-gdb.git] / sim / common / syscall.c
CommitLineData
c906108c 1/* Remote target system call support.
41ee5402 2 Copyright 1997, 1998, 2002, 2004 Free Software Foundation, Inc.
c906108c
SS
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
41ee5402 28#include "cconfig.h"
c906108c
SS
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
027e2a04
HPN
41#ifdef HAVE_STRING_H
42#include <string.h>
43#elif defined (HAVE_STRINGS_H)
44#include <strings.h>
45#endif
c906108c
SS
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>
3c25f8c7 54#include "gdb/callback.h"
c906108c
SS
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
027e2a04
HPN
76/* Path to be prepended to syscalls with absolute paths, and to be
77 chdir:ed at startup, if not empty. */
78char *simulator_sysroot = "";
79
c906108c
SS
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
83static int
84get_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.
027e2a04
HPN
113 The result is that of get_string, but prepended with
114 simulator_sysroot if the string starts with '/'.
c906108c
SS
115 If an error occurs, no buffer is left malloc'd. */
116
117static int
118get_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;
027e2a04 126 int sysroot_len = strlen (simulator_sysroot);
c906108c 127
027e2a04 128 result = get_string (cb, sc, buf, MAX_PATH_LEN - sysroot_len, addr);
c906108c 129 if (result == 0)
027e2a04
HPN
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 }
c906108c
SS
147 else
148 free (buf);
149 return result;
150}
151
152/* Perform a system call on behalf of the target. */
153
154CB_RC
155cb_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
82571856
HPN
403 case CB_SYS_rename :
404 {
405 char *path1, *path2;
406
407 errcode = get_path (cb, sc, sc->arg1, &path1);
408 if (errcode != 0)
409 {
410 result = -1;
411 errcode = EFAULT;
412 goto FinishSyscall;
413 }
414 errcode = get_path (cb, sc, sc->arg2, &path2);
415 if (errcode != 0)
416 {
417 result = -1;
418 errcode = EFAULT;
419 free (path1);
420 goto FinishSyscall;
421 }
422 result = (*cb->rename) (cb, path1, path2);
423 free (path1);
424 free (path2);
425 if (result < 0)
426 goto ErrorFinish;
427 }
428 break;
429
c906108c
SS
430 case CB_SYS_stat :
431 {
432 char *path,*buf;
433 int buflen;
434 struct stat statbuf;
435 TADDR addr = sc->arg2;
436
437 errcode = get_path (cb, sc, sc->arg1, &path);
438 if (errcode != 0)
439 {
440 result = -1;
441 goto FinishSyscall;
442 }
443 result = (*cb->stat) (cb, path, &statbuf);
444 free (path);
445 if (result < 0)
446 goto ErrorFinish;
447 buflen = cb_host_to_target_stat (cb, NULL, NULL);
448 buf = xmalloc (buflen);
449 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
450 {
451 /* The translation failed. This is due to an internal
452 host program error, not the target's fault. */
453 free (buf);
454 errcode = ENOSYS;
455 result = -1;
456 goto FinishSyscall;
457 }
458 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
459 {
460 free (buf);
461 errcode = EINVAL;
462 result = -1;
463 goto FinishSyscall;
464 }
465 free (buf);
466 }
467 break;
468
469 case CB_SYS_fstat :
470 {
471 char *buf;
472 int buflen;
473 struct stat statbuf;
474 TADDR addr = sc->arg2;
475
476 result = (*cb->fstat) (cb, sc->arg1, &statbuf);
477 if (result < 0)
478 goto ErrorFinish;
479 buflen = cb_host_to_target_stat (cb, NULL, NULL);
480 buf = xmalloc (buflen);
481 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
482 {
483 /* The translation failed. This is due to an internal
484 host program error, not the target's fault. */
485 free (buf);
486 errcode = ENOSYS;
487 result = -1;
488 goto FinishSyscall;
489 }
490 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
491 {
492 free (buf);
493 errcode = EINVAL;
494 result = -1;
495 goto FinishSyscall;
496 }
497 free (buf);
498 }
499 break;
500
0d3cd463
HPN
501 case CB_SYS_lstat :
502 {
503 char *path, *buf;
504 int buflen;
505 struct stat statbuf;
506 TADDR addr = sc->arg2;
507
508 errcode = get_path (cb, sc, sc->arg1, &path);
509 if (errcode != 0)
510 {
511 result = -1;
512 goto FinishSyscall;
513 }
514 result = (*cb->lstat) (cb, path, &statbuf);
515 free (path);
516 if (result < 0)
517 goto ErrorFinish;
518
519 buflen = cb_host_to_target_stat (cb, NULL, NULL);
520 buf = xmalloc (buflen);
521 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
522 {
523 /* The translation failed. This is due to an internal
524 host program error, not the target's fault.
525 Unfortunately, it's hard to test this case, so there's no
526 test-case for this execution path. */
527 free (buf);
528 errcode = ENOSYS;
529 result = -1;
530 goto FinishSyscall;
531 }
532
533 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
534 {
535 free (buf);
536 errcode = EINVAL;
537 result = -1;
538 goto FinishSyscall;
539 }
540
541 free (buf);
542 }
543 break;
544
c906108c
SS
545 case CB_SYS_time :
546 {
547 /* FIXME: May wish to change CB_SYS_time to something else.
548 We might also want gettimeofday or times, but if system calls
549 can be built on others, we can keep the number we have to support
550 here down. */
551 time_t t = (*cb->time) (cb, (time_t *) 0);
552 result = t;
553 /* It is up to target code to process the argument to time(). */
554 }
555 break;
556
557 case CB_SYS_chdir :
558 case CB_SYS_chmod :
559 case CB_SYS_utime :
560 /* fall through for now */
561
562 default :
563 result = -1;
564 errcode = ENOSYS;
565 break;
566 }
567
568 FinishSyscall:
569 sc->result = result;
570 if (errcode == 0)
571 sc->errcode = 0;
572 else
573 sc->errcode = cb_host_to_target_errno (cb, errcode);
574 return CB_RC_OK;
575
576 ErrorFinish:
577 sc->result = result;
578 sc->errcode = (*cb->get_errno) (cb);
579 return CB_RC_OK;
580}