1 : /*
2 : * Copyright 2010 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can
4 : * be 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/shared/platform/nacl_check.h"
19 : #include "native_client/src/shared/platform/nacl_log.h"
20 : #include "native_client/src/trusted/gdb_rsp/abi.h"
21 : #include "native_client/src/trusted/gdb_rsp/util.h"
22 : #include "native_client/src/trusted/port/event.h"
23 : #include "native_client/src/trusted/port/platform.h"
24 :
25 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
26 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
27 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
28 :
29 :
30 : /*
31 : * Define the OS specific portions of gdb_utils IPlatform interface.
32 : */
33 :
34 :
35 0 : static port::IEvent* GetLaunchEvent() {
36 0 : static port::IEvent* event_ = port::IEvent::Allocate();
37 0 : return event_;
38 : }
39 :
40 : namespace port {
41 :
42 : struct StartInfo_t {
43 : port::IPlatform::ThreadFunc_t func_;
44 : void *cookie_;
45 : volatile uint32_t id_;
46 : };
47 :
48 : // Get the OS id of this thread
49 0 : uint32_t IPlatform::GetCurrentThread() {
50 0 : return static_cast<uint32_t>(syscall(SYS_gettid));
51 : }
52 :
53 : // Use start stub, to record thread id, and signal launcher
54 0 : static void *StartFunc(void* cookie) {
55 0 : StartInfo_t* info = reinterpret_cast<StartInfo_t*>(cookie);
56 0 : info->id_ = (uint32_t) syscall(SYS_gettid);
57 :
58 0 : printf("Started thread...\n");
59 0 : GetLaunchEvent()->Signal();
60 0 : info->func_(info->cookie_);
61 :
62 0 : return NULL;
63 : }
64 :
65 0 : uint32_t IPlatform::CreateThread(ThreadFunc_t func, void* cookie) {
66 : pthread_t thread;
67 : StartInfo_t info;
68 :
69 : // Setup the thread information
70 0 : info.func_ = func;
71 0 : info.cookie_ = cookie;
72 :
73 0 : printf("Creating thread...\n");
74 :
75 : // Redirect to stub and wait for signal before continuing
76 0 : if (pthread_create(&thread, NULL, StartFunc, &info) == 0) {
77 0 : GetLaunchEvent()->Wait();
78 0 : printf("Found thread...\n");
79 0 : return info.id_;
80 : }
81 :
82 0 : return 0;
83 : }
84 :
85 0 : void IPlatform::Relinquish(uint32_t msec) {
86 0 : usleep(msec * 1000);
87 0 : }
88 :
89 : // In order to read from a pointer that might not be valid, we use the
90 : // trick of getting the kernel to do it on our behalf.
91 0 : static bool SafeMemoryCopy(void *dest, void *src, size_t len) {
92 : // The trick only works if we are copying less than the buffer size
93 : // of a pipe. For now, return an error on larger sizes.
94 : // TODO(mseaborn): If we need to copy more, we would have to break
95 : // it up into smaller parts.
96 0 : const size_t kPipeBufferBound = 0x1000;
97 0 : if (len > kPipeBufferBound)
98 0 : return false;
99 :
100 0 : bool success = false;
101 : int pipe_fds[2];
102 0 : if (pipe(pipe_fds) != 0)
103 0 : return false;
104 0 : ssize_t sent = write(pipe_fds[1], src, len);
105 0 : if (sent == static_cast<ssize_t>(len)) {
106 0 : ssize_t got = read(pipe_fds[0], dest, len);
107 0 : if (got == static_cast<ssize_t>(len))
108 0 : success = true;
109 : }
110 0 : CHECK(close(pipe_fds[0]) == 0);
111 0 : CHECK(close(pipe_fds[1]) == 0);
112 0 : return success;
113 : }
114 :
115 0 : bool IPlatform::GetMemory(uint64_t virt, uint32_t len, void *dst) {
116 0 : return SafeMemoryCopy(dst, reinterpret_cast<void*>(virt), len);
117 : }
118 :
119 0 : bool IPlatform::SetMemory(uint64_t virt, uint32_t len, void *src) {
120 0 : uintptr_t page_mask = NACL_PAGESIZE - 1;
121 0 : uintptr_t page = virt & ~page_mask;
122 0 : uintptr_t mapping_size = ((virt + len + page_mask) & ~page_mask) - page;
123 0 : if (mprotect(reinterpret_cast<void*>(page), mapping_size,
124 : PROT_READ | PROT_WRITE) != 0) {
125 0 : return false;
126 : }
127 0 : bool succeeded = SafeMemoryCopy(reinterpret_cast<void*>(virt), src, len);
128 : // TODO(mseaborn): We assume here that SetMemory() is being used to
129 : // set or remove a breakpoint in the code area, so that PROT_READ |
130 : // PROT_EXEC are the correct flags to restore the mapping to.
131 : // The earlier mprotect() does not tell us what the original flags
132 : // were. To find this out we could either:
133 : // * read /proc/self/maps (not available inside outer sandbox); or
134 : // * use service_runtime's own mapping tables.
135 : // Alternatively, we could modify code the same way nacl_text.c does.
136 0 : if (mprotect(reinterpret_cast<void*>(page), mapping_size,
137 : PROT_READ | PROT_EXEC) != 0) {
138 0 : return false;
139 : }
140 0 : return succeeded;
141 : }
142 :
143 : } // End of port namespace
144 :
|