int __cdecl main(int argc, char *argv[]) { int err; /* Initialize the PAL environment */ err = PAL_Initialize(argc, argv); if(0 != err) { return FAIL; } PAL_InitializeDebug(); PAL_Terminate(); return 0; }
// // Init sets up all the objects that the RC thread will need to run. // HRESULT DebuggerRCThread::Init(void) { HRESULT hr = S_OK; HANDLE rightSideEventAvailable = NULL; HANDLE rightSideEventRead = NULL; HANDLE leftSideUnmanagedWaitEvent = NULL; HANDLE syncThreadIsLockFree = NULL; WCHAR tmpName[256]; NAME_EVENT_BUFFER; SECURITY_ATTRIBUTES *pSA = NULL; if (m_debugger == NULL) return E_INVALIDARG; // Init should only be called once. if (g_pRCThread != NULL) return E_FAIL; g_pRCThread = this; m_rgDCB = new DebuggerIPCControlBlock *[IPC_TARGET_COUNT]; if (NULL == m_rgDCB) { return E_OUTOFMEMORY; } memset( m_rgDCB, 0, sizeof(DebuggerIPCControlBlock *)*IPC_TARGET_COUNT); // Create 2 events for managing favors: unnamed, auto-reset, default=not-signaled m_FavorAvailableEvent = WszCreateEvent(NULL, FALSE, FALSE, NULL); if (m_FavorAvailableEvent == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } m_FavorReadEvent = WszCreateEvent(NULL, FALSE, FALSE, NULL); if (m_FavorReadEvent == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } // Create the thread control event. m_threadControlEvent = WszCreateEvent(NULL, FALSE, FALSE, NAME_EVENT(L"ThreadControlEvent")); if (m_threadControlEvent == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } // Create the helper thread can go event. Manual reset, and // initially signaled. m_helperThreadCanGoEvent = WszCreateEvent(NULL, TRUE, TRUE, NAME_EVENT(L"HelperThreadCanGoEvent")); if (m_helperThreadCanGoEvent == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } // We need to setup the shared memory and control block. // Get shared memory block from the IPCManager. if (g_pIPCManagerInterface == NULL) { LOG((LF_CORDB, LL_INFO10000, "DRCT::I: g_pIPCManagerInterface == NULL, can't create IPC Block\n")); hr = E_FAIL; goto exit; } hr = g_pIPCManagerInterface->GetSecurityAttributes(GetCurrentProcessId(), &pSA); if (FAILED(hr)) goto exit; // Create the events that the thread will need to receive events // from the out of process piece on the right side. // We will not fail out if CreateEvent fails for RSEA or RSER. Because // the worst case is that debugger cannot attach to debuggee. // rightSideEventAvailable = WszCreateEvent(pSA, FALSE, FALSE, NAME_EVENT(L"RightSideEventAvailable")); rightSideEventRead = WszCreateEvent(pSA, FALSE, FALSE, NAME_EVENT(L"RightSideEventRead")); leftSideUnmanagedWaitEvent = WszCreateEvent(NULL, TRUE, FALSE, NAME_EVENT(L"LeftSideUnmanagedWaitEvent")); if (leftSideUnmanagedWaitEvent == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } syncThreadIsLockFree = WszCreateEvent(NULL, TRUE, FALSE, NAME_EVENT(L"SyncThreadIsLockFree")); if (syncThreadIsLockFree == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } m_rgDCB[IPC_TARGET_OUTOFPROC] = g_pIPCManagerInterface->GetDebugBlock(); // Don't fail out because the SHM failed to create #if _DEBUG if (m_rgDCB[IPC_TARGET_OUTOFPROC] == NULL) { LOG((LF_CORDB, LL_INFO10000, "DRCT::I: Failed to get Debug IPC block from IPCManager.\n")); } #endif // _DEBUG // Copy RSEA and RSER into the control block only if SHM is created without error. if (m_rgDCB[IPC_TARGET_OUTOFPROC]) { hr = m_rgDCB[IPC_TARGET_OUTOFPROC]->Init(rightSideEventAvailable, rightSideEventRead, NULL, NULL, leftSideUnmanagedWaitEvent, syncThreadIsLockFree); if (FAILED(hr)) goto exit; // We have to ensure that most of the runtime offsets for the out-of-proc DCB are initialized right away. This is // needed to support certian races during an interop attach. Since we can't know whether an interop attach will ever // happen or not, we are forced to do this now. Note: this is really too early, as some data structures haven't been // initialized yet! hr = EnsureRuntimeOffsetsInit(IPC_TARGET_OUTOFPROC); if (FAILED(hr)) goto exit; // Note: we have to mark that we need the runtime offsets re-initialized for the out-of-proc DCB. This is because // things like the patch table aren't initialized yet. Calling NeedRuntimeOffsetsReInit() ensures that this happens // before we really need the patch table. NeedRuntimeOffsetsReInit(IPC_TARGET_OUTOFPROC); m_rgDCB[IPC_TARGET_OUTOFPROC]->m_helperThreadStartAddr = (void *) DebuggerRCThread::ThreadProcStatic; m_rgDCB[IPC_TARGET_OUTOFPROC]->m_leftSideProtocolCurrent = CorDB_LeftSideProtocolCurrent; m_rgDCB[IPC_TARGET_OUTOFPROC]->m_leftSideProtocolMinSupported = CorDB_LeftSideProtocolMinSupported; LOG((LF_CORDB, LL_INFO10, "DRCT::I: version info: %d.%d.%d current protocol=%d, min protocol=%d\n", m_rgDCB[IPC_TARGET_OUTOFPROC]->m_verMajor, m_rgDCB[IPC_TARGET_OUTOFPROC]->m_verMinor, m_rgDCB[IPC_TARGET_OUTOFPROC]->m_checkedBuild, m_rgDCB[IPC_TARGET_OUTOFPROC]->m_leftSideProtocolCurrent, m_rgDCB[IPC_TARGET_OUTOFPROC]->m_leftSideProtocolMinSupported)); } // Next we'll create the setup sync event for the right side - this // solves a race condition of "who gets to the setup code first?" // Since there's no guarantee that the thread executing managed // code will be executed after us, we've got to do this for // the inproc portion of the code, as well. hr = CreateSetupSyncEvent(); if (FAILED(hr)) goto exit; if (GetLastError() == ERROR_ALREADY_EXISTS) { // the event already exists. LOG((LF_CORDB, LL_INFO10000, "DRCT::I: setup sync event already exists.\n")); // Need to do some delayed initialization of the debugger services. DebuggerController::Initialize(); // Wait for the Setup Sync event before continuing. DWORD ret = WaitForSingleObject(m_SetupSyncEvent, INFINITE); if (ret != WAIT_OBJECT_0) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } // We no longer need this event now. CloseHandle(m_SetupSyncEvent); m_SetupSyncEvent = NULL; // Open LSEA and LSER (which would have been // created by Right side) swprintf(tmpName, CorDBIPCLSEventAvailName, GetCurrentProcessId()); if (m_rgDCB[IPC_TARGET_OUTOFPROC]) { m_rgDCB[IPC_TARGET_OUTOFPROC]->m_leftSideEventAvailable = WszOpenEvent(EVENT_ALL_ACCESS, true, tmpName ); if (m_rgDCB[IPC_TARGET_OUTOFPROC]->m_leftSideEventAvailable == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } } swprintf(tmpName, CorDBIPCLSEventReadName, GetCurrentProcessId()); if (m_rgDCB[IPC_TARGET_OUTOFPROC]) { m_rgDCB[IPC_TARGET_OUTOFPROC]->m_leftSideEventRead = WszOpenEvent(EVENT_ALL_ACCESS, true, tmpName ); if (m_rgDCB[IPC_TARGET_OUTOFPROC]->m_leftSideEventRead == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto exit; } } LOG((LF_CORDB, LL_INFO10000,"DRCT::I: calling PAL_InitializeDebug.\n")); // Tell the PAL that we're trying to debug PAL_InitializeDebug(); // At this point, the control block is complete and all four // events are available and valid for this process. // Since the sync event was created by the Right Side, // we'll need to mark the debugger as "attached." g_pEEInterface->MarkDebuggerAttached(); m_debugger->m_debuggerAttached = TRUE; } else { LOG((LF_CORDB, LL_INFO10000, "DRCT::I: setup sync event was created.\n")); // At this point, only RSEA and RSER are in the control // block. LSEA and LSER will remain invalid until the first // receipt of an event from the Right Side. // Set the Setup Sync event to let the Right Side know that // we've finished setting up the control block. SetEvent(m_SetupSyncEvent); } // Now do this all again for the inproc stuff m_rgDCB[IPC_TARGET_INPROC] = GetInprocControlBlock(); if (m_rgDCB[IPC_TARGET_INPROC] == NULL) { hr = E_OUTOFMEMORY; goto exit; } m_rgDCB[IPC_TARGET_INPROC]->Init(NULL, NULL, NULL, NULL, NULL, NULL); exit: g_pIPCManagerInterface->DestroySecurityAttributes(pSA); return hr; }