| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
| 6 #if defined(HOST_OS_FUCHSIA) | 6 #if defined(HOST_OS_FUCHSIA) |
| 7 | 7 |
| 8 #include "vm/thread_interrupter.h" | 8 #include "vm/thread_interrupter.h" |
| 9 | 9 |
| 10 #include <magenta/process.h> | 10 #include <magenta/process.h> |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 // feature is added for it. | 33 // feature is added for it. |
| 34 | 34 |
| 35 // A scope within which a target thread is suspended. When the scope is exited, | 35 // A scope within which a target thread is suspended. When the scope is exited, |
| 36 // the thread is resumed and its handle is closed. | 36 // the thread is resumed and its handle is closed. |
| 37 class ThreadSuspendScope { | 37 class ThreadSuspendScope { |
| 38 public: | 38 public: |
| 39 explicit ThreadSuspendScope(mx_handle_t thread_handle) | 39 explicit ThreadSuspendScope(mx_handle_t thread_handle) |
| 40 : thread_handle_(thread_handle), suspended_(true) { | 40 : thread_handle_(thread_handle), suspended_(true) { |
| 41 mx_status_t status = mx_task_suspend(thread_handle); | 41 mx_status_t status = mx_task_suspend(thread_handle); |
| 42 // If a thread is somewhere where suspend is impossible, mx_task_suspend() | 42 // If a thread is somewhere where suspend is impossible, mx_task_suspend() |
| 43 // can return ERR_NOT_SUPPORTED. | 43 // can return MX_ERR_NOT_SUPPORTED. |
| 44 if (status != NO_ERROR) { | 44 if (status != MX_OK) { |
| 45 if (FLAG_trace_thread_interrupter) { | 45 if (FLAG_trace_thread_interrupter) { |
| 46 OS::PrintErr("ThreadInterrupter: mx_task_suspend failed: %s\n", | 46 OS::PrintErr("ThreadInterrupter: mx_task_suspend failed: %s\n", |
| 47 mx_status_get_string(status)); | 47 mx_status_get_string(status)); |
| 48 } | 48 } |
| 49 suspended_ = false; | 49 suspended_ = false; |
| 50 } | 50 } |
| 51 } | 51 } |
| 52 | 52 |
| 53 ~ThreadSuspendScope() { | 53 ~ThreadSuspendScope() { |
| 54 if (suspended_) { | 54 if (suspended_) { |
| 55 mx_status_t status = mx_task_resume(thread_handle_, 0); | 55 mx_status_t status = mx_task_resume(thread_handle_, 0); |
| 56 if (status != NO_ERROR) { | 56 if (status != MX_OK) { |
| 57 // If we fail to resume a thread, then it's likely the program will | 57 // If we fail to resume a thread, then it's likely the program will |
| 58 // hang. Crash instead. | 58 // hang. Crash instead. |
| 59 FATAL1("mx_task_resume failed: %s", mx_status_get_string(status)); | 59 FATAL1("mx_task_resume failed: %s", mx_status_get_string(status)); |
| 60 } | 60 } |
| 61 } | 61 } |
| 62 mx_handle_close(thread_handle_); | 62 mx_handle_close(thread_handle_); |
| 63 } | 63 } |
| 64 | 64 |
| 65 bool suspended() const { return suspended_; } | 65 bool suspended() const { return suspended_; } |
| 66 | 66 |
| 67 private: | 67 private: |
| 68 mx_handle_t thread_handle_; | 68 mx_handle_t thread_handle_; |
| 69 bool suspended_; | 69 bool suspended_; |
| 70 | 70 |
| 71 DISALLOW_ALLOCATION(); | 71 DISALLOW_ALLOCATION(); |
| 72 DISALLOW_COPY_AND_ASSIGN(ThreadSuspendScope); | 72 DISALLOW_COPY_AND_ASSIGN(ThreadSuspendScope); |
| 73 }; | 73 }; |
| 74 | 74 |
| 75 class ThreadInterrupterFuchsia : public AllStatic { | 75 class ThreadInterrupterFuchsia : public AllStatic { |
| 76 public: | 76 public: |
| 77 #if defined(TARGET_ARCH_X64) | 77 #if defined(TARGET_ARCH_X64) |
| 78 static bool GrabRegisters(mx_handle_t thread, InterruptedThreadState* state) { | 78 static bool GrabRegisters(mx_handle_t thread, InterruptedThreadState* state) { |
| 79 mx_x86_64_general_regs_t regs; | 79 mx_x86_64_general_regs_t regs; |
| 80 uint32_t regset_size; | 80 uint32_t regset_size; |
| 81 mx_status_t status = mx_thread_read_state( | 81 mx_status_t status = mx_thread_read_state( |
| 82 thread, MX_THREAD_STATE_REGSET0, ®s, sizeof(regs), ®set_size); | 82 thread, MX_THREAD_STATE_REGSET0, ®s, sizeof(regs), ®set_size); |
| 83 if (status != NO_ERROR) { | 83 if (status != MX_OK) { |
| 84 if (FLAG_trace_thread_interrupter) { | 84 if (FLAG_trace_thread_interrupter) { |
| 85 OS::PrintErr("ThreadInterrupter failed to get registers: %s\n", | 85 OS::PrintErr("ThreadInterrupter failed to get registers: %s\n", |
| 86 mx_status_get_string(status)); | 86 mx_status_get_string(status)); |
| 87 } | 87 } |
| 88 return false; | 88 return false; |
| 89 } | 89 } |
| 90 state->pc = static_cast<uintptr_t>(regs.rip); | 90 state->pc = static_cast<uintptr_t>(regs.rip); |
| 91 state->fp = static_cast<uintptr_t>(regs.rbp); | 91 state->fp = static_cast<uintptr_t>(regs.rbp); |
| 92 state->csp = static_cast<uintptr_t>(regs.rsp); | 92 state->csp = static_cast<uintptr_t>(regs.rsp); |
| 93 state->dsp = static_cast<uintptr_t>(regs.rsp); | 93 state->dsp = static_cast<uintptr_t>(regs.rsp); |
| 94 return true; | 94 return true; |
| 95 } | 95 } |
| 96 #elif defined(TARGET_ARCH_ARM64) | 96 #elif defined(TARGET_ARCH_ARM64) |
| 97 static bool GrabRegisters(mx_handle_t thread, InterruptedThreadState* state) { | 97 static bool GrabRegisters(mx_handle_t thread, InterruptedThreadState* state) { |
| 98 mx_arm64_general_regs_t regs; | 98 mx_arm64_general_regs_t regs; |
| 99 uint32_t regset_size; | 99 uint32_t regset_size; |
| 100 mx_status_t status = mx_thread_read_state( | 100 mx_status_t status = mx_thread_read_state( |
| 101 thread, MX_THREAD_STATE_REGSET0, ®s, sizeof(regs), ®set_size); | 101 thread, MX_THREAD_STATE_REGSET0, ®s, sizeof(regs), ®set_size); |
| 102 if (status != NO_ERROR) { | 102 if (status != MX_OK) { |
| 103 if (FLAG_trace_thread_interrupter) { | 103 if (FLAG_trace_thread_interrupter) { |
| 104 OS::PrintErr("ThreadInterrupter failed to get registers: %s\n", | 104 OS::PrintErr("ThreadInterrupter failed to get registers: %s\n", |
| 105 mx_status_get_string(status)); | 105 mx_status_get_string(status)); |
| 106 } | 106 } |
| 107 return false; | 107 return false; |
| 108 } | 108 } |
| 109 state->pc = static_cast<uintptr_t>(regs.pc); | 109 state->pc = static_cast<uintptr_t>(regs.pc); |
| 110 state->fp = static_cast<uintptr_t>(regs.r[FPREG]); | 110 state->fp = static_cast<uintptr_t>(regs.r[FPREG]); |
| 111 state->csp = static_cast<uintptr_t>(regs.sp); | 111 state->csp = static_cast<uintptr_t>(regs.sp); |
| 112 state->dsp = static_cast<uintptr_t>(regs.r[SPREG]); | 112 state->dsp = static_cast<uintptr_t>(regs.r[SPREG]); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 124 | 124 |
| 125 // Get a handle on the target thread. | 125 // Get a handle on the target thread. |
| 126 const mx_koid_t target_thread_koid = os_thread->id(); | 126 const mx_koid_t target_thread_koid = os_thread->id(); |
| 127 if (FLAG_trace_thread_interrupter) { | 127 if (FLAG_trace_thread_interrupter) { |
| 128 OS::PrintErr("ThreadInterrupter: interrupting thread with koid=%d\n", | 128 OS::PrintErr("ThreadInterrupter: interrupting thread with koid=%d\n", |
| 129 target_thread_koid); | 129 target_thread_koid); |
| 130 } | 130 } |
| 131 mx_handle_t target_thread_handle; | 131 mx_handle_t target_thread_handle; |
| 132 status = mx_object_get_child(mx_process_self(), target_thread_koid, | 132 status = mx_object_get_child(mx_process_self(), target_thread_koid, |
| 133 MX_RIGHT_SAME_RIGHTS, &target_thread_handle); | 133 MX_RIGHT_SAME_RIGHTS, &target_thread_handle); |
| 134 if (status != NO_ERROR) { | 134 if (status != MX_OK) { |
| 135 if (FLAG_trace_thread_interrupter) { | 135 if (FLAG_trace_thread_interrupter) { |
| 136 OS::PrintErr("ThreadInterrupter: mx_object_get_child failed: %s\n", | 136 OS::PrintErr("ThreadInterrupter: mx_object_get_child failed: %s\n", |
| 137 mx_status_get_string(status)); | 137 mx_status_get_string(status)); |
| 138 } | 138 } |
| 139 return; | 139 return; |
| 140 } | 140 } |
| 141 if (target_thread_handle == MX_HANDLE_INVALID) { | 141 if (target_thread_handle == MX_HANDLE_INVALID) { |
| 142 if (FLAG_trace_thread_interrupter) { | 142 if (FLAG_trace_thread_interrupter) { |
| 143 OS::PrintErr( | 143 OS::PrintErr( |
| 144 "ThreadInterrupter: mx_object_get_child gave an invalid " | 144 "ThreadInterrupter: mx_object_get_child gave an invalid " |
| 145 "thread handle!"); | 145 "thread handle!"); |
| 146 } | 146 } |
| 147 return; | 147 return; |
| 148 } | 148 } |
| 149 | 149 |
| 150 // This scope suspends the thread. When we exit the scope, the thread is | 150 // This scope suspends the thread. When we exit the scope, the thread is |
| 151 // resumed, and the thread handle is closed. | 151 // resumed, and the thread handle is closed. |
| 152 ThreadSuspendScope tss(target_thread_handle); | 152 ThreadSuspendScope tss(target_thread_handle); |
| 153 if (!tss.suspended()) { | 153 if (!tss.suspended()) { |
| 154 return; | 154 return; |
| 155 } | 155 } |
| 156 | 156 |
| 157 // Check that the thread is suspended. | 157 // Check that the thread is suspended. |
| 158 status = PollThreadUntilSuspended(target_thread_handle); | 158 status = PollThreadUntilSuspended(target_thread_handle); |
| 159 if (status != NO_ERROR) { | 159 if (status != MX_OK) { |
| 160 return; | 160 return; |
| 161 } | 161 } |
| 162 | 162 |
| 163 // Grab the target thread's registers. | 163 // Grab the target thread's registers. |
| 164 InterruptedThreadState its; | 164 InterruptedThreadState its; |
| 165 if (!GrabRegisters(target_thread_handle, &its)) { | 165 if (!GrabRegisters(target_thread_handle, &its)) { |
| 166 return; | 166 return; |
| 167 } | 167 } |
| 168 // Currently we sample only threads that are associated | 168 // Currently we sample only threads that are associated |
| 169 // with an isolate. It is safe to call 'os_thread->thread()' | 169 // with an isolate. It is safe to call 'os_thread->thread()' |
| (...skipping 26 matching lines...) Expand all Loading... |
| 196 | 196 |
| 197 static mx_status_t PollThreadUntilSuspended(mx_handle_t thread_handle) { | 197 static mx_status_t PollThreadUntilSuspended(mx_handle_t thread_handle) { |
| 198 const intptr_t kMaxPollAttempts = 10; | 198 const intptr_t kMaxPollAttempts = 10; |
| 199 intptr_t poll_tries = 0; | 199 intptr_t poll_tries = 0; |
| 200 while (poll_tries < kMaxPollAttempts) { | 200 while (poll_tries < kMaxPollAttempts) { |
| 201 mx_info_thread_t thread_info; | 201 mx_info_thread_t thread_info; |
| 202 mx_status_t status = | 202 mx_status_t status = |
| 203 mx_object_get_info(thread_handle, MX_INFO_THREAD, &thread_info, | 203 mx_object_get_info(thread_handle, MX_INFO_THREAD, &thread_info, |
| 204 sizeof(thread_info), NULL, NULL); | 204 sizeof(thread_info), NULL, NULL); |
| 205 poll_tries++; | 205 poll_tries++; |
| 206 if (status != NO_ERROR) { | 206 if (status != MX_OK) { |
| 207 if (FLAG_trace_thread_interrupter) { | 207 if (FLAG_trace_thread_interrupter) { |
| 208 OS::PrintErr("ThreadInterrupter: mx_object_get_info failed: %s\n", | 208 OS::PrintErr("ThreadInterrupter: mx_object_get_info failed: %s\n", |
| 209 mx_status_get_string(status)); | 209 mx_status_get_string(status)); |
| 210 } | 210 } |
| 211 return status; | 211 return status; |
| 212 } | 212 } |
| 213 if (thread_info.state == MX_THREAD_STATE_SUSPENDED) { | 213 if (thread_info.state == MX_THREAD_STATE_SUSPENDED) { |
| 214 // Success. | 214 // Success. |
| 215 return NO_ERROR; | 215 return MX_OK; |
| 216 } | 216 } |
| 217 if (thread_info.state == MX_THREAD_STATE_RUNNING) { | 217 if (thread_info.state == MX_THREAD_STATE_RUNNING) { |
| 218 // Poll. | 218 // Poll. |
| 219 continue; | 219 continue; |
| 220 } | 220 } |
| 221 if (FLAG_trace_thread_interrupter) { | 221 if (FLAG_trace_thread_interrupter) { |
| 222 OS::PrintErr("ThreadInterrupter: Thread is not suspended: %s\n", | 222 OS::PrintErr("ThreadInterrupter: Thread is not suspended: %s\n", |
| 223 ThreadStateGetString(thread_info.state)); | 223 ThreadStateGetString(thread_info.state)); |
| 224 } | 224 } |
| 225 return ERR_BAD_STATE; | 225 return MX_ERR_BAD_STATE; |
| 226 } | 226 } |
| 227 if (FLAG_trace_thread_interrupter) { | 227 if (FLAG_trace_thread_interrupter) { |
| 228 OS::PrintErr("ThreadInterrupter: Exceeded max suspend poll tries\n"); | 228 OS::PrintErr("ThreadInterrupter: Exceeded max suspend poll tries\n"); |
| 229 } | 229 } |
| 230 return ERR_BAD_STATE; | 230 return MX_ERR_BAD_STATE; |
| 231 } | 231 } |
| 232 }; | 232 }; |
| 233 | 233 |
| 234 | 234 |
| 235 bool ThreadInterrupter::IsDebuggerAttached() { | 235 bool ThreadInterrupter::IsDebuggerAttached() { |
| 236 return false; | 236 return false; |
| 237 } | 237 } |
| 238 | 238 |
| 239 | 239 |
| 240 void ThreadInterrupter::InterruptThread(OSThread* thread) { | 240 void ThreadInterrupter::InterruptThread(OSThread* thread) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 257 | 257 |
| 258 void ThreadInterrupter::RemoveSignalHandler() { | 258 void ThreadInterrupter::RemoveSignalHandler() { |
| 259 // Nothing to do on Fuchsia. | 259 // Nothing to do on Fuchsia. |
| 260 } | 260 } |
| 261 | 261 |
| 262 #endif // !PRODUCT | 262 #endif // !PRODUCT |
| 263 | 263 |
| 264 } // namespace dart | 264 } // namespace dart |
| 265 | 265 |
| 266 #endif // defined(HOST_OS_FUCHSIA) | 266 #endif // defined(HOST_OS_FUCHSIA) |
| OLD | NEW |