Fix crash on app list start page contents not existing.
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / kernel_wrap_glibc.cc
bloba7d0986bc8d154929c01be64ad8721a48a9c529f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <sys/types.h> // Include something that will define __GLIBC__.
6 #include "nacl_io/kernel_wrap.h" // IRT_EXT is turned on in this header.
8 // The entire file is wrapped in this #if. We do this so this .cc file can be
9 // compiled, even on a non-glibc build.
10 #if !defined(NACL_IO_IRT_EXT) && defined(__native_client__) && \
11 defined(__GLIBC__)
13 #include <alloca.h>
14 #include <assert.h>
15 #include <dirent.h>
16 #include <errno.h>
17 #include <irt.h>
18 #include <irt_syscalls.h>
19 #include <nacl_stat.h>
20 #include <string.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
24 #include "nacl_io/kernel_intercept.h"
25 #include "nacl_io/kernel_wrap_real.h"
26 #include "nacl_io/log.h"
27 #include "nacl_io/osmman.h"
28 #include "nacl_io/ostime.h"
30 namespace {
32 void stat_to_nacl_stat(const struct stat* buf, nacl_abi_stat* nacl_buf) {
33 memset(nacl_buf, 0, sizeof(struct nacl_abi_stat));
34 nacl_buf->nacl_abi_st_dev = buf->st_dev;
35 nacl_buf->nacl_abi_st_ino = buf->st_ino;
36 nacl_buf->nacl_abi_st_mode = buf->st_mode;
37 nacl_buf->nacl_abi_st_nlink = buf->st_nlink;
38 nacl_buf->nacl_abi_st_uid = buf->st_uid;
39 nacl_buf->nacl_abi_st_gid = buf->st_gid;
40 nacl_buf->nacl_abi_st_rdev = buf->st_rdev;
41 nacl_buf->nacl_abi_st_size = buf->st_size;
42 nacl_buf->nacl_abi_st_blksize = buf->st_blksize;
43 nacl_buf->nacl_abi_st_blocks = buf->st_blocks;
44 nacl_buf->nacl_abi_st_atime = buf->st_atime;
45 nacl_buf->nacl_abi_st_atimensec = buf->st_atimensec;
46 nacl_buf->nacl_abi_st_mtime = buf->st_mtime;
47 nacl_buf->nacl_abi_st_mtimensec = buf->st_mtimensec;
48 nacl_buf->nacl_abi_st_ctime = buf->st_ctime;
49 nacl_buf->nacl_abi_st_ctimensec = buf->st_ctimensec;
52 void nacl_stat_to_stat(const nacl_abi_stat* nacl_buf, struct stat* buf) {
53 memset(buf, 0, sizeof(struct stat));
54 buf->st_dev = nacl_buf->nacl_abi_st_dev;
55 buf->st_ino = nacl_buf->nacl_abi_st_ino;
56 buf->st_mode = nacl_buf->nacl_abi_st_mode;
57 buf->st_nlink = nacl_buf->nacl_abi_st_nlink;
58 buf->st_uid = nacl_buf->nacl_abi_st_uid;
59 buf->st_gid = nacl_buf->nacl_abi_st_gid;
60 buf->st_rdev = nacl_buf->nacl_abi_st_rdev;
61 buf->st_size = nacl_buf->nacl_abi_st_size;
62 buf->st_blksize = nacl_buf->nacl_abi_st_blksize;
63 buf->st_blocks = nacl_buf->nacl_abi_st_blocks;
64 buf->st_atime = nacl_buf->nacl_abi_st_atime;
65 buf->st_atimensec = nacl_buf->nacl_abi_st_atimensec;
66 buf->st_mtime = nacl_buf->nacl_abi_st_mtime;
67 buf->st_mtimensec = nacl_buf->nacl_abi_st_mtimensec;
68 buf->st_ctime = nacl_buf->nacl_abi_st_ctime;
69 buf->st_ctimensec = nacl_buf->nacl_abi_st_ctimensec;
72 } // namespace
74 // From native_client/src/trusted/service_runtime/include/sys/dirent.h
76 #ifndef nacl_abi___ino_t_defined
77 #define nacl_abi___ino_t_defined
78 typedef int64_t nacl_abi___ino_t;
79 typedef nacl_abi___ino_t nacl_abi_ino_t;
80 #endif
82 #ifndef nacl_abi___off_t_defined
83 #define nacl_abi___off_t_defined
84 typedef int64_t nacl_abi__off_t;
85 typedef nacl_abi__off_t nacl_abi_off_t;
86 #endif
88 /* We need a way to define the maximum size of a name. */
89 #ifndef MAXNAMLEN
90 # ifdef NAME_MAX
91 # define MAXNAMLEN NAME_MAX
92 # else
93 # define MAXNAMLEN 255
94 # endif
95 #endif
97 struct nacl_abi_dirent {
98 nacl_abi_ino_t nacl_abi_d_ino;
99 nacl_abi_off_t nacl_abi_d_off;
100 uint16_t nacl_abi_d_reclen;
101 char nacl_abi_d_name[MAXNAMLEN + 1];
104 static const int d_name_shift = offsetof (dirent, d_name) -
105 offsetof (struct nacl_abi_dirent, nacl_abi_d_name);
107 EXTERN_C_BEGIN
109 // Macro to get the REAL function pointer
110 #define REAL(name) __nacl_irt_##name##_real
112 // Macro to get the WRAP function
113 #define WRAP(name) __nacl_irt_##name##_wrap
115 // Declare REAL function pointer.
116 #define DECLARE_REAL_PTR(name) typeof(__nacl_irt_##name) REAL(name);
118 // Assign the REAL function pointer.
119 #define ASSIGN_REAL_PTR(name) \
120 assert(__nacl_irt_##name != NULL); \
121 REAL(name) = __nacl_irt_##name;
123 // Switch IRT's pointer to the REAL pointer
124 #define USE_REAL(name) __nacl_irt_##name = (typeof(__nacl_irt_##name))REAL(name)
126 // Switch IRT's pointer to the WRAP function
127 #define USE_WRAP(name) __nacl_irt_##name = (typeof(__nacl_irt_##name))WRAP(name)
129 #define EXPAND_SYMBOL_LIST_OPERATION(OP) \
130 OP(chdir); \
131 OP(close); \
132 OP(dup); \
133 OP(dup2); \
134 OP(exit); \
135 OP(fstat); \
136 OP(getcwd); \
137 OP(getdents); \
138 OP(mkdir); \
139 OP(open); \
140 OP(poll); \
141 OP(read); \
142 OP(rmdir); \
143 OP(seek); \
144 OP(stat); \
145 OP(select); \
146 OP(write); \
147 OP(mmap); \
148 OP(munmap); \
149 OP(open_resource); \
151 OP(socket); \
152 OP(accept); \
153 OP(bind); \
154 OP(listen); \
155 OP(connect); \
156 OP(send); \
157 OP(sendmsg); \
158 OP(sendto); \
159 OP(recv); \
160 OP(recvmsg); \
161 OP(recvfrom); \
162 OP(getpeername); \
163 OP(getsockname); \
164 OP(getsockopt); \
165 OP(setsockopt); \
166 OP(socketpair); \
167 OP(shutdown); \
169 OP(chmod); \
170 OP(access); \
171 OP(unlink); \
172 OP(fchdir); \
173 OP(fchmod); \
174 OP(fsync); \
175 OP(fdatasync); \
176 OP(lstat); \
177 OP(link); \
178 OP(readlink); \
179 OP(utimes);
181 // TODO(bradnelson): Add these as well.
182 // OP(epoll_create);
183 // OP(epoll_create1);
184 // OP(epoll_ctl);
185 // OP(epoll_pwait);
186 // OP(ppoll);
187 // OP(pselect);
189 EXPAND_SYMBOL_LIST_OPERATION(DECLARE_REAL_PTR);
191 int WRAP(chdir)(const char* pathname) {
192 ERRNO_RTN(ki_chdir(pathname));
195 int WRAP(close)(int fd) {
196 ERRNO_RTN(ki_close(fd));
199 int WRAP(dup)(int fd, int* newfd) NOTHROW {
200 *newfd = ki_dup(fd);
201 RTN_ERRNO_IF(*newfd < 0);
202 return 0;
205 int WRAP(dup2)(int fd, int newfd) NOTHROW {
206 ERRNO_RTN(ki_dup2(fd, newfd));
209 void WRAP(exit)(int status) {
210 ki_exit(status);
213 int WRAP(fstat)(int fd, struct nacl_abi_stat* nacl_buf) {
214 struct stat buf;
215 memset(&buf, 0, sizeof(struct stat));
216 int res = ki_fstat(fd, &buf);
217 RTN_ERRNO_IF(res < 0);
218 stat_to_nacl_stat(&buf, nacl_buf);
219 return 0;
222 int WRAP(getcwd)(char* buf, size_t size) {
223 RTN_ERRNO_IF(ki_getcwd(buf, size) == NULL);
224 return 0;
227 int WRAP(getdents)(int fd, dirent* nacl_buf, size_t nacl_count, size_t* nread) {
228 int nacl_offset = 0;
229 // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s).
230 // nacl_abi_dirent(s) are smaller than dirent(s), so nacl_count bytes buffer
231 // is enough
232 char* buf = (char*)alloca(nacl_count);
233 int offset = 0;
234 int count;
236 count = ki_getdents(fd, buf, nacl_count);
237 RTN_ERRNO_IF(count < 0);
239 while (offset < count) {
240 dirent* d = (dirent*)(buf + offset);
241 nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)((char*)nacl_buf + nacl_offset);
242 nacl_d->nacl_abi_d_ino = d->d_ino;
243 nacl_d->nacl_abi_d_off = d->d_off;
244 nacl_d->nacl_abi_d_reclen = d->d_reclen - d_name_shift;
245 size_t d_name_len = d->d_reclen - offsetof(dirent, d_name);
246 memcpy(nacl_d->nacl_abi_d_name, d->d_name, d_name_len);
248 offset += d->d_reclen;
249 nacl_offset += nacl_d->nacl_abi_d_reclen;
252 *nread = nacl_offset;
253 return 0;
256 int WRAP(mkdir)(const char* pathname, mode_t mode) {
257 RTN_ERRNO_IF(ki_mkdir(pathname, mode) < 0);
258 return 0;
261 int WRAP(mmap)(void** addr,
262 size_t length,
263 int prot,
264 int flags,
265 int fd,
266 off_t offset) {
267 if (flags & MAP_ANONYMOUS)
268 return REAL(mmap)(addr, length, prot, flags, fd, offset);
270 *addr = ki_mmap(*addr, length, prot, flags, fd, offset);
271 RTN_ERRNO_IF(*addr == (void*)-1);
272 return 0;
275 int WRAP(munmap)(void* addr, size_t length) {
276 // Always let the real munmap run on the address range. It is not an error if
277 // there are no mapped pages in that range.
278 ki_munmap(addr, length);
279 return REAL(munmap)(addr, length);
282 int WRAP(open)(const char* pathname, int oflag, mode_t mode, int* newfd) {
283 *newfd = ki_open(pathname, oflag, mode);
284 RTN_ERRNO_IF(*newfd < 0);
285 return 0;
288 int WRAP(open_resource)(const char* file, int* fd) {
289 *fd = ki_open_resource(file);
290 RTN_ERRNO_IF(*fd < 0);
291 return 0;
294 int WRAP(poll)(struct pollfd* fds, nfds_t nfds, int timeout, int* count) {
295 *count = ki_poll(fds, nfds, timeout);
296 RTN_ERRNO_IF(*count < 0);
297 return 0;
300 int WRAP(read)(int fd, void* buf, size_t count, size_t* nread) {
301 ssize_t signed_nread = ki_read(fd, buf, count);
302 *nread = static_cast<size_t>(signed_nread);
303 RTN_ERRNO_IF(signed_nread < 0);
304 return 0;
307 int WRAP(rmdir)(const char* pathname) {
308 RTN_ERRNO_IF(ki_rmdir(pathname) < 0);
309 return 0;
312 int WRAP(seek)(int fd, off_t offset, int whence, off_t* new_offset) {
313 *new_offset = ki_lseek(fd, offset, whence);
314 RTN_ERRNO_IF(*new_offset < 0);
315 return 0;
318 int WRAP(select)(int nfds,
319 fd_set* readfds,
320 fd_set* writefds,
321 fd_set* exceptfds,
322 struct timeval* timeout,
323 int* count) {
324 *count = ki_select(nfds, readfds, writefds, exceptfds, timeout);
325 RTN_ERRNO_IF(*count < 0);
326 return 0;
329 int WRAP(stat)(const char* pathname, struct nacl_abi_stat* nacl_buf) {
330 struct stat buf;
331 memset(&buf, 0, sizeof(struct stat));
332 int res = ki_stat(pathname, &buf);
333 RTN_ERRNO_IF(res < 0);
334 stat_to_nacl_stat(&buf, nacl_buf);
335 return 0;
338 int WRAP(lstat)(const char* pathname, struct nacl_abi_stat* nacl_buf) {
339 struct stat buf;
340 memset(&buf, 0, sizeof(struct stat));
341 int res = ki_lstat(pathname, &buf);
342 RTN_ERRNO_IF(res < 0);
343 stat_to_nacl_stat(&buf, nacl_buf);
344 return 0;
347 int WRAP(link)(const char* pathname, const char* newpath) {
348 ERRNO_RTN(ki_link(pathname, newpath));
351 int WRAP(readlink)(const char* pathname,
352 char* buf,
353 size_t count,
354 size_t* nread) {
355 int rtn = ki_readlink(pathname, buf, count);
356 RTN_ERRNO_IF(rtn < 0);
357 *nread = rtn;
358 return 0;
361 int WRAP(utimes)(const char *filename, const struct timeval *times) {
362 ERRNO_RTN(ki_utimes(filename, times));
365 int WRAP(chmod)(const char* pathname, mode_t mode) {
366 ERRNO_RTN(ki_chmod(pathname, mode));
369 int WRAP(access)(const char* pathname, int amode) {
370 ERRNO_RTN(ki_access(pathname, amode));
373 int WRAP(unlink)(const char* pathname) {
374 ERRNO_RTN(ki_unlink(pathname));
377 int WRAP(fchdir)(int fd) {
378 ERRNO_RTN(ki_fchdir(fd));
381 int WRAP(fchmod)(int fd, mode_t mode) {
382 ERRNO_RTN(ki_fchmod(fd, mode));
385 int WRAP(fsync)(int fd) {
386 ERRNO_RTN(ki_fsync(fd));
389 int WRAP(fdatasync)(int fd) {
390 ERRNO_RTN(ki_fdatasync(fd));
393 int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) {
394 ssize_t signed_nwrote = ki_write(fd, buf, count);
395 *nwrote = static_cast<size_t>(signed_nwrote);
396 RTN_ERRNO_IF(signed_nwrote < 0);
397 return 0;
400 int WRAP(accept)(int sockfd,
401 struct sockaddr* addr,
402 socklen_t* addrlen,
403 int* sd) {
404 *sd = ki_accept(sockfd, addr, addrlen);
405 RTN_ERRNO_IF(*sd < 0);
406 return 0;
409 int WRAP(bind)(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
410 ERRNO_RTN(ki_bind(sockfd, addr, addrlen));
413 int WRAP(connect)(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
414 ERRNO_RTN(ki_connect(sockfd, addr, addrlen));
417 int WRAP(getpeername)(int sockfd, struct sockaddr* addr, socklen_t* addrlen) {
418 ERRNO_RTN(ki_getpeername(sockfd, addr, addrlen));
421 int WRAP(getsockname)(int sockfd, struct sockaddr* addr, socklen_t* addrlen) {
422 ERRNO_RTN(ki_getsockname(sockfd, addr, addrlen));
425 int WRAP(getsockopt)(int sockfd,
426 int level,
427 int optname,
428 void* optval,
429 socklen_t* optlen) {
430 ERRNO_RTN(ki_getsockopt(sockfd, level, optname, optval, optlen));
433 int WRAP(setsockopt)(int sockfd,
434 int level,
435 int optname,
436 const void* optval,
437 socklen_t optlen) {
438 ERRNO_RTN(ki_setsockopt(sockfd, level, optname, optval, optlen));
441 int WRAP(listen)(int sockfd, int backlog) {
442 ERRNO_RTN(ki_listen(sockfd, backlog));
445 int WRAP(recv)(int sockfd, void* buf, size_t len, int flags, int* count) {
446 ssize_t signed_nread = ki_recv(sockfd, buf, len, flags);
447 *count = static_cast<int>(signed_nread);
448 RTN_ERRNO_IF(signed_nread < 0);
449 return 0;
452 int WRAP(recvfrom)(int sockfd,
453 void* buf,
454 size_t len,
455 int flags,
456 struct sockaddr* addr,
457 socklen_t* addrlen,
458 int* count) {
459 ssize_t signed_nread = ki_recvfrom(sockfd, buf, len, flags, addr, addrlen);
460 *count = static_cast<int>(signed_nread);
461 RTN_ERRNO_IF(signed_nread < 0);
462 return 0;
465 int WRAP(recvmsg)(int sockfd, struct msghdr* msg, int flags, int* count) {
466 ssize_t signed_nread = ki_recvmsg(sockfd, msg, flags);
467 *count = static_cast<int>(signed_nread);
468 RTN_ERRNO_IF(signed_nread < 0);
469 return 0;
472 ssize_t WRAP(send)(int sockfd, const void* buf, size_t len, int flags,
473 int* count) {
474 ssize_t signed_nread = ki_send(sockfd, buf, len, flags);
475 *count = static_cast<int>(signed_nread);
476 RTN_ERRNO_IF(signed_nread < 0);
477 return 0;
480 ssize_t WRAP(sendto)(int sockfd,
481 const void* buf,
482 size_t len,
483 int flags,
484 const struct sockaddr* addr,
485 socklen_t addrlen,
486 int* count) {
487 ssize_t signed_nread = ki_sendto(sockfd, buf, len, flags, addr, addrlen);
488 *count = static_cast<int>(signed_nread);
489 RTN_ERRNO_IF(signed_nread < 0);
490 return 0;
493 ssize_t WRAP(sendmsg)(int sockfd,
494 const struct msghdr* msg,
495 int flags,
496 int* count) {
497 ssize_t signed_nread = ki_sendmsg(sockfd, msg, flags);
498 *count = static_cast<int>(signed_nread);
499 RTN_ERRNO_IF(signed_nread < 0);
500 return 0;
503 int WRAP(shutdown)(int sockfd, int how) {
504 RTN_ERRNO_IF(ki_shutdown(sockfd, how) < 0);
505 return 0;
508 int WRAP(socket)(int domain, int type, int protocol, int* sd) {
509 *sd = ki_socket(domain, type, protocol);
510 RTN_ERRNO_IF(*sd < 0);
511 return 0;
514 int WRAP(socketpair)(int domain, int type, int protocol, int* sv) {
515 RTN_ERRNO_IF(ki_socketpair(domain, type, protocol, sv) < 0);
516 return 0;
519 static void assign_real_pointers() {
520 static bool assigned = false;
521 if (!assigned) {
522 EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
523 assigned = true;
527 #define CHECK_REAL(func) \
528 if (!REAL(func)) { \
529 assign_real_pointers(); \
530 if (!REAL(func)) \
531 return ENOSYS; \
534 // "real" functions, i.e. the unwrapped original functions.
536 int _real_close(int fd) {
537 CHECK_REAL(close);
538 return REAL(close)(fd);
541 void _real_exit(int status) {
542 if (!REAL(exit))
543 assign_real_pointers();
544 REAL(exit)(status);
547 int _real_fstat(int fd, struct stat* buf) {
548 struct nacl_abi_stat st;
549 CHECK_REAL(fstat);
550 int err = REAL(fstat)(fd, &st);
551 if (err) {
552 errno = err;
553 return -1;
556 nacl_stat_to_stat(&st, buf);
557 return 0;
560 int _real_getdents(int fd, void* buf, size_t count, size_t* nread) {
561 // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s).
562 // See WRAP(getdents) above.
563 char* nacl_buf = (char*)alloca(count);
564 size_t offset = 0;
565 size_t nacl_offset = 0;
566 size_t nacl_nread;
567 CHECK_REAL(getdents);
568 int err = REAL(getdents)(fd, (dirent*)nacl_buf, count, &nacl_nread);
569 if (err)
570 return err;
572 while (nacl_offset < nacl_nread) {
573 dirent* d = (dirent*)((char*)buf + offset);
574 nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)(nacl_buf + nacl_offset);
575 d->d_ino = nacl_d->nacl_abi_d_ino;
576 d->d_off = nacl_d->nacl_abi_d_off;
577 d->d_reclen = nacl_d->nacl_abi_d_reclen + d_name_shift;
578 size_t d_name_len =
579 nacl_d->nacl_abi_d_reclen - offsetof(nacl_abi_dirent, nacl_abi_d_name);
580 memcpy(d->d_name, nacl_d->nacl_abi_d_name, d_name_len);
582 offset += d->d_reclen;
583 offset += nacl_d->nacl_abi_d_reclen;
586 *nread = offset;
587 return 0;
590 int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
591 CHECK_REAL(seek);
592 return REAL(seek)(fd, offset, whence, new_offset);
595 int _real_mkdir(const char* pathname, mode_t mode) {
596 CHECK_REAL(mkdir);
597 return REAL(mkdir)(pathname, mode);
600 int _real_mmap(void** addr,
601 size_t length,
602 int prot,
603 int flags,
604 int fd,
605 off_t offset) {
606 CHECK_REAL(mmap);
607 return REAL(mmap)(addr, length, prot, flags, fd, offset);
610 int _real_munmap(void* addr, size_t length) {
611 CHECK_REAL(munmap);
612 return REAL(munmap)(addr, length);
615 int _real_open(const char* pathname, int oflag, mode_t mode, int* newfd) {
616 CHECK_REAL(open);
617 return REAL(open)(pathname, oflag, mode, newfd);
620 int _real_open_resource(const char* file, int* fd) {
621 CHECK_REAL(open_resource);
622 return REAL(open_resource)(file, fd);
625 int _real_read(int fd, void* buf, size_t count, size_t* nread) {
626 CHECK_REAL(read);
627 return REAL(read)(fd, buf, count, nread);
630 int _real_rmdir(const char* pathname) {
631 CHECK_REAL(rmdir);
632 return REAL(rmdir)(pathname);
635 int _real_write(int fd, const void* buf, size_t count, size_t* nwrote) {
636 CHECK_REAL(write);
637 return REAL(write)(fd, buf, count, nwrote);
640 int _real_getcwd(char* pathname, size_t len) {
641 CHECK_REAL(getcwd);
642 return REAL(getcwd)(pathname, len);
645 static bool s_wrapped = false;
646 void kernel_wrap_init() {
647 if (!s_wrapped) {
648 LOG_TRACE("kernel_wrap_init");
649 assign_real_pointers();
650 EXPAND_SYMBOL_LIST_OPERATION(USE_WRAP)
651 s_wrapped = true;
655 void kernel_wrap_uninit() {
656 if (s_wrapped) {
657 LOG_TRACE("kernel_wrap_uninit");
658 EXPAND_SYMBOL_LIST_OPERATION(USE_REAL)
659 s_wrapped = false;
663 EXTERN_C_END
665 #endif // defined(__native_client__) && defined(__GLIBC__)