xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/syscall.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
1 /* Remote target system call support.
2    Copyright 1997-2024 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 3 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
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 
26 /* This must come before any other includes.  */
27 #include "defs.h"
28 
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 
40 #include "ansidecl.h"
41 #include "libiberty.h"
42 
43 #include "sim/callback.h"
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 
64 /* Path to be prepended to syscalls with absolute paths, and to be
65    chdir:ed at startup, if not empty.  */
66 char *simulator_sysroot = "";
67 
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 
71 int
72 cb_get_string (host_callback *cb, CB_SYSCALL *sc, char *buf, int buflen,
73 	       TADDR addr)
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);
84 
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.
97    The result is that of get_string, but prepended with
98    simulator_sysroot if the string starts with '/'.
99    If an error occurs, no buffer is left malloc'd.  */
100 
101 static int
102 get_path (host_callback *cb, CB_SYSCALL *sc, TADDR addr, char **bufp)
103 {
104   char *buf = xmalloc (MAX_PATH_LEN);
105   int result;
106   int sysroot_len = strlen (simulator_sysroot);
107 
108   result = cb_get_string (cb, sc, buf, MAX_PATH_LEN - sysroot_len, addr);
109   if (result == 0)
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     }
127   else
128     free (buf);
129   return result;
130 }
131 
132 /* Perform a system call on behalf of the target.  */
133 
134 CB_RC
135 cb_syscall (host_callback *cb, CB_SYSCALL *sc)
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     {
144     case CB_SYS_argc:
145       result = countargv (cb->argv);
146       break;
147 
148     case CB_SYS_argnlen:
149       {
150 	if (sc->arg1 >= 0 && sc->arg1 < countargv (cb->argv))
151 	  result = strlen (cb->argv[sc->arg1]);
152 	else
153 	  {
154 	    result = -1;
155 	    errcode = EINVAL;
156 	  }
157       }
158       break;
159 
160     case CB_SYS_argn:
161       {
162 	if (sc->arg1 >= 0 && sc->arg1 < countargv (cb->argv))
163 	  {
164 	    const char *argn = cb->argv[sc->arg1];
165 	    int len = strlen (argn);
166 	    int written = sc->write_mem (cb, sc, sc->arg2, argn, len + 1);
167 
168 	    if (written == len + 1)
169 	      result = sc->arg2;
170 	    else
171 	      {
172 		result = -1;
173 		errcode = EINVAL;
174 	      }
175 	  }
176 	else
177 	  {
178 	    result = -1;
179 	    errcode = EINVAL;
180 	  }
181       }
182       break;
183 
184     case CB_SYS_argvlen :
185       {
186 	/* Compute how much space is required to store the argv,envp
187 	   strings so that the program can allocate the space and then
188 	   call SYS_argv to fetch the values.  */
189 	int argc, envc, arglen, envlen;
190 	char **argv = cb->argv;
191 	char **envp = cb->envp;
192 
193 	argc = arglen = 0;
194 	if (argv)
195 	  {
196 	    for ( ; argv[argc]; ++argc)
197 	      arglen += strlen (argv[argc]) + 1;
198 	  }
199 	envc = envlen = 0;
200 	if (envp)
201 	  {
202 	    for ( ; envp[envc]; ++envc)
203 	      envlen += strlen (envp[envc]) + 1;
204 	  }
205 	result = arglen + 1 + envlen + 1;
206 	break;
207       }
208 
209     case CB_SYS_argv :
210       {
211 	/* Pointer to target's buffer.  */
212 	TADDR tbuf = sc->arg1;
213 	/* Buffer size.  */
214 	int bufsize = sc->arg2;
215 	int written = 0;
216 	int argc, envc, len, ret;
217 	char **argv = cb->argv;
218 	char **envp = cb->envp;
219 
220 	result = -1;
221 
222 	argc = 0;
223 	if (argv)
224 	  {
225 	    for ( ; argv[argc]; ++argc)
226 	      {
227 		len = strlen (argv[argc]) + 1;
228 		if (written + len > bufsize)
229 		  goto efault;
230 
231 		ret = (*sc->write_mem) (cb, sc, tbuf + written, argv[argc],
232 					len);
233 		if (ret != len)
234 		  goto einval;
235 
236 		written += ret;
237 	      }
238 	  }
239 	/* Double NUL bytes indicates end of strings.  */
240 	if (written >= bufsize)
241 	  goto efault;
242 	if ((*sc->write_mem) (cb, sc, tbuf + written, "", 1) != 1)
243 	  goto einval;
244 	++written;
245 
246 	envc = 0;
247 	if (envp)
248 	  {
249 	    for ( ; envp[envc]; ++envc)
250 	      {
251 		len = strlen (envp[envc]) + 1;
252 		if (written + len > bufsize)
253 		  goto efault;
254 
255 		ret = (*sc->write_mem) (cb, sc, tbuf + written, envp[envc],
256 					len);
257 		if (ret != len)
258 		  goto einval;
259 		written += ret;
260 	      }
261 	  }
262 	/* Double NUL bytes indicates end of strings.  */
263 	if (written >= bufsize)
264 	  goto efault;
265 	if ((*sc->write_mem) (cb, sc, tbuf + written, "", 1) != 1)
266 	  goto einval;
267 
268 	result = argc;
269 	sc->result2 = envc;
270 	break;
271 
272  efault:
273 	errcode = EFAULT;
274 	goto FinishSyscall;
275 
276  einval:
277 	errcode = EINVAL;
278 	goto FinishSyscall;
279       }
280 
281     case CB_SYS_exit :
282       /* Caller must catch and handle; see sim_syscall as an example.  */
283       break;
284 
285     case CB_SYS_open :
286       {
287 	char *path;
288 
289 	errcode = get_path (cb, sc, sc->arg1, &path);
290 	if (errcode != 0)
291 	  {
292 	    result = -1;
293 	    goto FinishSyscall;
294 	  }
295 	result = (*cb->open) (cb, path, sc->arg2 /*, sc->arg3*/);
296 	free (path);
297 	if (result < 0)
298 	  goto ErrorFinish;
299       }
300       break;
301 
302     case CB_SYS_close :
303       result = (*cb->close) (cb, sc->arg1);
304       if (result < 0)
305 	goto ErrorFinish;
306       break;
307 
308     case CB_SYS_read :
309       {
310 	/* ??? Perfect handling of error conditions may require only one
311 	   call to cb->read.  One can't assume all the data is
312 	   contiguously stored in host memory so that would require
313 	   malloc'ing/free'ing the space.  Maybe later.  */
314 	char buf[FILE_XFR_SIZE];
315 	int fd = sc->arg1;
316 	TADDR addr = sc->arg2;
317 	size_t count = sc->arg3;
318 	size_t bytes_read = 0;
319 	int bytes_written;
320 
321 	while (count > 0)
322 	  {
323 	    if (cb_is_stdin (cb, fd))
324 	      result = (int) (*cb->read_stdin) (cb, buf,
325 						(count < FILE_XFR_SIZE
326 						 ? count : FILE_XFR_SIZE));
327 	    else
328 	      result = (int) (*cb->read) (cb, fd, buf,
329 					  (count < FILE_XFR_SIZE
330 					   ? count : FILE_XFR_SIZE));
331 	    if (result == -1)
332 	      goto ErrorFinish;
333 	    if (result == 0)	/* EOF */
334 	      break;
335 	    bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result);
336 	    if (bytes_written != result)
337 	      {
338 		result = -1;
339 		errcode = EINVAL;
340 		goto FinishSyscall;
341 	      }
342 	    bytes_read += result;
343 	    count -= result;
344 	    addr += result;
345 	    /* If this is a short read, don't go back for more */
346 	    if (result != FILE_XFR_SIZE)
347 	      break;
348 	  }
349 	result = bytes_read;
350       }
351       break;
352 
353     case CB_SYS_write :
354       {
355 	/* ??? Perfect handling of error conditions may require only one
356 	   call to cb->write.  One can't assume all the data is
357 	   contiguously stored in host memory so that would require
358 	   malloc'ing/free'ing the space.  Maybe later.  */
359 	char buf[FILE_XFR_SIZE];
360 	int fd = sc->arg1;
361 	TADDR addr = sc->arg2;
362 	size_t count = sc->arg3;
363 	int bytes_read;
364 	size_t bytes_written = 0;
365 
366 	while (count > 0)
367 	  {
368 	    int bytes_to_read = count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE;
369 	    bytes_read = (*sc->read_mem) (cb, sc, addr, buf, bytes_to_read);
370 	    if (bytes_read != bytes_to_read)
371 	      {
372 		result = -1;
373 		errcode = EINVAL;
374 		goto FinishSyscall;
375 	      }
376 	    if (cb_is_stdout (cb, fd))
377 	      {
378 		result = (int) (*cb->write_stdout) (cb, buf, bytes_read);
379 		(*cb->flush_stdout) (cb);
380 	      }
381 	    else if (cb_is_stderr (cb, fd))
382 	      {
383 		result = (int) (*cb->write_stderr) (cb, buf, bytes_read);
384 		(*cb->flush_stderr) (cb);
385 	      }
386 	    else
387 	      result = (int) (*cb->write) (cb, fd, buf, bytes_read);
388 	    if (result == -1)
389 	      goto ErrorFinish;
390 	    bytes_written += result;
391 	    count -= result;
392 	    addr += result;
393 	  }
394 	result = bytes_written;
395       }
396       break;
397 
398     case CB_SYS_lseek :
399       {
400 	int fd = sc->arg1;
401 	unsigned long offset = sc->arg2;
402 	int whence = sc->arg3;
403 
404 	result = (*cb->lseek) (cb, fd, offset, whence);
405 	if (result < 0)
406 	  goto ErrorFinish;
407       }
408       break;
409 
410     case CB_SYS_unlink :
411       {
412 	char *path;
413 
414 	errcode = get_path (cb, sc, sc->arg1, &path);
415 	if (errcode != 0)
416 	  {
417 	    result = -1;
418 	    goto FinishSyscall;
419 	  }
420 	result = (*cb->unlink) (cb, path);
421 	free (path);
422 	if (result < 0)
423 	  goto ErrorFinish;
424       }
425       break;
426 
427     case CB_SYS_truncate :
428       {
429 	char *path;
430 	long len = sc->arg2;
431 
432 	errcode = get_path (cb, sc, sc->arg1, &path);
433 	if (errcode != 0)
434 	  {
435 	    result = -1;
436 	    errcode = EFAULT;
437 	    goto FinishSyscall;
438 	  }
439 	result = (*cb->truncate) (cb, path, len);
440 	free (path);
441 	if (result < 0)
442 	  goto ErrorFinish;
443       }
444       break;
445 
446     case CB_SYS_ftruncate :
447       {
448 	int fd = sc->arg1;
449 	long len = sc->arg2;
450 
451 	result = (*cb->ftruncate) (cb, fd, len);
452 	if (result < 0)
453 	  goto ErrorFinish;
454       }
455       break;
456 
457     case CB_SYS_rename :
458       {
459 	char *path1, *path2;
460 
461 	errcode = get_path (cb, sc, sc->arg1, &path1);
462 	if (errcode != 0)
463 	  {
464 	    result = -1;
465 	    errcode = EFAULT;
466 	    goto FinishSyscall;
467 	  }
468 	errcode = get_path (cb, sc, sc->arg2, &path2);
469 	if (errcode != 0)
470 	  {
471 	    result = -1;
472 	    errcode = EFAULT;
473 	    free (path1);
474 	    goto FinishSyscall;
475 	  }
476 	result = (*cb->rename) (cb, path1, path2);
477 	free (path1);
478 	free (path2);
479 	if (result < 0)
480 	  goto ErrorFinish;
481       }
482       break;
483 
484     case CB_SYS_stat :
485       {
486 	char *path,*buf;
487 	int buflen;
488 	struct stat statbuf;
489 	TADDR addr = sc->arg2;
490 
491 	errcode = get_path (cb, sc, sc->arg1, &path);
492 	if (errcode != 0)
493 	  {
494 	    result = -1;
495 	    goto FinishSyscall;
496 	  }
497 	result = (*cb->to_stat) (cb, path, &statbuf);
498 	free (path);
499 	if (result < 0)
500 	  goto ErrorFinish;
501 	buflen = cb_host_to_target_stat (cb, NULL, NULL);
502 	buf = xmalloc (buflen);
503 	if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
504 	  {
505 	    /* The translation failed.  This is due to an internal
506 	       host program error, not the target's fault.  */
507 	    free (buf);
508 	    errcode = ENOSYS;
509 	    result = -1;
510 	    goto FinishSyscall;
511 	  }
512 	if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
513 	  {
514 	    free (buf);
515 	    errcode = EINVAL;
516 	    result = -1;
517 	    goto FinishSyscall;
518 	  }
519 	free (buf);
520       }
521       break;
522 
523     case CB_SYS_fstat :
524       {
525 	char *buf;
526 	int buflen;
527 	struct stat statbuf;
528 	TADDR addr = sc->arg2;
529 
530 	result = (*cb->to_fstat) (cb, sc->arg1, &statbuf);
531 	if (result < 0)
532 	  goto ErrorFinish;
533 	buflen = cb_host_to_target_stat (cb, NULL, NULL);
534 	buf = xmalloc (buflen);
535 	if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
536 	  {
537 	    /* The translation failed.  This is due to an internal
538 	       host program error, not the target's fault.  */
539 	    free (buf);
540 	    errcode = ENOSYS;
541 	    result = -1;
542 	    goto FinishSyscall;
543 	  }
544 	if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
545 	  {
546 	    free (buf);
547 	    errcode = EINVAL;
548 	    result = -1;
549 	    goto FinishSyscall;
550 	  }
551 	free (buf);
552       }
553       break;
554 
555     case CB_SYS_lstat :
556       {
557 	char *path, *buf;
558 	int buflen;
559 	struct stat statbuf;
560 	TADDR addr = sc->arg2;
561 
562 	errcode = get_path (cb, sc, sc->arg1, &path);
563 	if (errcode != 0)
564 	  {
565 	    result = -1;
566 	    goto FinishSyscall;
567 	  }
568 	result = (*cb->to_lstat) (cb, path, &statbuf);
569 	free (path);
570 	if (result < 0)
571 	  goto ErrorFinish;
572 
573 	buflen = cb_host_to_target_stat (cb, NULL, NULL);
574 	buf = xmalloc (buflen);
575 	if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
576 	  {
577 	    /* The translation failed.  This is due to an internal
578 	       host program error, not the target's fault.
579 	       Unfortunately, it's hard to test this case, so there's no
580 	       test-case for this execution path.  */
581 	    free (buf);
582 	    errcode = ENOSYS;
583 	    result = -1;
584 	    goto FinishSyscall;
585 	  }
586 
587 	if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
588 	  {
589 	    free (buf);
590 	    errcode = EINVAL;
591 	    result = -1;
592 	    goto FinishSyscall;
593 	  }
594 
595 	free (buf);
596       }
597       break;
598 
599     case CB_SYS_pipe :
600       {
601 	int p[2];
602 	char *target_p = xcalloc (1, cb->target_sizeof_int * 2);
603 
604 	result = (*cb->pipe) (cb, p);
605 	if (result != 0)
606 	  goto ErrorFinish;
607 
608 	cb_store_target_endian (cb, target_p, cb->target_sizeof_int, p[0]);
609 	cb_store_target_endian (cb, target_p + cb->target_sizeof_int,
610 				cb->target_sizeof_int, p[1]);
611 	if ((*sc->write_mem) (cb, sc, sc->arg1, target_p,
612 			      cb->target_sizeof_int * 2)
613 	    != cb->target_sizeof_int * 2)
614 	  {
615 	    /* Close the pipe fd:s.  */
616 	    (*cb->close) (cb, p[0]);
617 	    (*cb->close) (cb, p[1]);
618 	    errcode = EFAULT;
619 	    result = -1;
620 	  }
621 
622 	free (target_p);
623       }
624       break;
625 
626     case CB_SYS_getpid:
627       /* POSIX says getpid always succeeds.  */
628       result = (*cb->getpid) (cb);
629       break;
630 
631     case CB_SYS_kill:
632       /* If killing self, leave it to the caller to process so it can send the
633 	 signal to the engine.  */
634       if (sc->arg1 == (*cb->getpid) (cb))
635 	{
636 	  result = -1;
637 	  errcode = ENOSYS;
638 	}
639       else
640 	{
641 	  int signum = cb_target_to_host_signal (cb, sc->arg2);
642 
643 	  result = (*cb->kill) (cb, sc->arg1, signum);
644 	  cb->last_errno = errno;
645 	  goto ErrorFinish;
646 	}
647       break;
648 
649     case CB_SYS_time :
650       {
651 	/* FIXME: May wish to change CB_SYS_time to something else.
652 	   We might also want gettimeofday or times, but if system calls
653 	   can be built on others, we can keep the number we have to support
654 	   here down.  */
655 	time_t t = (*cb->time) (cb);
656 	result = t;
657 	/* It is up to target code to process the argument to time().  */
658       }
659       break;
660 
661     case CB_SYS_chdir :
662     case CB_SYS_chmod :
663     case CB_SYS_utime :
664       /* fall through for now */
665 
666     default :
667       result = -1;
668       errcode = ENOSYS;
669       break;
670     }
671 
672  FinishSyscall:
673   sc->result = result;
674   if (errcode == 0)
675     sc->errcode = 0;
676   else
677     sc->errcode = cb_host_to_target_errno (cb, errcode);
678   return CB_RC_OK;
679 
680  ErrorFinish:
681   sc->result = result;
682   sc->errcode = (*cb->get_errno) (cb);
683   return CB_RC_OK;
684 }
685