xref: /netbsd-src/external/gpl3/gdb/dist/sim/rx/syscalls.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /* syscalls.c --- implement system calls for the RX simulator.
2 
3 Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
4 Free Software Foundation, Inc.
5 Contributed by Red Hat, Inc.
6 
7 This file is part of the GNU simulators.
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 
23 #include "config.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <sys/time.h>
29 
30 #include "gdb/callback.h"
31 
32 #include "cpu.h"
33 #include "mem.h"
34 #include "syscalls.h"
35 
36 #include "syscall.h"
37 
38 /* The current syscall callbacks we're using.  */
39 static struct host_callback_struct *callbacks;
40 
41 void
42 set_callbacks (struct host_callback_struct *cb)
43 {
44   callbacks = cb;
45 }
46 
47 
48 /* Arguments 1..4 are in R1..R4, remainder on stack.
49 
50    Return value in R1..R4 as needed.
51      structs bigger than 16 bytes: pointer pushed on stack last
52 
53    We only support arguments that fit in general registers.
54 
55    The system call number is in R5.  We expect ssycalls to look like
56    this in libgloss:
57 
58    _exit:
59    	mov	#SYS_exit, r5
60 	int	#255
61 	rts
62 */
63 
64 int argp, stackp;
65 
66 static int
67 arg ()
68 {
69   int rv = 0;
70   argp++;
71 
72   if (argp < 4)
73     return get_reg (argp);
74 
75   rv = mem_get_si (get_reg (sp) + stackp);
76   stackp += 4;
77   return rv;
78 }
79 
80 static void
81 read_target (char *buffer, int address, int count, int asciiz)
82 {
83   char byte;
84   while (count > 0)
85     {
86       byte = mem_get_qi (address++);
87       *buffer++ = byte;
88       if (asciiz && (byte == 0))
89 	return;
90       count--;
91     }
92 }
93 
94 static void
95 write_target (char *buffer, int address, int count, int asciiz)
96 {
97   char byte;
98   while (count > 0)
99     {
100       byte = *buffer++;
101       mem_put_qi (address++, byte);
102       if (asciiz && (byte == 0))
103 	return;
104       count--;
105     }
106 }
107 
108 #define PTRSZ (A16 ? 2 : 3)
109 
110 static char *callnames[] = {
111   "SYS_zero",
112   "SYS_exit",
113   "SYS_open",
114   "SYS_close",
115   "SYS_read",
116   "SYS_write",
117   "SYS_lseek",
118   "SYS_unlink",
119   "SYS_getpid",
120   "SYS_kill",
121   "SYS_fstat",
122   "SYS_sbrk",
123   "SYS_argvlen",
124   "SYS_argv",
125   "SYS_chdir",
126   "SYS_stat",
127   "SYS_chmod",
128   "SYS_utime",
129   "SYS_time",
130   "SYS_gettimeofday",
131   "SYS_times",
132   "SYS_link"
133 };
134 
135 int
136 rx_syscall (int id)
137 {
138   static char buf[256];
139   int rv;
140 
141   argp = 0;
142   stackp = 4;
143   if (trace)
144     printf ("\033[31m/* SYSCALL(%d) = %s */\033[0m\n", id, id <= SYS_link ? callnames[id] : "unknown");
145   switch (id)
146     {
147     case SYS_exit:
148       {
149 	int ec = arg ();
150 	if (verbose)
151 	  printf ("[exit %d]\n", ec);
152 	return RX_MAKE_EXITED (ec);
153       }
154       break;
155 
156     case SYS_open:
157       {
158 	int path = arg ();
159 	/* The open function is defined as taking a variable number of arguments
160 	   because the third parameter to it is optional:
161 	     open (const char * filename, int flags, ...);
162 	   Hence the oflags and cflags arguments will be on the stack and we need
163 	   to skip the (empty) argument registers r3 and r4.  */
164 	argp = 4;
165 	int oflags = arg ();
166 	int cflags = arg ();
167 
168 	read_target (buf, path, 256, 1);
169 	if (trace)
170 	  printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags);
171 
172 	if (callbacks)
173 	  /* The callback vector ignores CFLAGS.  */
174 	  rv = callbacks->open (callbacks, buf, oflags);
175 	else
176 	  {
177 	    int h_oflags = 0;
178 
179 	    if (oflags & 0x0001)
180 	      h_oflags |= O_WRONLY;
181 	    if (oflags & 0x0002)
182 	      h_oflags |= O_RDWR;
183 	    if (oflags & 0x0200)
184 	      h_oflags |= O_CREAT;
185 	    if (oflags & 0x0008)
186 	      h_oflags |= O_APPEND;
187 	    if (oflags & 0x0400)
188 	      h_oflags |= O_TRUNC;
189 	    rv = open (buf, h_oflags, cflags);
190 	  }
191 	if (trace)
192 	  printf ("%d\n", rv);
193 	put_reg (1, rv);
194       }
195       break;
196 
197     case SYS_close:
198       {
199 	int fd = arg ();
200 
201 	if (callbacks)
202 	  rv = callbacks->close (callbacks, fd);
203 	else if (fd > 2)
204 	  rv = close (fd);
205 	else
206 	  rv = 0;
207 	if (trace)
208 	  printf ("close(%d) = %d\n", fd, rv);
209 	put_reg (1, rv);
210       }
211       break;
212 
213     case SYS_read:
214       {
215 	int fd = arg ();
216 	int addr = arg ();
217 	int count = arg ();
218 
219 	if (count > sizeof (buf))
220 	  count = sizeof (buf);
221 	if (callbacks)
222 	  rv = callbacks->read (callbacks, fd, buf, count);
223 	else
224 	  rv = read (fd, buf, count);
225 	if (trace)
226 	  printf ("read(%d,%d) = %d\n", fd, count, rv);
227 	if (rv > 0)
228 	  write_target (buf, addr, rv, 0);
229 	put_reg (1, rv);
230       }
231       break;
232 
233     case SYS_write:
234       {
235 	int fd = arg ();
236 	int addr = arg ();
237 	int count = arg ();
238 
239 	if (count > sizeof (buf))
240 	  count = sizeof (buf);
241 	if (trace)
242 	  printf ("write(%d,0x%x,%d)\n", fd, addr, count);
243 	read_target (buf, addr, count, 0);
244 	if (trace)
245 	  fflush (stdout);
246 	if (callbacks)
247 	  rv = callbacks->write (callbacks, fd, buf, count);
248 	else
249 	  rv = write (fd, buf, count);
250 	if (trace)
251 	  printf ("write(%d,%d) = %d\n", fd, count, rv);
252 	put_reg (1, rv);
253       }
254       break;
255 
256     case SYS_getpid:
257       put_reg (1, 42);
258       break;
259 
260     case SYS_gettimeofday:
261       {
262 	int tvaddr = arg ();
263 	struct timeval tv;
264 
265 	rv = gettimeofday (&tv, 0);
266 	if (trace)
267 	  printf ("gettimeofday: %ld sec %ld usec to 0x%x\n", tv.tv_sec,
268 		  tv.tv_usec, tvaddr);
269 	mem_put_si (tvaddr, tv.tv_sec);
270 	mem_put_si (tvaddr + 4, tv.tv_usec);
271 	put_reg (1, rv);
272       }
273       break;
274 
275     case SYS_kill:
276       {
277 	int pid = arg ();
278 	int sig = arg ();
279 	if (pid == 42)
280 	  {
281 	    if (verbose)
282 	      printf ("[signal %d]\n", sig);
283 	    return RX_MAKE_STOPPED (sig);
284 	  }
285       }
286       break;
287 
288     case 11:
289       {
290 	int heaptop_arg = arg ();
291 	if (trace)
292 	  printf ("sbrk: heap top set to %x\n", heaptop_arg);
293 	heaptop = heaptop_arg;
294 	if (heapbottom == 0)
295 	  heapbottom = heaptop_arg;
296       }
297       break;
298 
299     case 255:
300       {
301 	int addr = arg ();
302 	mem_put_si (addr, rx_cycles + mem_usage_cycles());
303       }
304       break;
305 
306     }
307   return RX_MAKE_STEPPED ();
308 }
309