windows-nt/Source/XPSP1/NT/sdktools/debuggers/minidump/nt4.c

576 lines
13 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1999-2002 Microsoft Corporation
Module Name:
nt4.c
Abstract:
NT 4 specific routines.
The following routine are exported from this file:
o Nt4OpenThread
o Nt4GetProcessInfo
o Nt4EnumProcessModules
o Nt4GetModuleFileNameExW
Author:
Matthew D Hendel (math) 10-Sept-1999
Revision History:
Environment:
NT 4.0 only.
--*/
#include "pch.h"
#include "ntx.h"
#include "nt4.h"
#include "nt4p.h"
#include "impl.h"
BOOL
WINAPI
Nt4EnumProcessModules(
HANDLE hProcess,
HMODULE *lphModule,
DWORD cb,
LPDWORD lpcbNeeded
);
HANDLE
WINAPI
Nt4OpenThread(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwThreadId
)
{
NTSTATUS Status;
NT4_OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
NT4_CLIENT_ID ClientId;
ClientId.UniqueThread = (HANDLE)LongToHandle(dwThreadId);
ClientId.UniqueProcess = (HANDLE)NULL;
Nt4InitializeObjectAttributes(
&Obja,
NULL,
(bInheritHandle ? NT4_OBJ_INHERIT : 0),
NULL,
NULL
);
Status = NtOpenThread(
&Handle,
(ACCESS_MASK)dwDesiredAccess,
(POBJECT_ATTRIBUTES)&Obja,
(PCLIENT_ID)&ClientId
);
if ( NT_SUCCESS(Status) ) {
return Handle;
}
else {
return NULL;
}
}
BOOL
Nt4GetProcessInfo(
IN HANDLE hProcess,
IN ULONG ProcessId,
IN ULONG DumpType,
IN MINIDUMP_CALLBACK_ROUTINE CallbackRoutine,
IN PVOID CallbackParam,
OUT PINTERNAL_PROCESS * ProcessRet
)
{
BOOL Succ;
ULONG i;
NTSTATUS Status;
ULONG BufferSize;
LPVOID Buffer;
PNT4_SYSTEM_PROCESS_INFORMATION ProcessInfo;
PNT4_SYSTEM_THREAD_INFORMATION ThreadInfo;
PINTERNAL_THREAD Thread;
PINTERNAL_MODULE Module;
PINTERNAL_PROCESS Process;
HMODULE Modules [ 512 ];
ULONG ModulesSize;
ULONG NumberOfModules;
ULONG_PTR Next;
BufferSize = 64 * KBYTE;
Buffer = NULL;
do {
if (Buffer) {
FreeMemory (Buffer);
}
Buffer = AllocMemory ( BufferSize );
if ( Buffer == NULL) {
return FALSE;
}
Status = NtQuerySystemInformation (
Nt4SystemProcessInformation,
Buffer,
BufferSize,
NULL
);
if (!NT_SUCCESS (Status) && Status != STATUS_INFO_LENGTH_MISMATCH) {
GenAccumulateStatus(MDSTATUS_CALL_FAILED);
return FALSE;
}
BufferSize += (8 * KBYTE);
} while (Status == STATUS_INFO_LENGTH_MISMATCH);
//
// Find the correct process in the process list.
//
ProcessInfo = (PNT4_SYSTEM_PROCESS_INFORMATION) Buffer;
while (ProcessInfo->NextEntryOffset &&
ProcessInfo->UniqueProcessId != (HANDLE) ProcessId) {
Next = ((ULONG_PTR)ProcessInfo + ProcessInfo->NextEntryOffset);
ProcessInfo = (PNT4_SYSTEM_PROCESS_INFORMATION) Next;
}
//
// Could not find a matching process in the process list.
//
if (ProcessInfo->UniqueProcessId != (HANDLE) ProcessId) {
Succ = FALSE;
GenAccumulateStatus(MDSTATUS_INTERNAL_ERROR);
goto Exit;
}
//
// Create an INTERNAL_PROCESS object and copy the process information
// into it.
//
Process = GenAllocateProcessObject ( hProcess, ProcessId );
if ( Process == NULL ) {
return FALSE;
}
//
// Walk the thread list for this process, copying thread information
// for each thread. Walking the thread list also suspends all the threads
// in the process. This should be done before walking the module list
// to minimize the number of race conditions.
//
ThreadInfo = (PNT4_SYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
Process->NumberOfThreads = 0;
for (i = 0; i < ProcessInfo->NumberOfThreads; i++) {
ULONG WriteFlags;
if (!GenExecuteIncludeThreadCallback(hProcess,
ProcessId,
DumpType,
(ULONG)ThreadInfo->ClientId.UniqueThread,
CallbackRoutine,
CallbackParam,
&WriteFlags) ||
IsFlagClear(WriteFlags, ThreadWriteThread)) {
ThreadInfo++;
continue;
}
Status = GenAllocateThreadObject (
Process,
hProcess,
(ULONG) ThreadInfo->ClientId.UniqueThread,
DumpType,
WriteFlags,
&Thread
);
if (FAILED(Status)) {
Succ = FALSE;
goto Exit;
}
// If Status is S_FALSE it means that the thread
// couldn't be opened and probably exited before
// we got to it. Just continue on.
if (Status == S_OK) {
InsertTailList (&Process->ThreadList, &Thread->ThreadsLink);
Process->NumberOfThreads++;
}
ThreadInfo++;
}
//
// Get the module information. Use PSAPI since it actually works.
//
ModulesSize = 0;
Succ = Nt4EnumProcessModules (
Process->ProcessHandle,
Modules,
sizeof (Modules),
&ModulesSize
);
if ( !Succ ) {
GenAccumulateStatus(MDSTATUS_CALL_FAILED);
goto Exit;
}
NumberOfModules = ModulesSize / sizeof (HMODULE);
for (i = 0; i < NumberOfModules; i++) {
ULONG WriteFlags;
if (!GenExecuteIncludeModuleCallback(hProcess,
ProcessId,
DumpType,
(LONG_PTR)Modules[i],
CallbackRoutine,
CallbackParam,
&WriteFlags) ||
IsFlagClear(WriteFlags, ModuleWriteModule)) {
continue;
}
Module = NtxAllocateModuleObject (
Process,
Process->ProcessHandle,
(LONG_PTR) Modules [ i ],
DumpType,
WriteFlags,
NULL
);
if ( Module == NULL ) {
Succ = FALSE;
goto Exit;
}
InsertTailList (&Process->ModuleList, &Module->ModulesLink);
}
Process->NumberOfModules = NumberOfModules;
Succ = TRUE;
Exit:
if ( Buffer ) {
FreeMemory ( Buffer );
Buffer = NULL;
}
if ( !Succ && Process != NULL ) {
GenFreeProcessObject ( Process );
Process = NULL;
}
*ProcessRet = Process;
return Succ;
}
//
// From PSAPI
//
BOOL
Nt4FindModule(
IN HANDLE hProcess,
IN HMODULE hModule,
OUT PNT4_LDR_DATA_TABLE_ENTRY LdrEntryData
)
/*++
Routine Description:
This function retrieves the loader table entry for the specified
module. The function copies the entry into the buffer pointed to
by the LdrEntryData parameter.
Arguments:
hProcess - Supplies the target process.
hModule - Identifies the module whose loader entry is being
requested. A value of NULL references the module handle
associated with the image file that was used to create the
process.
LdrEntryData - Returns the requested table entry.
Return Value:
TRUE if a matching entry was found.
--*/
{
NT4_PROCESS_BASIC_INFORMATION BasicInfo;
NTSTATUS Status;
PNT4_PEB Peb;
PNT4_PEB_LDR_DATA Ldr;
PLIST_ENTRY LdrHead;
PLIST_ENTRY LdrNext;
Status = NtQueryInformationProcess(
hProcess,
Nt4ProcessBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
return(FALSE);
}
Peb = BasicInfo.PebBaseAddress;
if ( hModule == NULL ) {
if (!ReadProcessMemory(hProcess, &Peb->ImageBaseAddress, &hModule, sizeof(hModule), NULL)) {
return(FALSE);
}
}
//
// Ldr = Peb->Ldr
//
if (!ReadProcessMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL)) {
return (FALSE);
}
if (!Ldr) {
// Ldr might be null (for instance, if the process hasn't started yet).
SetLastError(ERROR_INVALID_HANDLE);
return (FALSE);
}
LdrHead = &Ldr->InMemoryOrderModuleList;
//
// LdrNext = Head->Flink;
//
if (!ReadProcessMemory(hProcess, &LdrHead->Flink, &LdrNext, sizeof(LdrNext), NULL)) {
return(FALSE);
}
while (LdrNext != LdrHead) {
PNT4_LDR_DATA_TABLE_ENTRY LdrEntry;
LdrEntry = CONTAINING_RECORD(
LdrNext,
NT4_LDR_DATA_TABLE_ENTRY,
InMemoryOrderLinks);
if (!ReadProcessMemory(hProcess, LdrEntry, LdrEntryData, sizeof(*LdrEntryData), NULL)) {
return(FALSE);
}
if ((HMODULE) LdrEntryData->DllBase == hModule) {
return(TRUE);
}
LdrNext = LdrEntryData->InMemoryOrderLinks.Flink;
}
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
BOOL
WINAPI
Nt4EnumProcessModules(
HANDLE hProcess,
HMODULE *lphModule,
DWORD cb,
LPDWORD lpcbNeeded
)
{
NT4_PROCESS_BASIC_INFORMATION BasicInfo;
NTSTATUS Status;
PNT4_PEB Peb;
PNT4_PEB_LDR_DATA Ldr;
PLIST_ENTRY LdrHead;
PLIST_ENTRY LdrNext;
DWORD chMax;
DWORD ch;
Status = NtQueryInformationProcess(
hProcess,
Nt4ProcessBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
return(FALSE);
}
Peb = BasicInfo.PebBaseAddress;
//
// Ldr = Peb->Ldr
//
if (!ReadProcessMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL)) {
return(FALSE);
}
LdrHead = &Ldr->InMemoryOrderModuleList;
//
// LdrNext = Head->Flink;
//
if (!ReadProcessMemory(hProcess, &LdrHead->Flink, &LdrNext, sizeof(LdrNext), NULL)) {
return(FALSE);
}
chMax = cb / sizeof(HMODULE);
ch = 0;
while (LdrNext != LdrHead) {
PNT4_LDR_DATA_TABLE_ENTRY LdrEntry;
NT4_LDR_DATA_TABLE_ENTRY LdrEntryData;
LdrEntry = CONTAINING_RECORD(
LdrNext,
NT4_LDR_DATA_TABLE_ENTRY,
InMemoryOrderLinks);
if (!ReadProcessMemory(hProcess, LdrEntry, &LdrEntryData, sizeof(LdrEntryData), NULL)) {
return(FALSE);
}
if (ch < chMax) {
try {
lphModule[ch] = (HMODULE) LdrEntryData.DllBase;
}
except (EXCEPTION_EXECUTE_HANDLER) {
return(FALSE);
}
}
ch++;
LdrNext = LdrEntryData.InMemoryOrderLinks.Flink;
}
try {
*lpcbNeeded = ch * sizeof(HMODULE);
}
except (EXCEPTION_EXECUTE_HANDLER) {
return(FALSE);
}
return(TRUE);
}
DWORD
WINAPI
Nt4GetModuleFileNameExW(
HANDLE hProcess,
HMODULE hModule,
LPWSTR lpFilename,
DWORD nSize
)
/*++
Routine Description:
This function retrieves the full pathname of the executable file
from which the specified module was loaded. The function copies the
null-terminated filename into the buffer pointed to by the
lpFilename parameter.
Routine Description:
hModule - Identifies the module whose executable file name is being
requested. A value of NULL references the module handle
associated with the image file that was used to create the
process.
lpFilename - Points to the buffer that is to receive the filename.
nSize - Specifies the maximum number of characters to copy. If the
filename is longer than the maximum number of characters
specified by the nSize parameter, it is truncated.
Return Value:
The return value specifies the actual length of the string copied to
the buffer. A return value of zero indicates an error and extended
error status is available using the GetLastError function.
Arguments:
--*/
{
NT4_LDR_DATA_TABLE_ENTRY LdrEntryData;
DWORD cb;
if (!Nt4FindModule(hProcess, hModule, &LdrEntryData)) {
return(0);
}
nSize *= sizeof(WCHAR);
cb = LdrEntryData.FullDllName.MaximumLength;
if ( nSize < cb ) {
cb = nSize;
}
if (!ReadProcessMemory(hProcess, LdrEntryData.FullDllName.Buffer, lpFilename, cb, NULL)) {
return(0);
}
if (cb == LdrEntryData.FullDllName.MaximumLength) {
cb -= sizeof(WCHAR);
}
return(cb / sizeof(WCHAR));
}