| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | //***************************************************************************** |
| 5 | // File: reimpl.cpp |
| 6 | // |
| 7 | |
| 8 | // |
| 9 | // Data-access-specific reimplementations of standard code. |
| 10 | // |
| 11 | //***************************************************************************** |
| 12 | |
| 13 | #include "stdafx.h" |
| 14 | |
| 15 | // |
| 16 | // Get the Thread instance for a specific OS thread ID |
| 17 | // |
| 18 | // Arguments: |
| 19 | // osThread - the OS thread ID of interest. |
| 20 | // |
| 21 | // Return value: |
| 22 | // A Thread object marshalled from the target corresponding to the specified OS thread |
| 23 | // ID, or NULL if there is no such Thread. |
| 24 | // |
| 25 | // Notes: |
| 26 | // We used to accept a thread ID of '0' to mean "use the current thread", which was based on |
| 27 | // ICLRDataTarget::GetCurrentThreadID. But this is error-prone and not well-defined (many data targets |
| 28 | // don't implement that API). It's better to require explicit thread IDs to be passed down when they |
| 29 | // are needed. |
| 30 | // |
| 31 | Thread* __stdcall |
| 32 | DacGetThread(ULONG32 osThread) |
| 33 | { |
| 34 | _ASSERTE(osThread > 0); |
| 35 | |
| 36 | if (!g_dacImpl) |
| 37 | { |
| 38 | DacError(E_UNEXPECTED); |
| 39 | UNREACHABLE(); |
| 40 | } |
| 41 | |
| 42 | // Note that if we had access to TLS, we could get this at index gThreadTLSIndex for the specified |
| 43 | // thread. However, this is the only place we might want to use TLS, and it's not performance critical, |
| 44 | // so we haven't added TLS support to ICorDebugDataTarget (the legacy ICLRDataTarget interface has it though) |
| 45 | |
| 46 | // Scan the whole thread store to see if there's a matching thread. |
| 47 | |
| 48 | if (!ThreadStore::s_pThreadStore) |
| 49 | { |
| 50 | return NULL; |
| 51 | } |
| 52 | |
| 53 | Thread* thread = ThreadStore::s_pThreadStore->m_ThreadList.GetHead(); |
| 54 | while (thread) |
| 55 | { |
| 56 | if (thread->GetOSThreadId() == osThread) |
| 57 | { |
| 58 | return thread; |
| 59 | } |
| 60 | |
| 61 | thread = ThreadStore::s_pThreadStore->m_ThreadList.GetNext(thread); |
| 62 | } |
| 63 | |
| 64 | return NULL; |
| 65 | } |
| 66 | |
| 67 | EXTERN_C Thread* GetThread() |
| 68 | { |
| 69 | // In dac mode it's unlikely that the thread calling dac |
| 70 | // is actually the same "current thread" that the runtime cares |
| 71 | // about. Fail all queries of the current thread by |
| 72 | // the runtime code to catch any inadvertent usage. |
| 73 | // Enumerating the ThreadStore is the proper way to get access |
| 74 | // to specific Thread objects. |
| 75 | DacError(E_UNEXPECTED); |
| 76 | return NULL; |
| 77 | } |
| 78 | |
| 79 | BOOL |
| 80 | DacGetThreadContext(Thread* thread, T_CONTEXT* context) |
| 81 | { |
| 82 | SUPPORTS_DAC; |
| 83 | |
| 84 | if (!g_dacImpl) |
| 85 | { |
| 86 | DacError(E_UNEXPECTED); |
| 87 | UNREACHABLE(); |
| 88 | } |
| 89 | |
| 90 | // XXX Microsoft - How do you retrieve the context for |
| 91 | // a Thread that's not running? |
| 92 | if (!thread->GetOSThreadId() || |
| 93 | thread->GetOSThreadId() == 0xbaadf00d) |
| 94 | { |
| 95 | DacError(E_UNEXPECTED); |
| 96 | UNREACHABLE(); |
| 97 | } |
| 98 | |
| 99 | ULONG32 contextFlags; |
| 100 | |
| 101 | contextFlags = CONTEXT_ALL; |
| 102 | |
| 103 | HRESULT status = |
| 104 | g_dacImpl->m_pTarget-> |
| 105 | GetThreadContext(thread->GetOSThreadId(), contextFlags, |
| 106 | sizeof(*context), (PBYTE)context); |
| 107 | if (status != S_OK) |
| 108 | { |
| 109 | DacError(status); |
| 110 | UNREACHABLE(); |
| 111 | } |
| 112 | |
| 113 | return TRUE; |
| 114 | } |
| 115 | |
| 116 | |