1 /* Support files for GNU libc.  Files in the system namespace go here.
2    Files in the C namespace (ie those that do not start with an
3    underscore) go in .c.  */
4 
5 #include <_ansi.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <sys/fcntl.h>
9 #include <stdio.h>
10 #include <time.h>
11 #include <sys/time.h>
12 #include <sys/times.h>
13 #include <errno.h>
14 #include <reent.h>
15 #include <signal.h>
16 #include <unistd.h>
17 #include <sys/wait.h>
18 #include "swi.h"
19 
20 /* Forward prototypes.  */
21 int     _system     _PARAMS ((const char *));
22 int     _rename     _PARAMS ((const char *, const char *));
23 int     _isatty		_PARAMS ((int));
24 clock_t _times		_PARAMS ((struct tms *));
25 int     _gettimeofday	_PARAMS ((struct timeval *, void *));
26 void    _raise 		_PARAMS ((void));
27 int     _unlink		_PARAMS ((const char *));
28 int     _link 		_PARAMS ((void));
29 int     _stat 		_PARAMS ((const char *, struct stat *));
30 int     _fstat 		_PARAMS ((int, struct stat *));
31 caddr_t _sbrk		_PARAMS ((int));
32 int     _getpid		_PARAMS ((int));
33 int     _kill		_PARAMS ((int, int));
34 void    _exit		_PARAMS ((int));
35 int     _close		_PARAMS ((int));
36 int     _swiclose	_PARAMS ((int));
37 int     _open		_PARAMS ((const char *, int, ...));
38 int     _swiopen	_PARAMS ((const char *, int));
39 int     _write 		_PARAMS ((int, char *, int));
40 int     _swiwrite	_PARAMS ((int, char *, int));
41 int     _lseek		_PARAMS ((int, int, int));
42 int     _swilseek	_PARAMS ((int, int, int));
43 int     _read		_PARAMS ((int, char *, int));
44 int     _swiread	_PARAMS ((int, char *, int));
45 void    initialise_monitor_handles _PARAMS ((void));
46 
47 static int	wrap		_PARAMS ((int));
48 static int	error		_PARAMS ((int));
49 static int	get_errno	_PARAMS ((void));
50 static int	remap_handle	_PARAMS ((int));
51 static int 	findslot	_PARAMS ((int));
52 
53 /* Register name faking - works in collusion with the linker.  */
54 register char * stack_ptr asm ("sp");
55 
56 
57 /* following is copied from libc/stdio/local.h to check std streams */
58 extern void   _EXFUN(__sinit,(struct _reent *));
59 #define CHECK_INIT(ptr) \
60   do						\
61     {						\
62       if ((ptr) && !(ptr)->__sdidinit)		\
63 	__sinit (ptr);				\
64     }						\
65   while (0)
66 
67 /* Adjust our internal handles to stay away from std* handles.  */
68 #define FILE_HANDLE_OFFSET (0x20)
69 
70 static int monitor_stdin;
71 static int monitor_stdout;
72 static int monitor_stderr;
73 
74 /* Struct used to keep track of the file position, just so we
75    can implement fseek(fh,x,SEEK_CUR).  */
76 typedef struct
77 {
78   int handle;
79   int pos;
80 }
81 poslog;
82 
83 #define MAX_OPEN_FILES 20
84 static poslog openfiles [MAX_OPEN_FILES];
85 
86 static int
findslot(int fh)87 findslot (int fh)
88 {
89   int i;
90   for (i = 0; i < MAX_OPEN_FILES; i ++)
91     if (openfiles[i].handle == fh)
92       break;
93   return i;
94 }
95 
96 /* Function to convert std(in|out|err) handles to internal versions.  */
97 static int
remap_handle(int fh)98 remap_handle (int fh)
99 {
100   CHECK_INIT(_REENT);
101 
102   if (fh == STDIN_FILENO)
103     return monitor_stdin;
104   if (fh == STDOUT_FILENO)
105     return monitor_stdout;
106   if (fh == STDERR_FILENO)
107     return monitor_stderr;
108 
109   return fh - FILE_HANDLE_OFFSET;
110 }
111 
112 void
initialise_monitor_handles(void)113 initialise_monitor_handles (void)
114 {
115   int i;
116 
117 #ifdef ARM_RDI_MONITOR
118   int volatile block[3];
119 
120   block[0] = (int) ":tt";
121   block[2] = 3;     /* length of filename */
122   block[1] = 0;     /* mode "r" */
123   monitor_stdin = do_AngelSWI (AngelSWI_Reason_Open, (void *) block);
124 
125   block[0] = (int) ":tt";
126   block[2] = 3;     /* length of filename */
127   block[1] = 4;     /* mode "w" */
128   monitor_stdout = monitor_stderr = do_AngelSWI (AngelSWI_Reason_Open, (void *) block);
129 #else
130   int fh;
131   const char * name;
132 
133   name = ":tt";
134   asm ("mov r0,%2; mov r1, #0; swi %a1; mov %0, r0"
135        : "=r"(fh)
136        : "i" (SWI_Open),"r"(name)
137        : "r0","r1");
138   monitor_stdin = fh;
139 
140   name = ":tt";
141   asm ("mov r0,%2; mov r1, #4; swi %a1; mov %0, r0"
142        : "=r"(fh)
143        : "i" (SWI_Open),"r"(name)
144        : "r0","r1");
145   monitor_stdout = monitor_stderr = fh;
146 #endif
147 
148   for (i = 0; i < MAX_OPEN_FILES; i ++)
149     openfiles[i].handle = -1;
150 
151   openfiles[0].handle = monitor_stdin;
152   openfiles[0].pos = 0;
153   openfiles[1].handle = monitor_stdout;
154   openfiles[1].pos = 0;
155 }
156 
157 static int
get_errno(void)158 get_errno (void)
159 {
160 #ifdef ARM_RDI_MONITOR
161   return do_AngelSWI (AngelSWI_Reason_Errno, NULL);
162 #else
163   asm ("swi %a0" :: "i" (SWI_GetErrno));
164 #endif
165 }
166 
167 static int
error(int result)168 error (int result)
169 {
170   errno = get_errno ();
171   return result;
172 }
173 
174 static int
wrap(int result)175 wrap (int result)
176 {
177   if (result == -1)
178     return error (-1);
179   return result;
180 }
181 
182 /* Returns # chars not! written.  */
183 int
_swiread(int file,char * ptr,int len)184 _swiread (int file,
185 	  char * ptr,
186 	  int len)
187 {
188   int fh = remap_handle (file);
189 #ifdef ARM_RDI_MONITOR
190   int block[3];
191 
192   block[0] = fh;
193   block[1] = (int) ptr;
194   block[2] = len;
195 
196   return do_AngelSWI (AngelSWI_Reason_Read, block);
197 #else
198   asm ("mov r0, %1; mov r1, %2;mov r2, %3; swi %a0"
199        : /* No outputs */
200        : "i"(SWI_Read), "r"(fh), "r"(ptr), "r"(len)
201        : "r0","r1","r2");
202 #endif
203 }
204 
205 int __attribute__((weak))
_read(int file,char * ptr,int len)206 _read (int file,
207        char * ptr,
208        int len)
209 {
210   int slot = findslot (remap_handle (file));
211   int x = _swiread (file, ptr, len);
212 
213   if (x < 0)
214     return error (-1);
215 
216   if (slot != MAX_OPEN_FILES)
217     openfiles [slot].pos += len - x;
218 
219   /* x == len is not an error, at least if we want feof() to work.  */
220   return len - x;
221 }
222 
223 int
_swilseek(int file,int ptr,int dir)224 _swilseek (int file,
225 	   int ptr,
226 	   int dir)
227 {
228   int res;
229   int fh = remap_handle (file);
230   int slot = findslot (fh);
231 #ifdef ARM_RDI_MONITOR
232   int block[2];
233 #endif
234 
235   if (dir == SEEK_CUR)
236     {
237       if (slot == MAX_OPEN_FILES)
238 	return -1;
239       ptr = openfiles[slot].pos + ptr;
240       dir = SEEK_SET;
241     }
242 
243 #ifdef ARM_RDI_MONITOR
244   if (dir == SEEK_END)
245     {
246       block[0] = fh;
247       ptr += do_AngelSWI (AngelSWI_Reason_FLen, block);
248     }
249 
250   /* This code only does absolute seeks.  */
251   block[0] = remap_handle (file);
252   block[1] = ptr;
253   res = do_AngelSWI (AngelSWI_Reason_Seek, block);
254 #else
255   if (dir == SEEK_END)
256     {
257       asm ("mov r0, %2; swi %a1; mov %0, r0"
258 	   : "=r" (res)
259 	   : "i" (SWI_Flen), "r" (fh)
260 	   : "r0");
261       ptr += res;
262     }
263 
264   /* This code only does absolute seeks.  */
265   asm ("mov r0, %2; mov r1, %3; swi %a1; mov %0, r0"
266        : "=r" (res)
267        : "i" (SWI_Seek), "r" (fh), "r" (ptr)
268        : "r0", "r1");
269 #endif
270 
271   if (slot != MAX_OPEN_FILES && res == 0)
272     openfiles[slot].pos = ptr;
273 
274   /* This is expected to return the position in the file.  */
275   return res == 0 ? ptr : -1;
276 }
277 
278 int
_lseek(int file,int ptr,int dir)279 _lseek (int file,
280 	int ptr,
281 	int dir)
282 {
283   return wrap (_swilseek (file, ptr, dir));
284 }
285 
286 /* Returns #chars not! written.  */
287 int
_swiwrite(int file,char * ptr,int len)288 _swiwrite (
289 	   int    file,
290 	   char * ptr,
291 	   int    len)
292 {
293   int fh = remap_handle (file);
294 #ifdef ARM_RDI_MONITOR
295   int block[3];
296 
297   block[0] = fh;
298   block[1] = (int) ptr;
299   block[2] = len;
300 
301   return do_AngelSWI (AngelSWI_Reason_Write, block);
302 #else
303   asm ("mov r0, %1; mov r1, %2;mov r2, %3; swi %a0"
304        : /* No outputs */
305        : "i"(SWI_Write), "r"(fh), "r"(ptr), "r"(len)
306        : "r0","r1","r2");
307 #endif
308 }
309 
310 int __attribute__((weak))
_write(int file,char * ptr,int len)311 _write (int    file,
312 	char * ptr,
313 	int    len)
314 {
315   int slot = findslot (remap_handle (file));
316   int x = _swiwrite (file, ptr,len);
317 
318   if (x == -1 || x == len)
319     return error (-1);
320 
321   if (slot != MAX_OPEN_FILES)
322     openfiles[slot].pos += len - x;
323 
324   return len - x;
325 }
326 
327 extern int strlen (const char *);
328 
329 int
_swiopen(const char * path,int flags)330 _swiopen (const char * path,
331 	  int          flags)
332 {
333   int aflags = 0, fh;
334 #ifdef ARM_RDI_MONITOR
335   int block[3];
336 #endif
337 
338   int i = findslot (-1);
339 
340   if (i == MAX_OPEN_FILES)
341     return -1;
342 
343   /* The flags are Unix-style, so we need to convert them.  */
344 #ifdef O_BINARY
345   if (flags & O_BINARY)
346     aflags |= 1;
347 #endif
348 
349   if (flags & O_RDWR)
350     aflags |= 2;
351 
352   if (flags & O_CREAT)
353     aflags |= 4;
354 
355   if (flags & O_TRUNC)
356     aflags |= 4;
357 
358   if (flags & O_APPEND)
359     {
360       aflags &= ~4;     /* Can't ask for w AND a; means just 'a'.  */
361       aflags |= 8;
362     }
363 
364 #ifdef ARM_RDI_MONITOR
365   block[0] = (int) path;
366   block[2] = strlen (path);
367   block[1] = aflags;
368 
369   fh = do_AngelSWI (AngelSWI_Reason_Open, block);
370 
371 #else
372   asm ("mov r0,%2; mov r1, %3; swi %a1; mov %0, r0"
373        : "=r"(fh)
374        : "i" (SWI_Open),"r"(path),"r"(aflags)
375        : "r0","r1");
376 #endif
377 
378   if (fh >= 0)
379     {
380       openfiles[i].handle = fh;
381       openfiles[i].pos = 0;
382     }
383 
384   return fh >= 0 ? fh + FILE_HANDLE_OFFSET : error (fh);
385 }
386 
387 int
_open(const char * path,int flags,...)388 _open (const char * path,
389        int          flags,
390        ...)
391 {
392   return wrap (_swiopen (path, flags));
393 }
394 
395 int
_swiclose(int file)396 _swiclose (int file)
397 {
398   int myhan = remap_handle (file);
399   int slot = findslot (myhan);
400 
401   if (slot != MAX_OPEN_FILES)
402     openfiles[slot].handle = -1;
403 
404 #ifdef ARM_RDI_MONITOR
405   return do_AngelSWI (AngelSWI_Reason_Close, & myhan);
406 #else
407   asm ("mov r0, %1; swi %a0" :: "i" (SWI_Close),"r"(myhan):"r0");
408 #endif
409 }
410 
411 int
_close(int file)412 _close (int file)
413 {
414   return wrap (_swiclose (file));
415 }
416 
417 int
_kill(int pid,int sig)418 _kill (int pid, int sig)
419 {
420   (void)pid; (void)sig;
421 #ifdef ARM_RDI_MONITOR
422   /* Note: The pid argument is thrown away.  */
423   switch (sig) {
424 	  case SIGABRT:
425 		  return do_AngelSWI (AngelSWI_Reason_ReportException,
426 				  (void *) ADP_Stopped_RunTimeError);
427 	  default:
428 		  return do_AngelSWI (AngelSWI_Reason_ReportException,
429 				  (void *) ADP_Stopped_ApplicationExit);
430   }
431 #else
432   asm ("swi %a0" :: "i" (SWI_Exit));
433 #endif
434 }
435 
436 void
_exit(int status)437 _exit (int status)
438 {
439   /* There is only one SWI for both _exit and _kill. For _exit, call
440      the SWI with the second argument set to -1, an invalid value for
441      signum, so that the SWI handler can distinguish the two calls.
442      Note: The RDI implementation of _kill throws away both its
443      arguments.  */
444   _kill(status, -1);
445 }
446 
447 int
_getpid(int n)448 _getpid (int n)
449 {
450   return 1;
451   n = n;
452 }
453 
454 caddr_t __attribute__((weak))
_sbrk(int incr)455 _sbrk (int incr)
456 {
457   extern char   end asm ("end");	/* Defined by the linker.  */
458   static char * heap_end;
459   char *        prev_heap_end;
460 
461   if (heap_end == NULL)
462     heap_end = & end;
463 
464   prev_heap_end = heap_end;
465 
466   if (heap_end + incr > stack_ptr)
467     {
468       /* Some of the libstdc++-v3 tests rely upon detecting
469 	 out of memory errors, so do not abort here.  */
470 #if 0
471       extern void abort (void);
472 
473       _write (1, "_sbrk: Heap and stack collision\n", 32);
474 
475       abort ();
476 #else
477       errno = ENOMEM;
478       return (caddr_t) -1;
479 #endif
480     }
481 
482   heap_end += incr;
483 
484   return (caddr_t) prev_heap_end;
485 }
486 
487 extern void memset (struct stat *, int, unsigned int);
488 
489 int
_fstat(int file,struct stat * st)490 _fstat (int file, struct stat * st)
491 {
492   memset (st, 0, sizeof (* st));
493   st->st_mode = S_IFCHR;
494   st->st_blksize = 1024;
495   return 0;
496   file = file;
497 }
498 
_stat(const char * fname,struct stat * st)499 int _stat (const char *fname, struct stat *st)
500 {
501   int file;
502 
503   /* The best we can do is try to open the file readonly.  If it exists,
504      then we can guess a few things about it.  */
505   if ((file = _open (fname, O_RDONLY)) < 0)
506     return -1;
507 
508   memset (st, 0, sizeof (* st));
509   st->st_mode = S_IFREG | S_IREAD;
510   st->st_blksize = 1024;
511   _swiclose (file); /* Not interested in the error.  */
512   return 0;
513 }
514 
515 int
_link(void)516 _link (void)
517 {
518   return -1;
519 }
520 
521 int
_unlink(const char * path)522 _unlink (const char *path)
523 {
524 #ifdef ARM_RDI_MONITOR
525   int block[2];
526   block[0] = path;
527   block[1] = strlen(path);
528   return wrap (do_AngelSWI (AngelSWI_Reason_Remove, block)) ? -1 : 0;
529 #else
530   return -1;
531 #endif
532 }
533 
534 void
_raise(void)535 _raise (void)
536 {
537   return;
538 }
539 
540 int
_gettimeofday(struct timeval * tp,void * tzvp)541 _gettimeofday (struct timeval * tp, void * tzvp)
542 {
543   struct timezone *tzp = tzvp;
544   if (tp)
545     {
546     /* Ask the host for the seconds since the Unix epoch.  */
547 #ifdef ARM_RDI_MONITOR
548       tp->tv_sec = do_AngelSWI (AngelSWI_Reason_Time,NULL);
549 #else
550       {
551         int value;
552         asm ("swi %a1; mov %0, r0" : "=r" (value): "i" (SWI_Time) : "r0");
553         tp->tv_sec = value;
554       }
555 #endif
556       tp->tv_usec = 0;
557     }
558 
559   /* Return fixed data for the timezone.  */
560   if (tzp)
561     {
562       tzp->tz_minuteswest = 0;
563       tzp->tz_dsttime = 0;
564     }
565 
566   return 0;
567 }
568 
569 /* Return a clock that ticks at 100Hz.  */
570 clock_t
_times(struct tms * tp)571 _times (struct tms * tp)
572 {
573   clock_t timeval;
574 
575 #ifdef ARM_RDI_MONITOR
576   timeval = do_AngelSWI (AngelSWI_Reason_Clock,NULL);
577 #else
578   asm ("swi %a1; mov %0, r0" : "=r" (timeval): "i" (SWI_Clock) : "r0");
579 #endif
580 
581   if (tp)
582     {
583       tp->tms_utime  = timeval;	/* user time */
584       tp->tms_stime  = 0;	/* system time */
585       tp->tms_cutime = 0;	/* user time, children */
586       tp->tms_cstime = 0;	/* system time, children */
587     }
588 
589   return timeval;
590 };
591 
592 
593 int
_isatty(int fd)594 _isatty (int fd)
595 {
596 #ifdef ARM_RDI_MONITOR
597   int fh = remap_handle (fd);
598   return wrap (do_AngelSWI (AngelSWI_Reason_IsTTY, &fh));
599 #else
600   return (fd <= 2) ? 1 : 0;  /* one of stdin, stdout, stderr */
601 #endif
602 }
603 
604 int
_system(const char * s)605 _system (const char *s)
606 {
607 #ifdef ARM_RDI_MONITOR
608   int block[2];
609   int e;
610 
611   /* Hmmm.  The ARM debug interface specification doesn't say whether
612      SYS_SYSTEM does the right thing with a null argument, or assign any
613      meaning to its return value.  Try to do something reasonable....  */
614   if (!s)
615     return 1;  /* maybe there is a shell available? we can hope. :-P */
616   block[0] = s;
617   block[1] = strlen (s);
618   e = wrap (do_AngelSWI (AngelSWI_Reason_System, block));
619   if ((e >= 0) && (e < 256))
620     {
621       /* We have to convert e, an exit status to the encoded status of
622          the command.  To avoid hard coding the exit status, we simply
623 	 loop until we find the right position.  */
624       int exit_code;
625 
626       for (exit_code = e; e && WEXITSTATUS (e) != exit_code; e <<= 1)
627 	continue;
628     }
629   return e;
630 #else
631   if (s == NULL)
632     return 0;
633   errno = ENOSYS;
634   return -1;
635 #endif
636 }
637 
638 int
_rename(const char * oldpath,const char * newpath)639 _rename (const char * oldpath, const char * newpath)
640 {
641 #ifdef ARM_RDI_MONITOR
642   int block[4];
643   block[0] = oldpath;
644   block[1] = strlen(oldpath);
645   block[2] = newpath;
646   block[3] = strlen(newpath);
647   return wrap (do_AngelSWI (AngelSWI_Reason_Rename, block)) ? -1 : 0;
648 #else
649   errno = ENOSYS;
650   return -1;
651 #endif
652 }
653