]>
Commit | Line | Data |
---|---|---|
c906108c | 1 | /* Remote target callback routines. |
3666a048 | 2 | Copyright 1995-2021 Free Software Foundation, Inc. |
c906108c SS |
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 | |
4744ac1b | 9 | the Free Software Foundation; either version 3 of the License, or |
c906108c SS |
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 | |
4744ac1b | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
c906108c SS |
19 | |
20 | /* This file provides a standard way for targets to talk to the host OS | |
21 | level. */ | |
22 | ||
23 | #ifdef HAVE_CONFIG_H | |
a6ff997c | 24 | #include "config.h" |
936df756 | 25 | #endif |
c906108c | 26 | #include "ansidecl.h" |
c906108c | 27 | #include <stdarg.h> |
c906108c | 28 | #include <stdio.h> |
c906108c | 29 | #include <stdlib.h> |
c906108c | 30 | #include <string.h> |
97f669ed HPN |
31 | /* For PIPE_BUF. */ |
32 | #include <limits.h> | |
c906108c SS |
33 | #include <errno.h> |
34 | #include <fcntl.h> | |
35 | #include <time.h> | |
36 | #include <sys/types.h> | |
37 | #include <sys/stat.h> | |
3c25f8c7 | 38 | #include "gdb/callback.h" |
c906108c | 39 | #include "targ-vals.h" |
97f669ed HPN |
40 | /* For xmalloc. */ |
41 | #include "libiberty.h" | |
c906108c SS |
42 | |
43 | #ifdef HAVE_UNISTD_H | |
44 | #include <unistd.h> | |
45 | #endif | |
46 | ||
33aa0cbb PB |
47 | #ifndef PIPE_BUF |
48 | #define PIPE_BUF 512 | |
49 | #endif | |
50 | ||
c906108c SS |
51 | /* ??? sim_cb_printf should be cb_printf, but until the callback support is |
52 | broken out of the simulator directory, these are here to not require | |
53 | sim-utils.h. */ | |
bdca5ee4 TT |
54 | void sim_cb_printf (host_callback *, const char *, ...); |
55 | void sim_cb_eprintf (host_callback *, const char *, ...); | |
c906108c SS |
56 | |
57 | extern CB_TARGET_DEFS_MAP cb_init_syscall_map[]; | |
58 | extern CB_TARGET_DEFS_MAP cb_init_errno_map[]; | |
59 | extern CB_TARGET_DEFS_MAP cb_init_open_map[]; | |
60 | ||
c906108c SS |
61 | /* Set the callback copy of errno from what we see now. */ |
62 | ||
028f6515 | 63 | static int |
1a8a700e | 64 | wrap (host_callback *p, int val) |
c906108c SS |
65 | { |
66 | p->last_errno = errno; | |
67 | return val; | |
68 | } | |
69 | ||
70 | /* Make sure the FD provided is ok. If not, return non-zero | |
71 | and set errno. */ | |
72 | ||
028f6515 | 73 | static int |
1a8a700e | 74 | fdbad (host_callback *p, int fd) |
c906108c | 75 | { |
594ee3a7 | 76 | if (fd < 0 || fd > MAX_CALLBACK_FDS || p->fd_buddy[fd] < 0) |
c906108c | 77 | { |
fee17b35 | 78 | p->last_errno = EBADF; |
c906108c SS |
79 | return -1; |
80 | } | |
81 | return 0; | |
82 | } | |
83 | ||
028f6515 | 84 | static int |
1a8a700e | 85 | fdmap (host_callback *p, int fd) |
c906108c SS |
86 | { |
87 | return p->fdmap[fd]; | |
88 | } | |
89 | ||
028f6515 | 90 | static int |
1a8a700e | 91 | os_close (host_callback *p, int fd) |
c906108c SS |
92 | { |
93 | int result; | |
594ee3a7 | 94 | int i, next; |
c906108c SS |
95 | |
96 | result = fdbad (p, fd); | |
97 | if (result) | |
98 | return result; | |
594ee3a7 JR |
99 | /* If this file descripter has one or more buddies (originals / |
100 | duplicates from a dup), just remove it from the circular list. */ | |
101 | for (i = fd; (next = p->fd_buddy[i]) != fd; ) | |
102 | i = next; | |
103 | if (fd != i) | |
104 | p->fd_buddy[i] = p->fd_buddy[fd]; | |
105 | else | |
97f669ed HPN |
106 | { |
107 | if (p->ispipe[fd]) | |
108 | { | |
109 | int other = p->ispipe[fd]; | |
110 | int reader, writer; | |
111 | ||
112 | if (other > 0) | |
113 | { | |
114 | /* Closing the read side. */ | |
115 | reader = fd; | |
116 | writer = other; | |
117 | } | |
118 | else | |
119 | { | |
120 | /* Closing the write side. */ | |
121 | writer = fd; | |
122 | reader = -other; | |
123 | } | |
124 | ||
125 | /* If there was data in the buffer, make a last "now empty" | |
126 | call, then deallocate data. */ | |
127 | if (p->pipe_buffer[writer].buffer != NULL) | |
128 | { | |
129 | (*p->pipe_empty) (p, reader, writer); | |
130 | free (p->pipe_buffer[writer].buffer); | |
131 | p->pipe_buffer[writer].buffer = NULL; | |
132 | } | |
133 | ||
134 | /* Clear pipe data for this side. */ | |
135 | p->pipe_buffer[fd].size = 0; | |
136 | p->ispipe[fd] = 0; | |
137 | ||
138 | /* If this was the first close, mark the other side as the | |
139 | only remaining side. */ | |
140 | if (fd != abs (other)) | |
141 | p->ispipe[abs (other)] = -other; | |
142 | p->fd_buddy[fd] = -1; | |
143 | return 0; | |
144 | } | |
145 | ||
146 | result = wrap (p, close (fdmap (p, fd))); | |
147 | } | |
594ee3a7 | 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 | |
1a8a700e | 159 | os_poll_quit (host_callback *p) |
c906108c SS |
160 | { |
161 | #if defined(__GO32__) | |
162 | int kbhit (); | |
163 | int getkey (); | |
164 | if (kbhit ()) | |
165 | { | |
166 | int k = getkey (); | |
167 | if (k == 1) | |
168 | { | |
169 | return 1; | |
170 | } | |
171 | else if (k == 2) | |
172 | { | |
173 | return 1; | |
174 | } | |
028f6515 | 175 | else |
c906108c SS |
176 | { |
177 | sim_cb_eprintf (p, "CTRL-A to quit, CTRL-B to quit harder\n"); | |
178 | } | |
179 | } | |
180 | #endif | |
181 | #if defined (_MSC_VER) | |
182 | /* NB - this will not compile! */ | |
34b47c38 | 183 | int k = win32pollquit (); |
c906108c SS |
184 | if (k == 1) |
185 | return 1; | |
186 | else if (k == 2) | |
187 | return 1; | |
188 | #endif | |
189 | return 0; | |
190 | } | |
191 | #else | |
192 | #define os_poll_quit 0 | |
193 | #endif /* defined(__GO32__) || defined(_MSC_VER) */ | |
194 | ||
028f6515 | 195 | static int |
1a8a700e | 196 | os_get_errno (host_callback *p) |
c906108c SS |
197 | { |
198 | return cb_host_to_target_errno (p, p->last_errno); | |
199 | } | |
200 | ||
201 | ||
028f6515 | 202 | static int |
1a8a700e | 203 | os_isatty (host_callback *p, int fd) |
c906108c SS |
204 | { |
205 | int result; | |
206 | ||
207 | result = fdbad (p, fd); | |
208 | if (result) | |
209 | return result; | |
210 | result = wrap (p, isatty (fdmap (p, fd))); | |
211 | ||
212 | return result; | |
213 | } | |
214 | ||
028f6515 | 215 | static int |
1a8a700e | 216 | os_lseek (host_callback *p, int fd, long off, int way) |
c906108c SS |
217 | { |
218 | int result; | |
219 | ||
220 | result = fdbad (p, fd); | |
221 | if (result) | |
222 | return result; | |
0bd15c7f | 223 | result = wrap (p, lseek (fdmap (p, fd), off, way)); |
c906108c SS |
224 | return result; |
225 | } | |
226 | ||
028f6515 | 227 | static int |
1a8a700e | 228 | os_open (host_callback *p, const char *name, int flags) |
c906108c SS |
229 | { |
230 | int i; | |
231 | for (i = 0; i < MAX_CALLBACK_FDS; i++) | |
232 | { | |
594ee3a7 | 233 | if (p->fd_buddy[i] < 0) |
c906108c SS |
234 | { |
235 | int f = open (name, cb_target_to_host_open (p, flags), 0644); | |
236 | if (f < 0) | |
237 | { | |
238 | p->last_errno = errno; | |
239 | return f; | |
240 | } | |
594ee3a7 | 241 | p->fd_buddy[i] = i; |
c906108c SS |
242 | p->fdmap[i] = f; |
243 | return i; | |
244 | } | |
245 | } | |
246 | p->last_errno = EMFILE; | |
247 | return -1; | |
248 | } | |
249 | ||
028f6515 | 250 | static int |
1a8a700e | 251 | os_read (host_callback *p, int fd, char *buf, int len) |
c906108c SS |
252 | { |
253 | int result; | |
254 | ||
255 | result = fdbad (p, fd); | |
256 | if (result) | |
257 | return result; | |
97f669ed HPN |
258 | if (p->ispipe[fd]) |
259 | { | |
260 | int writer = p->ispipe[fd]; | |
261 | ||
262 | /* Can't read from the write-end. */ | |
263 | if (writer < 0) | |
264 | { | |
265 | p->last_errno = EBADF; | |
266 | return -1; | |
267 | } | |
268 | ||
269 | /* Nothing to read if nothing is written. */ | |
270 | if (p->pipe_buffer[writer].size == 0) | |
271 | return 0; | |
272 | ||
273 | /* Truncate read request size to buffer size minus what's already | |
274 | read. */ | |
275 | if (len > p->pipe_buffer[writer].size - p->pipe_buffer[fd].size) | |
276 | len = p->pipe_buffer[writer].size - p->pipe_buffer[fd].size; | |
277 | ||
278 | memcpy (buf, p->pipe_buffer[writer].buffer + p->pipe_buffer[fd].size, | |
279 | len); | |
280 | ||
281 | /* Account for what we just read. */ | |
282 | p->pipe_buffer[fd].size += len; | |
283 | ||
284 | /* If we've read everything, empty and deallocate the buffer and | |
285 | signal buffer-empty to client. (This isn't expected to be a | |
286 | hot path in the simulator, so we don't hold on to the buffer.) */ | |
287 | if (p->pipe_buffer[fd].size == p->pipe_buffer[writer].size) | |
288 | { | |
289 | free (p->pipe_buffer[writer].buffer); | |
290 | p->pipe_buffer[writer].buffer = NULL; | |
291 | p->pipe_buffer[fd].size = 0; | |
292 | p->pipe_buffer[writer].size = 0; | |
293 | (*p->pipe_empty) (p, fd, writer); | |
294 | } | |
295 | ||
296 | return len; | |
297 | } | |
298 | ||
c906108c SS |
299 | result = wrap (p, read (fdmap (p, fd), buf, len)); |
300 | return result; | |
301 | } | |
302 | ||
028f6515 | 303 | static int |
1a8a700e | 304 | os_read_stdin (host_callback *p, char *buf, int len) |
c906108c SS |
305 | { |
306 | return wrap (p, read (0, buf, len)); | |
307 | } | |
308 | ||
028f6515 | 309 | static int |
1a8a700e | 310 | os_write (host_callback *p, int fd, const char *buf, int len) |
c906108c SS |
311 | { |
312 | int result; | |
313 | int real_fd; | |
314 | ||
315 | result = fdbad (p, fd); | |
316 | if (result) | |
317 | return result; | |
97f669ed HPN |
318 | |
319 | if (p->ispipe[fd]) | |
320 | { | |
321 | int reader = -p->ispipe[fd]; | |
322 | ||
323 | /* Can't write to the read-end. */ | |
324 | if (reader < 0) | |
325 | { | |
326 | p->last_errno = EBADF; | |
327 | return -1; | |
328 | } | |
329 | ||
330 | /* Can't write to pipe with closed read end. | |
331 | FIXME: We should send a SIGPIPE. */ | |
332 | if (reader == fd) | |
333 | { | |
334 | p->last_errno = EPIPE; | |
335 | return -1; | |
336 | } | |
337 | ||
338 | /* As a sanity-check, we bail out it the buffered contents is much | |
339 | larger than the size of the buffer on the host. We don't want | |
340 | to run out of memory in the simulator due to a target program | |
341 | bug if we can help it. Unfortunately, regarding the value that | |
342 | reaches the simulated program, it's no use returning *less* | |
343 | than the requested amount, because cb_syscall loops calling | |
344 | this function until the whole amount is done. */ | |
345 | if (p->pipe_buffer[fd].size + len > 10 * PIPE_BUF) | |
346 | { | |
347 | p->last_errno = EFBIG; | |
348 | return -1; | |
349 | } | |
350 | ||
351 | p->pipe_buffer[fd].buffer | |
352 | = xrealloc (p->pipe_buffer[fd].buffer, p->pipe_buffer[fd].size + len); | |
353 | memcpy (p->pipe_buffer[fd].buffer + p->pipe_buffer[fd].size, | |
354 | buf, len); | |
355 | p->pipe_buffer[fd].size += len; | |
356 | ||
357 | (*p->pipe_nonempty) (p, reader, fd); | |
358 | return len; | |
359 | } | |
360 | ||
c906108c SS |
361 | real_fd = fdmap (p, fd); |
362 | switch (real_fd) | |
363 | { | |
364 | default: | |
365 | result = wrap (p, write (real_fd, buf, len)); | |
366 | break; | |
367 | case 1: | |
368 | result = p->write_stdout (p, buf, len); | |
369 | break; | |
370 | case 2: | |
371 | result = p->write_stderr (p, buf, len); | |
372 | break; | |
373 | } | |
374 | return result; | |
375 | } | |
376 | ||
028f6515 | 377 | static int |
1a8a700e | 378 | os_write_stdout (host_callback *p ATTRIBUTE_UNUSED, const char *buf, int len) |
c906108c SS |
379 | { |
380 | return fwrite (buf, 1, len, stdout); | |
381 | } | |
382 | ||
383 | static void | |
1a8a700e | 384 | os_flush_stdout (host_callback *p ATTRIBUTE_UNUSED) |
c906108c SS |
385 | { |
386 | fflush (stdout); | |
387 | } | |
388 | ||
028f6515 | 389 | static int |
1a8a700e | 390 | os_write_stderr (host_callback *p ATTRIBUTE_UNUSED, const char *buf, int len) |
c906108c SS |
391 | { |
392 | return fwrite (buf, 1, len, stderr); | |
393 | } | |
394 | ||
395 | static void | |
1a8a700e | 396 | os_flush_stderr (host_callback *p ATTRIBUTE_UNUSED) |
c906108c SS |
397 | { |
398 | fflush (stderr); | |
399 | } | |
400 | ||
028f6515 | 401 | static int |
1a8a700e | 402 | os_rename (host_callback *p, const char *f1, const char *f2) |
c906108c SS |
403 | { |
404 | return wrap (p, rename (f1, f2)); | |
405 | } | |
406 | ||
407 | ||
408 | static int | |
1a8a700e | 409 | os_system (host_callback *p, const char *s) |
c906108c SS |
410 | { |
411 | return wrap (p, system (s)); | |
412 | } | |
413 | ||
028f6515 | 414 | static long |
1a8a700e | 415 | os_time (host_callback *p, long *t) |
c906108c SS |
416 | { |
417 | return wrap (p, time (t)); | |
418 | } | |
419 | ||
420 | ||
028f6515 | 421 | static int |
1a8a700e | 422 | os_unlink (host_callback *p, const char *f1) |
c906108c SS |
423 | { |
424 | return wrap (p, unlink (f1)); | |
425 | } | |
426 | ||
427 | static int | |
1a8a700e | 428 | os_stat (host_callback *p, const char *file, struct stat *buf) |
c906108c SS |
429 | { |
430 | /* ??? There is an issue of when to translate to the target layout. | |
431 | One could do that inside this function, or one could have the | |
432 | caller do it. It's more flexible to let the caller do it, though | |
433 | I'm not sure the flexibility will ever be useful. */ | |
434 | return wrap (p, stat (file, buf)); | |
435 | } | |
436 | ||
437 | static int | |
1a8a700e | 438 | os_fstat (host_callback *p, int fd, struct stat *buf) |
c906108c SS |
439 | { |
440 | if (fdbad (p, fd)) | |
441 | return -1; | |
97f669ed HPN |
442 | |
443 | if (p->ispipe[fd]) | |
444 | { | |
0c4507fd | 445 | #if defined (HAVE_STRUCT_STAT_ST_ATIME) || defined (HAVE_STRUCT_STAT_ST_CTIME) || defined (HAVE_STRUCT_STAT_ST_MTIME) |
97f669ed | 446 | time_t t = (*p->time) (p, NULL); |
0c4507fd | 447 | #endif |
97f669ed HPN |
448 | |
449 | /* We have to fake the struct stat contents, since the pipe is | |
450 | made up in the simulator. */ | |
451 | memset (buf, 0, sizeof (*buf)); | |
452 | ||
453 | #ifdef HAVE_STRUCT_STAT_ST_MODE | |
454 | buf->st_mode = S_IFIFO; | |
455 | #endif | |
456 | ||
457 | /* If more accurate tracking than current-time is needed (for | |
458 | example, on GNU/Linux we get accurate numbers), the p->time | |
459 | callback (which may be something other than os_time) should | |
460 | happen for each read and write, and we'd need to keep track of | |
461 | atime, ctime and mtime. */ | |
462 | #ifdef HAVE_STRUCT_STAT_ST_ATIME | |
463 | buf->st_atime = t; | |
464 | #endif | |
465 | #ifdef HAVE_STRUCT_STAT_ST_CTIME | |
466 | buf->st_ctime = t; | |
467 | #endif | |
468 | #ifdef HAVE_STRUCT_STAT_ST_MTIME | |
469 | buf->st_mtime = t; | |
470 | #endif | |
471 | return 0; | |
472 | } | |
473 | ||
c906108c SS |
474 | /* ??? There is an issue of when to translate to the target layout. |
475 | One could do that inside this function, or one could have the | |
476 | caller do it. It's more flexible to let the caller do it, though | |
477 | I'm not sure the flexibility will ever be useful. */ | |
478 | return wrap (p, fstat (fdmap (p, fd), buf)); | |
479 | } | |
480 | ||
0d3cd463 | 481 | static int |
1a8a700e | 482 | os_lstat (host_callback *p, const char *file, struct stat *buf) |
0d3cd463 HPN |
483 | { |
484 | /* NOTE: hpn/2004-12-12: Same issue here as with os_fstat. */ | |
33aa0cbb | 485 | #ifdef HAVE_LSTAT |
0d3cd463 | 486 | return wrap (p, lstat (file, buf)); |
33aa0cbb PB |
487 | #else |
488 | return wrap (p, stat (file, buf)); | |
489 | #endif | |
0d3cd463 HPN |
490 | } |
491 | ||
028f6515 | 492 | static int |
1a8a700e | 493 | os_ftruncate (host_callback *p, int fd, long len) |
8822d001 JR |
494 | { |
495 | int result; | |
496 | ||
497 | result = fdbad (p, fd); | |
97f669ed HPN |
498 | if (p->ispipe[fd]) |
499 | { | |
500 | p->last_errno = EINVAL; | |
501 | return -1; | |
502 | } | |
8822d001 JR |
503 | if (result) |
504 | return result; | |
33aa0cbb | 505 | #ifdef HAVE_FTRUNCATE |
8822d001 | 506 | result = wrap (p, ftruncate (fdmap (p, fd), len)); |
33aa0cbb PB |
507 | #else |
508 | p->last_errno = EINVAL; | |
509 | result = -1; | |
510 | #endif | |
8822d001 JR |
511 | return result; |
512 | } | |
513 | ||
514 | static int | |
1a8a700e | 515 | os_truncate (host_callback *p, const char *file, long len) |
8822d001 | 516 | { |
33aa0cbb | 517 | #ifdef HAVE_TRUNCATE |
ee3073b5 | 518 | return wrap (p, truncate (file, len)); |
33aa0cbb PB |
519 | #else |
520 | p->last_errno = EINVAL; | |
521 | return -1; | |
522 | #endif | |
8822d001 JR |
523 | } |
524 | ||
97f669ed | 525 | static int |
1a8a700e | 526 | os_pipe (host_callback *p, int *filedes) |
97f669ed HPN |
527 | { |
528 | int i; | |
529 | ||
530 | /* We deliberately don't use fd 0. It's probably stdin anyway. */ | |
531 | for (i = 1; i < MAX_CALLBACK_FDS; i++) | |
532 | { | |
533 | int j; | |
534 | ||
535 | if (p->fd_buddy[i] < 0) | |
536 | for (j = i + 1; j < MAX_CALLBACK_FDS; j++) | |
537 | if (p->fd_buddy[j] < 0) | |
538 | { | |
539 | /* Found two free fd:s. Set stat to allocated and mark | |
540 | pipeness. */ | |
541 | p->fd_buddy[i] = i; | |
542 | p->fd_buddy[j] = j; | |
543 | p->ispipe[i] = j; | |
544 | p->ispipe[j] = -i; | |
545 | filedes[0] = i; | |
546 | filedes[1] = j; | |
547 | ||
548 | /* Poison the FD map to make bugs apparent. */ | |
549 | p->fdmap[i] = -1; | |
550 | p->fdmap[j] = -1; | |
551 | return 0; | |
552 | } | |
553 | } | |
554 | ||
555 | p->last_errno = EMFILE; | |
556 | return -1; | |
557 | } | |
558 | ||
559 | /* Stub functions for pipe support. They should always be overridden in | |
560 | targets using the pipe support, but that's up to the target. */ | |
561 | ||
562 | /* Called when the simulator says that the pipe at (reader, writer) is | |
563 | now empty (so the writer should leave its waiting state). */ | |
564 | ||
565 | static void | |
1a8a700e | 566 | os_pipe_empty (host_callback *p, int reader, int writer) |
97f669ed HPN |
567 | { |
568 | } | |
569 | ||
570 | /* Called when the simulator says the pipe at (reader, writer) is now | |
571 | non-empty (so the writer should wait). */ | |
572 | ||
573 | static void | |
1a8a700e | 574 | os_pipe_nonempty (host_callback *p, int reader, int writer) |
97f669ed HPN |
575 | { |
576 | } | |
577 | ||
c906108c | 578 | static int |
1a8a700e | 579 | os_shutdown (host_callback *p) |
c906108c | 580 | { |
594ee3a7 | 581 | int i, next, j; |
c906108c SS |
582 | for (i = 0; i < MAX_CALLBACK_FDS; i++) |
583 | { | |
594ee3a7 JR |
584 | int do_close = 1; |
585 | ||
97f669ed HPN |
586 | /* Zero out all pipe state. Don't call callbacks for non-empty |
587 | pipes; the target program has likely terminated at this point | |
588 | or we're called at initialization time. */ | |
589 | p->ispipe[i] = 0; | |
590 | p->pipe_buffer[i].size = 0; | |
591 | p->pipe_buffer[i].buffer = NULL; | |
592 | ||
594ee3a7 JR |
593 | next = p->fd_buddy[i]; |
594 | if (next < 0) | |
595 | continue; | |
596 | do | |
597 | { | |
598 | j = next; | |
599 | if (j == MAX_CALLBACK_FDS) | |
600 | do_close = 0; | |
601 | next = p->fd_buddy[j]; | |
602 | p->fd_buddy[j] = -1; | |
603 | /* At the initial call of os_init, we got -1, 0, 0, 0, ... */ | |
604 | if (next < 0) | |
605 | { | |
0242f9ea | 606 | p->fd_buddy[i] = -1; |
594ee3a7 JR |
607 | do_close = 0; |
608 | break; | |
609 | } | |
610 | } | |
611 | while (j != i); | |
612 | if (do_close) | |
c906108c | 613 | close (p->fdmap[i]); |
c906108c SS |
614 | } |
615 | return 1; | |
616 | } | |
617 | ||
618 | static int | |
1a8a700e | 619 | os_init (host_callback *p) |
c906108c SS |
620 | { |
621 | int i; | |
622 | ||
623 | os_shutdown (p); | |
624 | for (i = 0; i < 3; i++) | |
625 | { | |
626 | p->fdmap[i] = i; | |
594ee3a7 | 627 | p->fd_buddy[i] = i - 1; |
c906108c | 628 | } |
594ee3a7 JR |
629 | p->fd_buddy[0] = MAX_CALLBACK_FDS; |
630 | p->fd_buddy[MAX_CALLBACK_FDS] = 2; | |
c906108c SS |
631 | |
632 | p->syscall_map = cb_init_syscall_map; | |
633 | p->errno_map = cb_init_errno_map; | |
634 | p->open_map = cb_init_open_map; | |
635 | ||
636 | return 1; | |
637 | } | |
638 | ||
5accf1ff | 639 | /* DEPRECATED */ |
c906108c SS |
640 | |
641 | /* VARARGS */ | |
642 | static void | |
6d358e86 | 643 | os_printf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...) |
c906108c SS |
644 | { |
645 | va_list args; | |
c906108c | 646 | va_start (args, format); |
c906108c SS |
647 | |
648 | vfprintf (stdout, format, args); | |
649 | va_end (args); | |
650 | } | |
651 | ||
652 | /* VARARGS */ | |
653 | static void | |
6d358e86 | 654 | os_vprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args) |
c906108c SS |
655 | { |
656 | vprintf (format, args); | |
657 | } | |
658 | ||
659 | /* VARARGS */ | |
660 | static void | |
6d358e86 | 661 | os_evprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args) |
c906108c SS |
662 | { |
663 | vfprintf (stderr, format, args); | |
664 | } | |
665 | ||
666 | /* VARARGS */ | |
1a8a700e MF |
667 | #ifdef __GNUC__ |
668 | __attribute__ ((__noreturn__)) | |
669 | #endif | |
c906108c | 670 | static void |
6d358e86 | 671 | os_error (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...) |
c906108c SS |
672 | { |
673 | va_list args; | |
c906108c | 674 | va_start (args, format); |
c906108c SS |
675 | |
676 | vfprintf (stderr, format, args); | |
677 | fprintf (stderr, "\n"); | |
678 | ||
679 | va_end (args); | |
680 | exit (1); | |
681 | } | |
682 | ||
683 | host_callback default_callback = | |
684 | { | |
685 | os_close, | |
686 | os_get_errno, | |
687 | os_isatty, | |
688 | os_lseek, | |
689 | os_open, | |
690 | os_read, | |
691 | os_read_stdin, | |
692 | os_rename, | |
693 | os_system, | |
694 | os_time, | |
695 | os_unlink, | |
696 | os_write, | |
697 | os_write_stdout, | |
698 | os_flush_stdout, | |
699 | os_write_stderr, | |
700 | os_flush_stderr, | |
701 | ||
702 | os_stat, | |
703 | os_fstat, | |
0d3cd463 | 704 | os_lstat, |
c906108c | 705 | |
8822d001 JR |
706 | os_ftruncate, |
707 | os_truncate, | |
708 | ||
97f669ed HPN |
709 | os_pipe, |
710 | os_pipe_empty, | |
711 | os_pipe_nonempty, | |
712 | ||
c906108c SS |
713 | os_poll_quit, |
714 | ||
715 | os_shutdown, | |
716 | os_init, | |
717 | ||
718 | os_printf_filtered, /* deprecated */ | |
719 | ||
720 | os_vprintf_filtered, | |
721 | os_evprintf_filtered, | |
722 | os_error, | |
723 | ||
724 | 0, /* last errno */ | |
725 | ||
726 | { 0, }, /* fdmap */ | |
594ee3a7 | 727 | { -1, }, /* fd_buddy */ |
97f669ed HPN |
728 | { 0, }, /* ispipe */ |
729 | { { 0, 0 }, }, /* pipe_buffer */ | |
c906108c SS |
730 | |
731 | 0, /* syscall_map */ | |
732 | 0, /* errno_map */ | |
733 | 0, /* open_map */ | |
734 | 0, /* signal_map */ | |
735 | 0, /* stat_map */ | |
028f6515 | 736 | |
f4f8cce4 HPN |
737 | /* Defaults expected to be overridden at initialization, where needed. */ |
738 | BFD_ENDIAN_UNKNOWN, /* target_endian */ | |
97f669ed | 739 | 4, /* target_sizeof_int */ |
f4f8cce4 | 740 | |
c906108c SS |
741 | HOST_CALLBACK_MAGIC, |
742 | }; | |
743 | \f | |
744 | /* Read in a file describing the target's system call values. | |
745 | E.g. maybe someone will want to use something other than newlib. | |
746 | This assumes that the basic system call recognition and value passing/ | |
747 | returning is supported. So maybe some coding/recompilation will be | |
748 | necessary, but not as much. | |
749 | ||
750 | If an error occurs, the existing mapping is not changed. */ | |
751 | ||
752 | CB_RC | |
1a8a700e | 753 | cb_read_target_syscall_maps (host_callback *cb, const char *file) |
c906108c SS |
754 | { |
755 | CB_TARGET_DEFS_MAP *syscall_map, *errno_map, *open_map, *signal_map; | |
756 | const char *stat_map; | |
757 | FILE *f; | |
758 | ||
759 | if ((f = fopen (file, "r")) == NULL) | |
760 | return CB_RC_ACCESS; | |
761 | ||
762 | /* ... read in and parse file ... */ | |
763 | ||
764 | fclose (f); | |
765 | return CB_RC_NO_MEM; /* FIXME:wip */ | |
766 | ||
767 | /* Free storage allocated for any existing maps. */ | |
768 | if (cb->syscall_map) | |
769 | free (cb->syscall_map); | |
770 | if (cb->errno_map) | |
771 | free (cb->errno_map); | |
772 | if (cb->open_map) | |
773 | free (cb->open_map); | |
774 | if (cb->signal_map) | |
775 | free (cb->signal_map); | |
776 | if (cb->stat_map) | |
777 | free ((PTR) cb->stat_map); | |
778 | ||
779 | cb->syscall_map = syscall_map; | |
780 | cb->errno_map = errno_map; | |
781 | cb->open_map = open_map; | |
782 | cb->signal_map = signal_map; | |
783 | cb->stat_map = stat_map; | |
784 | ||
785 | return CB_RC_OK; | |
786 | } | |
787 | ||
6362a3f8 MF |
788 | /* General utility functions to search a map for a value. */ |
789 | ||
790 | static const CB_TARGET_DEFS_MAP * | |
791 | cb_target_map_entry (const CB_TARGET_DEFS_MAP map[], int target_val) | |
792 | { | |
793 | const CB_TARGET_DEFS_MAP *m; | |
794 | ||
7aec3bb9 | 795 | for (m = &map[0]; m->target_val != -1; ++m) |
6362a3f8 MF |
796 | if (m->target_val == target_val) |
797 | return m; | |
798 | ||
799 | return NULL; | |
800 | } | |
801 | ||
802 | static const CB_TARGET_DEFS_MAP * | |
803 | cb_host_map_entry (const CB_TARGET_DEFS_MAP map[], int host_val) | |
804 | { | |
805 | const CB_TARGET_DEFS_MAP *m; | |
806 | ||
7aec3bb9 | 807 | for (m = &map[0]; m->host_val != -1; ++m) |
6362a3f8 MF |
808 | if (m->host_val == host_val) |
809 | return m; | |
810 | ||
811 | return NULL; | |
812 | } | |
813 | ||
c906108c SS |
814 | /* Translate the target's version of a syscall number to the host's. |
815 | This isn't actually the host's version, rather a canonical form. | |
816 | ??? Perhaps this should be renamed to ..._canon_syscall. */ | |
817 | ||
818 | int | |
1a8a700e | 819 | cb_target_to_host_syscall (host_callback *cb, int target_val) |
c906108c | 820 | { |
6362a3f8 MF |
821 | const CB_TARGET_DEFS_MAP *m = |
822 | cb_target_map_entry (cb->syscall_map, target_val); | |
c906108c | 823 | |
6362a3f8 | 824 | return m ? m->host_val : -1; |
c906108c SS |
825 | } |
826 | ||
827 | /* FIXME: sort tables if large. | |
828 | Alternatively, an obvious improvement for errno conversion is | |
829 | to machine generate a function with a large switch(). */ | |
830 | ||
831 | /* Translate the host's version of errno to the target's. */ | |
832 | ||
833 | int | |
1a8a700e | 834 | cb_host_to_target_errno (host_callback *cb, int host_val) |
c906108c | 835 | { |
6362a3f8 | 836 | const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->errno_map, host_val); |
c906108c SS |
837 | |
838 | /* ??? Which error to return in this case is up for grabs. | |
839 | Note that some missing values may have standard alternatives. | |
840 | For now return 0 and require caller to deal with it. */ | |
6362a3f8 | 841 | return m ? m->target_val : 0; |
c906108c SS |
842 | } |
843 | ||
844 | /* Given a set of target bitmasks for the open system call, | |
845 | return the host equivalent. | |
846 | Mapping open flag values is best done by looping so there's no need | |
847 | to machine generate this function. */ | |
848 | ||
849 | int | |
1a8a700e | 850 | cb_target_to_host_open (host_callback *cb, int target_val) |
c906108c SS |
851 | { |
852 | int host_val = 0; | |
853 | CB_TARGET_DEFS_MAP *m; | |
854 | ||
855 | for (m = &cb->open_map[0]; m->host_val != -1; ++m) | |
856 | { | |
857 | switch (m->target_val) | |
858 | { | |
859 | /* O_RDONLY can be (and usually is) 0 which needs to be treated | |
860 | specially. */ | |
861 | case TARGET_O_RDONLY : | |
862 | case TARGET_O_WRONLY : | |
863 | case TARGET_O_RDWR : | |
864 | if ((target_val & (TARGET_O_RDONLY | TARGET_O_WRONLY | TARGET_O_RDWR)) | |
865 | == m->target_val) | |
866 | host_val |= m->host_val; | |
867 | /* Handle the host/target differentiating between binary and | |
868 | text mode. Only one case is of importance */ | |
869 | #if ! defined (TARGET_O_BINARY) && defined (O_BINARY) | |
870 | host_val |= O_BINARY; | |
871 | #endif | |
872 | break; | |
873 | default : | |
874 | if ((m->target_val & target_val) == m->target_val) | |
875 | host_val |= m->host_val; | |
876 | break; | |
877 | } | |
878 | } | |
879 | ||
880 | return host_val; | |
881 | } | |
882 | ||
f4f8cce4 | 883 | /* Utility for e.g. cb_host_to_target_stat to store values in the target's |
1a8a700e MF |
884 | stat struct. |
885 | ||
886 | ??? The "val" must be as big as target word size. */ | |
c906108c | 887 | |
f4f8cce4 | 888 | void |
1a8a700e | 889 | cb_store_target_endian (host_callback *cb, char *p, int size, long val) |
c906108c | 890 | { |
f4f8cce4 | 891 | if (cb->target_endian == BFD_ENDIAN_BIG) |
c906108c SS |
892 | { |
893 | p += size; | |
894 | while (size-- > 0) | |
895 | { | |
896 | *--p = val; | |
897 | val >>= 8; | |
898 | } | |
899 | } | |
900 | else | |
901 | { | |
902 | while (size-- > 0) | |
903 | { | |
904 | *p++ = val; | |
905 | val >>= 8; | |
906 | } | |
907 | } | |
908 | } | |
909 | ||
910 | /* Translate a host's stat struct into a target's. | |
911 | If HS is NULL, just compute the length of the buffer required, | |
912 | TS is ignored. | |
913 | ||
914 | The result is the size of the target's stat struct, | |
6439295f | 915 | or zero if an error occurred during the translation. */ |
c906108c SS |
916 | |
917 | int | |
1a8a700e | 918 | cb_host_to_target_stat (host_callback *cb, const struct stat *hs, PTR ts) |
c906108c SS |
919 | { |
920 | const char *m = cb->stat_map; | |
921 | char *p; | |
c906108c SS |
922 | |
923 | if (hs == NULL) | |
924 | ts = NULL; | |
925 | p = ts; | |
926 | ||
927 | while (m) | |
928 | { | |
929 | char *q = strchr (m, ','); | |
930 | int size; | |
931 | ||
932 | /* FIXME: Use sscanf? */ | |
933 | if (q == NULL) | |
934 | { | |
935 | /* FIXME: print error message */ | |
936 | return 0; | |
937 | } | |
938 | size = atoi (q + 1); | |
939 | if (size == 0) | |
940 | { | |
941 | /* FIXME: print error message */ | |
942 | return 0; | |
943 | } | |
944 | ||
945 | if (hs != NULL) | |
946 | { | |
e1591da4 | 947 | if (0) |
697afb65 HPN |
948 | ; |
949 | /* Defined here to avoid emacs indigestion on a lone "else". */ | |
950 | #undef ST_x | |
951 | #define ST_x(FLD) \ | |
952 | else if (strncmp (m, #FLD, q - m) == 0) \ | |
f4f8cce4 | 953 | cb_store_target_endian (cb, p, size, hs->FLD) |
697afb65 HPN |
954 | |
955 | #ifdef HAVE_STRUCT_STAT_ST_DEV | |
956 | ST_x (st_dev); | |
957 | #endif | |
958 | #ifdef HAVE_STRUCT_STAT_ST_INO | |
959 | ST_x (st_ino); | |
960 | #endif | |
961 | #ifdef HAVE_STRUCT_STAT_ST_MODE | |
962 | ST_x (st_mode); | |
963 | #endif | |
964 | #ifdef HAVE_STRUCT_STAT_ST_NLINK | |
965 | ST_x (st_nlink); | |
966 | #endif | |
967 | #ifdef HAVE_STRUCT_STAT_ST_UID | |
968 | ST_x (st_uid); | |
969 | #endif | |
970 | #ifdef HAVE_STRUCT_STAT_ST_GID | |
971 | ST_x (st_gid); | |
972 | #endif | |
973 | #ifdef HAVE_STRUCT_STAT_ST_RDEV | |
974 | ST_x (st_rdev); | |
975 | #endif | |
976 | #ifdef HAVE_STRUCT_STAT_ST_SIZE | |
977 | ST_x (st_size); | |
978 | #endif | |
979 | #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE | |
980 | ST_x (st_blksize); | |
981 | #endif | |
982 | #ifdef HAVE_STRUCT_STAT_ST_BLOCKS | |
983 | ST_x (st_blocks); | |
984 | #endif | |
985 | #ifdef HAVE_STRUCT_STAT_ST_ATIME | |
986 | ST_x (st_atime); | |
987 | #endif | |
988 | #ifdef HAVE_STRUCT_STAT_ST_MTIME | |
989 | ST_x (st_mtime); | |
990 | #endif | |
991 | #ifdef HAVE_STRUCT_STAT_ST_CTIME | |
992 | ST_x (st_ctime); | |
993 | #endif | |
994 | #undef ST_x | |
c906108c SS |
995 | /* FIXME:wip */ |
996 | else | |
f4f8cce4 HPN |
997 | /* Unsupported field, store 0. */ |
998 | cb_store_target_endian (cb, p, size, 0); | |
c906108c SS |
999 | } |
1000 | ||
1001 | p += size; | |
1002 | m = strchr (q, ':'); | |
1003 | if (m) | |
1004 | ++m; | |
1005 | } | |
1006 | ||
1007 | return p - (char *) ts; | |
1008 | } | |
1009 | \f | |
1010 | /* Cover functions to the vfprintf callbacks. | |
1011 | ||
1012 | ??? If one thinks of the callbacks as a subsystem onto itself [or part of | |
1013 | a larger "remote target subsystem"] with a well defined interface, then | |
1014 | one would think that the subsystem would provide these. However, until | |
1015 | one is allowed to create such a subsystem (with its own source tree | |
1016 | independent of any particular user), such a critter can't exist. Thus | |
1017 | these functions are here for the time being. */ | |
1018 | ||
1019 | void | |
1020 | sim_cb_printf (host_callback *p, const char *fmt, ...) | |
1021 | { | |
1022 | va_list ap; | |
1023 | ||
1024 | va_start (ap, fmt); | |
1025 | p->vprintf_filtered (p, fmt, ap); | |
1026 | va_end (ap); | |
1027 | } | |
1028 | ||
1029 | void | |
1030 | sim_cb_eprintf (host_callback *p, const char *fmt, ...) | |
1031 | { | |
1032 | va_list ap; | |
1033 | ||
1034 | va_start (ap, fmt); | |
1035 | p->evprintf_filtered (p, fmt, ap); | |
1036 | va_end (ap); | |
1037 | } | |
b981d709 DJ |
1038 | |
1039 | int | |
1040 | cb_is_stdin (host_callback *cb, int fd) | |
1041 | { | |
1042 | return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 0; | |
1043 | } | |
1044 | ||
eb639c50 DJ |
1045 | int |
1046 | cb_is_stdout (host_callback *cb, int fd) | |
1047 | { | |
1048 | return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 1; | |
1049 | } | |
1050 | ||
1051 | int | |
1052 | cb_is_stderr (host_callback *cb, int fd) | |
1053 | { | |
1054 | return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 2; | |
1055 | } | |
6362a3f8 MF |
1056 | \f |
1057 | const char * | |
1058 | cb_host_str_syscall (host_callback *cb, int host_val) | |
1059 | { | |
1060 | const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->syscall_map, host_val); | |
1061 | ||
1062 | return m ? m->name : NULL; | |
1063 | } | |
1064 | ||
1065 | const char * | |
1066 | cb_host_str_errno (host_callback *cb, int host_val) | |
1067 | { | |
1068 | const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->errno_map, host_val); | |
1069 | ||
1070 | return m ? m->name : NULL; | |
1071 | } | |
1072 | ||
1073 | const char * | |
1074 | cb_host_str_signal (host_callback *cb, int host_val) | |
1075 | { | |
1076 | const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->signal_map, host_val); | |
1077 | ||
1078 | return m ? m->name : NULL; | |
1079 | } | |
1080 | ||
1081 | const char * | |
1082 | cb_target_str_syscall (host_callback *cb, int target_val) | |
1083 | { | |
1084 | const CB_TARGET_DEFS_MAP *m = | |
1085 | cb_target_map_entry (cb->syscall_map, target_val); | |
1086 | ||
1087 | return m ? m->name : NULL; | |
1088 | } | |
1089 | ||
1090 | const char * | |
1091 | cb_target_str_errno (host_callback *cb, int target_val) | |
1092 | { | |
1093 | const CB_TARGET_DEFS_MAP *m = | |
1094 | cb_target_map_entry (cb->errno_map, target_val); | |
1095 | ||
1096 | return m ? m->name : NULL; | |
1097 | } | |
1098 | ||
1099 | const char * | |
1100 | cb_target_str_signal (host_callback *cb, int target_val) | |
1101 | { | |
1102 | const CB_TARGET_DEFS_MAP *m = | |
1103 | cb_target_map_entry (cb->signal_map, target_val); | |
1104 | ||
1105 | return m ? m->name : NULL; | |
1106 | } |