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 <stdexcept>
8 : #include <string.h>
9 :
10 : #include "native_client/src/shared/platform/nacl_log.h"
11 : #include "native_client/src/trusted/gdb_rsp/abi.h"
12 : #include "native_client/src/trusted/port/mutex.h"
13 : #include "native_client/src/trusted/port/platform.h"
14 : #include "native_client/src/trusted/port/thread.h"
15 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
16 :
17 : /*
18 : * Define the OS specific portions of gdb_utils IThread interface.
19 : */
20 :
21 : namespace {
22 :
23 : const int kX86TrapFlag = 1 << 8;
24 :
25 : } // namespace
26 :
27 : namespace port {
28 :
29 : static IThread::CatchFunc_t s_CatchFunc = NULL;
30 : static void* s_CatchCookie = NULL;
31 :
32 0 : static IMutex* ThreadGetLock() {
33 0 : static IMutex* mutex_ = IMutex::Allocate();
34 0 : return mutex_;
35 : }
36 :
37 0 : static IThread::ThreadMap_t *ThreadGetMap() {
38 0 : static IThread::ThreadMap_t* map_ = new IThread::ThreadMap_t;
39 0 : return map_;
40 : }
41 :
42 : class Thread : public IThread {
43 : public:
44 0 : explicit Thread(uint32_t id) : ref_(1), id_(id), state_(DEAD) {}
45 0 : ~Thread() {}
46 :
47 0 : uint32_t GetId() {
48 0 : return id_;
49 : }
50 :
51 0 : State GetState() {
52 0 : return state_;
53 : }
54 :
55 0 : virtual bool Suspend() {
56 : // TODO(mseaborn): Implement this. Unlike with Windows'
57 : // SuspendThread(), a thread cannot be suspended from another
58 : // thread in Unix. We would have to send the thread a signal to
59 : // ask it to suspend.
60 0 : return false;
61 : }
62 :
63 0 : virtual bool Resume() {
64 : // TODO(mseaborn): Implement this.
65 0 : return false;
66 : }
67 :
68 : // TODO(mseaborn): Similar logic is duplicated in the Windows version.
69 0 : virtual bool SetStep(bool on) {
70 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
71 0 : if (on) {
72 0 : context_.flags |= kX86TrapFlag;
73 : } else {
74 0 : context_.flags &= ~kX86TrapFlag;
75 : }
76 0 : return true;
77 : #else
78 : // TODO(mseaborn): Implement for ARM.
79 : UNREFERENCED_PARAMETER(on);
80 : return false;
81 : #endif
82 : }
83 :
84 0 : virtual bool GetRegister(uint32_t index, void *dst, uint32_t len) {
85 0 : const gdb_rsp::Abi *abi = gdb_rsp::Abi::Get();
86 0 : const gdb_rsp::Abi::RegDef *reg = abi->GetRegisterDef(index);
87 0 : memcpy(dst, (char *) &context_ + reg->offset_, len);
88 0 : return false;
89 : }
90 :
91 0 : virtual bool SetRegister(uint32_t index, void* src, uint32_t len) {
92 0 : const gdb_rsp::Abi *abi = gdb_rsp::Abi::Get();
93 0 : const gdb_rsp::Abi::RegDef *reg = abi->GetRegisterDef(index);
94 0 : memcpy((char *) &context_ + reg->offset_, src, len);
95 0 : return false;
96 : }
97 :
98 : // This is not used and could be removed.
99 0 : virtual void* GetContext() { return NULL; }
100 :
101 0 : static enum NaClSignalResult SignalHandler(int signal, void *ucontext) {
102 : struct NaClSignalContext context;
103 0 : NaClSignalContextFromHandler(&context, ucontext);
104 0 : if (NaClSignalContextIsUntrusted(&context)) {
105 0 : uint32_t thread_id = IPlatform::GetCurrentThread();
106 0 : Thread* thread = static_cast<Thread*>(Acquire(thread_id));
107 0 : State old_state = thread->state_;
108 0 : thread->state_ = SIGNALED;
109 0 : thread->context_ = context;
110 :
111 0 : if (s_CatchFunc != NULL)
112 0 : s_CatchFunc(thread_id, signal, s_CatchCookie);
113 :
114 0 : NaClSignalContextToHandler(ucontext, &thread->context_);
115 0 : thread->state_ = old_state;
116 0 : Release(thread);
117 0 : return NACL_SIGNAL_RETURN;
118 : } else {
119 : // Do not attempt to debug crashes in trusted code.
120 0 : return NACL_SIGNAL_SEARCH;
121 : }
122 : }
123 :
124 : private:
125 : uint32_t ref_;
126 : uint32_t id_;
127 : State state_;
128 : struct NaClSignalContext context_;
129 :
130 : friend class IThread;
131 : };
132 :
133 : // TODO(mseaborn): This is duplicated in the Windows version.
134 0 : IThread* IThread::Acquire(uint32_t id, bool create) {
135 0 : MutexLock lock(ThreadGetLock());
136 : Thread* thread;
137 0 : ThreadMap_t &map = *ThreadGetMap();
138 :
139 : // Check if we have that thread
140 0 : if (map.count(id)) {
141 0 : thread = static_cast<Thread*>(map[id]);
142 0 : thread->ref_++;
143 0 : return thread;
144 : }
145 :
146 : // If not, can we create it?
147 0 : if (create) {
148 : // If not add it to the map
149 0 : thread = new Thread(id);
150 0 : map[id] = thread;
151 0 : return thread;
152 : }
153 :
154 0 : return NULL;
155 : }
156 :
157 : // TODO(mseaborn): This is duplicated in the Windows version.
158 0 : void IThread::Release(IThread *ithread) {
159 0 : MutexLock lock(ThreadGetLock());
160 0 : Thread* thread = static_cast<Thread*>(ithread);
161 0 : thread->ref_--;
162 :
163 0 : if (thread->ref_ == 0) {
164 0 : ThreadGetMap()->erase(thread->id_);
165 0 : delete static_cast<IThread*>(thread);
166 0 : }
167 0 : }
168 :
169 0 : void IThread::SetExceptionCatch(IThread::CatchFunc_t func, void *cookie) {
170 0 : NaClSignalHandlerAdd(Thread::SignalHandler);
171 0 : s_CatchFunc = func;
172 0 : s_CatchCookie = cookie;
173 0 : }
174 :
175 :
176 : } // End of port namespace
177 :
|