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