Commit | Line | Data |
---|---|---|
c906108c | 1 | /* Remote target callback routines. |
41ee5402 DJ |
2 | Copyright 1995, 1996, 1997, 2000, 2002, 2003, 2004 |
3 | Free Software Foundation, Inc. | |
c906108c SS |
4 | Contributed by Cygnus Solutions. |
5 | ||
6 | This file is part of GDB. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GAS; see the file COPYING. If not, write to the Free Software | |
20 | Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
21 | ||
22 | /* This file provides a standard way for targets to talk to the host OS | |
23 | level. */ | |
24 | ||
25 | #ifdef HAVE_CONFIG_H | |
41ee5402 | 26 | #include "cconfig.h" |
c906108c SS |
27 | #endif |
28 | #include "ansidecl.h" | |
29 | #ifdef ANSI_PROTOTYPES | |
30 | #include <stdarg.h> | |
31 | #else | |
32 | #include <varargs.h> | |
33 | #endif | |
34 | #include <stdio.h> | |
35 | #ifdef HAVE_STDLIB_H | |
36 | #include <stdlib.h> | |
37 | #endif | |
38 | #ifdef HAVE_STRING_H | |
39 | #include <string.h> | |
40 | #else | |
41 | #ifdef HAVE_STRINGS_H | |
42 | #include <strings.h> | |
43 | #endif | |
44 | #endif | |
45 | #include <errno.h> | |
46 | #include <fcntl.h> | |
47 | #include <time.h> | |
48 | #include <sys/types.h> | |
49 | #include <sys/stat.h> | |
3c25f8c7 | 50 | #include "gdb/callback.h" |
c906108c SS |
51 | #include "targ-vals.h" |
52 | ||
53 | #ifdef HAVE_UNISTD_H | |
54 | #include <unistd.h> | |
55 | #endif | |
56 | ||
57 | /* ??? sim_cb_printf should be cb_printf, but until the callback support is | |
58 | broken out of the simulator directory, these are here to not require | |
59 | sim-utils.h. */ | |
60 | void sim_cb_printf PARAMS ((host_callback *, const char *, ...)); | |
61 | void sim_cb_eprintf PARAMS ((host_callback *, const char *, ...)); | |
62 | ||
63 | extern CB_TARGET_DEFS_MAP cb_init_syscall_map[]; | |
64 | extern CB_TARGET_DEFS_MAP cb_init_errno_map[]; | |
65 | extern CB_TARGET_DEFS_MAP cb_init_open_map[]; | |
66 | ||
67 | extern int system PARAMS ((const char *)); | |
68 | ||
69 | static int os_init PARAMS ((host_callback *)); | |
70 | static int os_shutdown PARAMS ((host_callback *)); | |
71 | static int os_unlink PARAMS ((host_callback *, const char *)); | |
72 | static long os_time PARAMS ((host_callback *, long *)); | |
73 | static int os_system PARAMS ((host_callback *, const char *)); | |
74 | static int os_rename PARAMS ((host_callback *, const char *, const char *)); | |
75 | static int os_write_stdout PARAMS ((host_callback *, const char *, int)); | |
76 | static void os_flush_stdout PARAMS ((host_callback *)); | |
77 | static int os_write_stderr PARAMS ((host_callback *, const char *, int)); | |
78 | static void os_flush_stderr PARAMS ((host_callback *)); | |
79 | static int os_write PARAMS ((host_callback *, int, const char *, int)); | |
80 | static int os_read_stdin PARAMS ((host_callback *, char *, int)); | |
81 | static int os_read PARAMS ((host_callback *, int, char *, int)); | |
82 | static int os_open PARAMS ((host_callback *, const char *, int)); | |
83 | static int os_lseek PARAMS ((host_callback *, int, long, int)); | |
84 | static int os_isatty PARAMS ((host_callback *, int)); | |
85 | static int os_get_errno PARAMS ((host_callback *)); | |
86 | static int os_close PARAMS ((host_callback *, int)); | |
87 | static void os_vprintf_filtered PARAMS ((host_callback *, const char *, va_list)); | |
88 | static void os_evprintf_filtered PARAMS ((host_callback *, const char *, va_list)); | |
89 | static void os_error PARAMS ((host_callback *, const char *, ...)); | |
90 | static int fdmap PARAMS ((host_callback *, int)); | |
91 | static int fdbad PARAMS ((host_callback *, int)); | |
92 | static int wrap PARAMS ((host_callback *, int)); | |
93 | ||
94 | /* Set the callback copy of errno from what we see now. */ | |
95 | ||
96 | static int | |
97 | wrap (p, val) | |
98 | host_callback *p; | |
99 | int val; | |
100 | { | |
101 | p->last_errno = errno; | |
102 | return val; | |
103 | } | |
104 | ||
105 | /* Make sure the FD provided is ok. If not, return non-zero | |
106 | and set errno. */ | |
107 | ||
108 | static int | |
109 | fdbad (p, fd) | |
110 | host_callback *p; | |
111 | int fd; | |
112 | { | |
594ee3a7 | 113 | if (fd < 0 || fd > MAX_CALLBACK_FDS || p->fd_buddy[fd] < 0) |
c906108c SS |
114 | { |
115 | p->last_errno = EINVAL; | |
116 | return -1; | |
117 | } | |
118 | return 0; | |
119 | } | |
120 | ||
121 | static int | |
122 | fdmap (p, fd) | |
123 | host_callback *p; | |
124 | int fd; | |
125 | { | |
126 | return p->fdmap[fd]; | |
127 | } | |
128 | ||
129 | static int | |
130 | os_close (p, fd) | |
131 | host_callback *p; | |
132 | int fd; | |
133 | { | |
134 | int result; | |
594ee3a7 | 135 | int i, next; |
c906108c SS |
136 | |
137 | result = fdbad (p, fd); | |
138 | if (result) | |
139 | return result; | |
594ee3a7 JR |
140 | /* If this file descripter has one or more buddies (originals / |
141 | duplicates from a dup), just remove it from the circular list. */ | |
142 | for (i = fd; (next = p->fd_buddy[i]) != fd; ) | |
143 | i = next; | |
144 | if (fd != i) | |
145 | p->fd_buddy[i] = p->fd_buddy[fd]; | |
146 | else | |
147 | result = wrap (p, close (fdmap (p, fd))); | |
148 | p->fd_buddy[fd] = -1; | |
c906108c SS |
149 | |
150 | return result; | |
151 | } | |
152 | ||
153 | ||
154 | /* taken from gdb/util.c:notice_quit() - should be in a library */ | |
155 | ||
156 | ||
157 | #if defined(__GO32__) || defined (_MSC_VER) | |
158 | static int | |
159 | os_poll_quit (p) | |
160 | host_callback *p; | |
161 | { | |
162 | #if defined(__GO32__) | |
163 | int kbhit (); | |
164 | int getkey (); | |
165 | if (kbhit ()) | |
166 | { | |
167 | int k = getkey (); | |
168 | if (k == 1) | |
169 | { | |
170 | return 1; | |
171 | } | |
172 | else if (k == 2) | |
173 | { | |
174 | return 1; | |
175 | } | |
176 | else | |
177 | { | |
178 | sim_cb_eprintf (p, "CTRL-A to quit, CTRL-B to quit harder\n"); | |
179 | } | |
180 | } | |
181 | #endif | |
182 | #if defined (_MSC_VER) | |
183 | /* NB - this will not compile! */ | |
184 | int k = win32pollquit(); | |
185 | if (k == 1) | |
186 | return 1; | |
187 | else if (k == 2) | |
188 | return 1; | |
189 | #endif | |
190 | return 0; | |
191 | } | |
192 | #else | |
193 | #define os_poll_quit 0 | |
194 | #endif /* defined(__GO32__) || defined(_MSC_VER) */ | |
195 | ||
196 | static int | |
197 | os_get_errno (p) | |
198 | host_callback *p; | |
199 | { | |
200 | return cb_host_to_target_errno (p, p->last_errno); | |
201 | } | |
202 | ||
203 | ||
204 | static int | |
205 | os_isatty (p, fd) | |
206 | host_callback *p; | |
207 | int fd; | |
208 | { | |
209 | int result; | |
210 | ||
211 | result = fdbad (p, fd); | |
212 | if (result) | |
213 | return result; | |
214 | result = wrap (p, isatty (fdmap (p, fd))); | |
215 | ||
216 | return result; | |
217 | } | |
218 | ||
219 | static int | |
220 | os_lseek (p, fd, off, way) | |
221 | host_callback *p; | |
222 | int fd; | |
223 | long off; | |
224 | int way; | |
225 | { | |
226 | int result; | |
227 | ||
228 | result = fdbad (p, fd); | |
229 | if (result) | |
230 | return result; | |
231 | result = lseek (fdmap (p, fd), off, way); | |
232 | return result; | |
233 | } | |
234 | ||
235 | static int | |
236 | os_open (p, name, flags) | |
237 | host_callback *p; | |
238 | const char *name; | |
239 | int flags; | |
240 | { | |
241 | int i; | |
242 | for (i = 0; i < MAX_CALLBACK_FDS; i++) | |
243 | { | |
594ee3a7 | 244 | if (p->fd_buddy[i] < 0) |
c906108c SS |
245 | { |
246 | int f = open (name, cb_target_to_host_open (p, flags), 0644); | |
247 | if (f < 0) | |
248 | { | |
249 | p->last_errno = errno; | |
250 | return f; | |
251 | } | |
594ee3a7 | 252 | p->fd_buddy[i] = i; |
c906108c SS |
253 | p->fdmap[i] = f; |
254 | return i; | |
255 | } | |
256 | } | |
257 | p->last_errno = EMFILE; | |
258 | return -1; | |
259 | } | |
260 | ||
261 | static int | |
262 | os_read (p, fd, buf, len) | |
263 | host_callback *p; | |
264 | int fd; | |
265 | char *buf; | |
266 | int len; | |
267 | { | |
268 | int result; | |
269 | ||
270 | result = fdbad (p, fd); | |
271 | if (result) | |
272 | return result; | |
273 | result = wrap (p, read (fdmap (p, fd), buf, len)); | |
274 | return result; | |
275 | } | |
276 | ||
277 | static int | |
278 | os_read_stdin (p, buf, len) | |
279 | host_callback *p; | |
280 | char *buf; | |
281 | int len; | |
282 | { | |
283 | return wrap (p, read (0, buf, len)); | |
284 | } | |
285 | ||
286 | static int | |
287 | os_write (p, fd, buf, len) | |
288 | host_callback *p; | |
289 | int fd; | |
290 | const char *buf; | |
291 | int len; | |
292 | { | |
293 | int result; | |
294 | int real_fd; | |
295 | ||
296 | result = fdbad (p, fd); | |
297 | if (result) | |
298 | return result; | |
299 | real_fd = fdmap (p, fd); | |
300 | switch (real_fd) | |
301 | { | |
302 | default: | |
303 | result = wrap (p, write (real_fd, buf, len)); | |
304 | break; | |
305 | case 1: | |
306 | result = p->write_stdout (p, buf, len); | |
307 | break; | |
308 | case 2: | |
309 | result = p->write_stderr (p, buf, len); | |
310 | break; | |
311 | } | |
312 | return result; | |
313 | } | |
314 | ||
315 | static int | |
316 | os_write_stdout (p, buf, len) | |
6d358e86 | 317 | host_callback *p ATTRIBUTE_UNUSED; |
c906108c SS |
318 | const char *buf; |
319 | int len; | |
320 | { | |
321 | return fwrite (buf, 1, len, stdout); | |
322 | } | |
323 | ||
324 | static void | |
325 | os_flush_stdout (p) | |
6d358e86 | 326 | host_callback *p ATTRIBUTE_UNUSED; |
c906108c SS |
327 | { |
328 | fflush (stdout); | |
329 | } | |
330 | ||
331 | static int | |
332 | os_write_stderr (p, buf, len) | |
6d358e86 | 333 | host_callback *p ATTRIBUTE_UNUSED; |
c906108c SS |
334 | const char *buf; |
335 | int len; | |
336 | { | |
337 | return fwrite (buf, 1, len, stderr); | |
338 | } | |
339 | ||
340 | static void | |
341 | os_flush_stderr (p) | |
6d358e86 | 342 | host_callback *p ATTRIBUTE_UNUSED; |
c906108c SS |
343 | { |
344 | fflush (stderr); | |
345 | } | |
346 | ||
347 | static int | |
348 | os_rename (p, f1, f2) | |
349 | host_callback *p; | |
350 | const char *f1; | |
351 | const char *f2; | |
352 | { | |
353 | return wrap (p, rename (f1, f2)); | |
354 | } | |
355 | ||
356 | ||
357 | static int | |
358 | os_system (p, s) | |
359 | host_callback *p; | |
360 | const char *s; | |
361 | { | |
362 | return wrap (p, system (s)); | |
363 | } | |
364 | ||
365 | static long | |
366 | os_time (p, t) | |
367 | host_callback *p; | |
368 | long *t; | |
369 | { | |
370 | return wrap (p, time (t)); | |
371 | } | |
372 | ||
373 | ||
374 | static int | |
375 | os_unlink (p, f1) | |
376 | host_callback *p; | |
377 | const char *f1; | |
378 | { | |
379 | return wrap (p, unlink (f1)); | |
380 | } | |
381 | ||
382 | static int | |
383 | os_stat (p, file, buf) | |
384 | host_callback *p; | |
385 | const char *file; | |
386 | struct stat *buf; | |
387 | { | |
388 | /* ??? There is an issue of when to translate to the target layout. | |
389 | One could do that inside this function, or one could have the | |
390 | caller do it. It's more flexible to let the caller do it, though | |
391 | I'm not sure the flexibility will ever be useful. */ | |
392 | return wrap (p, stat (file, buf)); | |
393 | } | |
394 | ||
395 | static int | |
396 | os_fstat (p, fd, buf) | |
397 | host_callback *p; | |
398 | int fd; | |
399 | struct stat *buf; | |
400 | { | |
401 | if (fdbad (p, fd)) | |
402 | return -1; | |
403 | /* ??? There is an issue of when to translate to the target layout. | |
404 | One could do that inside this function, or one could have the | |
405 | caller do it. It's more flexible to let the caller do it, though | |
406 | I'm not sure the flexibility will ever be useful. */ | |
407 | return wrap (p, fstat (fdmap (p, fd), buf)); | |
408 | } | |
409 | ||
8822d001 JR |
410 | static int |
411 | os_ftruncate (p, fd, len) | |
412 | host_callback *p; | |
413 | int fd; | |
414 | long len; | |
415 | { | |
416 | int result; | |
417 | ||
418 | result = fdbad (p, fd); | |
419 | if (result) | |
420 | return result; | |
421 | result = wrap (p, ftruncate (fdmap (p, fd), len)); | |
422 | return result; | |
423 | } | |
424 | ||
425 | static int | |
426 | os_truncate (p, file, len) | |
427 | host_callback *p; | |
428 | const char *file; | |
429 | long len; | |
430 | { | |
ee3073b5 | 431 | return wrap (p, truncate (file, len)); |
8822d001 JR |
432 | } |
433 | ||
c906108c SS |
434 | static int |
435 | os_shutdown (p) | |
436 | host_callback *p; | |
437 | { | |
594ee3a7 | 438 | int i, next, j; |
c906108c SS |
439 | for (i = 0; i < MAX_CALLBACK_FDS; i++) |
440 | { | |
594ee3a7 JR |
441 | int do_close = 1; |
442 | ||
443 | next = p->fd_buddy[i]; | |
444 | if (next < 0) | |
445 | continue; | |
446 | do | |
447 | { | |
448 | j = next; | |
449 | if (j == MAX_CALLBACK_FDS) | |
450 | do_close = 0; | |
451 | next = p->fd_buddy[j]; | |
452 | p->fd_buddy[j] = -1; | |
453 | /* At the initial call of os_init, we got -1, 0, 0, 0, ... */ | |
454 | if (next < 0) | |
455 | { | |
0242f9ea | 456 | p->fd_buddy[i] = -1; |
594ee3a7 JR |
457 | do_close = 0; |
458 | break; | |
459 | } | |
460 | } | |
461 | while (j != i); | |
462 | if (do_close) | |
c906108c | 463 | close (p->fdmap[i]); |
c906108c SS |
464 | } |
465 | return 1; | |
466 | } | |
467 | ||
468 | static int | |
469 | os_init (p) | |
470 | host_callback *p; | |
471 | { | |
472 | int i; | |
473 | ||
474 | os_shutdown (p); | |
475 | for (i = 0; i < 3; i++) | |
476 | { | |
477 | p->fdmap[i] = i; | |
594ee3a7 | 478 | p->fd_buddy[i] = i - 1; |
c906108c | 479 | } |
594ee3a7 JR |
480 | p->fd_buddy[0] = MAX_CALLBACK_FDS; |
481 | p->fd_buddy[MAX_CALLBACK_FDS] = 2; | |
c906108c SS |
482 | |
483 | p->syscall_map = cb_init_syscall_map; | |
484 | p->errno_map = cb_init_errno_map; | |
485 | p->open_map = cb_init_open_map; | |
486 | ||
487 | return 1; | |
488 | } | |
489 | ||
5accf1ff | 490 | /* DEPRECATED */ |
c906108c SS |
491 | |
492 | /* VARARGS */ | |
493 | static void | |
494 | #ifdef ANSI_PROTOTYPES | |
6d358e86 | 495 | os_printf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...) |
c906108c SS |
496 | #else |
497 | os_printf_filtered (p, va_alist) | |
498 | host_callback *p; | |
499 | va_dcl | |
500 | #endif | |
501 | { | |
502 | va_list args; | |
503 | #ifdef ANSI_PROTOTYPES | |
504 | va_start (args, format); | |
505 | #else | |
506 | char *format; | |
507 | ||
508 | va_start (args); | |
509 | format = va_arg (args, char *); | |
510 | #endif | |
511 | ||
512 | vfprintf (stdout, format, args); | |
513 | va_end (args); | |
514 | } | |
515 | ||
516 | /* VARARGS */ | |
517 | static void | |
518 | #ifdef ANSI_PROTOTYPES | |
6d358e86 | 519 | os_vprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args) |
c906108c SS |
520 | #else |
521 | os_vprintf_filtered (p, format, args) | |
522 | host_callback *p; | |
523 | const char *format; | |
524 | va_list args; | |
525 | #endif | |
526 | { | |
527 | vprintf (format, args); | |
528 | } | |
529 | ||
530 | /* VARARGS */ | |
531 | static void | |
532 | #ifdef ANSI_PROTOTYPES | |
6d358e86 | 533 | os_evprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args) |
c906108c SS |
534 | #else |
535 | os_evprintf_filtered (p, format, args) | |
536 | host_callback *p; | |
537 | const char *format; | |
538 | va_list args; | |
539 | #endif | |
540 | { | |
541 | vfprintf (stderr, format, args); | |
542 | } | |
543 | ||
544 | /* VARARGS */ | |
545 | static void | |
546 | #ifdef ANSI_PROTOTYPES | |
6d358e86 | 547 | os_error (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...) |
c906108c SS |
548 | #else |
549 | os_error (p, va_alist) | |
550 | host_callback *p; | |
551 | va_dcl | |
552 | #endif | |
553 | { | |
554 | va_list args; | |
555 | #ifdef ANSI_PROTOTYPES | |
556 | va_start (args, format); | |
557 | #else | |
558 | char *format; | |
559 | ||
560 | va_start (args); | |
561 | format = va_arg (args, char *); | |
562 | #endif | |
563 | ||
564 | vfprintf (stderr, format, args); | |
565 | fprintf (stderr, "\n"); | |
566 | ||
567 | va_end (args); | |
568 | exit (1); | |
569 | } | |
570 | ||
571 | host_callback default_callback = | |
572 | { | |
573 | os_close, | |
574 | os_get_errno, | |
575 | os_isatty, | |
576 | os_lseek, | |
577 | os_open, | |
578 | os_read, | |
579 | os_read_stdin, | |
580 | os_rename, | |
581 | os_system, | |
582 | os_time, | |
583 | os_unlink, | |
584 | os_write, | |
585 | os_write_stdout, | |
586 | os_flush_stdout, | |
587 | os_write_stderr, | |
588 | os_flush_stderr, | |
589 | ||
590 | os_stat, | |
591 | os_fstat, | |
592 | ||
8822d001 JR |
593 | os_ftruncate, |
594 | os_truncate, | |
595 | ||
c906108c SS |
596 | os_poll_quit, |
597 | ||
598 | os_shutdown, | |
599 | os_init, | |
600 | ||
601 | os_printf_filtered, /* deprecated */ | |
602 | ||
603 | os_vprintf_filtered, | |
604 | os_evprintf_filtered, | |
605 | os_error, | |
606 | ||
607 | 0, /* last errno */ | |
608 | ||
609 | { 0, }, /* fdmap */ | |
594ee3a7 | 610 | { -1, }, /* fd_buddy */ |
c906108c SS |
611 | |
612 | 0, /* syscall_map */ | |
613 | 0, /* errno_map */ | |
614 | 0, /* open_map */ | |
615 | 0, /* signal_map */ | |
616 | 0, /* stat_map */ | |
617 | ||
618 | HOST_CALLBACK_MAGIC, | |
619 | }; | |
620 | \f | |
621 | /* Read in a file describing the target's system call values. | |
622 | E.g. maybe someone will want to use something other than newlib. | |
623 | This assumes that the basic system call recognition and value passing/ | |
624 | returning is supported. So maybe some coding/recompilation will be | |
625 | necessary, but not as much. | |
626 | ||
627 | If an error occurs, the existing mapping is not changed. */ | |
628 | ||
629 | CB_RC | |
630 | cb_read_target_syscall_maps (cb, file) | |
631 | host_callback *cb; | |
632 | const char *file; | |
633 | { | |
634 | CB_TARGET_DEFS_MAP *syscall_map, *errno_map, *open_map, *signal_map; | |
635 | const char *stat_map; | |
636 | FILE *f; | |
637 | ||
638 | if ((f = fopen (file, "r")) == NULL) | |
639 | return CB_RC_ACCESS; | |
640 | ||
641 | /* ... read in and parse file ... */ | |
642 | ||
643 | fclose (f); | |
644 | return CB_RC_NO_MEM; /* FIXME:wip */ | |
645 | ||
646 | /* Free storage allocated for any existing maps. */ | |
647 | if (cb->syscall_map) | |
648 | free (cb->syscall_map); | |
649 | if (cb->errno_map) | |
650 | free (cb->errno_map); | |
651 | if (cb->open_map) | |
652 | free (cb->open_map); | |
653 | if (cb->signal_map) | |
654 | free (cb->signal_map); | |
655 | if (cb->stat_map) | |
656 | free ((PTR) cb->stat_map); | |
657 | ||
658 | cb->syscall_map = syscall_map; | |
659 | cb->errno_map = errno_map; | |
660 | cb->open_map = open_map; | |
661 | cb->signal_map = signal_map; | |
662 | cb->stat_map = stat_map; | |
663 | ||
664 | return CB_RC_OK; | |
665 | } | |
666 | ||
667 | /* Translate the target's version of a syscall number to the host's. | |
668 | This isn't actually the host's version, rather a canonical form. | |
669 | ??? Perhaps this should be renamed to ..._canon_syscall. */ | |
670 | ||
671 | int | |
672 | cb_target_to_host_syscall (cb, target_val) | |
673 | host_callback *cb; | |
674 | int target_val; | |
675 | { | |
676 | CB_TARGET_DEFS_MAP *m; | |
677 | ||
678 | for (m = &cb->syscall_map[0]; m->target_val != -1; ++m) | |
679 | if (m->target_val == target_val) | |
680 | return m->host_val; | |
681 | ||
682 | return -1; | |
683 | } | |
684 | ||
685 | /* FIXME: sort tables if large. | |
686 | Alternatively, an obvious improvement for errno conversion is | |
687 | to machine generate a function with a large switch(). */ | |
688 | ||
689 | /* Translate the host's version of errno to the target's. */ | |
690 | ||
691 | int | |
692 | cb_host_to_target_errno (cb, host_val) | |
693 | host_callback *cb; | |
694 | int host_val; | |
695 | { | |
696 | CB_TARGET_DEFS_MAP *m; | |
697 | ||
698 | for (m = &cb->errno_map[0]; m->host_val; ++m) | |
699 | if (m->host_val == host_val) | |
700 | return m->target_val; | |
701 | ||
702 | /* ??? Which error to return in this case is up for grabs. | |
703 | Note that some missing values may have standard alternatives. | |
704 | For now return 0 and require caller to deal with it. */ | |
705 | return 0; | |
706 | } | |
707 | ||
708 | /* Given a set of target bitmasks for the open system call, | |
709 | return the host equivalent. | |
710 | Mapping open flag values is best done by looping so there's no need | |
711 | to machine generate this function. */ | |
712 | ||
713 | int | |
714 | cb_target_to_host_open (cb, target_val) | |
715 | host_callback *cb; | |
716 | int target_val; | |
717 | { | |
718 | int host_val = 0; | |
719 | CB_TARGET_DEFS_MAP *m; | |
720 | ||
721 | for (m = &cb->open_map[0]; m->host_val != -1; ++m) | |
722 | { | |
723 | switch (m->target_val) | |
724 | { | |
725 | /* O_RDONLY can be (and usually is) 0 which needs to be treated | |
726 | specially. */ | |
727 | case TARGET_O_RDONLY : | |
728 | case TARGET_O_WRONLY : | |
729 | case TARGET_O_RDWR : | |
730 | if ((target_val & (TARGET_O_RDONLY | TARGET_O_WRONLY | TARGET_O_RDWR)) | |
731 | == m->target_val) | |
732 | host_val |= m->host_val; | |
733 | /* Handle the host/target differentiating between binary and | |
734 | text mode. Only one case is of importance */ | |
735 | #if ! defined (TARGET_O_BINARY) && defined (O_BINARY) | |
736 | host_val |= O_BINARY; | |
737 | #endif | |
738 | break; | |
739 | default : | |
740 | if ((m->target_val & target_val) == m->target_val) | |
741 | host_val |= m->host_val; | |
742 | break; | |
743 | } | |
744 | } | |
745 | ||
746 | return host_val; | |
747 | } | |
748 | ||
749 | /* Utility for cb_host_to_target_stat to store values in the target's | |
750 | stat struct. */ | |
751 | ||
752 | static void | |
753 | store (p, size, val, big_p) | |
754 | char *p; | |
755 | int size; | |
756 | long val; /* ??? must be as big as target word size */ | |
757 | int big_p; | |
758 | { | |
759 | if (big_p) | |
760 | { | |
761 | p += size; | |
762 | while (size-- > 0) | |
763 | { | |
764 | *--p = val; | |
765 | val >>= 8; | |
766 | } | |
767 | } | |
768 | else | |
769 | { | |
770 | while (size-- > 0) | |
771 | { | |
772 | *p++ = val; | |
773 | val >>= 8; | |
774 | } | |
775 | } | |
776 | } | |
777 | ||
778 | /* Translate a host's stat struct into a target's. | |
779 | If HS is NULL, just compute the length of the buffer required, | |
780 | TS is ignored. | |
781 | ||
782 | The result is the size of the target's stat struct, | |
6439295f | 783 | or zero if an error occurred during the translation. */ |
c906108c SS |
784 | |
785 | int | |
786 | cb_host_to_target_stat (cb, hs, ts) | |
787 | host_callback *cb; | |
788 | const struct stat *hs; | |
789 | PTR ts; | |
790 | { | |
791 | const char *m = cb->stat_map; | |
792 | char *p; | |
793 | int big_p = 0; | |
794 | ||
795 | if (hs == NULL) | |
796 | ts = NULL; | |
797 | p = ts; | |
798 | ||
799 | while (m) | |
800 | { | |
801 | char *q = strchr (m, ','); | |
802 | int size; | |
803 | ||
804 | /* FIXME: Use sscanf? */ | |
805 | if (q == NULL) | |
806 | { | |
807 | /* FIXME: print error message */ | |
808 | return 0; | |
809 | } | |
810 | size = atoi (q + 1); | |
811 | if (size == 0) | |
812 | { | |
813 | /* FIXME: print error message */ | |
814 | return 0; | |
815 | } | |
816 | ||
817 | if (hs != NULL) | |
818 | { | |
819 | if (strncmp (m, "st_dev", q - m) == 0) | |
820 | store (p, size, hs->st_dev, big_p); | |
821 | else if (strncmp (m, "st_ino", q - m) == 0) | |
822 | store (p, size, hs->st_ino, big_p); | |
823 | /* FIXME:wip */ | |
824 | else | |
825 | store (p, size, 0, big_p); /* unsupported field, store 0 */ | |
826 | } | |
827 | ||
828 | p += size; | |
829 | m = strchr (q, ':'); | |
830 | if (m) | |
831 | ++m; | |
832 | } | |
833 | ||
834 | return p - (char *) ts; | |
835 | } | |
836 | \f | |
837 | /* Cover functions to the vfprintf callbacks. | |
838 | ||
839 | ??? If one thinks of the callbacks as a subsystem onto itself [or part of | |
840 | a larger "remote target subsystem"] with a well defined interface, then | |
841 | one would think that the subsystem would provide these. However, until | |
842 | one is allowed to create such a subsystem (with its own source tree | |
843 | independent of any particular user), such a critter can't exist. Thus | |
844 | these functions are here for the time being. */ | |
845 | ||
846 | void | |
847 | sim_cb_printf (host_callback *p, const char *fmt, ...) | |
848 | { | |
849 | va_list ap; | |
850 | ||
851 | va_start (ap, fmt); | |
852 | p->vprintf_filtered (p, fmt, ap); | |
853 | va_end (ap); | |
854 | } | |
855 | ||
856 | void | |
857 | sim_cb_eprintf (host_callback *p, const char *fmt, ...) | |
858 | { | |
859 | va_list ap; | |
860 | ||
861 | va_start (ap, fmt); | |
862 | p->evprintf_filtered (p, fmt, ap); | |
863 | va_end (ap); | |
864 | } |