]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/syscall.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.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 }