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 674 : 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 674 : const size_t kPipeBufferBound = 0x1000;
44 674 : if (len > kPipeBufferBound)
45 0 : return false;
46 :
47 674 : bool success = false;
48 674 : int pipe_fds[2];
49 674 : if (pipe(pipe_fds) != 0)
50 0 : return false;
51 674 : ssize_t sent = write(pipe_fds[1], src, len);
52 674 : if (sent == static_cast<ssize_t>(len)) {
53 670 : ssize_t got = read(pipe_fds[0], dest, len);
54 670 : if (got == static_cast<ssize_t>(len))
55 670 : success = true;
56 670 : }
57 2022 : CHECK(close(pipe_fds[0]) == 0);
58 2022 : CHECK(close(pipe_fds[1]) == 0);
59 674 : return success;
60 674 : }
61 :
62 534 : bool IPlatform::GetMemory(uint64_t virt, uint32_t len, void *dst) {
63 534 : return SafeMemoryCopy(dst, reinterpret_cast<void*>(virt), len);
64 : }
65 :
66 140 : bool IPlatform::SetMemory(struct NaClApp *nap, uint64_t virt, uint32_t len,
67 140 : void *src) {
68 140 : uintptr_t page_mask = NACL_PAGESIZE - 1;
69 140 : uintptr_t page = virt & ~page_mask;
70 140 : uintptr_t mapping_size = ((virt + len + page_mask) & ~page_mask) - page;
71 140 : bool is_code = virt + len <= nap->mem_start + nap->dynamic_text_end;
72 140 : if (is_code) {
73 136 : if (mprotect(reinterpret_cast<void*>(page), mapping_size,
74 : PROT_READ | PROT_WRITE) != 0) {
75 0 : return false;
76 : }
77 136 : }
78 140 : 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 140 : if (is_code) {
88 136 : if (mprotect(reinterpret_cast<void*>(page), mapping_size,
89 : PROT_READ | PROT_EXEC) != 0) {
90 0 : return false;
91 : }
92 136 : }
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 140 : NaClFlushCacheForDoublyMappedCode((uint8_t *) virt, (uint8_t *) virt, len);
97 140 : return succeeded;
98 140 : }
99 :
100 : } // End of port namespace
101 :
|