| /******************************************************************************* | |
| * Copyright (c) 2009 Nokia and others. | |
| * All rights reserved. This program and the accompanying materials | |
| * are made available under the terms of the Eclipse Public License v1.0 | |
| * which accompanies this distribution, and is available at | |
| * http://www.eclipse.org/legal/epl-v10.html | |
| * | |
| * Contributors: | |
| * Nokia - Initial API and implementation | |
| *******************************************************************************/ | |
| #include <iostream> | |
| #include "TCFHeaders.h" | |
| #include "WinDebugMonitor.h" | |
| #include "Logger.h" | |
| #include "WinProcess.h" | |
| #include "WinThread.h" | |
| #include "EventClientNotifier.h" | |
| #include "AgentUtils.h" | |
| #include "psapi.h" | |
| #include "AgentAction.h" | |
| #include "ContextManager.h" | |
| #include "LoggingService.h" | |
| #include "SettingsService.h" | |
| #define BUFSIZE 512 | |
| std::string GetExecutableInfo(HANDLE hFile, unsigned long& baseOfCode, unsigned long& codeSize) | |
| { | |
| codeSize = 0; | |
| BOOL bSuccess = FALSE; | |
| TCHAR pszFilename[MAX_PATH+1]; | |
| HANDLE hFileMap; | |
| std::wstring path; | |
| // Get the file size. | |
| DWORD dwFileSizeHi = 0; | |
| DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi); | |
| if( dwFileSizeLo == 0 && dwFileSizeHi == 0 ) | |
| { | |
| printf("Cannot map a file with a length of zero.\n"); | |
| return FALSE; | |
| } | |
| // Create a file mapping object. | |
| hFileMap = CreateFileMapping(hFile, | |
| NULL, | |
| PAGE_READONLY, | |
| 0, | |
| 1, | |
| NULL); | |
| if (hFileMap) | |
| { | |
| // Create a file mapping to get the file name. | |
| void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1); | |
| if (pMem) | |
| { | |
| PIMAGE_DOS_HEADER dosHeader=(PIMAGE_DOS_HEADER )pMem; | |
| PIMAGE_NT_HEADERS pNTHeader; | |
| pNTHeader = (PIMAGE_NT_HEADERS) ((DWORD)dosHeader + dosHeader->e_lfanew); | |
| if ( pNTHeader->Signature == IMAGE_NT_SIGNATURE ) | |
| { | |
| PIMAGE_OPTIONAL_HEADER OptionalHeader = (PIMAGE_OPTIONAL_HEADER)&pNTHeader->OptionalHeader; | |
| codeSize = OptionalHeader->SizeOfCode; | |
| baseOfCode = OptionalHeader->BaseOfCode; | |
| } | |
| if (GetMappedFileName (GetCurrentProcess(), | |
| pMem, | |
| pszFilename, | |
| MAX_PATH)) | |
| { | |
| // Translate path with device name to drive letters. | |
| TCHAR szTemp[BUFSIZE]; | |
| szTemp[0] = '\0'; | |
| if (GetLogicalDriveStrings(BUFSIZE-1, szTemp)) | |
| { | |
| TCHAR szName[MAX_PATH]; | |
| TCHAR szDrive[3] = TEXT(" :"); | |
| BOOL bFound = FALSE; | |
| TCHAR* p = szTemp; | |
| do | |
| { | |
| // Copy the drive letter to the template string | |
| *szDrive = *p; | |
| // Look up each device name | |
| if (QueryDosDevice(szDrive, szName, MAX_PATH)) | |
| { | |
| UINT uNameLen = _tcslen(szName); | |
| if (uNameLen < MAX_PATH) | |
| { | |
| bFound = _tcsnicmp(pszFilename, szName, | |
| uNameLen) == 0; | |
| if (bFound) | |
| { | |
| // Reconstruct pszFilename using szTempFile | |
| // Replace device path with DOS path | |
| TCHAR szTempFile[MAX_PATH]; | |
| snprintf(szTempFile, sizeof(szTempFile), | |
| TEXT("%s%s"), | |
| szDrive, | |
| pszFilename+uNameLen); | |
| strncpy(pszFilename, szTempFile, _tcslen(szTempFile)); | |
| pszFilename[_tcslen(szTempFile)] = 0; | |
| } | |
| } | |
| } | |
| // Go to the next NULL character. | |
| while (*p++); | |
| } while (!bFound && *p); // end of string | |
| } | |
| } | |
| bSuccess = TRUE; | |
| UnmapViewOfFile(pMem); | |
| } | |
| CloseHandle(hFileMap); | |
| } | |
| return AgentUtils::makeString(pszFilename); | |
| } | |
| WinDebugMonitor::WinDebugMonitor(const LaunchProcessParams& params) : | |
| DebugMonitor(params) | |
| { | |
| memset(&processInfo, 0, sizeof(processInfo)); | |
| handledInitialDebugBreakpoint = false; | |
| waitForDebugEvents = true; | |
| wfdeWait = 50; | |
| monitorThread_ = NULL; | |
| isAttach = false; | |
| } | |
| WinDebugMonitor::WinDebugMonitor(const AttachToProcessParams& params) : | |
| DebugMonitor(params) | |
| { | |
| memset(&processInfo, 0, sizeof(processInfo)); | |
| // TODO don't think the NTDLL!DbgBreakPoint applies when attaching but need to test. if you hit that breakpoint | |
| // right after attaching then this needs to be change to false | |
| handledInitialDebugBreakpoint = true; | |
| waitForDebugEvents = true; | |
| wfdeWait = 50; | |
| monitorThread_ = NULL; | |
| this->processID = (DWORD) params.processID; | |
| isAttach = true; | |
| } | |
| WinDebugMonitor::~WinDebugMonitor(void) | |
| { | |
| } | |
| void WinDebugMonitor::LaunchProcess(const LaunchProcessParams& params) throw (AgentException) | |
| { | |
| (new WinDebugMonitor(params))->StartMonitor(); | |
| } | |
| /* | |
| * Static method. Entry for attaching. | |
| */ | |
| void WinDebugMonitor::AttachToProcess(const AttachToProcessParams& params) throw (AgentException) | |
| { | |
| (new WinDebugMonitor(params))->StartMonitor(); | |
| } | |
| void WinDebugMonitor::StartDebug() { | |
| if (! isAttach) | |
| StartProcessForDebug(); | |
| else | |
| AttachToProcessForDebug(); | |
| } | |
| void WinDebugMonitor::AttachToProcessForDebug() | |
| { | |
| // Note this is supposed to reply to TCF request ProcessService::Command_Attach(). | |
| if (!DebugActiveProcess(processID)) | |
| { | |
| DWORD err = GetLastError(); | |
| AgentActionReply::postReply(channel, token, set_win32_errno(err)); | |
| } else { | |
| // Allow detach without kill. | |
| DebugSetProcessKillOnExit(false); | |
| // OK | |
| AgentActionReply::postReply(channel, token, 0); | |
| } | |
| } | |
| void WinDebugMonitor::StartProcessForDebug() | |
| { | |
| STARTUPINFO si; | |
| memset(&si, 0, sizeof(si)); | |
| si.cb = sizeof (si); | |
| si.dwFlags = STARTF_FORCEONFEEDBACK | STARTF_USESHOWWINDOW; | |
| si.wShowWindow = SW_SHOWNORMAL; | |
| TCHAR* argsBuffer = new TCHAR[args.size() + sizeof(TCHAR)]; | |
| strcpy(argsBuffer, args.c_str()); | |
| std::string exeName = executable; | |
| LPTSTR workingDirectory = NULL; | |
| if (directory.length() > 0) | |
| { | |
| workingDirectory = (LPTSTR)directory.c_str(); | |
| } | |
| char* envBuffer = NULL; | |
| std::string envString; | |
| if (environment.size() > 0) | |
| { | |
| std::vector<std::string>::iterator itEnvData; | |
| for (itEnvData = environment.begin(); itEnvData | |
| != environment.end(); itEnvData++) | |
| { | |
| std::string value = *itEnvData; | |
| envString += value; | |
| envString += char(0); | |
| } | |
| envString += char(0); | |
| envBuffer = new char[envString.length()]; | |
| memcpy(envBuffer, envString.c_str(), envString.length()); | |
| } | |
| if (!CreateProcess(exeName.c_str(), argsBuffer, | |
| (LPSECURITY_ATTRIBUTES)NULL, | |
| (LPSECURITY_ATTRIBUTES)NULL, | |
| FALSE, | |
| (GetDebugChildren() ? DEBUG_PROCESS : DEBUG_ONLY_THIS_PROCESS) | CREATE_NEW_CONSOLE, | |
| envBuffer, | |
| workingDirectory, //NULL, | |
| (LPSTARTUPINFO)&si, | |
| (LPPROCESS_INFORMATION)&processInfo)) | |
| { | |
| DWORD err = GetLastError(); | |
| std::string msg = "Failed to start process "; | |
| msg += '\"'; | |
| msg += AgentUtils::makeUTF8String(exeName); | |
| msg += "\""; | |
| err = set_win32_errno(err); | |
| AgentActionReply::postReply(channel, token, err, 1, new std::string(msg)); | |
| } else { | |
| // AOK | |
| AgentActionReply::postReply(channel, token, 0, 1); | |
| processID = processInfo.dwProcessId; | |
| } | |
| delete[] envBuffer; | |
| delete[] argsBuffer; | |
| } | |
| void WinDebugMonitor::CaptureMonitorThread() | |
| { | |
| DuplicateHandle(GetCurrentProcess(),GetCurrentThread(), | |
| GetCurrentProcess(),&monitorThread_, | |
| 0,FALSE,DUPLICATE_SAME_ACCESS); | |
| } | |
| DWORD WINAPI debuggerMonitorThread(LPVOID param) | |
| { | |
| WinDebugMonitor * dpm = (WinDebugMonitor*)param; | |
| try | |
| { | |
| dpm->CaptureMonitorThread(); | |
| dpm->StartDebug(); | |
| dpm->EventLoop(); | |
| } | |
| catch (const AgentException& e) | |
| { | |
| DWORD error = GetLastError(); | |
| trace(LOG_ALWAYS, "Agent Exception: code=%x: %s", error, e.what()); | |
| } | |
| return 0; | |
| } | |
| void WinDebugMonitor::Suspend() | |
| { | |
| SuspendThread(monitorThread_); | |
| } | |
| void WinDebugMonitor::Resume() | |
| { | |
| ResumeThread(monitorThread_); | |
| } | |
| void WinDebugMonitor::StartMonitor() | |
| { | |
| DWORD threadID = 0; | |
| HANDLE startThread = CreateThread( | |
| NULL, // default security attributes | |
| 0, // use default stack size | |
| debuggerMonitorThread, // thread function name | |
| this, // argument to thread function | |
| 0, // use default creation flags | |
| &threadID); // returns the thread identifier | |
| CloseHandle(startThread); | |
| } | |
| void WinDebugMonitor::EventLoop() | |
| { | |
| DEBUG_EVENT debugEvent; | |
| while (waitForDebugEvents) | |
| { | |
| if (WaitForDebugEvent(&debugEvent, wfdeWait)) | |
| HandleDebugEvent(debugEvent); | |
| else { | |
| DWORD err = GetLastError(); | |
| if (err == ERROR_SEM_TIMEOUT || err == 0) | |
| HandleNoDebugEvent(); | |
| else { | |
| trace(LOG_ALWAYS, "WinDebugMonitor::EventLoop: error %d", err); | |
| waitForDebugEvents = false; | |
| } | |
| } | |
| } | |
| trace(LOG_CONTEXT, "Monitor thread for process %d has exited. \n", processID); | |
| } | |
| void WinDebugMonitor::Attach(unsigned long pid, ContextAttachCallBack * done, void * data, int selfattach) { | |
| // TODO: implement | |
| } | |
| static const char * win32_debug_event_name(int event) { | |
| switch (event) { | |
| case CREATE_PROCESS_DEBUG_EVENT: | |
| return "CREATE_PROCESS_DEBUG_EVENT"; | |
| case CREATE_THREAD_DEBUG_EVENT: | |
| return "CREATE_THREAD_DEBUG_EVENT"; | |
| case EXCEPTION_DEBUG_EVENT: | |
| return "EXCEPTION_DEBUG_EVENT"; | |
| case EXIT_PROCESS_DEBUG_EVENT: | |
| return "EXIT_PROCESS_DEBUG_EVENT"; | |
| case EXIT_THREAD_DEBUG_EVENT: | |
| return "EXIT_THREAD_DEBUG_EVENT"; | |
| case LOAD_DLL_DEBUG_EVENT: | |
| return "LOAD_DLL_DEBUG_EVENT"; | |
| case OUTPUT_DEBUG_STRING_EVENT: | |
| return "OUTPUT_DEBUG_STRING_EVENT"; | |
| case UNLOAD_DLL_DEBUG_EVENT: | |
| return "UNLOAD_DLL_DEBUG_EVENT"; | |
| } | |
| return "Unknown"; | |
| } | |
| void WinDebugMonitor::HandleDebugEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| LogTrace("DebugProcessMonitor::HandleDebugEvent", "event code: %s", win32_debug_event_name(debugEvent.dwDebugEventCode)); | |
| switch (debugEvent.dwDebugEventCode) | |
| { | |
| case EXCEPTION_DEBUG_EVENT: | |
| HandleExceptionEvent(debugEvent); | |
| break; | |
| case CREATE_PROCESS_DEBUG_EVENT: | |
| HandleProcessCreatedEvent(debugEvent); | |
| break; | |
| case CREATE_THREAD_DEBUG_EVENT: | |
| HandleThreadCreatedEvent(debugEvent); | |
| break; | |
| case EXIT_PROCESS_DEBUG_EVENT: | |
| HandleProcessExitedEvent(debugEvent); | |
| return; | |
| case EXIT_THREAD_DEBUG_EVENT: | |
| HandleThreadExitedEvent(debugEvent); | |
| break; | |
| case LOAD_DLL_DEBUG_EVENT: | |
| HandleDLLLoadedEvent(debugEvent); | |
| break; | |
| case UNLOAD_DLL_DEBUG_EVENT: | |
| HandleDLLUnloadedEvent(debugEvent); | |
| break; | |
| case OUTPUT_DEBUG_STRING_EVENT: | |
| HandleDebugStringEvent(debugEvent); | |
| break; | |
| case RIP_EVENT: | |
| HandleSystemDebugErrorEvent(debugEvent); | |
| break; | |
| default: | |
| HandleUnknwonDebugEvent(debugEvent); | |
| break; | |
| } | |
| } | |
| void WinDebugMonitor::HandleNoDebugEvent() | |
| { | |
| while (!actions_.empty()) | |
| { | |
| AgentAction* action = actions_.front(); | |
| actions_.pop(); | |
| action->Run(); | |
| delete action; | |
| } | |
| } | |
| std::string WinDebugMonitor::GetDebugExceptionDescription(const EXCEPTION_DEBUG_INFO& exceptionInfo) { | |
| DWORD code = exceptionInfo.ExceptionRecord.ExceptionCode; | |
| const char* base = "Unknown Exception"; | |
| std::string detail; | |
| switch (code) { | |
| case EXCEPTION_SINGLE_STEP: | |
| base = "Step"; | |
| break; | |
| case EXCEPTION_BREAKPOINT: | |
| base = "Breakpoint"; | |
| break; | |
| case EXCEPTION_ACCESS_VIOLATION: | |
| base = "Access violation"; | |
| detail = " at 0x" + AgentUtils::IntToHexString(exceptionInfo.ExceptionRecord.ExceptionInformation[1]); | |
| break; | |
| case DBG_CONTROL_C: | |
| base = "Control-C"; | |
| break; | |
| case DBG_CONTROL_BREAK: | |
| base = "Control-Break"; | |
| break; | |
| case STATUS_DATATYPE_MISALIGNMENT: | |
| base = "Datatype misalignment"; | |
| break; | |
| case STATUS_IN_PAGE_ERROR: | |
| base = "Virtual memory paging error"; | |
| break; | |
| case STATUS_NO_MEMORY: | |
| base = "Out of memory"; | |
| break; | |
| case STATUS_ILLEGAL_INSTRUCTION: | |
| base = "Illegal instruction"; | |
| break; | |
| case STATUS_NONCONTINUABLE_EXCEPTION: | |
| base = "Noncontinuable exception"; | |
| break; | |
| case STATUS_INVALID_DISPOSITION: | |
| base = "Invalid disposition"; | |
| break; | |
| case STATUS_ARRAY_BOUNDS_EXCEEDED: | |
| base = "Array bounds exceeded"; | |
| break; | |
| case STATUS_FLOAT_DENORMAL_OPERAND: | |
| base = "Floating point denormal operand"; | |
| break; | |
| case STATUS_FLOAT_DIVIDE_BY_ZERO: | |
| base = "Floating point divide by zero"; | |
| break; | |
| case STATUS_FLOAT_INEXACT_RESULT: | |
| base = "Floating point inexact result"; | |
| break; | |
| case STATUS_FLOAT_INVALID_OPERATION: | |
| base = "Floating point invalid operation"; | |
| break; | |
| case STATUS_FLOAT_STACK_CHECK: | |
| base = "Floating point stack check"; | |
| break; | |
| case STATUS_FLOAT_OVERFLOW: | |
| base = "Floating point overflow"; | |
| break; | |
| case STATUS_FLOAT_UNDERFLOW: | |
| base = "Floating point underflow"; | |
| break; | |
| case STATUS_INTEGER_DIVIDE_BY_ZERO: | |
| base = "Integer divide by zero"; | |
| break; | |
| case STATUS_INTEGER_OVERFLOW: | |
| base = "Integer overflow"; | |
| break; | |
| case STATUS_PRIVILEGED_INSTRUCTION: | |
| base = "Privileged instruction"; | |
| break; | |
| case STATUS_STACK_OVERFLOW: | |
| base = "Stack overflow"; | |
| break; | |
| case STATUS_DLL_NOT_FOUND: | |
| base = "DLL not found"; | |
| // TODO: find out how to determine which DLL it was... | |
| break; | |
| case STATUS_DLL_INIT_FAILED: | |
| base = "DLL initialization failed"; | |
| break; | |
| case STATUS_ENTRYPOINT_NOT_FOUND: | |
| base = "Entry point not found"; | |
| break; | |
| case MS_CPLUS_EXCEPTION: | |
| base = "C++ exception"; | |
| break; | |
| case RPC_S_UNKNOWN_IF: | |
| base = "RPC unknown interface"; | |
| break; | |
| case RPC_S_SERVER_UNAVAILABLE: | |
| base = "RPC server unavailable"; | |
| break; | |
| } | |
| if (detail.size() > 0) { | |
| return std::string(base) + detail; | |
| } | |
| return base; | |
| } | |
| void WinDebugMonitor::HandleExceptionEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| EXCEPTION_RECORD &e = debugEvent.u.Exception.ExceptionRecord; | |
| LogTrace("DebugProcessMonitor::HandleExceptionEvent", "Exception in thread %d at 0x%x: code 0x%x (%s)", | |
| debugEvent.dwThreadId, e.ExceptionAddress, e.ExceptionCode, | |
| GetDebugExceptionDescription(debugEvent.u.Exception).c_str()); | |
| WinThread* thread = WinThread::GetThreadByID(debugEvent.dwProcessId, debugEvent.dwThreadId); | |
| if (!thread) | |
| assert(false); | |
| // ignore initial breakpoint in NTDLL!DbgBreakPoint for newly launched process if necessary | |
| if (!handledInitialDebugBreakpoint && e.ExceptionCode == EXCEPTION_BREAKPOINT) | |
| { | |
| trace(LOG_ALWAYS, "\t -- ignored: initial ntdll DbgBreakPoint breakpoint"); | |
| handledInitialDebugBreakpoint = true; | |
| // The "DBG_EXCEPTION_NOT_HANDLED" flag will make some other unknown breakpoint(s) in system dlls | |
| // show up on some machines. But "DBG_CONTINUE" won't. | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| return; | |
| } | |
| if (thread && SettingsService::reportExceptionEvent(debugEvent)) | |
| { | |
| trace(LOG_ALWAYS, "\t -- reported to host debugger."); | |
| thread->HandleException(debugEvent); | |
| } | |
| else | |
| { | |
| trace(LOG_ALWAYS, "\t -- ignored."); | |
| // Note DBG_EXCEPTION_NOT_HANDLED is used here. | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); | |
| } | |
| } | |
| void WinDebugMonitor::HandleProcessCreatedEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| WinProcess* process = new WinProcess(this, debugEvent); | |
| WinThread* thread = new WinThread(*process, debugEvent); | |
| process->SetDebugging(true); | |
| thread->SetDebugging(true); | |
| // record in our cache | |
| ContextManager::addContext(process); | |
| ContextManager::addContext(thread); | |
| // Notify host | |
| EventClientNotifier::SendContextAdded(process); | |
| EventClientNotifier::SendContextAdded(thread); | |
| unsigned long codeSize = 0; | |
| unsigned long baseOfCode = 0; | |
| std::string imageName = GetExecutableInfo(debugEvent.u.CreateProcessInfo.hFile, baseOfCode, codeSize); | |
| if (SettingsService::reportDebugEventForModule(imageName)) | |
| thread->HandleExecutableEvent(true, imageName, (unsigned long)debugEvent.u.CreateProcessInfo.lpBaseOfImage, codeSize + baseOfCode); | |
| else | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| CloseHandle(debugEvent.u.CreateProcessInfo.hFile); | |
| } | |
| void WinDebugMonitor::HandleThreadCreatedEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| WinProcess* process = WinProcess::GetProcessByID(debugEvent.dwProcessId); | |
| if (process) { | |
| WinThread* thread = new WinThread(*process, debugEvent); | |
| thread->SetDebugging(true); | |
| ContextManager::addContext(thread); | |
| EventClientNotifier::SendContextAdded(thread); | |
| } else { | |
| assert(false); | |
| } | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| } | |
| void WinDebugMonitor::HandleProcessExitedEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| WinProcess* process = WinProcess::GetProcessByID(debugEvent.dwProcessId); | |
| if (process) { | |
| EventClientNotifier::SendContextRemoved(process, true); | |
| } else { | |
| assert(false); | |
| } | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| } | |
| /** | |
| * Make sure monitor thread is killed after the process being debugged died or | |
| * is terminated. | |
| * Note there is one monitor thread for each debugged process. The "process_id" | |
| * passed in should be the process being monitored. | |
| */ | |
| void WinDebugMonitor::ProcessDied(DWORD process_id) | |
| { | |
| // Terminate monitor thread if the process being monitored has died. | |
| if (processID == process_id) | |
| waitForDebugEvents = false; | |
| else | |
| assert(false); | |
| } | |
| void WinDebugMonitor::HandleThreadExitedEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| WinThread* thread = WinThread::GetThreadByID(debugEvent.dwProcessId, debugEvent.dwThreadId); | |
| if (thread) { | |
| EventClientNotifier::SendContextRemoved(thread, true); | |
| } else { | |
| assert(false); | |
| } | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| } | |
| void WinDebugMonitor::HandleDLLLoadedEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| unsigned long codeSize = 0; | |
| unsigned long baseOfCode = 0; | |
| std::string moduleName = GetExecutableInfo(debugEvent.u.LoadDll.hFile, baseOfCode, codeSize); | |
| if (SettingsService::reportDebugEventForModule(moduleName)) | |
| { | |
| LogTrace("DebugProcessMonitor::HandleDLLLoadedEvent", "Base address: %8.8x %s", debugEvent.u.LoadDll.lpBaseOfDll, moduleName.c_str()); | |
| WinThread* thread = WinThread::GetThreadByID(debugEvent.dwProcessId, debugEvent.dwThreadId); | |
| if (thread) { | |
| thread->HandleExecutableEvent(true, moduleName, (unsigned long)debugEvent.u.LoadDll.lpBaseOfDll, codeSize); | |
| } | |
| } | |
| else | |
| { | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| } | |
| CloseHandle(debugEvent.u.LoadDll.hFile); | |
| } | |
| void WinDebugMonitor::HandleDLLUnloadedEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| // if our process knows about this dll then it must be in the list of modules to debug | |
| WinProcess* process = WinProcess::GetProcessByID(debugEvent.dwProcessId); | |
| if (process) | |
| { | |
| Properties props = process->GetExecutablesByAddress()[(unsigned long)debugEvent.u.UnloadDll.lpBaseOfDll]; | |
| if (!props.empty()) | |
| { | |
| WinThread* thread = WinThread::GetThreadByID(debugEvent.dwProcessId, debugEvent.dwThreadId); | |
| if (thread) { | |
| thread->HandleExecutableEvent(false, "", (unsigned long)debugEvent.u.UnloadDll.lpBaseOfDll, 0); | |
| } | |
| } | |
| } | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| } | |
| void WinDebugMonitor::HandleDebugStringEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| if (SettingsService::reportDebugStringEvents()) | |
| { | |
| WinProcess* process = WinProcess::GetProcessByID(debugEvent.dwProcessId); | |
| if (debugEvent.u.DebugString.fUnicode == 0) | |
| { | |
| int debugStringLength = debugEvent.u.DebugString.nDebugStringLength; | |
| char* debugStringBuffer = new char[debugStringLength + 1]; | |
| ReadProcessMemory(process->GetProcessHandle(), debugEvent.u.DebugString.lpDebugStringData, debugStringBuffer, | |
| debugStringLength,NULL); | |
| debugStringBuffer[debugStringLength] = 0; | |
| // convert from ansi to utf-8 | |
| wchar_t* wideChars = new wchar_t[debugStringLength]; | |
| // Covert to Unicode. | |
| if (MultiByteToWideChar(CP_ACP, 0, debugStringBuffer, debugStringLength, | |
| wideChars, debugStringLength) != 0) | |
| { | |
| int size_needed = WideCharToMultiByte(CP_UTF8, 0, wideChars, debugStringLength, NULL, 0, NULL, NULL); | |
| std::string strTo( size_needed, 0 ); | |
| WideCharToMultiByte(CP_UTF8, 0, wideChars, debugStringLength, &strTo[0], size_needed, NULL, NULL); | |
| // write console data, if console | |
| LoggingService::WriteLoggingMessage(channel, strTo, LoggingService::GetWindowsConsoleID()); | |
| LogTrace("DebugProcessMonitor::HandleDebugStringEvent", "%s", strTo.c_str()); | |
| } | |
| delete[] wideChars; | |
| delete[] debugStringBuffer; | |
| } | |
| } | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| } | |
| void WinDebugMonitor::HandleSystemDebugErrorEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| } | |
| void WinDebugMonitor::HandleUnknwonDebugEvent(DEBUG_EVENT& debugEvent) | |
| { | |
| ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); | |
| } | |
| void WinDebugMonitor::PostAction(AgentAction* action) | |
| { | |
| actions_.push(action); | |
| } | |