* syscall.c (cb_syscall) <case CB_SYS_lstat>: New case.
[platform/upstream/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_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 }