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