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 | ||
0d3cd463 HPN |
410 | static int |
411 | os_lstat (p, file, buf) | |
412 | host_callback *p; | |
413 | const char *file; | |
414 | struct stat *buf; | |
415 | { | |
416 | /* NOTE: hpn/2004-12-12: Same issue here as with os_fstat. */ | |
417 | return wrap (p, lstat (file, buf)); | |
418 | } | |
419 | ||
8822d001 JR |
420 | static int |
421 | os_ftruncate (p, fd, len) | |
422 | host_callback *p; | |
423 | int fd; | |
424 | long len; | |
425 | { | |
426 | int result; | |
427 | ||
428 | result = fdbad (p, fd); | |
429 | if (result) | |
430 | return result; | |
431 | result = wrap (p, ftruncate (fdmap (p, fd), len)); | |
432 | return result; | |
433 | } | |
434 | ||
435 | static int | |
436 | os_truncate (p, file, len) | |
437 | host_callback *p; | |
438 | const char *file; | |
439 | long len; | |
440 | { | |
ee3073b5 | 441 | return wrap (p, truncate (file, len)); |
8822d001 JR |
442 | } |
443 | ||
c906108c SS |
444 | static int |
445 | os_shutdown (p) | |
446 | host_callback *p; | |
447 | { | |
594ee3a7 | 448 | int i, next, j; |
c906108c SS |
449 | for (i = 0; i < MAX_CALLBACK_FDS; i++) |
450 | { | |
594ee3a7 JR |
451 | int do_close = 1; |
452 | ||
453 | next = p->fd_buddy[i]; | |
454 | if (next < 0) | |
455 | continue; | |
456 | do | |
457 | { | |
458 | j = next; | |
459 | if (j == MAX_CALLBACK_FDS) | |
460 | do_close = 0; | |
461 | next = p->fd_buddy[j]; | |
462 | p->fd_buddy[j] = -1; | |
463 | /* At the initial call of os_init, we got -1, 0, 0, 0, ... */ | |
464 | if (next < 0) | |
465 | { | |
0242f9ea | 466 | p->fd_buddy[i] = -1; |
594ee3a7 JR |
467 | do_close = 0; |
468 | break; | |
469 | } | |
470 | } | |
471 | while (j != i); | |
472 | if (do_close) | |
c906108c | 473 | close (p->fdmap[i]); |
c906108c SS |
474 | } |
475 | return 1; | |
476 | } | |
477 | ||
478 | static int | |
479 | os_init (p) | |
480 | host_callback *p; | |
481 | { | |
482 | int i; | |
483 | ||
484 | os_shutdown (p); | |
485 | for (i = 0; i < 3; i++) | |
486 | { | |
487 | p->fdmap[i] = i; | |
594ee3a7 | 488 | p->fd_buddy[i] = i - 1; |
c906108c | 489 | } |
594ee3a7 JR |
490 | p->fd_buddy[0] = MAX_CALLBACK_FDS; |
491 | p->fd_buddy[MAX_CALLBACK_FDS] = 2; | |
c906108c SS |
492 | |
493 | p->syscall_map = cb_init_syscall_map; | |
494 | p->errno_map = cb_init_errno_map; | |
495 | p->open_map = cb_init_open_map; | |
496 | ||
497 | return 1; | |
498 | } | |
499 | ||
5accf1ff | 500 | /* DEPRECATED */ |
c906108c SS |
501 | |
502 | /* VARARGS */ | |
503 | static void | |
504 | #ifdef ANSI_PROTOTYPES | |
6d358e86 | 505 | os_printf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...) |
c906108c SS |
506 | #else |
507 | os_printf_filtered (p, va_alist) | |
508 | host_callback *p; | |
509 | va_dcl | |
510 | #endif | |
511 | { | |
512 | va_list args; | |
513 | #ifdef ANSI_PROTOTYPES | |
514 | va_start (args, format); | |
515 | #else | |
516 | char *format; | |
517 | ||
518 | va_start (args); | |
519 | format = va_arg (args, char *); | |
520 | #endif | |
521 | ||
522 | vfprintf (stdout, format, args); | |
523 | va_end (args); | |
524 | } | |
525 | ||
526 | /* VARARGS */ | |
527 | static void | |
528 | #ifdef ANSI_PROTOTYPES | |
6d358e86 | 529 | os_vprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args) |
c906108c SS |
530 | #else |
531 | os_vprintf_filtered (p, format, args) | |
532 | host_callback *p; | |
533 | const char *format; | |
534 | va_list args; | |
535 | #endif | |
536 | { | |
537 | vprintf (format, args); | |
538 | } | |
539 | ||
540 | /* VARARGS */ | |
541 | static void | |
542 | #ifdef ANSI_PROTOTYPES | |
6d358e86 | 543 | os_evprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args) |
c906108c SS |
544 | #else |
545 | os_evprintf_filtered (p, format, args) | |
546 | host_callback *p; | |
547 | const char *format; | |
548 | va_list args; | |
549 | #endif | |
550 | { | |
551 | vfprintf (stderr, format, args); | |
552 | } | |
553 | ||
554 | /* VARARGS */ | |
555 | static void | |
556 | #ifdef ANSI_PROTOTYPES | |
6d358e86 | 557 | os_error (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...) |
c906108c SS |
558 | #else |
559 | os_error (p, va_alist) | |
560 | host_callback *p; | |
561 | va_dcl | |
562 | #endif | |
563 | { | |
564 | va_list args; | |
565 | #ifdef ANSI_PROTOTYPES | |
566 | va_start (args, format); | |
567 | #else | |
568 | char *format; | |
569 | ||
570 | va_start (args); | |
571 | format = va_arg (args, char *); | |
572 | #endif | |
573 | ||
574 | vfprintf (stderr, format, args); | |
575 | fprintf (stderr, "\n"); | |
576 | ||
577 | va_end (args); | |
578 | exit (1); | |
579 | } | |
580 | ||
581 | host_callback default_callback = | |
582 | { | |
583 | os_close, | |
584 | os_get_errno, | |
585 | os_isatty, | |
586 | os_lseek, | |
587 | os_open, | |
588 | os_read, | |
589 | os_read_stdin, | |
590 | os_rename, | |
591 | os_system, | |
592 | os_time, | |
593 | os_unlink, | |
594 | os_write, | |
595 | os_write_stdout, | |
596 | os_flush_stdout, | |
597 | os_write_stderr, | |
598 | os_flush_stderr, | |
599 | ||
600 | os_stat, | |
601 | os_fstat, | |
0d3cd463 | 602 | os_lstat, |
c906108c | 603 | |
8822d001 JR |
604 | os_ftruncate, |
605 | os_truncate, | |
606 | ||
c906108c SS |
607 | os_poll_quit, |
608 | ||
609 | os_shutdown, | |
610 | os_init, | |
611 | ||
612 | os_printf_filtered, /* deprecated */ | |
613 | ||
614 | os_vprintf_filtered, | |
615 | os_evprintf_filtered, | |
616 | os_error, | |
617 | ||
618 | 0, /* last errno */ | |
619 | ||
620 | { 0, }, /* fdmap */ | |
594ee3a7 | 621 | { -1, }, /* fd_buddy */ |
c906108c SS |
622 | |
623 | 0, /* syscall_map */ | |
624 | 0, /* errno_map */ | |
625 | 0, /* open_map */ | |
626 | 0, /* signal_map */ | |
627 | 0, /* stat_map */ | |
628 | ||
629 | HOST_CALLBACK_MAGIC, | |
630 | }; | |
631 | \f | |
632 | /* Read in a file describing the target's system call values. | |
633 | E.g. maybe someone will want to use something other than newlib. | |
634 | This assumes that the basic system call recognition and value passing/ | |
635 | returning is supported. So maybe some coding/recompilation will be | |
636 | necessary, but not as much. | |
637 | ||
638 | If an error occurs, the existing mapping is not changed. */ | |
639 | ||
640 | CB_RC | |
641 | cb_read_target_syscall_maps (cb, file) | |
642 | host_callback *cb; | |
643 | const char *file; | |
644 | { | |
645 | CB_TARGET_DEFS_MAP *syscall_map, *errno_map, *open_map, *signal_map; | |
646 | const char *stat_map; | |
647 | FILE *f; | |
648 | ||
649 | if ((f = fopen (file, "r")) == NULL) | |
650 | return CB_RC_ACCESS; | |
651 | ||
652 | /* ... read in and parse file ... */ | |
653 | ||
654 | fclose (f); | |
655 | return CB_RC_NO_MEM; /* FIXME:wip */ | |
656 | ||
657 | /* Free storage allocated for any existing maps. */ | |
658 | if (cb->syscall_map) | |
659 | free (cb->syscall_map); | |
660 | if (cb->errno_map) | |
661 | free (cb->errno_map); | |
662 | if (cb->open_map) | |
663 | free (cb->open_map); | |
664 | if (cb->signal_map) | |
665 | free (cb->signal_map); | |
666 | if (cb->stat_map) | |
667 | free ((PTR) cb->stat_map); | |
668 | ||
669 | cb->syscall_map = syscall_map; | |
670 | cb->errno_map = errno_map; | |
671 | cb->open_map = open_map; | |
672 | cb->signal_map = signal_map; | |
673 | cb->stat_map = stat_map; | |
674 | ||
675 | return CB_RC_OK; | |
676 | } | |
677 | ||
678 | /* Translate the target's version of a syscall number to the host's. | |
679 | This isn't actually the host's version, rather a canonical form. | |
680 | ??? Perhaps this should be renamed to ..._canon_syscall. */ | |
681 | ||
682 | int | |
683 | cb_target_to_host_syscall (cb, target_val) | |
684 | host_callback *cb; | |
685 | int target_val; | |
686 | { | |
687 | CB_TARGET_DEFS_MAP *m; | |
688 | ||
689 | for (m = &cb->syscall_map[0]; m->target_val != -1; ++m) | |
690 | if (m->target_val == target_val) | |
691 | return m->host_val; | |
692 | ||
693 | return -1; | |
694 | } | |
695 | ||
696 | /* FIXME: sort tables if large. | |
697 | Alternatively, an obvious improvement for errno conversion is | |
698 | to machine generate a function with a large switch(). */ | |
699 | ||
700 | /* Translate the host's version of errno to the target's. */ | |
701 | ||
702 | int | |
703 | cb_host_to_target_errno (cb, host_val) | |
704 | host_callback *cb; | |
705 | int host_val; | |
706 | { | |
707 | CB_TARGET_DEFS_MAP *m; | |
708 | ||
709 | for (m = &cb->errno_map[0]; m->host_val; ++m) | |
710 | if (m->host_val == host_val) | |
711 | return m->target_val; | |
712 | ||
713 | /* ??? Which error to return in this case is up for grabs. | |
714 | Note that some missing values may have standard alternatives. | |
715 | For now return 0 and require caller to deal with it. */ | |
716 | return 0; | |
717 | } | |
718 | ||
719 | /* Given a set of target bitmasks for the open system call, | |
720 | return the host equivalent. | |
721 | Mapping open flag values is best done by looping so there's no need | |
722 | to machine generate this function. */ | |
723 | ||
724 | int | |
725 | cb_target_to_host_open (cb, target_val) | |
726 | host_callback *cb; | |
727 | int target_val; | |
728 | { | |
729 | int host_val = 0; | |
730 | CB_TARGET_DEFS_MAP *m; | |
731 | ||
732 | for (m = &cb->open_map[0]; m->host_val != -1; ++m) | |
733 | { | |
734 | switch (m->target_val) | |
735 | { | |
736 | /* O_RDONLY can be (and usually is) 0 which needs to be treated | |
737 | specially. */ | |
738 | case TARGET_O_RDONLY : | |
739 | case TARGET_O_WRONLY : | |
740 | case TARGET_O_RDWR : | |
741 | if ((target_val & (TARGET_O_RDONLY | TARGET_O_WRONLY | TARGET_O_RDWR)) | |
742 | == m->target_val) | |
743 | host_val |= m->host_val; | |
744 | /* Handle the host/target differentiating between binary and | |
745 | text mode. Only one case is of importance */ | |
746 | #if ! defined (TARGET_O_BINARY) && defined (O_BINARY) | |
747 | host_val |= O_BINARY; | |
748 | #endif | |
749 | break; | |
750 | default : | |
751 | if ((m->target_val & target_val) == m->target_val) | |
752 | host_val |= m->host_val; | |
753 | break; | |
754 | } | |
755 | } | |
756 | ||
757 | return host_val; | |
758 | } | |
759 | ||
760 | /* Utility for cb_host_to_target_stat to store values in the target's | |
761 | stat struct. */ | |
762 | ||
763 | static void | |
764 | store (p, size, val, big_p) | |
765 | char *p; | |
766 | int size; | |
767 | long val; /* ??? must be as big as target word size */ | |
768 | int big_p; | |
769 | { | |
770 | if (big_p) | |
771 | { | |
772 | p += size; | |
773 | while (size-- > 0) | |
774 | { | |
775 | *--p = val; | |
776 | val >>= 8; | |
777 | } | |
778 | } | |
779 | else | |
780 | { | |
781 | while (size-- > 0) | |
782 | { | |
783 | *p++ = val; | |
784 | val >>= 8; | |
785 | } | |
786 | } | |
787 | } | |
788 | ||
789 | /* Translate a host's stat struct into a target's. | |
790 | If HS is NULL, just compute the length of the buffer required, | |
791 | TS is ignored. | |
792 | ||
793 | The result is the size of the target's stat struct, | |
6439295f | 794 | or zero if an error occurred during the translation. */ |
c906108c SS |
795 | |
796 | int | |
797 | cb_host_to_target_stat (cb, hs, ts) | |
798 | host_callback *cb; | |
799 | const struct stat *hs; | |
800 | PTR ts; | |
801 | { | |
802 | const char *m = cb->stat_map; | |
803 | char *p; | |
804 | int big_p = 0; | |
805 | ||
806 | if (hs == NULL) | |
807 | ts = NULL; | |
808 | p = ts; | |
809 | ||
810 | while (m) | |
811 | { | |
812 | char *q = strchr (m, ','); | |
813 | int size; | |
814 | ||
815 | /* FIXME: Use sscanf? */ | |
816 | if (q == NULL) | |
817 | { | |
818 | /* FIXME: print error message */ | |
819 | return 0; | |
820 | } | |
821 | size = atoi (q + 1); | |
822 | if (size == 0) | |
823 | { | |
824 | /* FIXME: print error message */ | |
825 | return 0; | |
826 | } | |
827 | ||
828 | if (hs != NULL) | |
829 | { | |
e1591da4 | 830 | if (0) |
697afb65 HPN |
831 | ; |
832 | /* Defined here to avoid emacs indigestion on a lone "else". */ | |
833 | #undef ST_x | |
834 | #define ST_x(FLD) \ | |
835 | else if (strncmp (m, #FLD, q - m) == 0) \ | |
836 | store (p, size, hs->FLD, big_p) | |
837 | ||
838 | #ifdef HAVE_STRUCT_STAT_ST_DEV | |
839 | ST_x (st_dev); | |
840 | #endif | |
841 | #ifdef HAVE_STRUCT_STAT_ST_INO | |
842 | ST_x (st_ino); | |
843 | #endif | |
844 | #ifdef HAVE_STRUCT_STAT_ST_MODE | |
845 | ST_x (st_mode); | |
846 | #endif | |
847 | #ifdef HAVE_STRUCT_STAT_ST_NLINK | |
848 | ST_x (st_nlink); | |
849 | #endif | |
850 | #ifdef HAVE_STRUCT_STAT_ST_UID | |
851 | ST_x (st_uid); | |
852 | #endif | |
853 | #ifdef HAVE_STRUCT_STAT_ST_GID | |
854 | ST_x (st_gid); | |
855 | #endif | |
856 | #ifdef HAVE_STRUCT_STAT_ST_RDEV | |
857 | ST_x (st_rdev); | |
858 | #endif | |
859 | #ifdef HAVE_STRUCT_STAT_ST_SIZE | |
860 | ST_x (st_size); | |
861 | #endif | |
862 | #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE | |
863 | ST_x (st_blksize); | |
864 | #endif | |
865 | #ifdef HAVE_STRUCT_STAT_ST_BLOCKS | |
866 | ST_x (st_blocks); | |
867 | #endif | |
868 | #ifdef HAVE_STRUCT_STAT_ST_ATIME | |
869 | ST_x (st_atime); | |
870 | #endif | |
871 | #ifdef HAVE_STRUCT_STAT_ST_MTIME | |
872 | ST_x (st_mtime); | |
873 | #endif | |
874 | #ifdef HAVE_STRUCT_STAT_ST_CTIME | |
875 | ST_x (st_ctime); | |
876 | #endif | |
877 | #undef ST_x | |
c906108c SS |
878 | /* FIXME:wip */ |
879 | else | |
880 | store (p, size, 0, big_p); /* unsupported field, store 0 */ | |
881 | } | |
882 | ||
883 | p += size; | |
884 | m = strchr (q, ':'); | |
885 | if (m) | |
886 | ++m; | |
887 | } | |
888 | ||
889 | return p - (char *) ts; | |
890 | } | |
891 | \f | |
892 | /* Cover functions to the vfprintf callbacks. | |
893 | ||
894 | ??? If one thinks of the callbacks as a subsystem onto itself [or part of | |
895 | a larger "remote target subsystem"] with a well defined interface, then | |
896 | one would think that the subsystem would provide these. However, until | |
897 | one is allowed to create such a subsystem (with its own source tree | |
898 | independent of any particular user), such a critter can't exist. Thus | |
899 | these functions are here for the time being. */ | |
900 | ||
901 | void | |
902 | sim_cb_printf (host_callback *p, const char *fmt, ...) | |
903 | { | |
904 | va_list ap; | |
905 | ||
906 | va_start (ap, fmt); | |
907 | p->vprintf_filtered (p, fmt, ap); | |
908 | va_end (ap); | |
909 | } | |
910 | ||
911 | void | |
912 | sim_cb_eprintf (host_callback *p, const char *fmt, ...) | |
913 | { | |
914 | va_list ap; | |
915 | ||
916 | va_start (ap, fmt); | |
917 | p->evprintf_filtered (p, fmt, ap); | |
918 | va_end (ap); | |
919 | } |