]> Git Repo - binutils.git/blob - sim/common/syscall.c
fcfb4176809a040edaec63d19d03da00bfe79c96
[binutils.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_truncate :
404       {
405         char *path;
406         long len = sc->arg2;
407
408         errcode = get_path (cb, sc, sc->arg1, &path);
409         if (errcode != 0)
410           {
411             result = -1;
412             errcode = EFAULT;
413             goto FinishSyscall;
414           }
415         result = (*cb->truncate) (cb, path, len);
416         free (path);
417         if (result < 0)
418           goto ErrorFinish;
419       }
420       break;
421
422     case CB_SYS_ftruncate :
423       {
424         int fd = sc->arg1;
425         long len = sc->arg2;
426
427         result = (*cb->ftruncate) (cb, fd, len);
428         if (result < 0)
429           goto ErrorFinish;
430       }
431       break;
432
433     case CB_SYS_rename :
434       {
435         char *path1, *path2;
436
437         errcode = get_path (cb, sc, sc->arg1, &path1);
438         if (errcode != 0)
439           {
440             result = -1;
441             errcode = EFAULT;
442             goto FinishSyscall;
443           }
444         errcode = get_path (cb, sc, sc->arg2, &path2);
445         if (errcode != 0)
446           {
447             result = -1;
448             errcode = EFAULT;
449             free (path1);
450             goto FinishSyscall;
451           }
452         result = (*cb->rename) (cb, path1, path2);
453         free (path1);
454         free (path2);
455         if (result < 0)
456           goto ErrorFinish;
457       }
458       break;
459
460     case CB_SYS_stat :
461       {
462         char *path,*buf;
463         int buflen;
464         struct stat statbuf;
465         TADDR addr = sc->arg2;
466
467         errcode = get_path (cb, sc, sc->arg1, &path);
468         if (errcode != 0)
469           {
470             result = -1;
471             goto FinishSyscall;
472           }
473         result = (*cb->stat) (cb, path, &statbuf);
474         free (path);
475         if (result < 0)
476           goto ErrorFinish;
477         buflen = cb_host_to_target_stat (cb, NULL, NULL);
478         buf = xmalloc (buflen);
479         if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
480           {
481             /* The translation failed.  This is due to an internal
482                host program error, not the target's fault.  */
483             free (buf);
484             errcode = ENOSYS;
485             result = -1;
486             goto FinishSyscall;
487           }
488         if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
489           {
490             free (buf);
491             errcode = EINVAL;
492             result = -1;
493             goto FinishSyscall;
494           }
495         free (buf);
496       }
497       break;
498
499     case CB_SYS_fstat :
500       {
501         char *buf;
502         int buflen;
503         struct stat statbuf;
504         TADDR addr = sc->arg2;
505
506         result = (*cb->fstat) (cb, sc->arg1, &statbuf);
507         if (result < 0)
508           goto ErrorFinish;
509         buflen = cb_host_to_target_stat (cb, NULL, NULL);
510         buf = xmalloc (buflen);
511         if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
512           {
513             /* The translation failed.  This is due to an internal
514                host program error, not the target's fault.  */
515             free (buf);
516             errcode = ENOSYS;
517             result = -1;
518             goto FinishSyscall;
519           }
520         if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
521           {
522             free (buf);
523             errcode = EINVAL;
524             result = -1;
525             goto FinishSyscall;
526           }
527         free (buf);
528       }
529       break;
530
531     case CB_SYS_lstat :
532       {
533         char *path, *buf;
534         int buflen;
535         struct stat statbuf;
536         TADDR addr = sc->arg2;
537
538         errcode = get_path (cb, sc, sc->arg1, &path);
539         if (errcode != 0)
540           {
541             result = -1;
542             goto FinishSyscall;
543           }
544         result = (*cb->lstat) (cb, path, &statbuf);
545         free (path);
546         if (result < 0)
547           goto ErrorFinish;
548
549         buflen = cb_host_to_target_stat (cb, NULL, NULL);
550         buf = xmalloc (buflen);
551         if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
552           {
553             /* The translation failed.  This is due to an internal
554                host program error, not the target's fault.
555                Unfortunately, it's hard to test this case, so there's no
556                test-case for this execution path.  */
557             free (buf);
558             errcode = ENOSYS;
559             result = -1;
560             goto FinishSyscall;
561           }
562
563         if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
564           {
565             free (buf);
566             errcode = EINVAL;
567             result = -1;
568             goto FinishSyscall;
569           }
570
571         free (buf);
572       }
573       break;
574
575     case CB_SYS_time :
576       {
577         /* FIXME: May wish to change CB_SYS_time to something else.
578            We might also want gettimeofday or times, but if system calls
579            can be built on others, we can keep the number we have to support
580            here down.  */
581         time_t t = (*cb->time) (cb, (time_t *) 0);
582         result = t;
583         /* It is up to target code to process the argument to time().  */
584       }
585       break;
586
587     case CB_SYS_chdir :
588     case CB_SYS_chmod :
589     case CB_SYS_utime :
590       /* fall through for now */
591
592     default :
593       result = -1;
594       errcode = ENOSYS;
595       break;
596     }
597
598  FinishSyscall:
599   sc->result = result;
600   if (errcode == 0)
601     sc->errcode = 0;
602   else
603     sc->errcode = cb_host_to_target_errno (cb, errcode);
604   return CB_RC_OK;
605
606  ErrorFinish:
607   sc->result = result;
608   sc->errcode = (*cb->get_errno) (cb);
609   return CB_RC_OK;
610 }
This page took 0.051156 seconds and 2 git commands to generate.