|
|
//----------------------------------------------------------------------------
//
// Process abstraction.
//
// Copyright (C) Microsoft Corporation, 2001-2002.
//
//----------------------------------------------------------------------------
#include "ntsdp.hpp"
#include <common.ver>
#define NTLDR_IMAGE_NAME "ntldr"
#define OSLOADER_IMAGE_NAME "osloader"
#define SETUPLDR_IMAGE_NAME "setupldr"
#define LDR_IMAGE_SIZE 0x80000
#define CSRSS_IMAGE_NAME "csrss.exe"
#define LSASS_IMAGE_NAME "lsass.exe"
#define SERVICES_IMAGE_NAME "services.exe"
void RestrictModNameChars(PCSTR ModName, PSTR RewriteBuffer) { PCSTR Scan = ModName; PSTR Write = RewriteBuffer;
while (*Scan) { if ((*Scan < 'a' || *Scan > 'z') && (*Scan < 'A' || *Scan > 'Z') && (*Scan < '0' || *Scan > '9') && *Scan != '_') { *Write++ = '_'; } else { *Write++ = *Scan; }
Scan++; } *Write = 0; }
//----------------------------------------------------------------------------
//
// ProcCorDataAccessServices.
//
//----------------------------------------------------------------------------
ProcCorDataAccessServices::ProcCorDataAccessServices(void) { m_Process = NULL; }
STDMETHODIMP ProcCorDataAccessServices::QueryInterface( THIS_ IN REFIID InterfaceId, OUT PVOID* Interface ) { if (DbgIsEqualIID(InterfaceId, IID_IUnknown) || DbgIsEqualIID(InterfaceId, __uuidof(ICorDataAccessServices))) { *Interface = (ICorDataAccessServices*)this; // No need to refcount as this class is contained.
return S_OK; } else { *Interface = NULL; return E_NOINTERFACE; } }
STDMETHODIMP_(ULONG) ProcCorDataAccessServices::AddRef( THIS ) { // No need to refcount as this class is contained.
return 1; }
STDMETHODIMP_(ULONG) ProcCorDataAccessServices::Release( THIS ) { // No need to refcount as this class is contained.
return 0; }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::GetMachineType( /* [out] */ ULONG32 *machine) { *machine = m_Process->m_Target->m_MachineType; return S_OK; }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::GetPointerSize( /* [out] */ ULONG32 *size) { *size = m_Process->m_Target->m_Machine->m_Ptr64 ? 8 : 4; return S_OK; }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::GetImageBase( /* [string][in] */ LPCWSTR name, /* [out] */ CORDATA_ADDRESS *base) { HRESULT Status; PSTR Ansi; INAME WhichName; ImageInfo* Image;
if ((Status = WideToAnsi(name, &Ansi)) != S_OK) { return Status; }
if (PathTail(Ansi) != Ansi) { WhichName = INAME_IMAGE_PATH; } else { WhichName = INAME_IMAGE_PATH_TAIL; }
if (Image = m_Process->FindImageByName(Ansi, 0, WhichName, FALSE)) { *base = Image->m_BaseOfImage; Status = S_OK; } else { Status = E_NOINTERFACE; }
FreeAnsi(Ansi); return Status; }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::ReadVirtual( /* [in] */ CORDATA_ADDRESS address, /* [length_is][size_is][out] */ PBYTE buffer, /* [in] */ ULONG32 request, /* [optional][out] */ ULONG32 *done) { return m_Process->m_Target-> ReadVirtual(m_Process, address, buffer, request, (PULONG)done); }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::WriteVirtual( /* [in] */ CORDATA_ADDRESS address, /* [size_is][in] */ PBYTE buffer, /* [in] */ ULONG32 request, /* [optional][out] */ ULONG32 *done) { return m_Process->m_Target-> WriteVirtual(m_Process, address, buffer, request, (PULONG)done); }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::GetTlsValue( /* [in] */ ULONG32 index, /* [out] */ CORDATA_ADDRESS* value) { HRESULT Status; ULONG64 SlotAddr;
if ((Status = m_Process->m_CurrentThread-> GetTlsSlotAddress((ULONG)index, &SlotAddr)) != S_OK) { return Status; }
return m_Process->m_Target-> ReadPointer(m_Process, m_Process->m_Target->m_Machine, SlotAddr, value); }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::SetTlsValue( /* [in] */ ULONG32 index, /* [in] */ CORDATA_ADDRESS value) { HRESULT Status; ULONG64 SlotAddr;
if ((Status = m_Process->m_CurrentThread-> GetTlsSlotAddress((ULONG)index, &SlotAddr)) != S_OK) { return Status; }
return m_Process->m_Target-> WritePointer(m_Process, m_Process->m_Target->m_Machine, SlotAddr, value); }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::GetCurrentThreadId( /* [out] */ ULONG32* threadId) { *threadId = g_Thread->m_SystemId; return S_OK; }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::GetThreadContext( /* [in] */ ULONG32 threadId, /* [in] */ ULONG32 contextFlags, /* [in] */ ULONG32 contextSize, /* [out, size_is(contextSize)] */ PBYTE context) { HRESULT Status; if (contextSize < m_Process->m_Target->m_TypeInfo.SizeTargetContext) { return E_INVALIDARG; }
ThreadInfo* Thread = m_Process->FindThreadBySystemId(threadId); if (!Thread) { return E_NOINTERFACE; }
m_Process->m_Target->ChangeRegContext(Thread); if ((Status = m_Process->m_Target->m_Machine-> GetContextState(MCTX_CONTEXT)) == S_OK) { Status = m_Process->m_Target->m_Machine-> ConvertContextTo(&m_Process->m_Target->m_Machine->m_Context, m_Process->m_Target->m_SystemVersion, m_Process->m_Target->m_TypeInfo.SizeTargetContext, context); }
m_Process->m_Target->ChangeRegContext(m_Process->m_CurrentThread);
return Status; }
HRESULT STDMETHODCALLTYPE ProcCorDataAccessServices::SetThreadContext( /* [in] */ ULONG32 threadId, /* [in] */ ULONG32 contextSize, /* [out, size_is(contextSize)] */ PBYTE context) { HRESULT Status; if (contextSize < m_Process->m_Target->m_TypeInfo.SizeTargetContext) { return E_INVALIDARG; }
ThreadInfo* Thread = m_Process->FindThreadBySystemId(threadId); if (!Thread) { return E_NOINTERFACE; }
m_Process->m_Target->ChangeRegContext(Thread); if ((Status = m_Process->m_Target->m_Machine-> GetContextState(MCTX_DIRTY)) == S_OK) { Status = m_Process->m_Target->m_Machine-> ConvertContextFrom(&m_Process->m_Target->m_Machine->m_Context, m_Process->m_Target->m_SystemVersion, m_Process->m_Target-> m_TypeInfo.SizeTargetContext, context); if (Status == S_OK) { NotifyChangeDebuggeeState(DEBUG_CDS_REGISTERS, DEBUG_ANY_ID); } }
m_Process->m_Target->ChangeRegContext(m_Process->m_CurrentThread);
return Status; }
//----------------------------------------------------------------------------
//
// ProcessInfo.
//
//----------------------------------------------------------------------------
ProcessInfo::ProcessInfo(TargetInfo* Target, ULONG SystemId, HANDLE SymHandle, ULONG64 SysHandle, ULONG Flags, ULONG Options) { m_Target = Target; m_UserId = FindNextUserId(LAYER_PROCESS);
m_Next = NULL; m_NumImages = 0; m_NumUnloadedModules = 0; m_ImageHead = NULL; m_ExecutableImage = NULL; m_SynthesizedImage = NULL; m_NumThreads = 0; m_ThreadHead = NULL; m_CurrentThread = NULL; m_SystemId = SystemId; m_Exited = FALSE; m_ModulesLoaded = FALSE; m_InitialBreakDone = (Flags & ENG_PROC_NO_INITIAL_BREAK) != 0; // Always ask for an "initial" break when the process
// won't generate its own initial break as the first
// break encountered will just be a normal break and
// so should cause a break-in.
m_InitialBreak = (Flags & ENG_PROC_NO_INITIAL_BREAK) || IS_KERNEL_TARGET(m_Target) || (g_EngOptions & DEBUG_ENGOPT_INITIAL_BREAK) != 0; m_InitialBreakWx86 = (g_EngOptions & DEBUG_ENGOPT_INITIAL_BREAK) != 0; m_DataOffset = 0; m_SymHandle = SymHandle; m_SysHandle = SysHandle; m_Flags = Flags; m_Options = Options; m_NumBreakpoints = 0; m_Breakpoints = NULL; m_BreakpointsTail = NULL; m_DynFuncTableList = 0; m_OopFuncTableDlls = NULL; m_RtlUnloadList = 0; ResetImplicitData(); m_CorImage = NULL; m_CorImageType = COR_DLL_INVALID; m_CorDebugDll = NULL; m_CorAccess = NULL; m_CorServices.m_Process = this; m_VirtualCache.SetProcess(this); PCHAR CacheEnv = getenv("_NT_DEBUG_CACHE_SIZE"); if (CacheEnv != NULL) { m_VirtualCache.m_MaxSize = atol(CacheEnv); }
m_VirtualCache.m_DecodePTEs = IS_KERNEL_TARGET(m_Target) && !(m_Target->m_KdVersion.Flags & DBGKD_VERS_FLAG_NOMM);
m_Target->InsertProcess(this);
SymInitialize(m_SymHandle, NULL, FALSE); SymRegisterCallback64(m_SymHandle, SymbolCallbackFunction, (ULONG_PTR)this);
if (IS_USER_TARGET(m_Target) && m_Target->m_MachineType != IMAGE_FILE_MACHINE_I386) { SymRegisterFunctionEntryCallback64 (m_SymHandle, TargetInfo::DynamicFunctionTableCallback, (ULONG_PTR)this); } SetSymbolSearchPath(this); SynthesizeSymbols(); }
ProcessInfo::~ProcessInfo(void) { ClearOopFuncTableDlls();
RELEASE(m_CorAccess); if (m_CorDebugDll) { FreeLibrary(m_CorDebugDll); } while (m_ThreadHead) { delete m_ThreadHead; } // Suppress notifications until all images are deleted.
g_EngNotify++;
while (m_ImageHead) { delete m_ImageHead; } delete m_SynthesizedImage; // Notification can use process information so put things
// in a clean state before notify.
m_SynthesizedImage = NULL;
g_EngNotify--; NotifyChangeSymbolState(DEBUG_CSS_UNLOADS, 0, this);
SymCleanup(m_SymHandle);
RemoveProcessBreakpoints(this);
if (m_Flags & ENG_PROC_THREAD_CLOSE_HANDLE) { DBG_ASSERT(IS_LIVE_USER_TARGET(m_Target) && ((LiveUserTargetInfo*)m_Target)->m_Services); ((LiveUserTargetInfo*)m_Target)->m_Services-> CloseHandle(m_SysHandle); }
m_Target->RemoveProcess(this);
g_UserIdFragmented[LAYER_PROCESS]++;
if (this == g_Process) { g_Process = NULL; } if (this == g_EventProcess) { g_EventProcess = NULL; DiscardLastEvent(); } if (g_StepTraceBp && g_StepTraceBp->m_Process == this) { g_StepTraceBp->m_Process = NULL; if (g_WatchFunctions.IsStarted()) { g_WatchFunctions.End(NULL); } ResetStepTrace(); g_StepTraceBp->m_Flags &= ~(DEBUG_BREAKPOINT_ENABLED | BREAKPOINT_INSERTED); } if (g_ScopeBuffer.State == ScopeFromContext && g_ScopeBuffer.Process == this) { ResetCurrentScopeLazy(); } }
ThreadInfo* ProcessInfo::FindThreadByUserId(ULONG Id) { ThreadInfo* Thread; ForProcessThreads(this) { if (Thread->m_UserId == Id) { return Thread; } } return NULL; }
ThreadInfo* ProcessInfo::FindThreadBySystemId(ULONG Id) { ThreadInfo* Thread; ForProcessThreads(this) { if (Thread->m_SystemId == Id) { return Thread; } } return NULL; }
ThreadInfo* ProcessInfo::FindThreadByHandle(ULONG64 Handle) { ThreadInfo* Thread; ForProcessThreads(this) { if (Thread->m_Handle == Handle) { return Thread; } } return NULL; }
void ProcessInfo::InsertThread(ThreadInfo* Thread) { ThreadInfo* Cur; ThreadInfo* Prev;
Prev = NULL; for (Cur = m_ThreadHead; Cur; Cur = Cur->m_Next) { if (Cur->m_UserId > Thread->m_UserId) { break; }
Prev = Cur; } Thread->m_Next = Cur; if (!Prev) { m_ThreadHead = Thread; } else { Prev->m_Next = Thread; }
m_NumThreads++; Thread->m_Process = this; if (!m_CurrentThread) { m_CurrentThread = Thread; }
m_Target->AddThreadToAllProcessInfo(this, Thread); }
void ProcessInfo::RemoveThread(ThreadInfo* Thread) { ThreadInfo* Cur; ThreadInfo* Prev;
Prev = NULL; for (Cur = m_ThreadHead; Cur; Cur = Cur->m_Next) { if (Cur == Thread) { break; }
Prev = Cur; }
if (!Cur) { return; } if (!Prev) { m_ThreadHead = Thread->m_Next; } else { Prev->m_Next = Thread->m_Next; }
m_NumThreads--; Thread->m_Process = NULL; if (m_CurrentThread == Thread) { m_CurrentThread = m_ThreadHead; }
m_Target->RemoveThreadFromAllProcessInfo(this, Thread); }
HRESULT ProcessInfo::CreateVirtualThreads(ULONG StartId, ULONG Threads) { ThreadInfo* Thread; while (Threads-- > 0) { Thread = new ThreadInfo(this, VIRTUAL_THREAD_ID(StartId), 0, VIRTUAL_THREAD_HANDLE(StartId), 0, 0); if (!Thread) { return E_OUTOFMEMORY; } StartId++; }
return S_OK; }
ImageInfo* ProcessInfo::FindImageByIndex(ULONG Index) { ImageInfo* Image = m_ImageHead; while (Index > 0 && Image != NULL) { Index--; Image = Image->m_Next; } return Image; }
ImageInfo* ProcessInfo::FindImageByOffset(ULONG64 Offset, BOOL AllowSynth) { ImageInfo* Image = m_ImageHead; while (Image != NULL && (Offset < Image->m_BaseOfImage || Offset >= Image->m_BaseOfImage + Image->m_SizeOfImage)) { Image = Image->m_Next; }
//
// If synthesized symbols are allowed, check those images
// also.
//
if (!Image && AllowSynth && m_SynthesizedImage && Offset >= m_SynthesizedImage->m_BaseOfImage && Offset < m_SynthesizedImage->m_BaseOfImage + m_SynthesizedImage->m_SizeOfImage) { Image = m_SynthesizedImage; } return Image; }
ImageInfo* ProcessInfo::FindImageByName(PCSTR Name, ULONG NameChars, INAME Which, BOOL AllowSynth) { if (NameChars == 0) { NameChars = strlen(Name); } ImageInfo* Image = m_ImageHead; while (Image != NULL) { PCSTR WhichStr;
switch(Which) { case INAME_IMAGE_PATH: WhichStr = Image->m_ImagePath; break; case INAME_IMAGE_PATH_TAIL: WhichStr = PathTail(Image->m_ImagePath); break; case INAME_MODULE: if (Image->m_OriginalModuleName[0] && strlen(Image->m_OriginalModuleName) == NameChars && !_memicmp(Image->m_OriginalModuleName, Name, NameChars)) { return Image; } WhichStr = Image->m_ModuleName; break; }
if (strlen(WhichStr) == NameChars && _memicmp(WhichStr, Name, NameChars) == 0) { break; }
Image = Image->m_Next; }
//
// If synthesized symbols are allowed, check those images
// also.
//
if (!Image && AllowSynth && m_SynthesizedImage && Which == INAME_MODULE && strlen(m_SynthesizedImage->m_ModuleName) == NameChars && !_memicmp(m_SynthesizedImage->m_ModuleName, Name, NameChars)) { Image = m_SynthesizedImage; } return Image; }
BOOL ProcessInfo::GetOffsetFromMod(PCSTR String, PULONG64 Offset) { if (!strchr(String, '!')) { ULONG Len; BOOL End; //
// Could be a module name or module$ for the end
// of a module.
//
Len = strlen(String); if (Len == 0) { return FALSE; }
if (String[Len - 1] == '$') { // Retrieving end-of-module.
Len--; End = TRUE; } else { End = FALSE; } ImageInfo* Image = FindImageByName(String, Len, INAME_MODULE, TRUE); if (Image) { if (End) { *Offset = Image->m_BaseOfImage + Image->m_SizeOfImage; } else { *Offset = Image->m_BaseOfImage; } return TRUE; } } return FALSE; }
COR_DLL IsCorDll(PCSTR ImagePath) { PCSTR ImagePathTail = PathTail(ImagePath); if (!_stricmp(ImagePathTail, "mscoree.dll")) { return COR_DLL_EE; } if (!_stricmp(ImagePathTail, "mscorwks.dll")) { return COR_DLL_WKS; } if (!_stricmp(ImagePathTail, "mscorsvr.dll")) { return COR_DLL_SVR; } return COR_DLL_INVALID; }
void ProcessInfo::InsertImage(ImageInfo* Image) { ImageInfo* Cur; ImageInfo* Prev;
Prev = NULL; for (Cur = m_ImageHead; Cur; Cur = Cur->m_Next) { if (Cur->m_BaseOfImage > Image->m_BaseOfImage) { break; }
Prev = Cur; } Image->m_Next = Cur; if (!Prev) { m_ImageHead = Image; } else { Prev->m_Next = Image; }
m_NumImages++; Image->m_Process = this; Image->m_Linked = TRUE;
if (m_ExecutableImage == NULL) { // Try and locate the executable image entry for
// the process to use as the process's name.
ULONG NameLen = strlen(Image->m_ImagePath); if (NameLen > 4 && !_stricmp(Image->m_ImagePath + NameLen - 4, ".exe")) { m_ExecutableImage = Image; } }
COR_DLL CorDll = IsCorDll(Image->m_ImagePath); if (CorDll > m_CorImageType) { m_CorImage = Image; m_CorImageType = CorDll; } }
void ProcessInfo::RemoveImage(ImageInfo* Image) { ImageInfo* Cur; ImageInfo* Prev;
Prev = NULL; for (Cur = m_ImageHead; Cur; Cur = Cur->m_Next) { if (Cur == Image) { break; }
Prev = Cur; }
if (!Cur) { return; } if (!Prev) { m_ImageHead = Image->m_Next; } else { Prev->m_Next = Image->m_Next; }
m_NumImages--; Image->m_Process = NULL; Image->m_Linked = FALSE; if (m_ExecutableImage == Image) { m_ExecutableImage = NULL; }
if (m_CorImageType != COR_DLL_INVALID && IsCorDll(Image->m_ImagePath) != COR_DLL_INVALID) { m_CorImage = NULL; m_CorImageType = COR_DLL_INVALID; } }
BOOL ProcessInfo::DeleteImageByName(PCSTR Name, INAME Which) { ImageInfo* Image;
for (Image = m_ImageHead; Image; Image = Image->m_Next) { PCSTR WhichStr;
switch(Which) { case INAME_IMAGE_PATH: WhichStr = Image->m_ImagePath; break; case INAME_IMAGE_PATH_TAIL: WhichStr = PathTail(Image->m_ImagePath); break; case INAME_MODULE: WhichStr = Image->m_ModuleName; break; } if (!_stricmp(WhichStr, Name)) { delete Image; return TRUE; } }
return FALSE; }
BOOL ProcessInfo::DeleteImageByBase(ULONG64 BaseOfImage) { ImageInfo* Image;
for (Image = m_ImageHead; Image; Image = Image->m_Next) { if (Image->m_BaseOfImage == BaseOfImage) { delete Image; return TRUE; } }
return FALSE; }
void ProcessInfo::DeleteImagesBelowOffset(ULONG64 Offset) { ImageInfo* Image, *Next; ULONG Count = 0; // Suppress notifications until all images are deleted.
g_EngNotify++;
for (Image = m_ImageHead; Image; Image = Next) { Next = Image->m_Next; if (Image->m_BaseOfImage < Offset) { delete Image; Count++; } }
g_EngNotify--; if (Count) { NotifyChangeSymbolState(DEBUG_CSS_UNLOADS, 0, this); } }
void ProcessInfo::DeleteImages(void) { // Suppress notifications until all images are deleted.
g_EngNotify++;
while (m_ImageHead) { delete m_ImageHead; }
g_EngNotify--; NotifyChangeSymbolState(DEBUG_CSS_UNLOADS, 0, this); }
HRESULT ProcessInfo::AddImage(PMODULE_INFO_ENTRY ModEntry, BOOL ForceSymbolLoad, ImageInfo** ImageAdded) { ImageInfo* ImageNew; IMAGEHLP_MODULE64 SymModInfo; ULONG64 LoadAddress; BOOL LoadSymbols = TRUE; PCSTR ImagePathTail; MODLOAD_DATA ModLoadData; HRESULT Status; BOOL ReusedExisting = FALSE;
#if DBG_MOD_LIST
dprintf("AddImage:\n" " ImagePath %s\n" " File %I64x\n" " BaseOfImage %I64x\n" " SizeOfImage %x\n" " CheckSum %x\n" " ModuleName %s\n" " ForceSymbolLoad %d\n", ModEntry->NamePtr, (ULONG64)(ULONG_PTR)File, ModEntry->Base, ModEntry->Size, ModEntry->CheckSum, ModEntry->ModuleName, ForceSymbolLoad); #endif
if (ModEntry->NamePtr == NULL) { WarnOut("AddImage(NULL) fails\n"); return E_INVALIDARG; }
if (ModEntry->NamePtr && IS_USER_TARGET(m_Target) && m_Target->m_PlatformId == VER_PLATFORM_WIN32_NT) { TranslateNtPathName(ModEntry->NamePtr); } //
// Search for existing image at same base address.
// If found, remove symbols, but leave image structure intact.
//
for (ImageNew = m_ImageHead; ImageNew; ImageNew = ImageNew->m_Next) { if (ImageNew->m_BaseOfImage == ModEntry->Base) { VerbOut("Force unload of %s\n", ImageNew->m_ImagePath); ImageNew->DeleteResources(FALSE); break; } }
//
// If we didn't reuse an existing image, allocate
// a new one.
//
if (!ImageNew) { ImageNew = new ImageInfo(this, ModEntry->NamePtr, ModEntry->Base, TRUE); if (ImageNew == NULL) { ErrOut("Unable to allocate memory for %s symbols.\n", ModEntry->NamePtr); return E_OUTOFMEMORY; }
// Module name is set later after possible renaming.
ImageNew->m_File = ModEntry->File; ImageNew->m_CheckSum = ModEntry->CheckSum; ImageNew->m_TimeDateStamp = ModEntry->TimeDateStamp; ImageNew->m_SymState = ISS_MATCHED; ImageNew->m_UserMode = ModEntry->UserMode; } else { ReusedExisting = TRUE; // Update the reused entry with the latest information.
if (ModEntry->NamePtr) { CopyString(ImageNew->m_ImagePath, ModEntry->NamePtr, DIMA(ImageNew->m_ImagePath)); } else { ImageNew->m_ImagePath[0] = 0; } }
// Always update the entry size as this allows users
// to update explicit entries (.reload image.ext=base,size)
// without having to unload them first.
ImageNew->m_SizeOfImage = ModEntry->Size;
ImagePathTail = PathTail(ImageNew->m_ImagePath);
if (ForceSymbolLoad) { // Try to load the image memory right away in this
// case to catch incomplete-information errors.
if (!ImageNew->DemandLoadImageMemory(!ReusedExisting, TRUE)) { if (!ReusedExisting) { g_EngNotify++; delete ImageNew; g_EngNotify--; } return E_OUTOFMEMORY; } } if (IS_KERNEL_TARGET(m_Target)) { CHAR Buf[MAX_IMAGE_PATH]; MODULE_ALIAS_LIST* ModAlias; //
// Determine the actual image name for kernel images which
// are known to have multiple identities.
//
if ((ModEntry->ModuleName && _stricmp(ModEntry->ModuleName, KERNEL_MODULE_NAME) == 0) || ModEntry->Base == m_Target->m_KdDebuggerData.KernBase) { ModAlias = &g_AliasLists[MODALIAS_KERNEL]; } else { ModAlias = FindModuleAliasList(ImagePathTail, NULL); } if (ModAlias) { if (GetModnameFromImage(this, ModEntry->Base, NULL, Buf, sizeof(Buf), FALSE)) { CopyString(ImageNew->m_ImagePath, Buf, DIMA(ImageNew->m_ImagePath)); } ModEntry->ModuleName = (PSTR)ModAlias->BaseModule; } else if (ImageNew->m_SizeOfImage == 0 && ((_stricmp(ImagePathTail, NTLDR_IMAGE_NAME) == 0) || (_stricmp(ImagePathTail, NTLDR_IMAGE_NAME ".exe") == 0) || (_stricmp(ImagePathTail, OSLOADER_IMAGE_NAME) == 0) || (_stricmp(ImagePathTail, OSLOADER_IMAGE_NAME ".exe") == 0) || (_stricmp(ImagePathTail, SETUPLDR_IMAGE_NAME) == 0) || (_stricmp(ImagePathTail, SETUPLDR_IMAGE_NAME ".exe") == 0))) { ImageNew->m_SizeOfImage = LDR_IMAGE_SIZE; } } else if (!IS_DUMP_TARGET(m_Target)) { //
// When debugging CSR, LSA or Services.exe, force the use of local-only
// symbols. Otherwise we can deadlock the entire machine when trying
// to load the symbol file from the network.
//
if (((LiveUserTargetInfo*)m_Target)->m_Local && (_stricmp(ImagePathTail, CSRSS_IMAGE_NAME) == 0 || _stricmp(ImagePathTail, LSASS_IMAGE_NAME) == 0 || _stricmp(ImagePathTail, SERVICES_IMAGE_NAME) == 0)) { if (g_EngOptions & DEBUG_ENGOPT_ALLOW_NETWORK_PATHS) { //
// Since the user has chambered a round and pointed the barrel
// of the gun at his head, we may as well tell him that it's
// going to hurt if he pulls the trigger.
//
WarnOut("WARNING: Using network symbols with %s\n", ImagePathTail); WarnOut("WARNING: You may deadlock your machine.\n"); } else { g_EngOptions |= DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS; } }
if (g_EngOptions & DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS) { DWORD NetPath;
NetPath = NetworkPathCheck(g_SymbolSearchPath); if (NetPath == ERROR_FILE_OFFLINE) { ErrOut("ERROR: sympath contained network references but " "they were not allowed.\n"); ErrOut("Symbols not loaded for %s\n", ImagePathTail); LoadSymbols = FALSE; } else if (NetPath == ERROR_BAD_PATHNAME) { VerbOut("WARNING: sympath contains invalid references.\n"); } } }
if (ModEntry->ModuleName == NULL) { CreateModuleNameFromPath(ImageNew->m_ImagePath, ImageNew->m_ModuleName); RestrictModNameChars(ImageNew->m_ModuleName, ImageNew->m_ModuleName); strcpy(ImageNew->m_OriginalModuleName, ImageNew->m_ModuleName); } else { RestrictModNameChars(ModEntry->ModuleName, ImageNew->m_ModuleName); //
// We have an alias, so keep original module name from path
//
CreateModuleNameFromPath(ImageNew->m_ImagePath, ImageNew->m_OriginalModuleName); RestrictModNameChars(ImageNew->m_OriginalModuleName, ImageNew->m_OriginalModuleName); } //
// Check for duplicate module names and
// image overlaps.
//
ImageInfo* Check; for (Check = m_ImageHead; Check != NULL; Check = Check->m_Next) { if (Check != ImageNew && !_strcmpi(ImageNew->m_ModuleName, Check->m_ModuleName)) { int Len = strlen(ImageNew->m_ModuleName); // Module names match, so qualify with the base address.
// Resulting name must be unique since base addresses are.
if (m_Target->m_Machine->m_Ptr64) { if (Len >= MAX_MODULE - 17) { Len = MAX_MODULE - 18; } sprintf(ImageNew->m_ModuleName + Len, "_%I64x", ModEntry->Base); } else { if (Len >= MAX_MODULE - 9) { Len = MAX_MODULE - 10; } sprintf(ImageNew->m_ModuleName + Len, "_%x", (ULONG)ModEntry->Base); } // Force all references to this module to be
// through the exact module name and not through
// an original name that may have been ambiguous.
ImageNew->m_OriginalModuleName[0] = 0; }
if (Check != ImageNew && ImageNew->m_BaseOfImage < Check->m_BaseOfImage + Check->m_SizeOfImage && Check->m_BaseOfImage < ImageNew->m_BaseOfImage + ImageNew->m_SizeOfImage) { WarnOut("WARNING: %s overlaps %s\n", ImageNew->m_ModuleName, Check->m_ModuleName); } }
//
// If we do not want to load symbolic information, just return here.
//
if (!LoadSymbols) { *ImageAdded = ImageNew; return S_OK; }
if (ModEntry->DebugHeader) { ModLoadData.ssize = sizeof(ModLoadData); ModLoadData.ssig = DBHHEADER_DEBUGDIRS; ModLoadData.data = ModEntry->DebugHeader; ModLoadData.size = ModEntry->SizeOfDebugHeader; ModLoadData.flags = 0; }
LoadAddress = SymLoadModuleEx(m_SymHandle, ImageNew->m_File, PrepareImagePath(ImageNew->m_ImagePath), ImageNew->m_ModuleName, ImageNew->m_BaseOfImage, ImageNew->m_SizeOfImage, ModEntry->DebugHeader ? &ModLoadData : NULL, 0); if (!LoadAddress) { Status = WIN32_LAST_STATUS(); VerbOut("SymLoadModule(%N, %N, \"%s\", \"%s\", %s, %x) fails\n", m_SymHandle, ImageNew->m_File, ImageNew->m_ImagePath, ImageNew->m_ModuleName, FormatAddr64(ImageNew->m_BaseOfImage), ImageNew->m_SizeOfImage); // We don't want deletion to notify of a symbol change
// if this is a partially newly created image.
if (!ReusedExisting) { g_EngNotify++; } delete ImageNew; if (!ReusedExisting) { g_EngNotify--; } return Status; }
if (!ImageNew->m_BaseOfImage) { ImageNew->m_BaseOfImage = LoadAddress; }
if (ForceSymbolLoad) { SymLoadModule64(m_SymHandle, NULL, NULL, NULL, ImageNew->m_BaseOfImage, 0); }
SymModInfo.SizeOfStruct = sizeof(SymModInfo); if (SymGetModuleInfo64(m_SymHandle, ImageNew->m_BaseOfImage, &SymModInfo)) { ImageNew->m_SizeOfImage = SymModInfo.ImageSize; } else { Status = WIN32_LAST_STATUS();
VerbOut("SymGetModuleInfo(%N, %s) fails\n", m_SymHandle, FormatAddr64(ImageNew->m_BaseOfImage));
// We don't want DelImage to notify of a symbol change
// if this is a partially newly created image.
if (!ReusedExisting) { g_EngNotify++; } delete ImageNew; if (!ReusedExisting) { g_EngNotify--; } return Status; }
if (ModEntry->ImageMachineTypeValid) { ImageNew->m_MachineType = ModEntry->MachineType; } StartOutLine(DEBUG_OUTPUT_VERBOSE, OUT_LINE_NO_PREFIX); VerbOut("ModLoad: %s %s %-8s\n", FormatAddr64(ImageNew->m_BaseOfImage), FormatAddr64(ImageNew->m_BaseOfImage + ImageNew->m_SizeOfImage), ImageNew->m_ImagePath);
NotifyChangeSymbolState(DEBUG_CSS_LOADS, ImageNew->m_BaseOfImage, this);
*ImageAdded = ImageNew; return S_OK; }
void ProcessInfo::SynthesizeSymbols(void) { // SynthesizeSymbols can result in symbol
// callbacks but the symbols involved aren't real symbols
// so suppress notifications.
g_EngNotify++; if (m_Target->m_TypeInfo.UmSharedUserDataOffset) { //
// Create a fake module for the shared user
// data area. Add a symbol for the system
// call stub there if a stub exists.
//
ImageInfo* Image;
Image = new ImageInfo(this, "SharedUserData", m_Target->m_TypeInfo.UmSharedUserDataOffset, FALSE); if (!Image) { WarnOut("Unable to create shared user data image\n"); } else { Image->m_SizeOfImage = m_Target->m_Machine->m_PageSize; strcpy(Image->m_ModuleName, Image->m_ImagePath); strcpy(Image->m_OriginalModuleName, Image->m_ImagePath); if (!SymLoadModuleEx(m_SymHandle, NULL, Image->m_ImagePath, Image->m_ModuleName, Image->m_BaseOfImage, Image->m_SizeOfImage, NULL, SLMFLAG_VIRTUAL)) { WarnOut("Unable to add shared user data module\n"); delete Image; } else if (m_Target->m_TypeInfo.UmSharedSysCallOffset && !SymAddSymbol(m_SymHandle, Image->m_BaseOfImage, "SystemCallStub", m_Target->m_TypeInfo.UmSharedSysCallOffset, m_Target->m_TypeInfo.UmSharedSysCallSize, 0)) { WarnOut("Unable to add system call symbol\n"); delete Image; } else { m_SynthesizedImage = Image; } } } g_EngNotify--; }
void ProcessInfo::VerifyKernel32Version(void) { ImageInfo* Image = FindImageByName("kernel32", 8, INAME_MODULE, FALSE); if (!Image) { return; } //
// Verify the OS version matches kernel32's image version.
//
IMAGE_NT_HEADERS64 NtHeaders; if (m_Target->ReadImageNtHeaders(this, Image->m_BaseOfImage, &NtHeaders) == S_OK) { if (NtHeaders.OptionalHeader.MajorImageVersion != m_Target->m_KdVersion.MajorVersion || NtHeaders.OptionalHeader.MinorImageVersion != m_Target->m_KdVersion.MinorVersion) { WarnOut("WARNING: System version is %d.%d but " "kernel32.dll is version %d.%d.\n", m_Target->m_KdVersion.MajorVersion, m_Target->m_KdVersion.MinorVersion, NtHeaders.OptionalHeader.MajorImageVersion, NtHeaders.OptionalHeader.MinorImageVersion); if (IS_USER_DUMP(m_Target)) { WarnOut("If this dump was generated by userdump.exe on " "Windows NT 4.0 the dump\n" "version is probably incorrect. " "Set DBGENG_FULL_DUMP_VERSION=4.0 in your\n" "environment to override the dump version.\n"); } } } }
BOOL ProcessInfo::DeleteExitedInfos(void) { ThreadInfo* Thread; ThreadInfo* ThreadNext; BOOL DeletedSomething = FALSE; for (Thread = m_ThreadHead; Thread; Thread = ThreadNext) { ThreadNext = Thread->m_Next; if (Thread->m_Exited) { delete Thread; DeletedSomething = TRUE; } }
ImageInfo* Image; ImageInfo* ImagePrev; ImageInfo* ImageNext;
ImagePrev = NULL; for (Image = m_ImageHead; Image; Image = ImageNext) { ImageNext = Image->m_Next; if (Image->m_Unloaded) { delete Image; DeletedSomething = TRUE; } else { ImagePrev = Image; } }
return DeletedSomething; }
void ProcessInfo::PrepareForExecution(void) { ThreadInfo* Thread;
ForProcessThreads(this) { Thread->PrepareForExecution(); } ResetImplicitData(); m_VirtualCache.Empty(); m_VirtualCache.SetForceDecodePtes(FALSE, m_Target);
FlushCorState(); }
void ProcessInfo::OutputThreadInfo(ThreadInfo* Match, BOOL Verbose) { ThreadInfo* Thread;
Thread = m_ThreadHead; while (Thread) { if (Match == NULL || Match == Thread) { ULONG64 DataOffset; HRESULT Status; char CurMark;
Status = m_Target-> GetThreadInfoDataOffset(Thread, 0, &DataOffset); if (Status != S_OK) { WarnOut("Unable to get thread data for thread %u\n", Thread->m_UserId); DataOffset = 0; }
if (Thread == g_Thread) { CurMark = '.'; } else if (Thread == g_EventThread) { CurMark = '#'; } else { CurMark = ' '; } dprintf("%c%3ld Id: %lx.%lx Suspend: %d Teb: %s ", CurMark, Thread->m_UserId, m_SystemId, Thread->m_SystemId, Thread->m_SuspendCount, FormatAddr64(DataOffset)); if (Thread->m_Frozen) { dprintf("Frozen "); } else { dprintf("Unfrozen"); } if (Thread->m_Name[0]) { dprintf(" \"%s\"", Thread->m_Name); } dprintf("\n");
if (Verbose) { dprintf(" "); if (!Thread->m_StartOffset) { if (m_Target-> GetThreadStartOffset(Thread, &Thread->m_StartOffset) != S_OK) { Thread->m_StartOffset = 0; } } if (Thread->m_StartOffset) { dprintf("Start: "); OutputSymAddr(Thread->m_StartOffset, SYMADDR_FORCE | SYMADDR_OFFSET, NULL); } dprintf("\n"); } }
if (CheckUserInterrupt()) { break; } Thread = Thread->m_Next; } }
HRESULT ProcessInfo::AddOopFuncTableDll(PWSTR Dll, ULONG64 Handle) { OUT_OF_PROC_FUNC_TABLE_DLL* OopDll;
OopDll = (OUT_OF_PROC_FUNC_TABLE_DLL*) malloc(sizeof(*OopDll) + (wcslen(Dll) + 1) * sizeof(Dll)); if (!OopDll) { return E_OUTOFMEMORY; }
OopDll->Next = m_OopFuncTableDlls; m_OopFuncTableDlls = OopDll; OopDll->Handle = Handle; wcscpy((PWSTR)(OopDll + 1), Dll);
return S_OK; }
void ProcessInfo::ClearOopFuncTableDlls(void) { while (m_OopFuncTableDlls) { OUT_OF_PROC_FUNC_TABLE_DLL* OopDll = m_OopFuncTableDlls; m_OopFuncTableDlls = OopDll->Next;
if (IS_LIVE_USER_TARGET(m_Target)) { ((LiveUserTargetInfo*)m_Target)->m_Services-> FreeLibrary(OopDll->Handle); }
free(OopDll); } } OUT_OF_PROC_FUNC_TABLE_DLL* ProcessInfo::FindOopFuncTableDll(PWSTR Dll) { OUT_OF_PROC_FUNC_TABLE_DLL* OopDll;
for (OopDll = m_OopFuncTableDlls; OopDll; OopDll = OopDll->Next) { if (!_wcsicmp(Dll, (PWSTR)(OopDll + 1))) { return OopDll; } }
return NULL; }
HRESULT ProcessInfo::LoadCorDebugDll(void) { HRESULT Status; MachineInfo* CorMachine; if (m_CorDebugDll) { return S_OK; } if (!m_CorImage || !(CorMachine = MachineTypeInfo(m_Target, m_CorImage->GetMachineType()))) { return E_UNEXPECTED; }
VS_FIXEDFILEINFO CorVer; if ((Status = m_Target-> GetImageVersionInformation(this, m_CorImage->m_ImagePath, m_CorImage->m_BaseOfImage, "\\", &CorVer, sizeof(CorVer), NULL)) != S_OK) { ErrOut("Unable to get version information for %s\n", m_CorImage->m_ModuleName); return Status; }
PSTR CorDacType;
switch(m_CorImageType) { case COR_DLL_EE: CorDacType = "ee"; break; case COR_DLL_WKS: CorDacType = "wks"; break; case COR_DLL_SVR: CorDacType = "svr"; break; default: ErrOut("Unknown runtime DLL type %s\n", m_CorImage->m_ModuleName); return E_INVALIDARG; } char DacDll[MAX_PATH]; PSTR CorImagePath = NULL; PSTR Tail;
// If this is a live session we want to look for the
// debug DLL in the same place that the runtime is.
// If this is a dump, we want to look in the same place
// that the runtime image file was mapped from.
if (IS_DUMP_TARGET(m_Target) && m_CorImage->m_MappedImagePath[0]) { CorImagePath = m_CorImage->m_MappedImagePath; } if (!CorImagePath) { CorImagePath = m_CorImage->m_ImagePath; } if (!CopyString(DacDll, CorImagePath, DIMA(DacDll))) { ErrOut("Runtime debugging DLL path overflow\n"); return E_OUTOFMEMORY; }
// We need to request the debugging DLL that runs
// using the currently running processor type and
// that can debug the current target's processor type.
#if defined(_X86_)
PSTR HostCpu = "x86"; #elif defined(_IA64_)
PSTR HostCpu = "IA64"; #elif defined(_AMD64_)
PSTR HostCpu = "AMD64"; #elif defined(_ARM_)
PSTR HostCpu = "ARM"; #else
#error Unknown processor.
#endif
Tail = (PSTR)PathTail(DacDll); if (!PrintString(Tail, (ULONG)(DIMA(DacDll) - (Tail - DacDll)), "mscordac%s_%s_%s_%u.%u.%u.%u%s.dll", CorDacType, HostCpu, CorMachine->m_AbbrevName, CorVer.dwFileVersionMS >> 16, CorVer.dwFileVersionMS & 0xffff, CorVer.dwFileVersionLS >> 16, CorVer.dwFileVersionLS & 0xffff, (CorVer.dwFileFlags & VS_FF_DEBUG) ? ((CorVer.dwFileFlags & VS_FF_PRIVATEBUILD) ? ".fastchecked" : ".checked") : "")) { ErrOut("Runtime debugging DLL path overflow\n"); return E_OUTOFMEMORY; }
//
// First try and load the debugging DLL using the same
// path as the runtime DLL. This makes it easy to pick
// up debugging DLLs that come with runtime installations.
//
PSTR DllPath = DacDll; m_CorDebugDll = LoadLibrary(DllPath); if (!m_CorDebugDll && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_MOD_NOT_FOUND)) { // Couldn't find it, so allow a path search.
DllPath = Tail; m_CorDebugDll = LoadLibrary(DllPath); } if (!m_CorDebugDll) { Status = WIN32_LAST_STATUS(); VerbOut("Unable to load runtime debug DLL %s, %s\n", DllPath, FormatStatusCode(Status)); return Status; }
PFN_CreateCorDataAccess Entry = (PFN_CreateCorDataAccess) GetProcAddress(m_CorDebugDll, "CreateCorDataAccess"); if (!Entry) { Status = WIN32_LAST_STATUS(); FreeLibrary(m_CorDebugDll); m_CorDebugDll = NULL; ErrOut("Runtime debug DLL %s missing entry point\n", DllPath); return Status; }
if ((Status = Entry(__uuidof(ICorDataAccess), &m_CorServices, (void**)&m_CorAccess)) != S_OK) { FreeLibrary(m_CorDebugDll); m_CorDebugDll = NULL; ErrOut("Runtime debug DLL %s init failure, %s\n", DllPath, FormatStatusCode(Status)); return Status; } VerbOut("Loaded runtime debug DLL %s\n", DllPath);
return S_OK; }
HRESULT ProcessInfo::IsCorCode(ULONG64 Native) { HRESULT Status;
if ((Status = LoadCorDebugDll()) != S_OK) { return Status; }
return m_CorAccess->IsCorCode(Native); }
HRESULT ProcessInfo::ConvertNativeToIlOffset(ULONG64 Native, PULONG64 ImageBase, PULONG32 MethodToken, PULONG32 MethodOffs) { HRESULT Status;
if ((Status = LoadCorDebugDll()) != S_OK) { return Status; }
if ((Status = m_CorAccess-> GetILOffsetFromTargetAddress(Native, ImageBase, MethodToken, MethodOffs)) != S_OK) { return Status; }
if (!FindImageByOffset(*ImageBase, FALSE)) { IMAGE_NT_HEADERS64 NtHdr; char Name[MAX_IMAGE_PATH]; // XXX drewb - Need to work out when the
// module list should be updated for managed
// code that's not system-loaded.
// We don't know about this module, so load it
// right now.
if (m_Target->ReadImageNtHeaders(this, *ImageBase, &NtHdr) == S_OK && GetModnameFromImage(this, *ImageBase, NULL, Name, DIMA(Name), TRUE)) { char ReloadCmd[MAX_IMAGE_PATH]; PCSTR ArgsRet;
PrintString(ReloadCmd, DIMA(ReloadCmd), "%s=0x%s,0x%x", Name, FormatAddr64(*ImageBase), NtHdr.OptionalHeader.SizeOfImage); m_Target->Reload(m_CurrentThread, ReloadCmd, &ArgsRet);
ImageInfo* Image = FindImageByOffset(*ImageBase, FALSE); if (Image) { Image->m_CorImage = TRUE; } } } return S_OK; }
HRESULT ProcessInfo::GetCorSymbol(ULONG64 Native, PSTR Buffer, ULONG BufferChars, PULONG64 Displacement) { HRESULT Status;
if ((Status = LoadCorDebugDll()) != S_OK) { return Status; }
WCHAR SymWide[MAX_SYMBOL_LEN]; if ((Status = m_CorAccess-> GetCodeSymbolForTargetAddress(Native, SymWide, DIMA(SymWide), Displacement)) != S_OK) { return Status; }
if (!WideCharToMultiByte(CP_ACP, 0, SymWide, -1, Buffer, BufferChars, NULL, NULL)) { return WIN32_LAST_STATUS(); }
return S_OK; }
ICorDataStackWalk* ProcessInfo::StartCorStack(ULONG32 CorThreadId) { HRESULT Status; ICorDataStackWalk* Walk;
if ((Status = LoadCorDebugDll()) != S_OK) { return NULL; }
if ((Status = m_CorAccess->StartStackWalk(CorThreadId, DAC_STACK_ALL_FRAMES, &Walk)) != S_OK) { return NULL; }
return Walk; }
HRESULT ProcessInfo::Terminate(void) { if (!IS_LIVE_USER_TARGET(m_Target)) { return E_UNEXPECTED; } PUSER_DEBUG_SERVICES Services = ((LiveUserTargetInfo*)m_Target)->m_Services; HRESULT Status = S_OK; if (!m_Exited) { if ((m_Flags & ENG_PROC_EXAMINED) == 0 && (Status = Services->TerminateProcess(m_SysHandle, E_FAIL)) != S_OK) { ErrOut("TerminateProcess failed, %s\n", FormatStatusCode(Status)); } else { MarkExited(); } }
return Status; }
HRESULT ProcessInfo::Detach(void) { if (!IS_LIVE_USER_TARGET(m_Target)) { return E_UNEXPECTED; } PUSER_DEBUG_SERVICES Services = ((LiveUserTargetInfo*)m_Target)->m_Services; HRESULT Status = S_OK; if (!m_Exited) { if ((m_Flags & ENG_PROC_EXAMINED) == 0 && (Status = Services->DetachProcess(m_SystemId)) != S_OK) { // Older systems don't support detach so
// don't show an error message in that case.
if (Status != E_NOTIMPL) { ErrOut("DebugActiveProcessStop(%d) failed, %s\n", m_SystemId, FormatStatusCode(Status)); } } else { MarkExited(); } }
return Status; }
HRESULT ProcessInfo::Abandon(void) { if (!IS_LIVE_USER_TARGET(m_Target)) { return E_UNEXPECTED; } PUSER_DEBUG_SERVICES Services = ((LiveUserTargetInfo*)m_Target)->m_Services; HRESULT Status;
if ((Status = Services->AbandonProcess(m_SysHandle)) != S_OK) { // Older systems don't support abandon so
// don't show an error message in that case.
if (Status != E_NOTIMPL) { ErrOut("Unable to abandon process\n"); } return Status; }
// We need to continue any existing event as it won't
// be returned from WaitForDebugEvent again. We
// do not want to resume execution, though.
if (m_Target->m_DeferContinueEvent) { if ((Status = Services->ContinueEvent(DBG_CONTINUE)) != S_OK) { ErrOut("Unable to continue abandoned event, %s\n", FormatStatusCode(Status)); return Status; } m_Target->m_DeferContinueEvent = FALSE; }
return Status; }
HRESULT ProcessInfo::GetImplicitThreadData(ThreadInfo* Thread, PULONG64 Offset) { HRESULT Status;
if (m_ImplicitThreadData == 0 || (m_ImplicitThreadDataIsDefault && Thread != m_ImplicitThreadDataThread)) { Status = SetImplicitThreadData(Thread, 0, FALSE); } else { Status = S_OK; } *Offset = m_ImplicitThreadData; return Status; }
HRESULT ProcessInfo::GetImplicitThreadDataTeb(ThreadInfo* Thread, PULONG64 Offset) { if (IS_USER_TARGET(m_Target)) { // In user mode the thread data is the TEB.
return GetImplicitThreadData(Thread, Offset); } else if (IS_KERNEL_TARGET(m_Target)) { return ReadImplicitThreadInfoPointer (Thread, m_Target->m_KdDebuggerData.OffsetKThreadTeb, Offset); } else { return E_UNEXPECTED; } }
HRESULT ProcessInfo::SetImplicitThreadData(ThreadInfo* Thread, ULONG64 Offset, BOOL Verbose) { HRESULT Status; BOOL Default = FALSE; if (Offset == 0) { if (!Thread || Thread->m_Process != this) { if (Verbose) { ErrOut("Unable to get the current thread data\n"); } return E_UNEXPECTED; } if ((Status = m_Target-> GetThreadInfoDataOffset(Thread, 0, &Offset)) != S_OK) { if (Verbose) { ErrOut("Unable to get the current thread data\n"); } return Status; } if (Offset == 0) { if (Verbose) { ErrOut("Current thread data is NULL\n"); } return E_FAIL; }
Default = TRUE; }
m_ImplicitThreadData = Offset; m_ImplicitThreadDataIsDefault = Default; m_ImplicitThreadDataThread = Thread; return S_OK; }
HRESULT ProcessInfo::ReadImplicitThreadInfoPointer(ThreadInfo* Thread, ULONG Offset, PULONG64 Ptr) { HRESULT Status; ULONG64 CurThread;
// Retrieve the current ETHREAD.
if ((Status = GetImplicitThreadData(Thread, &CurThread)) != S_OK) { return Status; }
return m_Target-> ReadPointer(this, m_Target->m_Machine, CurThread + Offset, Ptr); }
//----------------------------------------------------------------------------
//
// Functions.
//
//----------------------------------------------------------------------------
ProcessInfo* FindAnyProcessByUserId(ULONG Id) { TargetInfo* Target; ProcessInfo* Process;
ForAllLayersToProcess() { if (Process->m_UserId == Id) { return Process; } } return NULL; }
ProcessInfo* FindAnyProcessBySystemId(ULONG Id) { TargetInfo* Target; ProcessInfo* Process;
ForAllLayersToProcess() { if (Process->m_SystemId == Id) { return Process; } } return NULL; }
void ParseProcessCmds(void) { char Ch; ProcessInfo* Process; ULONG Id;
if (!g_Target) { error(BADTHREAD); } Ch = PeekChar(); if (Ch == '\0' || Ch == ';') { g_Target->OutputProcessInfo(NULL); } else { Process = g_Process; g_CurCmd++; if (Ch == '.') { ; } else if (Ch == '#') { Process = g_EventProcess; } else if (Ch == '*') { Process = NULL; } else if (Ch == '[') { g_CurCmd--; Id = (ULONG)GetTermExpression("Process ID missing from"); Process = FindAnyProcessByUserId(Id); if (Process == NULL) { error(BADPROCESS); } } else if (Ch == '~') { if (*g_CurCmd != '[') { error(SYNTAX); } Id = (ULONG)GetTermExpression("Process ID missing from"); Process = FindAnyProcessBySystemId(Id); if (Process == NULL) { error(BADPROCESS); } } else if (Ch >= '0' && Ch <= '9') { Id = 0; do { Id = Id * 10 + Ch - '0'; Ch = *g_CurCmd++; } while (Ch >= '0' && Ch <= '9'); g_CurCmd--; Process = FindAnyProcessByUserId(Id); if (Process == NULL) { error(BADPROCESS); } } else { g_CurCmd--; } Ch = PeekChar(); if (Ch == '\0' || Ch == ';') { g_Target->OutputProcessInfo(Process); } else { g_CurCmd++; if (tolower(Ch) == 's') { if (Process == NULL) { error(BADPROCESS); } if (Process->m_CurrentThread == NULL) { Process->m_CurrentThread = Process->m_ThreadHead; if (Process->m_CurrentThread == NULL) { error(BADPROCESS); } } SetPromptThread(Process->m_CurrentThread, SPT_DEFAULT_OCI_FLAGS); } else { g_CurCmd--; } } } }
//----------------------------------------------------------------------------
//
// Process creation and attach functions.
//
//----------------------------------------------------------------------------
HRESULT TerminateProcesses(void) { HRESULT Status;
if (!AnyLiveUserTargets()) { // Nothing to do.
return S_OK; } if (g_SymOptions & SYMOPT_SECURE) { ErrOut("SECURE: Process termination disallowed\n"); return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); }
Status = PrepareForSeparation(); if (Status != S_OK) { ErrOut("Unable to prepare for termination, %s\n", FormatStatusCode(Status)); return Status; }
TargetInfo* Target; HRESULT SingleStatus;
ForAllLayersToTarget() { // If we fail in the middle of killing things there
// isn't much that can be done so just attempt to
// kill as many things as possible.
if (IS_LIVE_USER_TARGET(Target) && (SingleStatus = Target->TerminateProcesses()) != S_OK) { Status = SingleStatus; } }
DiscardLastEvent();
return Status; }
HRESULT DetachProcesses(void) { HRESULT Status;
if (!AnyLiveUserTargets()) { // Nothing to do.
return S_OK; } if (g_SymOptions & SYMOPT_SECURE) { ErrOut("SECURE: Process detach disallowed\n"); return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); }
Status = PrepareForSeparation(); if (Status != S_OK) { ErrOut("Unable to prepare for detach, %s\n", FormatStatusCode(Status)); return Status; }
TargetInfo* Target; HRESULT SingleStatus;
ForAllLayersToTarget() { // If we fail in the middle of detaching things there
// isn't much that can be done so just attempt to
// detach as many things as possible.
if (IS_LIVE_USER_TARGET(Target) && (SingleStatus = Target->DetachProcesses()) != S_OK) { Status = SingleStatus; } }
DiscardLastEvent();
return Status; }
HRESULT SeparateCurrentProcess(ULONG Mode, PSTR Description) { if (!IS_LIVE_USER_TARGET(g_Target) || g_Process == NULL) { return E_INVALIDARG; } if (g_SymOptions & SYMOPT_SECURE) { ErrOut("SECURE: Process separation disallowed\n"); return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); } PUSER_DEBUG_SERVICES Services = ((LiveUserTargetInfo*)g_Target)->m_Services;
if ((Mode == SEP_DETACH || Mode == SEP_TERMINATE) && IS_CUR_CONTEXT_ACCESSIBLE()) { ADDR Pc;
// Move the PC past any current breakpoint instruction so that
// the process has a chance of running.
g_Machine->GetPC(&Pc); if (g_Machine->IsBreakpointInstruction(g_Process, &Pc)) { g_Machine->AdjustPCPastBreakpointInstruction (&Pc, DEBUG_BREAKPOINT_CODE); } } // Flush any buffered changes.
if (IS_CUR_CONTEXT_ACCESSIBLE()) { g_Target->FlushRegContext(); } if (g_EventProcess == g_Process && Mode != SEP_TERMINATE) { if (g_Target->m_DeferContinueEvent) { Services->ContinueEvent(DBG_CONTINUE); g_Target->m_DeferContinueEvent = FALSE; } } ((LiveUserTargetInfo*)g_Target)-> SuspendResumeThreads(g_Process, FALSE, NULL);
HRESULT Status; PSTR Operation;
switch(Mode) { case SEP_DETACH: Status = g_Process->Detach(); Operation = "Detached"; break; case SEP_TERMINATE: Status = g_Process->Terminate(); if ((g_Process->m_Flags & ENG_PROC_EXAMINED) == 0) { Operation = "Terminated. " "Exit thread and process events will occur."; } else { Operation = "Terminated"; } break; case SEP_ABANDON: Status = g_Process->Abandon(); Operation = "Abandoned"; break; } if (Status == S_OK) { if (Description != NULL) { strcpy(Description, Operation); }
// If we're detaching or abandoning it's safe to go
// ahead and remove the process now so that it
// can't be access further.
// If we're terminating we have to wait for
// the exit events to come through so
// keep the process until that happens.
if (Mode != SEP_TERMINATE) { delete g_Process; SetToAnyLayers(TRUE); } else { g_Process->m_Exited = FALSE; } } else { ((LiveUserTargetInfo*)g_Target)-> SuspendResumeThreads(g_Process, TRUE, NULL); }
return Status; }
|