* dlfcn.cc (dlopen): Reimplement RTLD_NODELETE for Windows 2000 using

internal datastructures.  Explain the code.
	* ntdll.h (struct _LDR_DATA_TABLE_ENTRY): Define.
	(struct _PEB_LDR_DATA): Define.
	(struct _PEB): Change PVOID LoaderData to PPEB_LDR_DATA Ldr.

	* fhandler_process.cc (format_process_maps): Call NtQueryVirtualMemory
	with valid return length pointer.  Explain why.
This commit is contained in:
Corinna Vinschen 2011-08-16 20:08:34 +00:00
parent 9d3b795b47
commit 833db5481f
4 changed files with 67 additions and 9 deletions

View File

@ -1,3 +1,14 @@
2011-08-16 Corinna Vinschen <corinna@vinschen.de>
* dlfcn.cc (dlopen): Reimplement RTLD_NODELETE for Windows 2000 using
internal datastructures. Explain the code.
* ntdll.h (struct _LDR_DATA_TABLE_ENTRY): Define.
(struct _PEB_LDR_DATA): Define.
(struct _PEB): Change PVOID LoaderData to PPEB_LDR_DATA Ldr.
* fhandler_process.cc (format_process_maps): Call NtQueryVirtualMemory
with valid return length pointer. Explain why.
2011-08-16 Corinna Vinschen <corinna@vinschen.de>
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.

View File

@ -120,12 +120,27 @@ dlopen (const char *name, int flags)
(HMODULE *) &ret))
{
/* Windows 2000 is missing the GetModuleHandleEx call, so we
just use a trick. Call LoadLibrary 10 times more if the
RTLD_NODELETE flag has been specified. That makes it
unlikely (but not impossible) that dlclose will actually
free the library. */
for (int i = 0; i < 10; ++i)
LoadLibraryW (path);
use a non-documented way to set the DLL to "don't free".
This is how it works: Fetch the Windows Loader data from
the PEB. Iterate backwards through the list of loaded
DLLs and compare the DllBase address with the address
returned by LoadLibrary. If they are equal we found the
right entry. Now set the LoadCount to -1, which is the
marker for a DLL which should never be free'd. */
PPEB_LDR_DATA ldr = NtCurrentTeb ()->Peb->Ldr;
for (PLDR_DATA_TABLE_ENTRY entry = (PLDR_DATA_TABLE_ENTRY)
ldr->InLoadOrderModuleList.Blink;
entry && entry->DllBase;
entry = (PLDR_DATA_TABLE_ENTRY)
entry->InLoadOrderLinks.Blink)
{
if (entry->DllBase == ret)
{
entry->LoadCount = (WORD) -1;
break;
}
}
}
}

View File

@ -960,12 +960,16 @@ format_process_maps (void *data, char *&destbuf)
// if a new allocation, figure out what kind it is
if (newbase && !last_pass && mb.State != MEM_FREE)
{
/* If the return length pointer is missing, NtQueryVirtualMemory
returns with STATUS_ACCESS_VIOLATION on Windows 2000. */
ULONG ret_len = 0;
st.st_dev = 0;
st.st_ino = 0;
if ((mb.Type & (MEM_MAPPED | MEM_IMAGE))
&& NT_SUCCESS (NtQueryVirtualMemory (proc, cur.abase,
&& NT_SUCCESS (status = NtQueryVirtualMemory (proc, cur.abase,
MemorySectionName,
msi, 65536, NULL)))
msi, 65536, &ret_len)))
{
PWCHAR dosname =
drive_maps.fixup_if_match (msi->SectionFileName.Buffer);

View File

@ -579,6 +579,34 @@ typedef struct _KERNEL_USER_TIMES
LARGE_INTEGER UserTime;
} KERNEL_USER_TIMES, *PKERNEL_USER_TIMES;
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
WORD LoadCount;
/* More follows. Left out since it's just not used. The aforementioned
part of the structure is stable from at least NT4 up to Windows 7,
including WOW64. */
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB_LDR_DATA
{
ULONG Length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _RTL_USER_PROCESS_PARAMETERS
{
ULONG AllocationSize;
@ -616,7 +644,7 @@ typedef struct _PEB
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[9];
PVOID LoaderData;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved3[4];
PVOID ProcessHeap;