1023 lines
23 KiB
C
1023 lines
23 KiB
C
/*
|
|
Copyright (c) 2013 Nathan LeRoux
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
*/
|
|
|
|
#include "dmincludes.h"
|
|
|
|
DMHRAPI DmStub()
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
PVOID __stdcall DmAllocatePool(ULONG cb)
|
|
{
|
|
return ExAllocatePoolWithTag(cb, 'xbdm');
|
|
}
|
|
|
|
PVOID __stdcall DmAllocatePoolWithTag(ULONG cb, ULONG tag)
|
|
{
|
|
return ExAllocatePoolWithTag(cb, tag);
|
|
}
|
|
|
|
PVOID DmAllocatePoolTypeWithTag(ULONG cb, ULONG tag, ULONG type)
|
|
{
|
|
return ExAllocatePoolTypeWithTag(cb, tag, type);
|
|
}
|
|
|
|
VOID __stdcall DmFreePool(PVOID p)
|
|
{
|
|
ExFreePool(p);
|
|
}
|
|
|
|
DMHRAPI DmGetXboxName(LPSTR szName, LPDWORD pcch)
|
|
{
|
|
DWORD i;
|
|
|
|
if(!szName || !pcch)
|
|
return E_INVALIDARG;
|
|
|
|
if(strlen(g_dmGlobals.rgchDbgName) >= *pcch)
|
|
return XBDM_BUFFER_TOO_SMALL;
|
|
|
|
for(i = 0;i < *pcch;i++)
|
|
{
|
|
szName[i] = g_dmGlobals.rgchDbgName[i];
|
|
|
|
if(g_dmGlobals.rgchDbgName[i] == 0)
|
|
break;
|
|
}
|
|
|
|
if(g_dmGlobals.rgchDbgName[i])
|
|
return XBDM_BUFFER_TOO_SMALL;
|
|
else
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
DMHRAPI DmGetXbeInfo(LPCSTR szName, PDM_XBE pdxbe)
|
|
{
|
|
return DmGetXbeInfoEx(szName, pdxbe, 0);
|
|
}
|
|
|
|
DMHRAPI DmGetXbeInfoEx(LPCSTR szName, PDM_XBE pdxbe, DWORD dwFlags)
|
|
{
|
|
if(!pdxbe)
|
|
return E_INVALIDARG;
|
|
|
|
if(dwFlags & DM_XBEONDISKONLY)
|
|
return XBDM_NOSUCHFILE;
|
|
|
|
ZeroMemory(pdxbe, sizeof(DM_XBE));
|
|
|
|
if(ExLoadedImageName)
|
|
strcpy(pdxbe->LaunchPath, ExLoadedImageName);
|
|
|
|
pdxbe->CheckSum = 0;
|
|
pdxbe->StackSize = 0;
|
|
pdxbe->TimeStamp = 0;
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
DMHRAPI DmGetMemory(LPCVOID lpbAddr, DWORD cb, LPVOID lpbBuf,
|
|
LPDWORD pcbRet)
|
|
{
|
|
DWORD page;
|
|
DWORD addr;
|
|
LPCSTR lpBuf = (LPCSTR)lpbBuf;
|
|
LPSTR lpAddr = (LPSTR)lpbAddr;
|
|
BOOL pageValid = TRUE;
|
|
|
|
if(!lpbBuf)
|
|
return E_INVALIDARG;
|
|
|
|
addr = (DWORD)lpbAddr;
|
|
page = addr + 0x1000;
|
|
|
|
while(pageValid && (addr < (DWORD)lpbAddr + cb))
|
|
{
|
|
if((addr ^ page) & 0xFFFFF000)
|
|
{
|
|
page = addr & 0xFFFFF000;
|
|
pageValid = MmIsAddressValid((LPVOID)addr);
|
|
}
|
|
|
|
if(pageValid)
|
|
pageValid = FGetMemory(addr, (PBYTE)lpBuf);
|
|
|
|
lpBuf++;
|
|
addr++;
|
|
}
|
|
|
|
if(!pageValid)
|
|
return XBDM_MEMUNMAPPED;
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
DMHRAPI DmSetMemory(LPVOID lpbAddr, DWORD cb, LPCVOID lpbBuf,
|
|
LPDWORD pcbRet)
|
|
{
|
|
DWORD page;
|
|
DWORD addr;
|
|
LPCSTR lpBuf = (LPCSTR)lpbBuf;
|
|
LPSTR lpAddr = (LPSTR)lpbAddr;
|
|
BOOL pageValid = TRUE;
|
|
|
|
if(!lpbBuf)
|
|
return E_INVALIDARG;
|
|
|
|
addr = (DWORD)lpbAddr;
|
|
page = addr + 0x1000;
|
|
|
|
while(pageValid && (addr < (DWORD)lpbAddr + cb))
|
|
{
|
|
if((addr ^ page) & 0xFFFFF000)
|
|
{
|
|
page = addr & 0xFFFFF000;
|
|
pageValid = MmIsAddressValid((LPVOID)addr);
|
|
}
|
|
|
|
if(pageValid)
|
|
pageValid = FSetMemory(addr, *lpBuf);
|
|
|
|
lpBuf++;
|
|
addr++;
|
|
}
|
|
|
|
if(!pageValid)
|
|
return XBDM_MEMUNMAPPED;
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
typedef struct _DM_WALK_MODULES
|
|
{
|
|
LIST_ENTRY Link;
|
|
DMN_MODLOAD_EX pdml;
|
|
} DM_WALK_MODULES;
|
|
|
|
DWORD g_ = 0;
|
|
DMHRAPI DmWalkLoadedModules(PDM_WALK_MODULES *ppdwm, PDMN_MODLOAD pdml)
|
|
{
|
|
HRESULT hr;
|
|
DMN_MODLOAD_EX dml;
|
|
|
|
dml.SizeOfStruct = sizeof(DMN_MODLOAD_EX);
|
|
|
|
hr = DmWalkLoadedModulesEx(ppdwm, &dml);
|
|
|
|
if(pdml)
|
|
memcpy(pdml, dml.Name, sizeof(DMN_MODLOAD));
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmWalkLoadedModulesEx(PDM_WALK_MODULES *ppdwm, PDMN_MODLOAD_EX pdml)
|
|
{
|
|
BYTE irql;
|
|
PLIST_ENTRY plemod;
|
|
PLIST_ENTRY ple = (PLIST_ENTRY)*ppdwm;
|
|
PLDR_DATA_TABLE_ENTRY pldte;
|
|
PDM_WALK_MODULES pdwm;
|
|
HRESULT hr = XBDM_NOERR;
|
|
PIMAGE_NT_HEADERS pinh;
|
|
|
|
if(!ppdwm || !pdml)
|
|
return E_INVALIDARG;
|
|
|
|
if(ple == NULL)
|
|
{
|
|
// Initialize the list entry
|
|
ple = (PLIST_ENTRY)DmAllocatePoolWithTag(sizeof(LIST_ENTRY), 'dmwm');
|
|
|
|
if(!ple)
|
|
return E_OUTOFMEMORY;
|
|
|
|
InitializeListHead(ple);
|
|
|
|
*ppdwm = (PDM_WALK_MODULES)ple;
|
|
|
|
irql = KfAcquireSpinLock(g_dmDebug.XexLoadedModuleListLock);
|
|
|
|
plemod = g_dmDebug.PsLoadedModuleList->Flink;
|
|
while(plemod != g_dmDebug.PsLoadedModuleList)
|
|
{
|
|
pldte = CONTAINING_RECORD(plemod, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
|
plemod = plemod->Flink;
|
|
|
|
pdwm = (PDM_WALK_MODULES)DmAllocatePoolWithTag(sizeof(DM_WALK_MODULES), 'dmwm');
|
|
|
|
if(!pdwm)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
pinh = RtlImageNtHeader(pldte->ImageBase);
|
|
|
|
ZeroMemory(pdwm, sizeof(DM_WALK_MODULES));
|
|
|
|
InsertTailList(ple, &pdwm->Link);
|
|
|
|
pdwm->pdml.SizeOfStruct = sizeof(DMN_MODLOAD_EX);
|
|
|
|
// Fetch ALL the info
|
|
pdwm->pdml.BaseAddress = pldte->ImageBase;
|
|
pdwm->pdml.CheckSum = pldte->CheckSum;
|
|
pdwm->pdml.Flags = 0;
|
|
if(!(pinh->FileHeader.Characteristics & 0x20))
|
|
pdwm->pdml.Flags |= DMN_MODFLAG_TLS;
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, pldte->BaseDllName.Buffer, -1, pdwm->pdml.Name, MAX_PATH, NULL, NULL);
|
|
pdwm->pdml.OriginalSize = _byteswap_ulong(pinh->OptionalHeader.SizeOfImage);
|
|
pdwm->pdml.PDataAddress = RtlImageDirectoryEntryToData(pldte->NtHeadersBase, TRUE, 3, &pdwm->pdml.PDataSize);
|
|
pdwm->pdml.Size = pldte->SizeOfNtImage;
|
|
pdwm->pdml.ThreadId = 0;//(DWORD)PsGetCurrentThread()->ThreadId;
|
|
pdwm->pdml.TimeStamp = pldte->TimeDateStamp;
|
|
}
|
|
|
|
KfReleaseSpinLock(g_dmDebug.XexLoadedModuleListLock, irql);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DmCloseLoadedModules(*ppdwm);
|
|
*ppdwm = NULL;
|
|
}
|
|
}
|
|
|
|
if(NT_SUCCESS(hr))
|
|
{
|
|
// Take an entry, copy the data, remove from list, free the memory
|
|
ple = ((PLIST_ENTRY)*ppdwm)->Flink;
|
|
|
|
if(ple->Flink == ple->Blink)
|
|
hr = XBDM_ENDOFLIST;
|
|
|
|
memcpy(pdml, &CONTAINING_RECORD(ple, DM_WALK_MODULES, Link)->pdml, sizeof(DMN_MODLOAD_EX));
|
|
|
|
ple->Flink->Blink = ple->Blink;
|
|
ple->Blink->Flink = ple->Flink;
|
|
|
|
DmFreePool(CONTAINING_RECORD(ple, DM_WALK_MODULES, Link));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmCloseLoadedModules(PDM_WALK_MODULES pdwm)
|
|
{
|
|
PLIST_ENTRY ple;
|
|
PDM_WALK_MODULES pdwm2;
|
|
|
|
if(!pdwm)
|
|
return E_INVALIDARG;
|
|
|
|
ple = ((PLIST_ENTRY)pdwm)->Flink;
|
|
while(ple != (PLIST_ENTRY)pdwm)
|
|
{
|
|
pdwm2 = CONTAINING_RECORD(ple, DM_WALK_MODULES, Link);
|
|
|
|
ple->Flink->Blink = ple->Blink;
|
|
ple->Blink->Flink = ple->Flink;
|
|
ple = ple->Flink;
|
|
|
|
DmFreePool(pdwm2);
|
|
}
|
|
|
|
DmFreePool(pdwm);
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
typedef struct _DM_WALK_MODSECT
|
|
{
|
|
LIST_ENTRY Link;
|
|
DMN_SECTIONLOAD pdml;
|
|
} DM_WALK_MODSECT;
|
|
DMHRAPI DmWalkModuleSections(PDM_WALK_MODSECT *ppWalkModSect, LPCSTR lzModName, PDMN_SECTIONLOAD pSecLoad)
|
|
{
|
|
BYTE irql;
|
|
PLIST_ENTRY ple = (PLIST_ENTRY)*ppWalkModSect;
|
|
PLDR_DATA_TABLE_ENTRY pldte;
|
|
HRESULT hr = XBDM_NOERR;
|
|
PIMAGE_SECTION_HEADER pish;
|
|
DWORD dw;
|
|
int i;
|
|
|
|
if(!ppWalkModSect || !pSecLoad)
|
|
return E_INVALIDARG;
|
|
|
|
if(ple == NULL)
|
|
{
|
|
// Initialize the list entry
|
|
ple = (PLIST_ENTRY)DmAllocatePoolWithTag(sizeof(LIST_ENTRY), 'dmwm');
|
|
|
|
if(!ple)
|
|
return E_OUTOFMEMORY;
|
|
|
|
InitializeListHead(ple);
|
|
|
|
*ppWalkModSect = (PDM_WALK_MODSECT)ple;
|
|
|
|
irql = KfAcquireSpinLock(g_dmDebug.XexLoadedModuleListLock);
|
|
|
|
if(NT_SUCCESS(hr = FGetModuleHandle(lzModName, &pldte, FALSE)))
|
|
{
|
|
pish = (PIMAGE_SECTION_HEADER)(RtlImageNtHeader(pldte->ImageBase) + 1);
|
|
|
|
for(i = 0;pish->Name[0];i++)
|
|
{
|
|
PDM_WALK_MODSECT pdmwm = (PDM_WALK_MODSECT)DmAllocatePoolWithTag(sizeof(DM_WALK_MODSECT), 'dmwm');
|
|
if(!pdmwm)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(pdmwm, sizeof(DM_WALK_MODSECT));
|
|
|
|
InsertTailList(ple, &pdmwm->Link);
|
|
|
|
pdmwm->pdml.Index = i + 1;
|
|
memcpy(pdmwm->pdml.Name, pish->Name, 8);
|
|
pdmwm->pdml.BaseAddress = (PVOID)(_byteswap_ulong(pish->VirtualAddress) + (DWORD)pldte->ImageBase);
|
|
pdmwm->pdml.Size = _byteswap_ulong(pish->Misc.VirtualSize);
|
|
pdmwm->pdml.Flags = 0;
|
|
dw = _byteswap_ulong(pish->Characteristics);
|
|
if(dw & 0x40000000)
|
|
pdmwm->pdml.Flags |= DMN_SECFLAG_READABLE;
|
|
if(dw & 0x80000000)
|
|
pdmwm->pdml.Flags |= DMN_SECFLAG_WRITEABLE;
|
|
if(dw & 0x20000000)
|
|
pdmwm->pdml.Flags |= DMN_SECFLAG_EXECUTABLE;
|
|
if(dw & 0x80)
|
|
pdmwm->pdml.Flags |= DMN_SECFLAG_UNINITIALIZED;
|
|
|
|
pish++;
|
|
}
|
|
}
|
|
KfReleaseSpinLock(g_dmDebug.XexLoadedModuleListLock, irql);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DmCloseModuleSections(*ppWalkModSect);
|
|
*ppWalkModSect = FALSE;
|
|
}
|
|
}
|
|
|
|
if(NT_SUCCESS(hr))
|
|
{
|
|
// Take an entry, copy the data, remove from list, free the memory
|
|
ple = ((PLIST_ENTRY)*ppWalkModSect)->Flink;
|
|
|
|
if(ple->Flink == ple->Blink)
|
|
hr = XBDM_ENDOFLIST;
|
|
|
|
memcpy(pSecLoad, &CONTAINING_RECORD(ple, DM_WALK_MODSECT, Link)->pdml, sizeof(DMN_SECTIONLOAD));
|
|
|
|
ple->Flink->Blink = ple->Blink;
|
|
ple->Blink->Flink = ple->Flink;
|
|
|
|
DmFreePool(CONTAINING_RECORD(ple, DM_WALK_MODULES, Link));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmCloseModuleSections(PDM_WALK_MODSECT pWalkMod)
|
|
{
|
|
PLIST_ENTRY ple;
|
|
PDM_WALK_MODSECT pdwm2;
|
|
|
|
if(!pWalkMod)
|
|
return E_INVALIDARG;
|
|
|
|
ple = ((PLIST_ENTRY)pWalkMod)->Flink;
|
|
while(ple != (PLIST_ENTRY)pWalkMod)
|
|
{
|
|
pdwm2 = CONTAINING_RECORD(ple, DM_WALK_MODSECT, Link);
|
|
|
|
ple->Flink->Blink = ple->Blink;
|
|
ple->Blink->Flink = ple->Flink;
|
|
ple = ple->Flink;
|
|
|
|
DmFreePool(pdwm2);
|
|
}
|
|
|
|
DmFreePool(pWalkMod);
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
DMHRAPI DmReboot(DWORD dwFlags)
|
|
{
|
|
return DmRebootEx(dwFlags, NULL, NULL, NULL);
|
|
}
|
|
|
|
ULONG __stdcall DmBootThread(LPVOID param)
|
|
{
|
|
XamLoaderLaunchTitleEx(g_dmGlobals.szBootTitle, g_dmGlobals.szBootPath, g_dmGlobals.szBootCmdLine, 0);
|
|
return 0;
|
|
}
|
|
|
|
BOOL FWouldSystemCrash()
|
|
{
|
|
BYTE irql;
|
|
PKTHREAD pthr;
|
|
PLIST_ENTRY ple;
|
|
BOOL fRet = FALSE;
|
|
DMTD *pdmtd;
|
|
int i;
|
|
|
|
irql = KfAcquireSpinLock(g_dmDebug.KeSystemProcess);
|
|
|
|
ple = g_dmDebug.KeSystemProcess->ThreadListHead.Flink;
|
|
|
|
for(i = 0;i < 2;i++)
|
|
{
|
|
while(ple != &g_dmDebug.KeSystemProcess->ThreadListHead && ple != &g_dmDebug.KeTitleProcess->ThreadListHead)
|
|
{
|
|
pthr = CONTAINING_RECORD(ple, KTHREAD, ThreadListEntry);
|
|
ple = ple->Flink;
|
|
|
|
pdmtd = (DMTD*)pthr->DebugMonitorData;
|
|
|
|
if(pdmtd &&
|
|
(pdmtd->StopReason == DM_EXCEPTION
|
|
|| pdmtd->StopReason == DM_BREAK
|
|
|| pdmtd->StopReason == DM_SINGLESTEP
|
|
|| pdmtd->StopReason == DM_DATABREAK
|
|
|| pdmtd->StopReason == DM_ASSERT
|
|
|| pdmtd->StopReason == DM_RIP))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
ple = g_dmDebug.KeTitleProcess->ThreadListHead.Flink;
|
|
}
|
|
|
|
KfReleaseSpinLock(g_dmDebug.KeSystemProcess, irql);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
DMHRAPI DmRebootEx(DWORD dwFlags, LPCSTR szImagePath, LPCSTR szMediaPath, LPCSTR szDbgCmdLine)
|
|
{
|
|
char sz[MAX_PATH];
|
|
char szM[MAX_PATH];
|
|
int i, j;
|
|
#ifdef _DEBUG
|
|
HANDLE h;
|
|
#endif
|
|
|
|
if((dwFlags & DMBOOT_WAIT) && (dwFlags & DMBOOT_STOP))
|
|
return E_INVALIDARG;
|
|
|
|
if(FWouldSystemCrash())
|
|
{
|
|
DwChangeExecState(DMN_EXEC_REBOOT, FALSE, TRUE, FALSE);
|
|
FStopServ();
|
|
if(KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
|
{
|
|
HalReturnToFirmware(1);
|
|
}
|
|
HalReturnToFirmware(6);
|
|
}
|
|
|
|
g_dmGlobals.dwBootFlags = dwFlags;
|
|
|
|
if(szImagePath)
|
|
strcpy_s(g_dmGlobals.szBootTitle, sizeof(g_dmGlobals.szBootTitle), szImagePath);
|
|
if(szMediaPath)
|
|
strcpy_s(g_dmGlobals.szBootPath, sizeof(g_dmGlobals.szBootPath), szMediaPath);
|
|
if(szDbgCmdLine)
|
|
strcpy_s(g_dmGlobals.szBootCmdLine, sizeof(g_dmGlobals.szBootCmdLine), szDbgCmdLine);
|
|
|
|
if(dwFlags & DMBOOT_COLD)
|
|
{
|
|
DwChangeExecState(DMN_EXEC_REBOOT, FALSE, TRUE, FALSE);
|
|
FStopServ();
|
|
|
|
FWriteGlobals();
|
|
|
|
if(KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
|
HalReturnToFirmware(1);
|
|
|
|
HalReturnToFirmware(6);
|
|
}
|
|
|
|
if(dwFlags & DMBOOT_TITLE)
|
|
{
|
|
szImagePath = sz;
|
|
szMediaPath = szM;
|
|
|
|
if(ExLoadedImageName)
|
|
{
|
|
strcpy_s(sz, sizeof(sz), ExLoadedImageName);
|
|
strcpy_s(szM, sizeof(szM), sz);
|
|
|
|
// Parse out the directory
|
|
for(i = 0, j = 0;szM[i];i++)
|
|
if(szM[i] == '\\' || szM[i] == '//')
|
|
j = i;
|
|
szM[j] = 0;
|
|
}
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
// To make sure we can't get stuck
|
|
DwChangeExecState(DMN_EXEC_START, TRUE, FALSE, FALSE);
|
|
|
|
DwChangeExecState(DMN_EXEC_REBOOT_TITLE, FALSE, TRUE, FALSE);
|
|
|
|
#ifdef _DEBUG
|
|
// DEVKIT
|
|
ExCreateThread(&h, 0, 0, 0, DmBootThread, 0, 0x400);
|
|
SetThreadPriority(h, THREAD_PRIORITY_TIME_CRITICAL);
|
|
CloseHandle(h);
|
|
|
|
Sleep(200);
|
|
|
|
#else
|
|
XamLoaderLaunchTitleEx(szImagePath, szMediaPath, szDbgCmdLine, 0);
|
|
#endif
|
|
|
|
if(KeGetCurrentProcessType() == 1)
|
|
ExTerminateThread(-1); // kill off this thread
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
LPCSTR ESysSymbolicLinkName = "\\system??\\E:";
|
|
LPCSTR ESymbolicLinkName = "\\??\\E:";
|
|
LPCSTR DEVKITSymbolicLinkName = "\\??\\DEVKIT:";
|
|
LPCSTR DEVKITSysSymbolicLinkName = "\\system??\\DEVKIT:";
|
|
LPCSTR DevkitDeviceName = "\\Device\\Harddisk0\\Partition1\\DEVKIT";
|
|
|
|
DMHRAPI DmMapDevkitDrive()
|
|
{
|
|
ANSI_STRING symName, devName;
|
|
NTSTATUS st;
|
|
|
|
DWORD b = KeGetCurrentProcessType();
|
|
|
|
if(b == 2)
|
|
RtlInitAnsiString(&symName, ESysSymbolicLinkName);
|
|
else
|
|
RtlInitAnsiString(&symName, ESymbolicLinkName);
|
|
|
|
RtlInitAnsiString(&devName, DevkitDeviceName);
|
|
|
|
st = ObCreateSymbolicLink(&symName, &devName);
|
|
|
|
if(st < STATUS_OBJECT_NAME_COLLISION && st < 0)
|
|
return (RtlNtStatusToDosError(st) & 0xFFFF) | 0x80070000;
|
|
|
|
if(b == 2)
|
|
RtlInitAnsiString(&symName, DEVKITSysSymbolicLinkName);
|
|
else
|
|
RtlInitAnsiString(&symName, DEVKITSymbolicLinkName);
|
|
|
|
st = ObCreateSymbolicLink(&symName, &devName);
|
|
|
|
if(st < STATUS_OBJECT_NAME_COLLISION && st < 0)
|
|
return (RtlNtStatusToDosError(st) & 0xFFFF) | 0x80070000;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
DMHRAPI DmSetDumpMode(DWORD dwDumpMode)
|
|
{
|
|
if(dwDumpMode > DM_DUMPMODE_DISABLED)
|
|
return E_INVALIDARG;
|
|
|
|
g_dmGlobals.dwDumpMode = dwDumpMode;
|
|
g_dmGlobals.bDirty = TRUE;
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
DMHRAPI DmGetDumpMode(DWORD * pdwDumpMode)
|
|
{
|
|
if(!pdwDumpMode)
|
|
return E_INVALIDARG;
|
|
|
|
*pdwDumpMode = g_dmGlobals.dwDumpMode;
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
HRESULT FGetModuleHandle(LPCSTR ModuleName, PLDR_DATA_TABLE_ENTRY *ppdte, BOOL bSpinLock)
|
|
{
|
|
BYTE irql;
|
|
PLDR_DATA_TABLE_ENTRY pdte;
|
|
PLIST_ENTRY ple;
|
|
HRESULT hr = XBDM_NOSUCHFILE;
|
|
char sz[MAX_PATH];
|
|
int i;
|
|
|
|
if(!ppdte || !ModuleName)
|
|
return E_INVALIDARG;
|
|
|
|
*ppdte = NULL;
|
|
|
|
if(bSpinLock)
|
|
irql = KfAcquireSpinLock(g_dmDebug.XexLoadedModuleListLock);
|
|
|
|
ple = g_dmDebug.PsLoadedModuleList->Flink;
|
|
while(ple != g_dmDebug.PsLoadedModuleList)
|
|
{
|
|
pdte = CONTAINING_RECORD(ple, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
|
ple = ple->Flink;
|
|
|
|
sz[0] = 0;
|
|
wcstombs_s(&i, sz, sizeof(sz), pdte->BaseDllName.Buffer, pdte->BaseDllName.Length);
|
|
|
|
if(!strnicmp(sz, ModuleName, sizeof(sz)))
|
|
{
|
|
*ppdte = pdte;
|
|
hr = XBDM_NOERR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(bSpinLock)
|
|
KfReleaseSpinLock(g_dmDebug.XexLoadedModuleListLock, irql);
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmGetThreadContext(DWORD dwThreadId, PXCONTEXT pdmcr)
|
|
{
|
|
PKTHREAD pthr;
|
|
BYTE irql;
|
|
DMTD *pdmtd;
|
|
HRESULT hr;
|
|
char *stack;
|
|
DWORD flags;
|
|
|
|
if(!pdmcr)
|
|
return E_INVALIDARG;
|
|
|
|
if(FAILED(ObLookupAnyThreadByThreadId(dwThreadId, &pthr)))
|
|
return XBDM_NOTHREAD;
|
|
|
|
irql = KfAcquireSpinLock(&pthr->Process->ThreadListLock);
|
|
|
|
flags = pdmcr->ContextFlags;
|
|
ZeroMemory(pdmcr, sizeof(XCONTEXT));
|
|
|
|
pdmtd = (DMTD*)pthr->DebugMonitorData;
|
|
|
|
if(pdmtd && !(pdmtd->DebugFlags & DMFLAG_DEBUGTHREAD))
|
|
{
|
|
stack = (char*)pthr->KernelStack;
|
|
|
|
if(pdmtd->Context)
|
|
{
|
|
if(flags & CONTEXT_INTEGER)
|
|
{
|
|
pdmcr->ContextFlags |= CONTEXT_INTEGER;
|
|
|
|
memcpy(&pdmcr->Gpr0, &pdmtd->Context->Gpr0, ((char*)&pdmcr->Xer - (char*)&pdmcr->Gpr0));
|
|
}
|
|
if(flags & CONTEXT_CONTROL)
|
|
{
|
|
pdmcr->ContextFlags |= CONTEXT_CONTROL;
|
|
|
|
memcpy(&pdmcr->Msr, &pdmtd->Context->Msr, ((char*)&pdmcr->Ctr - (char*)&pdmcr->Msr));
|
|
}
|
|
if(flags & CONTEXT_FLOATING_POINT)
|
|
{
|
|
pdmcr->ContextFlags |= CONTEXT_FLOATING_POINT;
|
|
|
|
memcpy(&pdmcr->Fpscr, &pdmtd->Context->Fpscr, ((char*)&pdmcr->Fill - (char*)&pdmcr->Fpscr));
|
|
}
|
|
if(flags & CONTEXT_VECTOR)
|
|
{
|
|
pdmcr->ContextFlags |= CONTEXT_VECTOR;
|
|
|
|
memcpy(&pdmcr->Vscr[0], &pdmtd->Context->Vscr[0], ((char*)&pdmcr->Vr127[3] - (char*)&pdmcr->Vscr[0]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(flags & CONTEXT_INTEGER)
|
|
{
|
|
pdmcr->ContextFlags |= CONTEXT_INTEGER;
|
|
|
|
memset(&pdmcr->Gpr0, 0xFF, 0x70);
|
|
memcpy(&pdmcr->Gpr14, stack + 0x50, 0x90);
|
|
pdmcr->Xer = -1;
|
|
pdmcr->Cr = ((LPDWORD)stack)[0x38];
|
|
pdmcr->Gpr1 = (DWORD)stack;
|
|
}
|
|
if(flags & CONTEXT_CONTROL)
|
|
{
|
|
pdmcr->ContextFlags |= CONTEXT_CONTROL;
|
|
|
|
pdmcr->Msr = -1;
|
|
pdmcr->Iar = ((LPDWORD)stack)[0x39];
|
|
pdmcr->Ctr = -1;
|
|
pdmcr->Lr = ((LPDWORD)stack)[0x3A];
|
|
}
|
|
}
|
|
|
|
hr = XBDM_NOERR;
|
|
}
|
|
else
|
|
hr = XBDM_NOTHREAD;
|
|
|
|
KfReleaseSpinLock(&pthr->Process->ThreadListLock, irql);
|
|
|
|
ObDereferenceObject(pthr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmSetThreadContext(DWORD dwThreadId, PXCONTEXT pdmcr)
|
|
{
|
|
BYTE irql;
|
|
PKTHREAD pthr;
|
|
DMTD *pdmtd;
|
|
HRESULT hr = XBDM_NOERR;
|
|
|
|
if(!pdmcr)
|
|
return E_FAIL;
|
|
|
|
if(FAILED(ObLookupAnyThreadByThreadId(dwThreadId, &pthr)))
|
|
return XBDM_NOTHREAD;
|
|
|
|
irql = KfAcquireSpinLock(&pthr->Process->ThreadListLock);
|
|
|
|
pdmtd = (DMTD*)pthr->DebugMonitorData;
|
|
|
|
if(pdmtd && !(pdmtd->DebugFlags & DMFLAG_DEBUGTHREAD))
|
|
{
|
|
if(pdmtd->Context)
|
|
{
|
|
if(pdmcr->ContextFlags & CONTEXT_INTEGER)
|
|
memcpy(&pdmtd->Context->Gpr0, &pdmcr->Gpr0, ((char*)&pdmcr->Xer - (char*)&pdmcr->Gpr0));
|
|
if(pdmcr->ContextFlags & CONTEXT_CONTROL)
|
|
{
|
|
if(pdmcr->Msr & 0x400) // Just a quick fix
|
|
pdmtd->DebugFlags |= DMFLAG_SINGLESTEP;
|
|
|
|
memcpy(&pdmtd->Context->Msr, &pdmcr->Msr, ((char*)&pdmcr->Ctr - (char*)&pdmcr->Msr));
|
|
}
|
|
if(pdmcr->ContextFlags & CONTEXT_FLOATING_POINT)
|
|
memcpy(&pdmtd->Context->Fpscr, &pdmcr->Fpscr, ((char*)&pdmcr->Fill - (char*)&pdmcr->Fpscr));
|
|
if(pdmcr->ContextFlags & CONTEXT_VECTOR)
|
|
memcpy(&pdmtd->Context->Vscr[0], &pdmcr->Vscr[0], ((char*)&pdmcr->Vr127[3] - (char*)&pdmcr->Vscr[0]));
|
|
}
|
|
else
|
|
hr = XBDM_NOTSTOPPED;
|
|
}
|
|
|
|
KfReleaseSpinLock(&pthr->Process->ThreadListLock, irql);
|
|
ObDereferenceObject(pthr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmGetThreadList(LPDWORD rgdwThreads, LPDWORD pcThreads)
|
|
{
|
|
BYTE irql;
|
|
PLIST_ENTRY ple;
|
|
PKTHREAD pthr;
|
|
HRESULT hr = XBDM_NOERR;
|
|
DWORD cchThreads = 0;
|
|
DMTD *pdmtd;
|
|
int i;
|
|
|
|
if(!rgdwThreads || !pcThreads)
|
|
return E_FAIL;
|
|
|
|
if(*pcThreads == 0)
|
|
return XBDM_BUFFER_TOO_SMALL;
|
|
|
|
irql = KfAcquireSpinLock(&g_dmDebug.KeSystemProcess->ThreadListLock);
|
|
KeAcquireSpinLockAtRaisedIrql(&g_dmDebug.KeTitleProcess->ThreadListLock);
|
|
|
|
ple = g_dmDebug.KeSystemProcess->ThreadListHead.Flink;
|
|
for(i = 0;i < 2;i++)
|
|
{
|
|
while(ple != &g_dmDebug.KeSystemProcess->ThreadListHead && ple != &g_dmDebug.KeTitleProcess->ThreadListHead)
|
|
{
|
|
pthr = CONTAINING_RECORD(ple, KTHREAD, ThreadListEntry);
|
|
ple = ple->Flink;
|
|
|
|
if(!pthr->DebugMonitorData)
|
|
FInitThreadDebugData(pthr);
|
|
|
|
pdmtd = (DMTD*)pthr->DebugMonitorData;
|
|
|
|
if(pdmtd && !(pdmtd->DebugFlags & DMFLAG_DEBUGTHREAD))
|
|
{
|
|
if(cchThreads++ < *pcThreads)
|
|
rgdwThreads[cchThreads - 1] = (DWORD)pthr->ThreadId;
|
|
else
|
|
hr = XBDM_BUFFER_TOO_SMALL;
|
|
}
|
|
}
|
|
|
|
ple = g_dmDebug.KeTitleProcess->ThreadListHead.Flink;
|
|
}
|
|
|
|
*pcThreads = cchThreads;
|
|
|
|
KeReleaseSpinLockFromRaisedIrql(&g_dmDebug.KeTitleProcess->ThreadListLock);
|
|
KfReleaseSpinLock(&g_dmDebug.KeSystemProcess->ThreadListLock, irql);
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmContinueThread(DWORD dwThreadId, BOOL fException)
|
|
{
|
|
PKTHREAD pthr;
|
|
BYTE irql;
|
|
HRESULT hr = XBDM_NOERR;
|
|
DMTD *pdmtd;
|
|
|
|
if(dwExecState > 3)
|
|
return XBDM_NOTHREAD;
|
|
|
|
if(FAILED(ObLookupAnyThreadByThreadId(dwThreadId, &pthr)))
|
|
return XBDM_NOTHREAD;
|
|
|
|
irql = KfAcquireSpinLock(&pthr->Process->ThreadListLock);
|
|
|
|
pdmtd = (DMTD*)pthr->DebugMonitorData;
|
|
|
|
if(pdmtd && (pdmtd->DebugFlags & DMFLAG_CONTINUEABLE))
|
|
{
|
|
if(fException)
|
|
pdmtd->DebugFlags |= DMFLAG_EXCEPTION;
|
|
|
|
if(dwExecState != DMN_EXEC_START)
|
|
{
|
|
if(!(pdmtd->DebugFlags & DMFLAG_STOPPED))
|
|
{
|
|
pdmtd->DebugFlags |= DMFLAG_STOPPED;
|
|
KeSuspendThread(pthr);
|
|
}
|
|
}
|
|
|
|
pdmtd->DebugFlags &= ~DMFLAG_CONTINUEABLE;
|
|
|
|
KeSetEvent(pdmtd->DebugEvent, TRUE, FALSE);
|
|
}
|
|
else
|
|
hr = XBDM_NOTSTOPPED;
|
|
|
|
KfReleaseSpinLock(&pthr->Process->ThreadListLock, irql);
|
|
|
|
ObDereferenceObject(pthr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmStopOn(DWORD dwStopFlags, BOOL fStop)
|
|
{
|
|
// We should probably be synchronizing this for when titles feel like being dicks and not synchronizing
|
|
// Oh well :/
|
|
|
|
if(fStop)
|
|
g_dmGlobals.dwStopFlags |= dwStopFlags;
|
|
else
|
|
g_dmGlobals.dwStopFlags &= ~dwStopFlags;
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
DMHRAPI DmIsThreadStopped(DWORD dwThreadId, PDM_THREADSTOP pdmts)
|
|
{
|
|
PKTHREAD pthr;
|
|
DMTD *pdmtd;
|
|
BYTE irql;
|
|
HRESULT hr = XBDM_NOERR;
|
|
|
|
pdmts->NotifiedReason = DM_NONE;
|
|
|
|
if(FAILED(ObLookupAnyThreadByThreadId(dwThreadId, &pthr)))
|
|
return XBDM_NOTHREAD;
|
|
|
|
irql = KfAcquireSpinLock(&pthr->Process->ThreadListLock);
|
|
|
|
pdmtd = (DMTD*)pthr->DebugMonitorData;
|
|
|
|
if(pdmtd && !(pdmtd->DebugFlags & DMFLAG_DEBUGTHREAD))
|
|
{
|
|
if(pdmtd->Exception && (pdmtd->DebugFlags & DMFLAG_CONTINUEABLE))
|
|
{
|
|
// Time to play some FIGUREOUTWTFISWRONGWITHTHISTHREAD!
|
|
pdmts->NotifiedReason = pdmtd->StopReason;
|
|
switch(pdmtd->StopReason)
|
|
{
|
|
case DM_DEBUGSTR:
|
|
case DM_ASSERT:
|
|
pdmts->u.DebugStr.ThreadId = dwThreadId;
|
|
pdmts->u.DebugStr.String = (LPCSTR)pdmtd->Context->Gpr3;
|
|
pdmts->u.DebugStr.Length = (DWORD)pdmtd->Context->Gpr4;
|
|
break;
|
|
case DM_SINGLESTEP:
|
|
case DM_BREAK:
|
|
pdmts->u.Break.ThreadId = dwThreadId;
|
|
pdmts->u.Break.Address = (PVOID)pdmtd->Context->Iar;
|
|
break;
|
|
case DM_DATABREAK:
|
|
pdmts->u.DataBreak.ThreadId = dwThreadId;
|
|
pdmts->u.DataBreak.Address = (PVOID)pdmtd->Context->Iar;
|
|
pdmts->u.DataBreak.DataAddress = (PVOID)pdmtd->Exception->ExceptionInformation[1];
|
|
// if FMatchDataBreak
|
|
break;
|
|
case DM_EXCEPTION:
|
|
pdmts->u.Exception.ThreadId = dwThreadId;
|
|
pdmts->u.Exception.Address = (PVOID)pdmtd->Context->Iar;
|
|
if(pdmtd->DebugFlags & DMFLAG_FIRSTCHANCE)
|
|
pdmts->u.Exception.Flags = DM_EXCEPT_FIRSTCHANCE;
|
|
else
|
|
pdmts->u.Exception.Flags = 0;
|
|
|
|
pdmts->u.Exception.Information[0] = pdmtd->Exception->ExceptionInformation[0];
|
|
pdmts->u.Exception.Information[1] = pdmtd->Exception->ExceptionInformation[1];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
hr = XBDM_NOTSTOPPED;
|
|
}
|
|
else
|
|
hr = XBDM_NOTHREAD;
|
|
|
|
KfReleaseSpinLock(&pthr->Process->ThreadListLock, irql);
|
|
ObDereferenceObject(pthr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
DMHRAPI DmSuspendThread(DWORD dwThreadId)
|
|
{
|
|
PKTHREAD pthr;
|
|
|
|
if(FAILED(ObLookupAnyThreadByThreadId(dwThreadId, &pthr)))
|
|
return XBDM_NOTHREAD;
|
|
|
|
KeSuspendThread(pthr);
|
|
ObDereferenceObject(pthr);
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
DMHRAPI DmResumeThread(DWORD dwThreadId)
|
|
{
|
|
PKTHREAD pthr;
|
|
|
|
if(FAILED(ObLookupAnyThreadByThreadId(dwThreadId, &pthr)))
|
|
return XBDM_NOTHREAD;
|
|
|
|
KeResumeThread(pthr);
|
|
ObDereferenceObject(pthr);
|
|
|
|
return XBDM_NOERR;
|
|
}
|
|
|
|
DMHRAPI DmGetSystemInfo(PDM_SYSTEM_INFO pdmGetSystemInfo)
|
|
{
|
|
if(!pdmGetSystemInfo)
|
|
return E_INVALIDARG;
|
|
|
|
if(pdmGetSystemInfo->SizeOfStruct != sizeof(DM_SYSTEM_INFO))
|
|
return E_INVALIDARG;
|
|
|
|
memcpy(&pdmGetSystemInfo->BaseKernelVersion, &XboxKrnlBaseVersion, sizeof(DM_SYSTEM_INFO));
|
|
memcpy(&pdmGetSystemInfo->KernelVersion, &XboxKrnlVersion, sizeof(DM_SYSTEM_INFO));
|
|
|
|
pdmGetSystemInfo->XDKVersion.Major = 2;
|
|
pdmGetSystemInfo->XDKVersion.Minor = 0;
|
|
pdmGetSystemInfo->XDKVersion.Build = 20353;
|
|
pdmGetSystemInfo->XDKVersion.Qfe = 0;
|
|
|
|
pdmGetSystemInfo->dmSystemInfoFlags = (XboxHardwareInfo->Flags & 0x20) ? DM_XBOX_HW_FLAG_HDD : 0;
|
|
|
|
return XBDM_NOERR;
|
|
} |