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 <map>
8 : #include <string.h>
9 :
10 : #include "native_client/src/shared/platform/nacl_check.h"
11 : #include "native_client/src/shared/platform/nacl_log.h"
12 : #include "native_client/src/trusted/debug_stub/abi.h"
13 : #include "native_client/src/trusted/debug_stub/mutex.h"
14 : #include "native_client/src/trusted/debug_stub/thread.h"
15 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
16 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
17 : #include "native_client/src/trusted/service_runtime/thread_suspension.h"
18 :
19 : namespace {
20 :
21 : const int kX86TrapFlag = 1 << 8;
22 :
23 : } // namespace
24 :
25 : namespace port {
26 :
27 : // TODO(mseaborn): Merge Thread and IThread into a single class,
28 : // because there is only one implementation of IThread and the methods
29 : // do not need to be virtual.
30 :
31 : class Thread : public IThread {
32 : public:
33 40 : Thread(uint32_t id, struct NaClAppThread *natp)
34 40 : : id_(id), natp_(natp), fault_signal_(0) {}
35 12 : ~Thread() {}
36 :
37 : uint32_t GetId() {
38 73 : return id_;
39 : }
40 :
41 120 : virtual bool SetStep(bool on) {
42 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
43 120 : if (on) {
44 36 : context_.flags |= kX86TrapFlag;
45 36 : } else {
46 84 : context_.flags &= ~kX86TrapFlag;
47 : }
48 120 : return true;
49 : #else
50 : // TODO(mseaborn): Implement for ARM.
51 : UNREFERENCED_PARAMETER(on);
52 : return false;
53 : #endif
54 : }
55 :
56 2400 : virtual bool GetRegister(uint32_t index, void *dst, uint32_t len) {
57 2400 : const gdb_rsp::Abi *abi = gdb_rsp::Abi::Get();
58 2400 : const gdb_rsp::Abi::RegDef *reg = abi->GetRegisterDef(index);
59 2400 : memcpy(dst, (char *) &context_ + reg->offset_, len);
60 2400 : return false;
61 : }
62 :
63 384 : virtual bool SetRegister(uint32_t index, void* src, uint32_t len) {
64 384 : const gdb_rsp::Abi *abi = gdb_rsp::Abi::Get();
65 384 : const gdb_rsp::Abi::RegDef *reg = abi->GetRegisterDef(index);
66 384 : if (reg->type_ == gdb_rsp::Abi::READ_ONLY) {
67 : // Do not change read-only registers.
68 : // TODO(eaeltsin): it is an error if new value is not equal to old value.
69 : // Suppress it for now as this is used in G packet that writes all
70 : // registers at once, and its failure might confuse GDB.
71 : // We can start actually reporting the error when we support P packet
72 : // that writes registers one at a time, as failure to write a single
73 : // register should be much less confusing.
74 384 : } else if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 &&
75 : NACL_BUILD_SUBARCH == 64 &&
76 : reg->type_ == gdb_rsp::Abi::X86_64_TRUSTED_PTR) {
77 : // Do not change high 32 bits.
78 : // GDB should work with untrusted addresses, thus high 32 bits of new
79 : // value should be 0.
80 : // TODO(eaeltsin): this is not fully implemented yet, and high 32 bits
81 : // of new value may also be equal to high 32 bits of old value.
82 : // Other cases are definitely bogus.
83 144 : CHECK(len == 8);
84 48 : memcpy((char *) &context_ + reg->offset_, src, 4);
85 48 : } else {
86 224 : memcpy((char *) &context_ + reg->offset_, src, len);
87 : }
88 384 : return false;
89 : }
90 :
91 : virtual void CopyRegistersFromAppThread() {
92 92 : NaClAppThreadGetSuspendedRegisters(natp_, &context_);
93 92 : }
94 :
95 : virtual void CopyRegistersToAppThread() {
96 75 : NaClAppThreadSetSuspendedRegisters(natp_, &context_);
97 75 : }
98 :
99 : virtual void SuspendThread() {
100 11 : NaClUntrustedThreadSuspend(natp_, /* save_registers= */ 1);
101 11 : CopyRegistersFromAppThread();
102 11 : }
103 :
104 : virtual void ResumeThread() {
105 11 : CopyRegistersToAppThread();
106 11 : NaClUntrustedThreadResume(natp_);
107 11 : }
108 :
109 : // HasThreadFaulted() returns whether the given thread has been
110 : // blocked as a result of faulting. The thread does not need to be
111 : // currently suspended.
112 : virtual bool HasThreadFaulted() {
113 164 : return natp_->fault_signal != 0;
114 : }
115 :
116 : // UnqueueFaultedThread() takes a thread that has been blocked as a
117 : // result of faulting and unblocks it. As a precondition, the
118 : // thread must be currently suspended.
119 : virtual void UnqueueFaultedThread() {
120 84 : int exception_code;
121 252 : CHECK(NaClAppThreadUnblockIfFaulted(natp_, &exception_code));
122 84 : fault_signal_ = 0;
123 84 : }
124 :
125 : virtual int GetFaultSignal() {
126 255 : return fault_signal_;
127 : }
128 :
129 84 : virtual void SetFaultSignal(int signal) {
130 84 : fault_signal_ = signal;
131 84 : }
132 :
133 48 : virtual struct NaClSignalContext *GetContext() { return &context_; }
134 84 : virtual struct NaClAppThread *GetAppThread() { return natp_; }
135 :
136 : private:
137 : uint32_t id_;
138 : struct NaClAppThread *natp_;
139 : struct NaClSignalContext context_;
140 : int fault_signal_;
141 : };
142 :
143 20 : IThread *IThread::Create(uint32_t id, struct NaClAppThread *natp) {
144 40 : return new Thread(id, natp);
145 0 : }
146 :
147 : } // namespace port
|