1 : /*
2 : * Copyright (c) 2012 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 <stdio.h>
8 : #include <stdlib.h>
9 : #include <unistd.h>
10 : #include <sys/mman.h>
11 : #include <sys/types.h>
12 : #include <sys/syscall.h>
13 : #include <pthread.h>
14 :
15 : #include <map>
16 : #include <vector>
17 :
18 : #include "native_client/src/include/concurrency_ops.h"
19 : #include "native_client/src/shared/platform/nacl_check.h"
20 : #include "native_client/src/shared/platform/nacl_log.h"
21 : #include "native_client/src/trusted/debug_stub/abi.h"
22 : #include "native_client/src/trusted/debug_stub/util.h"
23 : #include "native_client/src/trusted/debug_stub/platform.h"
24 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
25 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
26 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
27 :
28 :
29 : /*
30 : * Define the OS specific portions of IPlatform interface.
31 : */
32 :
33 :
34 : namespace port {
35 :
36 : // In order to read from a pointer that might not be valid, we use the
37 : // trick of getting the kernel to do it on our behalf.
38 434 : static bool SafeMemoryCopy(void *dest, void *src, size_t len) {
39 : // The trick only works if we are copying less than the buffer size
40 : // of a pipe. For now, return an error on larger sizes.
41 : // TODO(mseaborn): If we need to copy more, we would have to break
42 : // it up into smaller parts.
43 434 : const size_t kPipeBufferBound = 0x1000;
44 434 : if (len > kPipeBufferBound)
45 0 : return false;
46 :
47 434 : bool success = false;
48 : int pipe_fds[2];
49 434 : if (pipe(pipe_fds) != 0)
50 0 : return false;
51 434 : ssize_t sent = write(pipe_fds[1], src, len);
52 434 : if (sent == static_cast<ssize_t>(len)) {
53 431 : ssize_t got = read(pipe_fds[0], dest, len);
54 431 : if (got == static_cast<ssize_t>(len))
55 431 : success = true;
56 : }
57 434 : CHECK(close(pipe_fds[0]) == 0);
58 434 : CHECK(close(pipe_fds[1]) == 0);
59 434 : return success;
60 : }
61 :
62 291 : bool IPlatform::GetMemory(uint64_t virt, uint32_t len, void *dst) {
63 291 : return SafeMemoryCopy(dst, reinterpret_cast<void*>(virt), len);
64 : }
65 :
66 143 : bool IPlatform::SetMemory(struct NaClApp *nap, uint64_t virt, uint32_t len,
67 : void *src) {
68 143 : uintptr_t page_mask = NACL_PAGESIZE - 1;
69 143 : uintptr_t page = virt & ~page_mask;
70 143 : uintptr_t mapping_size = ((virt + len + page_mask) & ~page_mask) - page;
71 143 : bool is_code = virt + len <= nap->mem_start + nap->dynamic_text_end;
72 143 : if (is_code) {
73 138 : if (mprotect(reinterpret_cast<void*>(page), mapping_size,
74 138 : PROT_READ | PROT_WRITE) != 0) {
75 0 : return false;
76 : }
77 : }
78 143 : bool succeeded = SafeMemoryCopy(reinterpret_cast<void*>(virt), src, len);
79 : // We use mprotect() only to modify code area, so PROT_READ | PROT_EXEC are
80 : // the correct flags to restore the mapping to in most cases. However, this
81 : // does not behave correctly for non-allocated pages in code area (where
82 : // we will make zeroed bytes executable) and zero page (where we additionally
83 : // prevent some null pointer exceptions).
84 : //
85 : // TODO(mseaborn): Handle those cases correctly. We might do that by modifying
86 : // code via the dynamic code area the same way nacl_text.c does.
87 143 : if (is_code) {
88 138 : if (mprotect(reinterpret_cast<void*>(page), mapping_size,
89 138 : PROT_READ | PROT_EXEC) != 0) {
90 0 : return false;
91 : }
92 : }
93 : // Flush the instruction cache in case we just modified code to add
94 : // or remove a breakpoint, otherwise breakpoints will not behave
95 : // reliably on ARM.
96 143 : NaClFlushCacheForDoublyMappedCode((uint8_t *) virt, (uint8_t *) virt, len);
97 143 : return succeeded;
98 : }
99 :
100 : } // End of port namespace
101 :
|