1 /* Remote target system call support.
2    Copyright 1997, 1998, 2002, 2004 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 "cconfig.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 "gdb/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
get_string(cb,sc,buf,buflen,addr)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
get_path(cb,sc,addr,bufp)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
cb_syscall(cb,sc)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 }
483