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