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