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