OSDN Git Service

* security.cc (get_file_attribute): Don't set errno.
[pf3gnuchains/pf3gnuchains3x.git] / sim / common / syscall.c
1 /* Remote target system call support.
2    Copyright 1997, 1998 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, need to consider target word size.  */
68 #define TWORD 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   TWORD result = 0, errcode = 0;
133
134   if (sc->magic != CB_SYSCALL_MAGIC)
135     abort ();
136
137   switch (cb_target_to_host_syscall (cb, sc->func))
138     {
139 #if 0 /* FIXME: wip */
140     case CB_SYS_argvlen :
141       {
142         /* Compute how much space is required to store the argv,envp
143            strings so that the program can allocate the space and then
144            call SYS_argv to fetch the values.  */
145         int addr_size = cb->addr_size;
146         int argc,envc,arglen,envlen;
147         const char **argv = cb->init_argv;
148         const char **envp = cb->init_envp;
149
150         argc = arglen = 0;
151         if (argv)
152           {
153             for ( ; argv[argc]; ++argc)
154               arglen += strlen (argv[argc]) + 1;
155           }
156         envc = envlen = 0;
157         if (envp)
158           {
159             for ( ; envp[envc]; ++envc)
160               envlen += strlen (envp[envc]) + 1;
161           }
162         result = arglen + envlen;
163         break;
164       }
165
166     case CB_SYS_argv :
167       {
168         /* Pointer to target's buffer.  */
169         TADDR tbuf = sc->arg1;
170         /* Buffer size.  */
171         int bufsize = sc->arg2;
172         /* Q is the target address of where all the strings go.  */
173         TADDR q;
174         int word_size = cb->word_size;
175         int i,argc,envc,len;
176         const char **argv = cb->init_argv;
177         const char **envp = cb->init_envp;
178
179         argc = 0;
180         if (argv)
181           {
182             for ( ; argv[argc]; ++argc)
183               {
184                 int len = strlen (argv[argc]);
185                 int written = (*sc->write_mem) (cb, sc, tbuf, argv[argc], len + 1);
186                 if (written != len)
187                   {
188                     result = -1;
189                     errcode = EINVAL;
190                     goto FinishSyscall;
191                   }
192                 tbuf = len + 1;
193               }
194           }
195         if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
196           {
197             result = -1;
198             errcode = EINVAL;
199             goto FinishSyscall;
200           }
201         tbuf++;
202         envc = 0;
203         if (envp)
204           {
205             for ( ; envp[envc]; ++envc)
206               {
207                 int len = strlen (envp[envc]);
208                 int written = (*sc->write_mem) (cb, sc, tbuf, envp[envc], len + 1);
209                 if (written != len)
210                   {
211                     result = -1;
212                     errcode = EINVAL;
213                     goto FinishSyscall;
214                   }
215                 tbuf = len + 1;
216               }
217           }
218         if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
219           {
220             result = -1;
221             errcode = EINVAL;
222             goto FinishSyscall;
223           }
224         result = argc;
225         sc->result2 = envc;
226         break;
227       }
228 #endif /* wip */
229
230     case CB_SYS_exit :
231       /* Caller must catch and handle.  */
232       break;
233
234     case CB_SYS_open :
235       {
236         char *path;
237
238         errcode = get_path (cb, sc, sc->arg1, &path);
239         if (errcode != 0)
240           {
241             result = -1;
242             goto FinishSyscall;
243           }
244         result = (*cb->open) (cb, path, sc->arg2 /*, sc->arg3*/);
245         free (path);
246         if (result < 0)
247           goto ErrorFinish;
248       }
249       break;
250
251     case CB_SYS_close :
252       result = (*cb->close) (cb, sc->arg1);
253       if (result < 0)
254         goto ErrorFinish;
255       break;
256
257     case CB_SYS_read :
258       {
259         /* ??? Perfect handling of error conditions may require only one
260            call to cb->read.  One can't assume all the data is
261            contiguously stored in host memory so that would require
262            malloc'ing/free'ing the space.  Maybe later.  */
263         char buf[FILE_XFR_SIZE];
264         int fd = sc->arg1;
265         TADDR addr = sc->arg2;
266         size_t count = sc->arg3;
267         size_t bytes_read = 0;
268         int bytes_written;
269
270         while (count > 0)
271           {
272             if (fd == 0)
273               result = (int) (*cb->read_stdin) (cb, buf,
274                                                 (count < FILE_XFR_SIZE
275                                                  ? count : FILE_XFR_SIZE));
276             else
277               result = (int) (*cb->read) (cb, fd, buf,
278                                           (count < FILE_XFR_SIZE
279                                            ? count : FILE_XFR_SIZE));
280             if (result == -1)
281               goto ErrorFinish;
282             if (result == 0)    /* EOF */
283               break;
284             bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result);
285             if (bytes_written != result)
286               {
287                 result = -1;
288                 errcode = EINVAL;
289                 goto FinishSyscall;
290               }
291             bytes_read += result;
292             count -= result;
293             addr += result;
294             /* If this is a short read, don't go back for more */
295             if (result != FILE_XFR_SIZE)
296               break;
297           }
298         result = bytes_read;
299       }
300       break;
301
302     case CB_SYS_write :
303       {
304         /* ??? Perfect handling of error conditions may require only one
305            call to cb->write.  One can't assume all the data is
306            contiguously stored in host memory so that would require
307            malloc'ing/free'ing the space.  Maybe later.  */
308         char buf[FILE_XFR_SIZE];
309         int fd = sc->arg1;
310         TADDR addr = sc->arg2;
311         size_t count = sc->arg3;
312         int bytes_read;
313         size_t bytes_written = 0;
314
315         while (count > 0)
316           {
317             int bytes_to_read = count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE;
318             bytes_read = (*sc->read_mem) (cb, sc, addr, buf, bytes_to_read);
319             if (bytes_read != bytes_to_read)
320               {
321                 result = -1;
322                 errcode = EINVAL;
323                 goto FinishSyscall;
324               }
325             if (fd == 1)
326               {
327                 result = (int) (*cb->write_stdout) (cb, buf, bytes_read);
328                 (*cb->flush_stdout) (cb);
329               }
330             else if (fd == 2)
331               {
332                 result = (int) (*cb->write_stderr) (cb, buf, bytes_read);
333                 (*cb->flush_stderr) (cb);
334               }
335             else
336               result = (int) (*cb->write) (cb, fd, buf, bytes_read);
337             if (result == -1)
338               goto ErrorFinish;
339             bytes_written += result;
340             count -= result;
341             addr += result;
342           }
343         result = bytes_written;
344       }
345       break;
346
347     case CB_SYS_lseek :
348       {
349         int fd = sc->arg1;
350         unsigned long offset = sc->arg2;
351         int whence = sc->arg3;
352
353         result = (*cb->lseek) (cb, fd, offset, whence);
354         if (result < 0)
355           goto ErrorFinish;
356       }
357       break;
358
359     case CB_SYS_unlink :
360       {
361         char *path;
362
363         errcode = get_path (cb, sc, sc->arg1, &path);
364         if (errcode != 0)
365           {
366             result = -1;
367             goto FinishSyscall;
368           }
369         result = (*cb->unlink) (cb, path);
370         free (path);
371         if (result < 0)
372           goto ErrorFinish;
373       }
374       break;
375
376     case CB_SYS_stat :
377       {
378         char *path,*buf;
379         int buflen;
380         struct stat statbuf;
381         TADDR addr = sc->arg2;
382
383         errcode = get_path (cb, sc, sc->arg1, &path);
384         if (errcode != 0)
385           {
386             result = -1;
387             goto FinishSyscall;
388           }
389         result = (*cb->stat) (cb, path, &statbuf);
390         free (path);
391         if (result < 0)
392           goto ErrorFinish;
393         buflen = cb_host_to_target_stat (cb, NULL, NULL);
394         buf = xmalloc (buflen);
395         if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
396           {
397             /* The translation failed.  This is due to an internal
398                host program error, not the target's fault.  */
399             free (buf);
400             errcode = ENOSYS;
401             result = -1;
402             goto FinishSyscall;
403           }
404         if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
405           {
406             free (buf);
407             errcode = EINVAL;
408             result = -1;
409             goto FinishSyscall;
410           }
411         free (buf);
412       }
413       break;
414
415     case CB_SYS_fstat :
416       {
417         char *buf;
418         int buflen;
419         struct stat statbuf;
420         TADDR addr = sc->arg2;
421
422         result = (*cb->fstat) (cb, sc->arg1, &statbuf);
423         if (result < 0)
424           goto ErrorFinish;
425         buflen = cb_host_to_target_stat (cb, NULL, NULL);
426         buf = xmalloc (buflen);
427         if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
428           {
429             /* The translation failed.  This is due to an internal
430                host program error, not the target's fault.  */
431             free (buf);
432             errcode = ENOSYS;
433             result = -1;
434             goto FinishSyscall;
435           }
436         if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
437           {
438             free (buf);
439             errcode = EINVAL;
440             result = -1;
441             goto FinishSyscall;
442           }
443         free (buf);
444       }
445       break;
446
447     case CB_SYS_time :
448       {
449         /* FIXME: May wish to change CB_SYS_time to something else.
450            We might also want gettimeofday or times, but if system calls
451            can be built on others, we can keep the number we have to support
452            here down.  */
453         time_t t = (*cb->time) (cb, (time_t *) 0);
454         result = t;
455         /* It is up to target code to process the argument to time().  */
456       }
457       break;
458
459     case CB_SYS_chdir :
460     case CB_SYS_chmod :
461     case CB_SYS_utime :
462       /* fall through for now */
463
464     default :
465       result = -1;
466       errcode = ENOSYS;
467       break;
468     }
469
470  FinishSyscall:
471   sc->result = result;
472   if (errcode == 0)
473     sc->errcode = 0;
474   else
475     sc->errcode = cb_host_to_target_errno (cb, errcode);
476   return CB_RC_OK;
477
478  ErrorFinish:
479   sc->result = result;
480   sc->errcode = (*cb->get_errno) (cb);
481   return CB_RC_OK;
482 }