]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/syscall.c
sim: syscall: fix argvlen & argv implementation
[thirdparty/binutils-gdb.git] / sim / common / syscall.c
CommitLineData
c906108c 1/* Remote target system call support.
3666a048 2 Copyright 1997-2021 Free Software Foundation, Inc.
c906108c
SS
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
4744ac1b 9 the Free Software Foundation; either version 3 of the License, or
c906108c
SS
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
4744ac1b 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
19
20/* This interface isn't intended to be specific to any particular kind
21 of remote (hardware, simulator, whatever). As such, support for it
22 (e.g. sim/common/callback.c) should *not* live in the simulator source
23 tree, nor should it live in the gdb source tree. K&R C must be
24 supported. */
25
6df01ab8
MF
26/* This must come before any other includes. */
27#include "defs.h"
28
c906108c
SS
29#include "ansidecl.h"
30#include "libiberty.h"
c906108c 31#include <stdarg.h>
c906108c 32#include <stdio.h>
c906108c 33#include <stdlib.h>
027e2a04 34#include <string.h>
c906108c
SS
35#ifdef HAVE_UNISTD_H
36#include <unistd.h>
37#endif
38#include <errno.h>
39#include <fcntl.h>
40#include <time.h>
41#include <sys/types.h>
42#include <sys/stat.h>
df68e12b 43#include "sim/callback.h"
c906108c
SS
44
45#ifndef ENOSYS
46#define ENOSYS EINVAL
47#endif
48#ifndef ENAMETOOLONG
49#define ENAMETOOLONG EINVAL
50#endif
51
52/* Maximum length of a path name. */
53#ifndef MAX_PATH_LEN
54#define MAX_PATH_LEN 1024
55#endif
56
57/* When doing file read/writes, do this many bytes at a time. */
58#define FILE_XFR_SIZE 4096
59
60/* FIXME: for now, need to consider target word size. */
61#define TWORD long
62#define TADDR unsigned long
63
027e2a04
HPN
64/* Path to be prepended to syscalls with absolute paths, and to be
65 chdir:ed at startup, if not empty. */
66char *simulator_sysroot = "";
67
c906108c
SS
68/* Utility of cb_syscall to fetch a path name or other string from the target.
69 The result is 0 for success or a host errno value. */
70
71712327 71int
1a8a700e
MF
72cb_get_string (host_callback *cb, CB_SYSCALL *sc, char *buf, int buflen,
73 TADDR addr)
c906108c
SS
74{
75 char *p, *pend;
76
77 for (p = buf, pend = buf + buflen; p < pend; ++p, ++addr)
78 {
79 /* No, it isn't expected that this would cause one transaction with
80 the remote target for each byte. The target could send the
81 path name along with the syscall request, and cache the file
82 name somewhere (or otherwise tweak this as desired). */
83 unsigned int count = (*sc->read_mem) (cb, sc, addr, p, 1);
028f6515 84
c906108c
SS
85 if (count != 1)
86 return EINVAL;
87 if (*p == 0)
88 break;
89 }
90 if (p == pend)
91 return ENAMETOOLONG;
92 return 0;
93}
94
95/* Utility of cb_syscall to fetch a path name.
96 The buffer is malloc'd and the address is stored in BUFP.
027e2a04
HPN
97 The result is that of get_string, but prepended with
98 simulator_sysroot if the string starts with '/'.
c906108c
SS
99 If an error occurs, no buffer is left malloc'd. */
100
101static int
1a8a700e 102get_path (host_callback *cb, CB_SYSCALL *sc, TADDR addr, char **bufp)
c906108c
SS
103{
104 char *buf = xmalloc (MAX_PATH_LEN);
105 int result;
027e2a04 106 int sysroot_len = strlen (simulator_sysroot);
c906108c 107
71712327 108 result = cb_get_string (cb, sc, buf, MAX_PATH_LEN - sysroot_len, addr);
c906108c 109 if (result == 0)
027e2a04
HPN
110 {
111 /* Prepend absolute paths with simulator_sysroot. Relative paths
112 are supposed to be relative to a chdir within that path, but at
113 this point unknown where. */
114 if (simulator_sysroot[0] != '\0' && *buf == '/')
115 {
116 /* Considering expected rareness of syscalls with absolute
117 file paths (compared to relative file paths and insn
118 execution), it does not seem worthwhile to rearrange things
119 to get rid of the string moves here; we'd need at least an
120 extra call to check the initial '/' in the path. */
121 memmove (buf + sysroot_len, buf, sysroot_len);
122 memcpy (buf, simulator_sysroot, sysroot_len);
123 }
124
125 *bufp = buf;
126 }
c906108c
SS
127 else
128 free (buf);
129 return result;
130}
131
132/* Perform a system call on behalf of the target. */
133
134CB_RC
1a8a700e 135cb_syscall (host_callback *cb, CB_SYSCALL *sc)
c906108c
SS
136{
137 TWORD result = 0, errcode = 0;
138
139 if (sc->magic != CB_SYSCALL_MAGIC)
140 abort ();
141
142 switch (cb_target_to_host_syscall (cb, sc->func))
143 {
c906108c
SS
144 case CB_SYS_argvlen :
145 {
146 /* Compute how much space is required to store the argv,envp
147 strings so that the program can allocate the space and then
148 call SYS_argv to fetch the values. */
fab6939b
MF
149 int argc, envc, arglen, envlen;
150 char **argv = cb->argv;
151 char **envp = cb->envp;
c906108c
SS
152
153 argc = arglen = 0;
154 if (argv)
155 {
156 for ( ; argv[argc]; ++argc)
157 arglen += strlen (argv[argc]) + 1;
158 }
159 envc = envlen = 0;
160 if (envp)
161 {
162 for ( ; envp[envc]; ++envc)
163 envlen += strlen (envp[envc]) + 1;
164 }
fab6939b 165 result = arglen + 1 + envlen + 1;
c906108c
SS
166 break;
167 }
168
169 case CB_SYS_argv :
170 {
171 /* Pointer to target's buffer. */
172 TADDR tbuf = sc->arg1;
173 /* Buffer size. */
174 int bufsize = sc->arg2;
fab6939b 175 int written = 0;
c906108c
SS
176 /* Q is the target address of where all the strings go. */
177 TADDR q;
fab6939b
MF
178 int i, argc, envc, len, ret;
179 char **argv = cb->argv;
180 char **envp = cb->envp;
181
182 result = -1;
c906108c
SS
183
184 argc = 0;
185 if (argv)
186 {
187 for ( ; argv[argc]; ++argc)
188 {
fab6939b
MF
189 len = strlen (argv[argc]) + 1;
190 if (written + len > bufsize)
191 goto efault;
192
193 ret = (*sc->write_mem) (cb, sc, tbuf + written, argv[argc],
194 len);
195 if (ret != len)
196 goto einval;
197
198 written += ret;
c906108c
SS
199 }
200 }
fab6939b
MF
201 /* Double NUL bytes indicates end of strings. */
202 if (written >= bufsize)
203 goto efault;
204 if ((*sc->write_mem) (cb, sc, tbuf + written, "", 1) != 1)
205 goto einval;
206 ++written;
207
c906108c
SS
208 envc = 0;
209 if (envp)
210 {
211 for ( ; envp[envc]; ++envc)
212 {
fab6939b
MF
213 len = strlen (envp[envc]) + 1;
214 if (written + len > bufsize)
215 goto efault;
216
217 ret = (*sc->write_mem) (cb, sc, tbuf + written, envp[envc],
218 len);
219 if (ret != len)
220 goto einval;
221 written += ret;
c906108c
SS
222 }
223 }
fab6939b
MF
224 /* Double NUL bytes indicates end of strings. */
225 if (written >= bufsize)
226 goto efault;
227 if ((*sc->write_mem) (cb, sc, tbuf + written, "", 1) != 1)
228 goto einval;
229
c906108c
SS
230 result = argc;
231 sc->result2 = envc;
232 break;
fab6939b
MF
233
234 efault:
235 errcode = EFAULT;
236 goto FinishSyscall;
237
238 einval:
239 errcode = EINVAL;
240 goto FinishSyscall;
c906108c 241 }
c906108c
SS
242
243 case CB_SYS_exit :
7d5c6c43 244 /* Caller must catch and handle; see sim_syscall as an example. */
c906108c
SS
245 break;
246
247 case CB_SYS_open :
248 {
249 char *path;
250
251 errcode = get_path (cb, sc, sc->arg1, &path);
252 if (errcode != 0)
253 {
254 result = -1;
255 goto FinishSyscall;
256 }
257 result = (*cb->open) (cb, path, sc->arg2 /*, sc->arg3*/);
258 free (path);
259 if (result < 0)
260 goto ErrorFinish;
261 }
262 break;
263
264 case CB_SYS_close :
265 result = (*cb->close) (cb, sc->arg1);
266 if (result < 0)
267 goto ErrorFinish;
268 break;
269
270 case CB_SYS_read :
271 {
272 /* ??? Perfect handling of error conditions may require only one
273 call to cb->read. One can't assume all the data is
274 contiguously stored in host memory so that would require
275 malloc'ing/free'ing the space. Maybe later. */
276 char buf[FILE_XFR_SIZE];
277 int fd = sc->arg1;
278 TADDR addr = sc->arg2;
279 size_t count = sc->arg3;
280 size_t bytes_read = 0;
281 int bytes_written;
282
283 while (count > 0)
284 {
b981d709 285 if (cb_is_stdin (cb, fd))
c906108c
SS
286 result = (int) (*cb->read_stdin) (cb, buf,
287 (count < FILE_XFR_SIZE
288 ? count : FILE_XFR_SIZE));
289 else
290 result = (int) (*cb->read) (cb, fd, buf,
291 (count < FILE_XFR_SIZE
292 ? count : FILE_XFR_SIZE));
293 if (result == -1)
294 goto ErrorFinish;
295 if (result == 0) /* EOF */
296 break;
297 bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result);
298 if (bytes_written != result)
299 {
300 result = -1;
301 errcode = EINVAL;
302 goto FinishSyscall;
303 }
304 bytes_read += result;
305 count -= result;
306 addr += result;
307 /* If this is a short read, don't go back for more */
308 if (result != FILE_XFR_SIZE)
309 break;
310 }
311 result = bytes_read;
312 }
313 break;
314
315 case CB_SYS_write :
316 {
317 /* ??? Perfect handling of error conditions may require only one
318 call to cb->write. One can't assume all the data is
319 contiguously stored in host memory so that would require
320 malloc'ing/free'ing the space. Maybe later. */
321 char buf[FILE_XFR_SIZE];
322 int fd = sc->arg1;
323 TADDR addr = sc->arg2;
324 size_t count = sc->arg3;
325 int bytes_read;
326 size_t bytes_written = 0;
327
328 while (count > 0)
329 {
330 int bytes_to_read = count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE;
331 bytes_read = (*sc->read_mem) (cb, sc, addr, buf, bytes_to_read);
332 if (bytes_read != bytes_to_read)
333 {
334 result = -1;
335 errcode = EINVAL;
336 goto FinishSyscall;
337 }
34b47c38 338 if (cb_is_stdout (cb, fd))
c906108c
SS
339 {
340 result = (int) (*cb->write_stdout) (cb, buf, bytes_read);
341 (*cb->flush_stdout) (cb);
342 }
34b47c38 343 else if (cb_is_stderr (cb, fd))
c906108c
SS
344 {
345 result = (int) (*cb->write_stderr) (cb, buf, bytes_read);
346 (*cb->flush_stderr) (cb);
347 }
348 else
349 result = (int) (*cb->write) (cb, fd, buf, bytes_read);
350 if (result == -1)
351 goto ErrorFinish;
352 bytes_written += result;
353 count -= result;
354 addr += result;
355 }
356 result = bytes_written;
357 }
358 break;
359
360 case CB_SYS_lseek :
361 {
362 int fd = sc->arg1;
363 unsigned long offset = sc->arg2;
364 int whence = sc->arg3;
365
366 result = (*cb->lseek) (cb, fd, offset, whence);
367 if (result < 0)
368 goto ErrorFinish;
369 }
370 break;
371
372 case CB_SYS_unlink :
373 {
374 char *path;
375
376 errcode = get_path (cb, sc, sc->arg1, &path);
377 if (errcode != 0)
378 {
379 result = -1;
380 goto FinishSyscall;
381 }
382 result = (*cb->unlink) (cb, path);
383 free (path);
384 if (result < 0)
385 goto ErrorFinish;
386 }
387 break;
388
5d945fec
HPN
389 case CB_SYS_truncate :
390 {
391 char *path;
392 long len = sc->arg2;
393
394 errcode = get_path (cb, sc, sc->arg1, &path);
395 if (errcode != 0)
396 {
397 result = -1;
398 errcode = EFAULT;
399 goto FinishSyscall;
400 }
401 result = (*cb->truncate) (cb, path, len);
402 free (path);
403 if (result < 0)
404 goto ErrorFinish;
405 }
406 break;
407
408 case CB_SYS_ftruncate :
409 {
410 int fd = sc->arg1;
411 long len = sc->arg2;
412
413 result = (*cb->ftruncate) (cb, fd, len);
414 if (result < 0)
415 goto ErrorFinish;
416 }
417 break;
418
82571856
HPN
419 case CB_SYS_rename :
420 {
421 char *path1, *path2;
422
423 errcode = get_path (cb, sc, sc->arg1, &path1);
424 if (errcode != 0)
425 {
426 result = -1;
427 errcode = EFAULT;
428 goto FinishSyscall;
429 }
430 errcode = get_path (cb, sc, sc->arg2, &path2);
431 if (errcode != 0)
432 {
433 result = -1;
434 errcode = EFAULT;
435 free (path1);
436 goto FinishSyscall;
437 }
438 result = (*cb->rename) (cb, path1, path2);
439 free (path1);
440 free (path2);
441 if (result < 0)
442 goto ErrorFinish;
443 }
444 break;
445
c906108c
SS
446 case CB_SYS_stat :
447 {
448 char *path,*buf;
449 int buflen;
450 struct stat statbuf;
451 TADDR addr = sc->arg2;
452
453 errcode = get_path (cb, sc, sc->arg1, &path);
454 if (errcode != 0)
455 {
456 result = -1;
457 goto FinishSyscall;
458 }
2d7bb758 459 result = (*cb->to_stat) (cb, path, &statbuf);
c906108c
SS
460 free (path);
461 if (result < 0)
462 goto ErrorFinish;
463 buflen = cb_host_to_target_stat (cb, NULL, NULL);
464 buf = xmalloc (buflen);
465 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
466 {
467 /* The translation failed. This is due to an internal
468 host program error, not the target's fault. */
469 free (buf);
470 errcode = ENOSYS;
471 result = -1;
472 goto FinishSyscall;
473 }
474 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
475 {
476 free (buf);
477 errcode = EINVAL;
478 result = -1;
479 goto FinishSyscall;
480 }
481 free (buf);
482 }
483 break;
484
485 case CB_SYS_fstat :
486 {
487 char *buf;
488 int buflen;
489 struct stat statbuf;
490 TADDR addr = sc->arg2;
491
2d7bb758 492 result = (*cb->to_fstat) (cb, sc->arg1, &statbuf);
c906108c
SS
493 if (result < 0)
494 goto ErrorFinish;
495 buflen = cb_host_to_target_stat (cb, NULL, NULL);
496 buf = xmalloc (buflen);
497 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
498 {
499 /* The translation failed. This is due to an internal
500 host program error, not the target's fault. */
501 free (buf);
502 errcode = ENOSYS;
503 result = -1;
504 goto FinishSyscall;
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 free (buf);
514 }
515 break;
516
0d3cd463
HPN
517 case CB_SYS_lstat :
518 {
519 char *path, *buf;
520 int buflen;
521 struct stat statbuf;
522 TADDR addr = sc->arg2;
523
524 errcode = get_path (cb, sc, sc->arg1, &path);
525 if (errcode != 0)
526 {
527 result = -1;
528 goto FinishSyscall;
529 }
2d7bb758 530 result = (*cb->to_lstat) (cb, path, &statbuf);
0d3cd463
HPN
531 free (path);
532 if (result < 0)
533 goto ErrorFinish;
534
535 buflen = cb_host_to_target_stat (cb, NULL, NULL);
536 buf = xmalloc (buflen);
537 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
538 {
539 /* The translation failed. This is due to an internal
540 host program error, not the target's fault.
541 Unfortunately, it's hard to test this case, so there's no
542 test-case for this execution path. */
543 free (buf);
544 errcode = ENOSYS;
545 result = -1;
546 goto FinishSyscall;
547 }
548
549 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
550 {
551 free (buf);
552 errcode = EINVAL;
553 result = -1;
554 goto FinishSyscall;
555 }
556
557 free (buf);
558 }
559 break;
560
97f669ed
HPN
561 case CB_SYS_pipe :
562 {
563 int p[2];
564 char *target_p = xcalloc (1, cb->target_sizeof_int * 2);
565
566 result = (*cb->pipe) (cb, p);
567 if (result != 0)
568 goto ErrorFinish;
569
570 cb_store_target_endian (cb, target_p, cb->target_sizeof_int, p[0]);
571 cb_store_target_endian (cb, target_p + cb->target_sizeof_int,
572 cb->target_sizeof_int, p[1]);
573 if ((*sc->write_mem) (cb, sc, sc->arg1, target_p,
574 cb->target_sizeof_int * 2)
575 != cb->target_sizeof_int * 2)
576 {
577 /* Close the pipe fd:s. */
578 (*cb->close) (cb, p[0]);
579 (*cb->close) (cb, p[1]);
580 errcode = EFAULT;
581 result = -1;
582 }
583
584 free (target_p);
585 }
586 break;
587
7da5cf78 588 case CB_SYS_getpid:
c45cffdb
MF
589 /* POSIX says getpid always succeeds. */
590 result = (*cb->getpid) (cb);
7da5cf78
MF
591 break;
592
d394a6ef
MF
593 case CB_SYS_kill:
594 /* If killing self, leave it to the caller to process so it can send the
595 signal to the engine. */
596 if (sc->arg1 == (*cb->getpid) (cb))
597 {
598 result = -1;
599 errcode = ENOSYS;
600 }
601 else
602 {
603 int signum = cb_target_to_host_signal (cb, sc->arg2);
604
605 result = (*cb->kill) (cb, sc->arg1, signum);
606 cb->last_errno = errno;
607 goto ErrorFinish;
608 }
609 break;
610
c906108c
SS
611 case CB_SYS_time :
612 {
613 /* FIXME: May wish to change CB_SYS_time to something else.
614 We might also want gettimeofday or times, but if system calls
615 can be built on others, we can keep the number we have to support
616 here down. */
00330cd1 617 time_t t = (*cb->time) (cb);
c906108c
SS
618 result = t;
619 /* It is up to target code to process the argument to time(). */
620 }
621 break;
622
623 case CB_SYS_chdir :
624 case CB_SYS_chmod :
625 case CB_SYS_utime :
626 /* fall through for now */
627
628 default :
629 result = -1;
630 errcode = ENOSYS;
631 break;
632 }
633
634 FinishSyscall:
635 sc->result = result;
636 if (errcode == 0)
637 sc->errcode = 0;
638 else
639 sc->errcode = cb_host_to_target_errno (cb, errcode);
640 return CB_RC_OK;
641
642 ErrorFinish:
643 sc->result = result;
644 sc->errcode = (*cb->get_errno) (cb);
645 return CB_RC_OK;
646}