| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2013 The Native Client Authors. All rights reserved. | |
| 3 * Use of this source code is governed by a BSD-style license that can be | |
| 4 * found in the LICENSE file. | |
| 5 */ | |
| 6 | |
| 7 #include <assert.h> | |
| 8 #include <errno.h> | |
| 9 #include <fcntl.h> | |
| 10 #include <limits.h> | |
| 11 #include <pthread.h> | |
| 12 #include <stdio.h> | |
| 13 #include <stdlib.h> | |
| 14 #include <string.h> | |
| 15 #include <sys/mman.h> | |
| 16 #include <sys/stat.h> | |
| 17 #include <sys/syscall.h> | |
| 18 #include <unistd.h> | |
| 19 | |
| 20 #if defined(__linux__) | |
| 21 # include <linux/futex.h> | |
| 22 #endif | |
| 23 | |
| 24 #include "native_client/src/include/elf32.h" | |
| 25 #include "native_client/src/include/elf_auxv.h" | |
| 26 #include "native_client/src/include/nacl_macros.h" | |
| 27 #include "native_client/src/trusted/service_runtime/include/machine/_types.h" | |
| 28 #include "native_client/src/trusted/service_runtime/include/sys/mman.h" | |
| 29 #include "native_client/src/trusted/service_runtime/include/sys/stat.h" | |
| 30 #include "native_client/src/trusted/service_runtime/include/sys/time.h" | |
| 31 #include "native_client/src/trusted/service_runtime/include/sys/unistd.h" | |
| 32 #include "native_client/src/untrusted/irt/irt.h" | |
| 33 #include "native_client/src/untrusted/irt/irt_dev.h" | |
| 34 | |
| 35 /* | |
| 36 * This is an implementation of NaCl's IRT interfaces that runs | |
| 37 * outside of the NaCl sandbox. | |
| 38 * | |
| 39 * This allows PNaCl to be used as a portability layer without the | |
| 40 * SFI-based sandboxing. PNaCl pexes can be translated to | |
| 41 * non-SFI-sandboxed native code and linked against this IRT | |
| 42 * implementation. | |
| 43 */ | |
| 44 | |
| 45 | |
| 46 #if defined(__ANDROID__) && !defined(FUTEX_PRIVATE_FLAG) | |
| 47 /* Android's Linux headers currently don't define this flag. */ | |
| 48 # define FUTEX_PRIVATE_FLAG 128 | |
| 49 #endif | |
| 50 | |
| 51 #if defined(__GLIBC__) | |
| 52 /* | |
| 53 * glibc's headers will define st_atimensec etc. fields, but only if | |
| 54 * _POSIX_SOURCE is defined, which disables many other declarations, | |
| 55 * such as nanosleep(), getpagesize(), MAP_ANON and clock_gettime(). | |
| 56 */ | |
| 57 # define st_atimensec st_atim.tv_nsec | |
| 58 # define st_mtimensec st_mtim.tv_nsec | |
| 59 # define st_ctimensec st_ctim.tv_nsec | |
| 60 #elif defined(__APPLE__) | |
| 61 /* | |
| 62 * Similarly, Mac OS X's headers will define st_atimensec etc. fields, | |
| 63 * but only if _POSIX_SOURCE is defined, which disables declarations | |
| 64 * such as _SC_NPROCESSORS_ONLN. | |
| 65 */ | |
| 66 # define st_atimensec st_atimespec.tv_nsec | |
| 67 # define st_mtimensec st_mtimespec.tv_nsec | |
| 68 # define st_ctimensec st_ctimespec.tv_nsec | |
| 69 #endif | |
| 70 | |
| 71 void _user_start(void *info); | |
| 72 void _start(void *info); | |
| 73 | |
| 74 /* TODO(mseaborn): Make threads work on Mac OS X. */ | |
| 75 #if defined(__APPLE__) | |
| 76 # define __thread /* nothing */ | |
| 77 #endif | |
| 78 static __thread void *g_tls_value; | |
| 79 | |
| 80 | |
| 81 /* | |
| 82 * The IRT functions in irt.h are declared as taking "struct timespec" | |
| 83 * and "struct timeval" pointers, but these are really "struct | |
| 84 * nacl_abi_timespec" and "struct nacl_abi_timeval" pointers in this | |
| 85 * unsandboxed context. | |
| 86 * | |
| 87 * To avoid changing irt.h for now and also avoid casting function | |
| 88 * pointers, we use the same type signatures as in irt.h and do the | |
| 89 * casting here. | |
| 90 */ | |
| 91 static void convert_from_nacl_timespec(struct timespec *dest, | |
| 92 const struct timespec *src_nacl) { | |
| 93 const struct nacl_abi_timespec *src = | |
| 94 (const struct nacl_abi_timespec *) src_nacl; | |
| 95 dest->tv_sec = src->tv_sec; | |
| 96 dest->tv_nsec = src->tv_nsec; | |
| 97 } | |
| 98 | |
| 99 static void convert_to_nacl_timespec(struct timespec *dest_nacl, | |
| 100 const struct timespec *src) { | |
| 101 struct nacl_abi_timespec *dest = (struct nacl_abi_timespec *) dest_nacl; | |
| 102 dest->tv_sec = src->tv_sec; | |
| 103 dest->tv_nsec = src->tv_nsec; | |
| 104 } | |
| 105 | |
| 106 static void convert_to_nacl_timeval(struct timeval *dest_nacl, | |
| 107 const struct timeval *src) { | |
| 108 struct nacl_abi_timeval *dest = (struct nacl_abi_timeval *) dest_nacl; | |
| 109 dest->nacl_abi_tv_sec = src->tv_sec; | |
| 110 dest->nacl_abi_tv_usec = src->tv_usec; | |
| 111 } | |
| 112 | |
| 113 static void convert_to_nacl_stat(struct stat *dest_nacl, | |
| 114 const struct stat *src) { | |
| 115 struct nacl_abi_stat *dest = (struct nacl_abi_stat *) dest_nacl; | |
| 116 dest->nacl_abi_st_dev = src->st_dev; | |
| 117 dest->nacl_abi_st_ino = src->st_ino; | |
| 118 dest->nacl_abi_st_mode = src->st_mode; | |
| 119 dest->nacl_abi_st_nlink = src->st_nlink; | |
| 120 dest->nacl_abi_st_uid = src->st_uid; | |
| 121 dest->nacl_abi_st_gid = src->st_gid; | |
| 122 dest->nacl_abi_st_rdev = src->st_rdev; | |
| 123 dest->nacl_abi_st_size = src->st_size; | |
| 124 dest->nacl_abi_st_blksize = src->st_blksize; | |
| 125 dest->nacl_abi_st_blocks = src->st_blocks; | |
| 126 dest->nacl_abi_st_atime = src->st_atime; | |
| 127 dest->nacl_abi_st_atimensec = src->st_atimensec; | |
| 128 dest->nacl_abi_st_mtime = src->st_mtime; | |
| 129 dest->nacl_abi_st_mtimensec = src->st_mtimensec; | |
| 130 dest->nacl_abi_st_ctime = src->st_ctime; | |
| 131 dest->nacl_abi_st_ctimensec = src->st_ctimensec; | |
| 132 } | |
| 133 | |
| 134 static void copy_flag(int *dest, int src, int new_flag, int old_flag) { | |
| 135 if ((src & old_flag) != 0) | |
| 136 *dest |= new_flag; | |
| 137 } | |
| 138 | |
| 139 /* Returns whether the conversion was successful. */ | |
| 140 static int convert_from_nacl_mmap_prot(int *prot, int prot_nacl) { | |
| 141 if ((prot_nacl & ~NACL_ABI_PROT_MASK) != 0) | |
| 142 return 0; | |
| 143 *prot = 0; | |
| 144 copy_flag(prot, prot_nacl, PROT_READ, NACL_ABI_PROT_READ); | |
| 145 copy_flag(prot, prot_nacl, PROT_WRITE, NACL_ABI_PROT_WRITE); | |
| 146 copy_flag(prot, prot_nacl, PROT_EXEC, NACL_ABI_PROT_EXEC); | |
| 147 return 1; | |
| 148 } | |
| 149 | |
| 150 /* Returns whether the conversion was successful. */ | |
| 151 static int convert_from_nacl_mmap_flags(int *flags, int flags_nacl) { | |
| 152 int allowed = NACL_ABI_MAP_SHARED | | |
| 153 NACL_ABI_MAP_PRIVATE | | |
| 154 NACL_ABI_MAP_FIXED | | |
| 155 NACL_ABI_MAP_ANON; | |
| 156 if ((flags_nacl & ~allowed) != 0) | |
| 157 return 0; | |
| 158 *flags = 0; | |
| 159 copy_flag(flags, flags_nacl, MAP_SHARED, NACL_ABI_MAP_SHARED); | |
| 160 copy_flag(flags, flags_nacl, MAP_PRIVATE, NACL_ABI_MAP_PRIVATE); | |
| 161 copy_flag(flags, flags_nacl, MAP_FIXED, NACL_ABI_MAP_FIXED); | |
| 162 copy_flag(flags, flags_nacl, MAP_ANON, NACL_ABI_MAP_ANON); | |
| 163 return 1; | |
| 164 } | |
| 165 | |
| 166 static int check_error(int result) { | |
| 167 if (result != 0) { | |
| 168 /* | |
| 169 * Check that we really have an error and don't indicate success | |
| 170 * mistakenly. | |
| 171 */ | |
| 172 assert(errno != 0); | |
| 173 return errno; | |
| 174 } | |
| 175 return 0; | |
| 176 } | |
| 177 | |
| 178 static int irt_close(int fd) { | |
| 179 return check_error(close(fd)); | |
| 180 } | |
| 181 | |
| 182 static int irt_dup(int fd, int *new_fd) { | |
| 183 int result = dup(fd); | |
| 184 if (result < 0) | |
| 185 return errno; | |
| 186 *new_fd = result; | |
| 187 return 0; | |
| 188 } | |
| 189 | |
| 190 static int irt_dup2(int fd, int new_fd) { | |
| 191 int result = dup2(fd, new_fd); | |
| 192 if (result < 0) | |
| 193 return errno; | |
| 194 assert(result == new_fd); | |
| 195 return 0; | |
| 196 } | |
| 197 | |
| 198 static int irt_read(int fd, void *buf, size_t count, size_t *nread) { | |
| 199 int result = read(fd, buf, count); | |
| 200 if (result < 0) | |
| 201 return errno; | |
| 202 *nread = result; | |
| 203 return 0; | |
| 204 } | |
| 205 | |
| 206 static int irt_write(int fd, const void *buf, size_t count, size_t *nwrote) { | |
| 207 int result = write(fd, buf, count); | |
| 208 if (result < 0) | |
| 209 return errno; | |
| 210 *nwrote = result; | |
| 211 return 0; | |
| 212 } | |
| 213 | |
| 214 static int irt_seek(int fd, nacl_abi_off_t offset, int whence, | |
| 215 nacl_abi_off_t *new_offset) { | |
| 216 off_t result = lseek(fd, offset, whence); | |
| 217 if (result < 0) | |
| 218 return errno; | |
| 219 *new_offset = result; | |
| 220 return 0; | |
| 221 } | |
| 222 | |
| 223 static int irt_fstat(int fd, struct stat *st) { | |
| 224 /* TODO(mseaborn): Implement this and convert "struct stat". */ | |
| 225 return ENOSYS; | |
| 226 } | |
| 227 | |
| 228 static void irt_exit(int status) { | |
| 229 _exit(status); | |
| 230 } | |
| 231 | |
| 232 static int irt_clock_func(clock_t *ticks) { | |
| 233 clock_t result = clock(); | |
| 234 if (result == (clock_t) -1) | |
| 235 return errno; | |
| 236 *ticks = result; | |
| 237 return 0; | |
| 238 } | |
| 239 | |
| 240 static int irt_gettod(struct timeval *time_nacl) { | |
| 241 struct timeval time; | |
| 242 int result = check_error(gettimeofday(&time, NULL)); | |
| 243 convert_to_nacl_timeval(time_nacl, &time); | |
| 244 return result; | |
| 245 } | |
| 246 | |
| 247 static int irt_sched_yield(void) { | |
| 248 return check_error(sched_yield()); | |
| 249 } | |
| 250 | |
| 251 static int irt_nanosleep(const struct timespec *requested_nacl, | |
| 252 struct timespec *remaining_nacl) { | |
| 253 struct timespec requested; | |
| 254 struct timespec remaining; | |
| 255 convert_from_nacl_timespec(&requested, requested_nacl); | |
| 256 int result = check_error(nanosleep(&requested, &remaining)); | |
| 257 if (remaining_nacl != NULL) | |
| 258 convert_to_nacl_timespec(remaining_nacl, &remaining); | |
| 259 return result; | |
| 260 } | |
| 261 | |
| 262 static int irt_sysconf(int name, int *value) { | |
| 263 switch (name) { | |
| 264 case NACL_ABI__SC_PAGESIZE: | |
| 265 /* | |
| 266 * For now, return the host's page size (typically 4k) rather | |
| 267 * than 64k (NaCl's usual page size), which pexes will usually | |
| 268 * be tested with. We could change this to 64k, but then the | |
| 269 * mmap() we define here should round up requested sizes to | |
| 270 * multiples of 64k. | |
| 271 */ | |
| 272 *value = getpagesize(); | |
| 273 return 0; | |
| 274 case NACL_ABI__SC_NPROCESSORS_ONLN: { | |
| 275 int result = sysconf(_SC_NPROCESSORS_ONLN); | |
| 276 if (result == 0) | |
| 277 return errno; | |
| 278 *value = result; | |
| 279 return 0; | |
| 280 } | |
| 281 default: | |
| 282 return EINVAL; | |
| 283 } | |
| 284 } | |
| 285 | |
| 286 static int irt_mmap(void **addr, size_t len, int prot, int flags, | |
| 287 int fd, nacl_irt_off_t off) { | |
| 288 int host_prot; | |
| 289 int host_flags; | |
| 290 if (!convert_from_nacl_mmap_prot(&host_prot, prot) || | |
| 291 !convert_from_nacl_mmap_flags(&host_flags, flags)) { | |
| 292 return EINVAL; | |
| 293 } | |
| 294 void *result = mmap(*addr, len, host_prot, host_flags, fd, off); | |
| 295 if (result == MAP_FAILED) | |
| 296 return errno; | |
| 297 *addr = result; | |
| 298 return 0; | |
| 299 } | |
| 300 | |
| 301 static int irt_munmap(void *addr, size_t len) { | |
| 302 return check_error(munmap(addr, len)); | |
| 303 } | |
| 304 | |
| 305 static int tls_init(void *ptr) { | |
| 306 g_tls_value = ptr; | |
| 307 return 0; | |
| 308 } | |
| 309 | |
| 310 static void *tls_get(void) { | |
| 311 return g_tls_value; | |
| 312 } | |
| 313 | |
| 314 void *__nacl_read_tp(void) { | |
| 315 return g_tls_value; | |
| 316 } | |
| 317 | |
| 318 struct thread_args { | |
| 319 void (*start_func)(void); | |
| 320 void *thread_ptr; | |
| 321 }; | |
| 322 | |
| 323 static void *start_thread(void *arg) { | |
| 324 struct thread_args args = *(struct thread_args *) arg; | |
| 325 free(arg); | |
| 326 g_tls_value = args.thread_ptr; | |
| 327 args.start_func(); | |
| 328 abort(); | |
| 329 } | |
| 330 | |
| 331 static int thread_create(void (*start_func)(void), void *stack, | |
| 332 void *thread_ptr) { | |
| 333 /* | |
| 334 * For now, we ignore the stack that user code provides and just use | |
| 335 * the stack that the host libpthread allocates. | |
| 336 */ | |
| 337 pthread_attr_t attr; | |
| 338 int error = pthread_attr_init(&attr); | |
| 339 if (error != 0) | |
| 340 return error; | |
| 341 error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | |
| 342 if (error != 0) | |
| 343 return error; | |
| 344 struct thread_args *args = malloc(sizeof(struct thread_args)); | |
| 345 if (args == NULL) { | |
| 346 error = ENOMEM; | |
| 347 goto cleanup; | |
| 348 } | |
| 349 args->start_func = start_func; | |
| 350 args->thread_ptr = thread_ptr; | |
| 351 pthread_t tid; | |
| 352 error = pthread_create(&tid, &attr, start_thread, args); | |
| 353 if (error != 0) | |
| 354 free(args); | |
| 355 cleanup: | |
| 356 pthread_attr_destroy(&attr); | |
| 357 return error; | |
| 358 } | |
| 359 | |
| 360 static void thread_exit(int32_t *stack_flag) { | |
| 361 *stack_flag = 0; /* Indicate that the user code's stack can be freed. */ | |
| 362 pthread_exit(NULL); | |
| 363 } | |
| 364 | |
| 365 static int thread_nice(const int nice) { | |
| 366 return 0; | |
| 367 } | |
| 368 | |
| 369 /* | |
| 370 * Mac OS X does not provide futexes or clock_gettime()/getres() natively. | |
| 371 * TODO(mseaborn): Make threads and clock_gettime() work on Mac OS X. | |
| 372 */ | |
| 373 #if defined(__linux__) | |
| 374 static int futex_wait_abs(volatile int *addr, int value, | |
| 375 const struct timespec *abstime_nacl) { | |
| 376 struct timespec reltime; | |
| 377 struct timespec *reltime_ptr = NULL; | |
| 378 if (abstime_nacl != NULL) { | |
| 379 struct timespec time_now; | |
| 380 if (clock_gettime(CLOCK_REALTIME, &time_now) != 0) | |
| 381 return errno; | |
| 382 | |
| 383 /* Convert the absolute time to a relative time. */ | |
| 384 const struct nacl_abi_timespec *abstime = | |
| 385 (const struct nacl_abi_timespec *) abstime_nacl; | |
| 386 reltime.tv_sec = abstime->tv_sec - time_now.tv_sec; | |
| 387 reltime.tv_nsec = abstime->tv_nsec - time_now.tv_nsec; | |
| 388 if (reltime.tv_nsec < 0) { | |
| 389 reltime.tv_sec -= 1; | |
| 390 reltime.tv_nsec += 1000000000; | |
| 391 } | |
| 392 /* | |
| 393 * Linux's FUTEX_WAIT returns EINVAL if given a negative relative | |
| 394 * time. But an absolute time that's in the past is a valid | |
| 395 * argument, for which we need to return ETIMEDOUT instead. | |
| 396 */ | |
| 397 if (reltime.tv_sec < 0) | |
| 398 return ETIMEDOUT; | |
| 399 reltime_ptr = &reltime; | |
| 400 } | |
| 401 return check_error(syscall(__NR_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, | |
| 402 value, reltime_ptr, 0, 0)); | |
| 403 } | |
| 404 | |
| 405 static int futex_wake(volatile int *addr, int nwake, int *count) { | |
| 406 int result = syscall(__NR_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, | |
| 407 nwake, 0, 0, 0); | |
| 408 if (result < 0) | |
| 409 return errno; | |
| 410 *count = result; | |
| 411 return 0; | |
| 412 } | |
| 413 | |
| 414 static int irt_clock_getres(nacl_irt_clockid_t clk_id, | |
| 415 struct timespec *time_nacl) { | |
| 416 struct timespec time; | |
| 417 int result = check_error(clock_getres(clk_id, &time)); | |
| 418 convert_to_nacl_timespec(time_nacl, &time); | |
| 419 return result; | |
| 420 } | |
| 421 | |
| 422 static int irt_clock_gettime(nacl_irt_clockid_t clk_id, | |
| 423 struct timespec *time_nacl) { | |
| 424 struct timespec time; | |
| 425 int result = check_error(clock_gettime(clk_id, &time)); | |
| 426 convert_to_nacl_timespec(time_nacl, &time); | |
| 427 return result; | |
| 428 } | |
| 429 #endif | |
| 430 | |
| 431 static int irt_open(const char *pathname, int flags, mode_t mode, int *new_fd) { | |
| 432 int fd = open(pathname, flags, mode); | |
| 433 if (fd < 0) | |
| 434 return errno; | |
| 435 *new_fd = fd; | |
| 436 return 0; | |
| 437 } | |
| 438 | |
| 439 static int irt_stat(const char *pathname, struct stat *stat_info_nacl) { | |
| 440 struct stat stat_info; | |
| 441 if (stat(pathname, &stat_info) != 0) | |
| 442 return errno; | |
| 443 convert_to_nacl_stat(stat_info_nacl, &stat_info); | |
| 444 return 0; | |
| 445 } | |
| 446 | |
| 447 static int irt_mkdir(const char *pathname, mode_t mode) { | |
| 448 return check_error(mkdir(pathname, mode)); | |
| 449 } | |
| 450 | |
| 451 static int irt_rmdir(const char *pathname) { | |
| 452 return check_error(rmdir(pathname)); | |
| 453 } | |
| 454 | |
| 455 static int irt_chdir(const char *pathname) { | |
| 456 return check_error(chdir(pathname)); | |
| 457 } | |
| 458 | |
| 459 static int irt_getcwd(char *pathname, size_t len) { | |
| 460 if (getcwd(pathname, len) == NULL) | |
| 461 return errno; | |
| 462 return 0; | |
| 463 } | |
| 464 | |
| 465 static int irt_unlink(const char *pathname) { | |
| 466 return check_error(unlink(pathname)); | |
| 467 } | |
| 468 | |
| 469 static int irt_getpid(int *pid) { | |
| 470 *pid = getpid(); | |
| 471 return 0; | |
| 472 } | |
| 473 | |
| 474 static void irt_stub_func(const char *name) { | |
| 475 fprintf(stderr, "Error: Unimplemented IRT function: %s\n", name); | |
| 476 abort(); | |
| 477 } | |
| 478 | |
| 479 #define DEFINE_STUB(name) \ | |
| 480 static void irt_stub_##name() { irt_stub_func(#name); } | |
| 481 #define USE_STUB(s, name) (typeof(s.name)) irt_stub_##name | |
| 482 | |
| 483 static const struct nacl_irt_basic irt_basic = { | |
| 484 irt_exit, | |
| 485 irt_gettod, | |
| 486 irt_clock_func, | |
| 487 irt_nanosleep, | |
| 488 irt_sched_yield, | |
| 489 irt_sysconf, | |
| 490 }; | |
| 491 | |
| 492 DEFINE_STUB(getdents) | |
| 493 static const struct nacl_irt_fdio irt_fdio = { | |
| 494 irt_close, | |
| 495 irt_dup, | |
| 496 irt_dup2, | |
| 497 irt_read, | |
| 498 irt_write, | |
| 499 irt_seek, | |
| 500 irt_fstat, | |
| 501 USE_STUB(irt_fdio, getdents), | |
| 502 }; | |
| 503 | |
| 504 DEFINE_STUB(mprotect) | |
| 505 static const struct nacl_irt_memory irt_memory = { | |
| 506 irt_mmap, | |
| 507 irt_munmap, | |
| 508 USE_STUB(irt_memory, mprotect), | |
| 509 }; | |
| 510 | |
| 511 static const struct nacl_irt_tls irt_tls = { | |
| 512 tls_init, | |
| 513 tls_get, | |
| 514 }; | |
| 515 | |
| 516 static const struct nacl_irt_thread irt_thread = { | |
| 517 thread_create, | |
| 518 thread_exit, | |
| 519 thread_nice, | |
| 520 }; | |
| 521 | |
| 522 #if defined(__linux__) | |
| 523 static const struct nacl_irt_futex irt_futex = { | |
| 524 futex_wait_abs, | |
| 525 futex_wake, | |
| 526 }; | |
| 527 | |
| 528 static const struct nacl_irt_clock irt_clock = { | |
| 529 irt_clock_getres, | |
| 530 irt_clock_gettime, | |
| 531 }; | |
| 532 #else | |
| 533 DEFINE_STUB(futex_wait_abs) | |
| 534 DEFINE_STUB(futex_wake) | |
| 535 static const struct nacl_irt_futex irt_futex = { | |
| 536 USE_STUB(irt_futex, futex_wait_abs), | |
| 537 USE_STUB(irt_futex, futex_wake), | |
| 538 }; | |
| 539 #endif | |
| 540 | |
| 541 DEFINE_STUB(truncate) | |
| 542 DEFINE_STUB(lstat) | |
| 543 DEFINE_STUB(link) | |
| 544 DEFINE_STUB(rename) | |
| 545 DEFINE_STUB(symlink) | |
| 546 DEFINE_STUB(chmod) | |
| 547 DEFINE_STUB(access) | |
| 548 DEFINE_STUB(readlink) | |
| 549 DEFINE_STUB(utimes) | |
| 550 static const struct nacl_irt_dev_filename irt_dev_filename = { | |
| 551 irt_open, | |
| 552 irt_stat, | |
| 553 irt_mkdir, | |
| 554 irt_rmdir, | |
| 555 irt_chdir, | |
| 556 irt_getcwd, | |
| 557 irt_unlink, | |
| 558 USE_STUB(irt_dev_filename, truncate), | |
| 559 USE_STUB(irt_dev_filename, lstat), | |
| 560 USE_STUB(irt_dev_filename, link), | |
| 561 USE_STUB(irt_dev_filename, rename), | |
| 562 USE_STUB(irt_dev_filename, symlink), | |
| 563 USE_STUB(irt_dev_filename, chmod), | |
| 564 USE_STUB(irt_dev_filename, access), | |
| 565 USE_STUB(irt_dev_filename, readlink), | |
| 566 USE_STUB(irt_dev_filename, utimes), | |
| 567 }; | |
| 568 | |
| 569 static const struct nacl_irt_dev_getpid irt_dev_getpid = { | |
| 570 irt_getpid, | |
| 571 }; | |
| 572 | |
| 573 struct nacl_interface_table { | |
| 574 const char *name; | |
| 575 const void *table; | |
| 576 size_t size; | |
| 577 }; | |
| 578 | |
| 579 static const struct nacl_interface_table irt_interfaces[] = { | |
| 580 { NACL_IRT_BASIC_v0_1, &irt_basic, sizeof(irt_basic) }, | |
| 581 { NACL_IRT_FDIO_v0_1, &irt_fdio, sizeof(irt_fdio) }, | |
| 582 { NACL_IRT_MEMORY_v0_3, &irt_memory, sizeof(irt_memory) }, | |
| 583 { NACL_IRT_TLS_v0_1, &irt_tls, sizeof(irt_tls) }, | |
| 584 { NACL_IRT_THREAD_v0_1, &irt_thread, sizeof(irt_thread) }, | |
| 585 { NACL_IRT_FUTEX_v0_1, &irt_futex, sizeof(irt_futex) }, | |
| 586 #if defined(__linux__) | |
| 587 { NACL_IRT_CLOCK_v0_1, &irt_clock, sizeof(irt_clock) }, | |
| 588 #endif | |
| 589 { NACL_IRT_DEV_FILENAME_v0_3, &irt_dev_filename, sizeof(irt_dev_filename) }, | |
| 590 { NACL_IRT_DEV_GETPID_v0_1, &irt_dev_getpid, sizeof(irt_dev_getpid) }, | |
| 591 }; | |
| 592 | |
| 593 static size_t irt_interface_query(const char *interface_ident, | |
| 594 void *table, size_t tablesize) { | |
| 595 unsigned i; | |
| 596 for (i = 0; i < NACL_ARRAY_SIZE(irt_interfaces); ++i) { | |
| 597 if (0 == strcmp(interface_ident, irt_interfaces[i].name)) { | |
| 598 const size_t size = irt_interfaces[i].size; | |
| 599 if (size <= tablesize) { | |
| 600 memcpy(table, irt_interfaces[i].table, size); | |
| 601 return size; | |
| 602 } | |
| 603 break; | |
| 604 } | |
| 605 } | |
| 606 fprintf(stderr, "Warning: unavailable IRT interface queried: %s\n", | |
| 607 interface_ident); | |
| 608 return 0; | |
| 609 } | |
| 610 | |
| 611 int main(int argc, char **argv, char **environ) { | |
| 612 /* Find size of environ array. */ | |
| 613 size_t env_count = 0; | |
| 614 while (environ[env_count] != NULL) | |
| 615 env_count++; | |
| 616 | |
| 617 size_t count = | |
| 618 1 /* cleanup_func pointer */ | |
| 619 + 2 /* envc and argc counts */ | |
| 620 + argc + 1 /* argv array, with terminator */ | |
| 621 + env_count + 1 /* environ array, with terminator */ | |
| 622 + 4; /* auxv: 2 entries, one of them the terminator */ | |
| 623 uintptr_t *data = malloc(count * sizeof(uintptr_t)); | |
| 624 if (data == NULL) { | |
| 625 fprintf(stderr, "Failed to allocate argv/env/auxv array\n"); | |
| 626 return 1; | |
| 627 } | |
| 628 size_t pos = 0; | |
| 629 data[pos++] = 0; /* cleanup_func pointer */ | |
| 630 data[pos++] = env_count; | |
| 631 data[pos++] = argc; | |
| 632 /* Copy arrays, with terminators. */ | |
| 633 size_t i; | |
| 634 for (i = 0; i < (size_t) argc; i++) | |
| 635 data[pos++] = (uintptr_t) argv[i]; | |
| 636 data[pos++] = 0; | |
| 637 for (i = 0; i < env_count; i++) | |
| 638 data[pos++] = (uintptr_t) environ[i]; | |
| 639 data[pos++] = 0; | |
| 640 /* auxv[0] */ | |
| 641 data[pos++] = AT_SYSINFO; | |
| 642 data[pos++] = (uintptr_t) irt_interface_query; | |
| 643 /* auxv[1] */ | |
| 644 data[pos++] = 0; | |
| 645 data[pos++] = 0; | |
| 646 assert(pos == count); | |
| 647 | |
| 648 /* | |
| 649 * On Linux, we rename _start() to _user_start() to avoid a clash | |
| 650 * with the "_start" routine in the host toolchain. On Mac OS X, | |
| 651 * lacking objcopy, doing the symbol renaming is trickier, but also | |
| 652 * unnecessary, because the host toolchain doesn't have a "_start" | |
| 653 * routine. | |
| 654 */ | |
| 655 #if defined(__APPLE__) | |
| 656 _start(data); | |
| 657 #else | |
| 658 _user_start(data); | |
| 659 #endif | |
| 660 return 1; | |
| 661 } | |
| OLD | NEW |