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