HRESULT BuildPlatformSpecificDataTarget(MachineInfo machineInfo, DWORD processId, ShimDataTarget ** ppDataTarget) { HandleHolder hDummy; HRESULT hr = E_FAIL; ShimRemoteDataTarget * pRemoteDataTarget = NULL; DbgTransportTarget * pProxy = g_pDbgTransportTarget; DbgTransportSession * pTransport = NULL; hr = pProxy->GetTransportForProcess(processId, &pTransport, &hDummy); if (FAILED(hr)) { goto Label_Exit; } if (!pTransport->WaitForSessionToOpen(10000)) { hr = CORDBG_E_TIMEOUT; goto Label_Exit; } pRemoteDataTarget = new (nothrow) ShimRemoteDataTarget(processId, pProxy, pTransport); if (pRemoteDataTarget == NULL) { hr = E_OUTOFMEMORY; goto Label_Exit; } _ASSERTE(SUCCEEDED(hr)); *ppDataTarget = pRemoteDataTarget; pRemoteDataTarget->AddRef(); // must addref out-parameters Label_Exit: if (FAILED(hr)) { if (pRemoteDataTarget != NULL) { // The ShimRemoteDataTarget has ownership of the proxy and the transport, // so we don't need to clean them up here. delete pRemoteDataTarget; } else { if (pTransport != NULL) { pProxy->ReleaseTransport(pTransport); } } } return hr; }
// Attach the debugger to this process. HRESULT DbgTransportPipeline::DebugActiveProcess(MachineInfo machineInfo, DWORD processId) { // INativeEventPipeline has a 1:1 relationship with CordbProcess. _ASSERTE(!IsTransportRunning()); HRESULT hr = E_FAIL; m_pProxy = g_pDbgTransportTarget; // Establish a connection to the actual runtime to be debugged. hr = m_pProxy->GetTransportForProcess(processId, &m_pTransport, &m_hProcess); if (SUCCEEDED(hr)) { // TODO: Pass this timeout as a parameter all the way from debugger // Wait for the connection to become useable (or time out). if (!m_pTransport->WaitForSessionToOpen(10000)) { hr = CORDBG_E_TIMEOUT; } else { if (!m_pTransport->UseAsDebugger(&m_ticket)) { hr = CORDBG_E_DEBUGGER_ALREADY_ATTACHED; } } } if (SUCCEEDED(hr)) { m_dwProcessId = processId; m_fRunning = TRUE; } else { Dispose(); } return hr; }
// Allocate and return an old-style event channel object for this target platform. HRESULT NewEventChannelForThisPlatform(CORDB_ADDRESS pLeftSideDCB, ICorDebugMutableDataTarget * pMutableDataTarget, DWORD dwProcessId, MachineInfo machineInfo, IEventChannel ** ppEventChannel) { // @dbgtodo Mac - Consider moving all of the transport logic to one place. // Perhaps add a new function on DbgTransportManager. HandleHolder hDummy; HRESULT hr = E_FAIL; RemoteEventChannel * pEventChannel = NULL; DebuggerIPCControlBlock * pDCBBuffer = NULL; DbgTransportTarget * pProxy = g_pDbgTransportTarget; DbgTransportSession * pTransport = NULL; hr = pProxy->GetTransportForProcess(dwProcessId, &pTransport, &hDummy); if (FAILED(hr)) { goto Label_Exit; } if (!pTransport->WaitForSessionToOpen(10000)) { hr = CORDBG_E_TIMEOUT; goto Label_Exit; } pDCBBuffer = new (nothrow) DebuggerIPCControlBlock; if (pDCBBuffer == NULL) { hr = E_OUTOFMEMORY; goto Label_Exit; } pEventChannel = new (nothrow) RemoteEventChannel(pDCBBuffer, pProxy, pTransport); if (pEventChannel == NULL) { hr = E_OUTOFMEMORY; goto Label_Exit; } _ASSERTE(SUCCEEDED(hr)); *ppEventChannel = pEventChannel; Label_Exit: if (FAILED(hr)) { if (pEventChannel != NULL) { // The IEventChannel has ownership of the proxy and the transport, // so we don't need to clean them up here. delete pEventChannel; } else { if (pTransport != NULL) { pProxy->ReleaseTransport(pTransport); } if (pDCBBuffer != NULL) { delete pDCBBuffer; } } } return hr; }
// Create an process under the debugger. HRESULT DbgTransportPipeline::CreateProcessUnderDebugger( MachineInfo machineInfo, LPCWSTR lpApplicationName, LPCWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { // INativeEventPipeline has a 1:1 relationship with CordbProcess. _ASSERTE(!IsTransportRunning()); // We don't support interop-debugging on the Mac. _ASSERTE(!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))); // When we're using a transport we can't deal with creating a suspended process (we need the process to // startup in order that it can start up a transport thread and reply to our messages). _ASSERTE(!(dwCreationFlags & CREATE_SUSPENDED)); // Connect to the debugger proxy on the remote machine and ask it to create a process for us. HRESULT hr = E_FAIL; m_pProxy = g_pDbgTransportTarget; hr = m_pProxy->CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); if (SUCCEEDED(hr)) { // Establish a connection to the actual runtime to be debugged. hr = m_pProxy->GetTransportForProcess(lpProcessInformation->dwProcessId, &m_pTransport, &m_hProcess); if (SUCCEEDED(hr)) { // Wait for the connection to become useable (or time out). if (!m_pTransport->WaitForSessionToOpen(10000)) { hr = CORDBG_E_TIMEOUT; } else { if (!m_pTransport->UseAsDebugger(&m_ticket)) { hr = CORDBG_E_DEBUGGER_ALREADY_ATTACHED; } } } } if (SUCCEEDED(hr)) { _ASSERTE((m_hProcess != NULL) && (m_hProcess != INVALID_HANDLE_VALUE)); m_dwProcessId = lpProcessInformation->dwProcessId; // For Mac remote debugging, we don't actually have a process handle to hand back to the debugger. // Instead, we return a handle to an event as the "process handle". The Win32 event thread also waits // on this event handle, and the event will be signaled when the proxy notifies us that the process // on the remote machine is terminated. However, normally the debugger calls CloseHandle() immediately // on the "process handle" after CreateProcess() returns. Doing so causes the Win32 event thread to // continue waiting on a closed event handle, and so it will never wake up. // (In fact, in Whidbey, we also duplicate the process handle in code:CordbProcess::Init.) if (!DuplicateHandle(GetCurrentProcess(), m_hProcess, GetCurrentProcess(), &(lpProcessInformation->hProcess), 0, // ignored since we are going to pass DUPLICATE_SAME_ACCESS FALSE, DUPLICATE_SAME_ACCESS)) { hr = HRESULT_FROM_GetLastError(); } } if (SUCCEEDED(hr)) { m_fRunning = TRUE; } else { Dispose(); } return hr; }