diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec index c688d8e4fa..a556b9a298 100644 --- a/dlls/kernel/kernel32.spec +++ b/dlls/kernel/kernel32.spec @@ -940,7 +940,7 @@ init MAIN_KernelInit @ stdcall SwitchToThread() SwitchToThread @ forward TryEnterCriticalSection ntdll.RtlTryEnterCriticalSection @ stdcall VirtualAllocEx(long ptr long long long) VirtualAllocEx -@ stub VirtualFreeEx +@ stdcall VirtualFreeEx(long ptr long long) VirtualFreeEx @ stub WriteFileGather #Win98 and higher diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index e32a2161c5..b52124e014 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -111,6 +111,7 @@ C_SRCS = \ signal_powerpc.c \ signal_sparc.c \ sync.c \ + virtual.c \ time.c \ wcstring.c diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 321bbe8d16..7367503385 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -293,17 +293,16 @@ static inline BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr ) size = (size + COMMIT_MASK) & ~COMMIT_MASK; if (size > subheap->size) size = subheap->size; if (size <= subheap->commitSize) return TRUE; - if (!VirtualAlloc( (char *)subheap + subheap->commitSize, - size - subheap->commitSize, MEM_COMMIT, - PAGE_EXECUTE_READWRITE)) + size -= subheap->commitSize; + if (NtAllocateVirtualMemory( GetCurrentProcess(), &ptr, (char *)subheap + subheap->commitSize, + &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) { WARN("Could not commit %08lx bytes at %08lx for heap %08lx\n", - size - subheap->commitSize, - (DWORD)((char *)subheap + subheap->commitSize), + size, (DWORD)((char *)subheap + subheap->commitSize), (DWORD)subheap->heap ); return FALSE; } - subheap->commitSize = size; + subheap->commitSize += size; return TRUE; } @@ -315,20 +314,23 @@ static inline BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr ) */ static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr ) { + void *addr; + ULONG decommit_size; + DWORD size = (DWORD)((char *)ptr - (char *)subheap); /* round to next block and add one full block */ size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1; if (size >= subheap->commitSize) return TRUE; - if (!VirtualFree( (char *)subheap + size, - subheap->commitSize - size, MEM_DECOMMIT )) + decommit_size = subheap->commitSize - size; + addr = (char *)subheap + size; + + if (NtFreeVirtualMemory( GetCurrentProcess(), &addr, &decommit_size, MEM_DECOMMIT )) { - WARN("Could not decommit %08lx bytes at %08lx for heap %08lx\n", - subheap->commitSize - size, - (DWORD)((char *)subheap + size), - (DWORD)subheap->heap ); + WARN("Could not decommit %08lx bytes at %08lx for heap %p\n", + decommit_size, (DWORD)((char *)subheap + size), subheap->heap ); return FALSE; } - subheap->commitSize = size; + subheap->commitSize -= decommit_size; return TRUE; } @@ -472,7 +474,7 @@ static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size) static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags, DWORD commitSize, DWORD totalSize ) { - SUBHEAP *subheap = (SUBHEAP *)address; + SUBHEAP *subheap; FREE_LIST_ENTRY *pEntry; int i; @@ -480,15 +482,16 @@ static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags, if (flags & HEAP_SHARED) commitSize = totalSize; /* always commit everything in a shared heap */ - if (!VirtualAlloc(address, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) + if (NtAllocateVirtualMemory( GetCurrentProcess(), &address, address, + &commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) { - WARN("Could not commit %08lx bytes for sub-heap %08lx\n", - commitSize, (DWORD)address ); + WARN("Could not commit %08lx bytes for sub-heap %p\n", commitSize, address ); return FALSE; } /* Fill the sub-heap structure */ + subheap = (SUBHEAP *)address; subheap->heap = heap; subheap->size = totalSize; subheap->commitSize = commitSize; @@ -560,10 +563,10 @@ static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, void *base, DWORD flags, if (!address) { /* allocate the memory block */ - if (!(address = VirtualAlloc( NULL, totalSize, MEM_RESERVE, PAGE_EXECUTE_READWRITE ))) + if (NtAllocateVirtualMemory( GetCurrentProcess(), &address, NULL, &totalSize, + MEM_RESERVE, PAGE_EXECUTE_READWRITE )) { - WARN("Could not VirtualAlloc %08lx bytes\n", - totalSize ); + WARN("Could not allocate %08lx bytes\n", totalSize ); return NULL; } } @@ -573,7 +576,8 @@ static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, void *base, DWORD flags, if (!HEAP_InitSubHeap( heap ? heap : (HEAP *)address, address, flags, commitSize, totalSize )) { - if (!base) VirtualFree( address, 0, MEM_RELEASE ); + ULONG size = 0; + if (!base) NtFreeVirtualMemory( GetCurrentProcess(), &address, &size, MEM_RELEASE ); return NULL; } @@ -988,7 +992,9 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE heap ) while (subheap) { SUBHEAP *next = subheap->next; - VirtualFree( subheap, 0, MEM_RELEASE ); + ULONG size = 0; + void *addr = subheap; + NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE ); subheap = next; } return 0; diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c index aec0229e51..f000929183 100644 --- a/dlls/ntdll/nt.c +++ b/dlls/ntdll/nt.c @@ -417,41 +417,6 @@ NTSTATUS WINAPI NtQueryInformationToken( * Section */ -/****************************************************************************** - * NtCreateSection [NTDLL.@] - * ZwCreateSection [NTDLL.@] - */ -NTSTATUS WINAPI NtCreateSection( - OUT PHANDLE SectionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN PLARGE_INTEGER MaximumSize OPTIONAL, - IN ULONG SectionPageProtection OPTIONAL, - IN ULONG AllocationAttributes, - IN HANDLE FileHandle OPTIONAL) -{ - FIXME("(%p,0x%08lx,%p,%p,0x%08lx,0x%08lx,0x%08x) stub\n", - SectionHandle,DesiredAccess, ObjectAttributes, - MaximumSize,SectionPageProtection,AllocationAttributes,FileHandle); - dump_ObjectAttributes(ObjectAttributes); - return 0; -} - -/****************************************************************************** - * NtOpenSection [NTDLL.@] - * ZwOpenSection [NTDLL.@] - */ -NTSTATUS WINAPI NtOpenSection( - PHANDLE SectionHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes) -{ - FIXME("(%p,0x%08lx,%p),stub!\n", - SectionHandle,DesiredAccess,ObjectAttributes); - dump_ObjectAttributes(ObjectAttributes); - return 0; -} - /****************************************************************************** * NtQuerySection [NTDLL.@] */ @@ -467,44 +432,6 @@ NTSTATUS WINAPI NtQuerySection( return 0; } -/****************************************************************************** - * NtMapViewOfSection [NTDLL.@] - * ZwMapViewOfSection [NTDLL.@] - * FUNCTION: Maps a view of a section into the virtual address space of a process - * - * ARGUMENTS: - * SectionHandle Handle of the section - * ProcessHandle Handle of the process - * BaseAddress Desired base address (or NULL) on entry - * Actual base address of the view on exit - * ZeroBits Number of high order address bits that must be zero - * CommitSize Size in bytes of the initially committed section of the view - * SectionOffset Offset in bytes from the beginning of the section to the beginning of the view - * ViewSize Desired length of map (or zero to map all) on entry - Actual length mapped on exit - * InheritDisposition Specified how the view is to be shared with - * child processes - * AllocateType Type of allocation for the pages - * Protect Protection for the committed region of the view - */ -NTSTATUS WINAPI NtMapViewOfSection( - HANDLE SectionHandle, - HANDLE ProcessHandle, - PVOID* BaseAddress, - ULONG ZeroBits, - ULONG CommitSize, - PLARGE_INTEGER SectionOffset, - PULONG ViewSize, - SECTION_INHERIT InheritDisposition, - ULONG AllocationType, - ULONG Protect) -{ - FIXME("(0x%08x,0x%08x,%p,0x%08lx,0x%08lx,%p,%p,0x%08x,0x%08lx,0x%08lx) stub\n", - SectionHandle,ProcessHandle,BaseAddress,ZeroBits,CommitSize,SectionOffset, - ViewSize,InheritDisposition,AllocationType,Protect); - return 0; -} - /* * ports */ diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index fdc0ffa131..75df84cb07 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -63,7 +63,7 @@ @ stub NtAlertThread @ stdcall NtAllocateLocallyUniqueId(ptr) NtAllocateLocallyUniqueId @ stdcall NtAllocateUuids(ptr ptr ptr) NtAllocateUuids -@ stub NtAllocateVirtualMemory +@ stdcall NtAllocateVirtualMemory(long ptr ptr ptr long long) NtAllocateVirtualMemory @ stub NtCallbackReturn @ stub NtCancelIoFile @ stub NtCancelTimer @@ -86,7 +86,7 @@ @ stdcall NtCreatePort(long long long long long) NtCreatePort @ stub NtCreateProcess @ stub NtCreateProfile -@ stdcall NtCreateSection(long long long long long long long) NtCreateSection +@ stdcall NtCreateSection(ptr long ptr ptr long long long) NtCreateSection @ stdcall NtCreateSemaphore(ptr long ptr long long) NtCreateSemaphore @ stdcall NtCreateSymbolicLinkObject(ptr long ptr ptr) NtCreateSymbolicLinkObject @ stub NtCreateThread @@ -108,9 +108,9 @@ @ stub NtFlushBuffersFile @ stub NtFlushInstructionCache @ stdcall NtFlushKey(long) NtFlushKey -@ stub NtFlushVirtualMemory +@ stdcall NtFlushVirtualMemory(long ptr ptr long) NtFlushVirtualMemory @ stub NtFlushWriteBuffer -@ stub NtFreeVirtualMemory +@ stdcall NtFreeVirtualMemory(long ptr ptr long) NtFreeVirtualMemory @ stdcall NtFsControlFile(long long long long long long long long long long) NtFsControlFile @ stub NtGetContextThread @ stub NtGetPlugPlayEvent @@ -122,9 +122,9 @@ @ stub NtLoadDriver @ stdcall NtLoadKey(ptr ptr) NtLoadKey @ stub NtLockFile -@ stub NtLockVirtualMemory +@ stdcall NtLockVirtualMemory(long ptr ptr long) NtLockVirtualMemory @ stub NtMakeTemporaryObject -@ stdcall NtMapViewOfSection(long long long long long long long long long long) NtMapViewOfSection +@ stdcall NtMapViewOfSection(long long ptr long long ptr ptr long long long) NtMapViewOfSection @ stub NtNotifyChangeDirectoryFile @ stdcall NtNotifyChangeKey(long long ptr ptr ptr long long ptr long long) NtNotifyChangeKey @ stdcall NtOpenDirectoryObject(long long long) NtOpenDirectoryObject @@ -137,7 +137,7 @@ @ stub NtOpenObjectAuditAlarm @ stub NtOpenProcess @ stdcall NtOpenProcessToken(long long long) NtOpenProcessToken -@ stdcall NtOpenSection(long long long) NtOpenSection +@ stdcall NtOpenSection(ptr long ptr) NtOpenSection @ stdcall NtOpenSemaphore(long long ptr) NtOpenSemaphore @ stdcall NtOpenSymbolicLinkObject (long long long) NtOpenSymbolicLinkObject @ stub NtOpenThread @@ -147,7 +147,7 @@ @ stub NtPrivilegeCheck @ stub NtPrivilegeObjectAuditAlarm @ stub NtPrivilegedServiceAuditAlarm -@ stub NtProtectVirtualMemory +@ stdcall NtProtectVirtualMemory(long ptr ptr long ptr) NtProtectVirtualMemory @ stdcall NtPulseEvent(long ptr) NtPulseEvent @ stub NtQueryAttributesFile @ stub NtQueryDefaultLocale @@ -176,7 +176,7 @@ @ stub NtQueryTimer @ stdcall NtQueryTimerResolution(long long long) NtQueryTimerResolution @ stdcall NtQueryValueKey(long long long long long long) NtQueryValueKey -@ stub NtQueryVirtualMemory +@ stdcall NtQueryVirtualMemory(long ptr long ptr long ptr) NtQueryVirtualMemory @ stdcall NtQueryVolumeInformationFile(long ptr ptr long long) NtQueryVolumeInformationFile @ stdcall NtRaiseException(ptr ptr long) NtRaiseException @ stub NtRaiseHardError @@ -241,8 +241,8 @@ @ stub NtUnloadDriver @ stdcall NtUnloadKey(long) NtUnloadKey @ stub NtUnlockFile -@ stub NtUnlockVirtualMemory -@ stub NtUnmapViewOfSection +@ stdcall NtUnlockVirtualMemory(long ptr ptr long) NtUnlockVirtualMemory +@ stdcall NtUnmapViewOfSection(long ptr) NtUnmapViewOfSection @ stub NtVdmControl @ stub NtW32Call @ stub NtWaitForMultipleObjects @@ -581,7 +581,7 @@ @ stub ZwAlertThread @ stub ZwAllocateLocallyUniqueId @ stub ZwAllocateUuids -@ stub ZwAllocateVirtualMemory +@ stdcall ZwAllocateVirtualMemory(long ptr ptr ptr long long) NtAllocateVirtualMemory @ stub ZwCallbackReturn @ stub ZwCancelIoFile @ stub ZwCancelTimer @@ -604,7 +604,7 @@ @ stdcall ZwCreatePort(long long long long long) NtCreatePort @ stub ZwCreateProcess @ stub ZwCreateProfile -@ stdcall ZwCreateSection(long long long long long long long) NtCreateSection +@ stdcall ZwCreateSection(ptr long ptr ptr long long long) NtCreateSection @ stub ZwCreateSemaphore @ stub ZwCreateSymbolicLinkObject @ stub ZwCreateThread @@ -625,9 +625,9 @@ @ stub ZwFlushBuffersFile @ stub ZwFlushInstructionCache @ stdcall ZwFlushKey(long) NtFlushKey -@ stub ZwFlushVirtualMemory +@ stdcall ZwFlushVirtualMemory(long ptr ptr long) NtFlushVirtualMemory @ stub ZwFlushWriteBuffer -@ stub ZwFreeVirtualMemory +@ stdcall ZwFreeVirtualMemory(long ptr ptr long) NtFreeVirtualMemory @ stdcall ZwFsControlFile(long long long long long long long long long long) NtFsControlFile @ stub ZwGetContextThread @ stub ZwGetPlugPlayEvent @@ -639,9 +639,9 @@ @ stub ZwLoadDriver @ stdcall ZwLoadKey(ptr ptr) NtLoadKey @ stub ZwLockFile -@ stub ZwLockVirtualMemory +@ stdcall ZwLockVirtualMemory(long ptr ptr long) NtLockVirtualMemory @ stub ZwMakeTemporaryObject -@ stdcall ZwMapViewOfSection(long long long long long long long long long long) NtMapViewOfSection +@ stdcall ZwMapViewOfSection(long long ptr long long ptr ptr long long long) NtMapViewOfSection @ stub ZwNotifyChangeDirectoryFile @ stdcall ZwNotifyChangeKey(long long ptr ptr ptr long long ptr long long) NtNotifyChangeKey @ stdcall ZwOpenDirectoryObject(long long long) NtOpenDirectoryObject @@ -654,7 +654,7 @@ @ stub ZwOpenObjectAuditAlarm @ stub ZwOpenProcess @ stdcall ZwOpenProcessToken(long long long) NtOpenProcessToken -@ stdcall ZwOpenSection(long long long) NtOpenSection +@ stdcall ZwOpenSection(ptr long ptr) NtOpenSection @ stub ZwOpenSemaphore @ stub ZwOpenSymbolicLinkObject @ stub ZwOpenThread @@ -664,7 +664,7 @@ @ stub ZwPrivilegeCheck @ stub ZwPrivilegeObjectAuditAlarm @ stub ZwPrivilegedServiceAuditAlarm -@ stub ZwProtectVirtualMemory +@ stdcall ZwProtectVirtualMemory(long ptr ptr long ptr) NtProtectVirtualMemory @ stub ZwPulseEvent @ stub ZwQueryAttributesFile @ stub ZwQueryDefaultLocale @@ -693,7 +693,7 @@ @ stub ZwQueryTimer @ stub ZwQueryTimerResolution @ stdcall ZwQueryValueKey(long ptr long ptr long ptr) NtQueryValueKey -@ stub ZwQueryVirtualMemory +@ stdcall ZwQueryVirtualMemory(long ptr long ptr long ptr) NtQueryVirtualMemory @ stdcall ZwQueryVolumeInformationFile(long ptr ptr long long) NtQueryVolumeInformationFile @ stub ZwRaiseException @ stub ZwRaiseHardError @@ -756,8 +756,8 @@ @ stub ZwUnloadDriver @ stdcall ZwUnloadKey(long) NtUnloadKey @ stub ZwUnlockFile -@ stub ZwUnlockVirtualMemory -@ stub ZwUnmapViewOfSection +@ stdcall ZwUnlockVirtualMemory(long ptr ptr long) NtUnlockVirtualMemory +@ stdcall ZwUnmapViewOfSection(long ptr) NtUnmapViewOfSection @ stub ZwVdmControl @ stub ZwW32Call @ stub ZwWaitForMultipleObjects diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c new file mode 100644 index 0000000000..15fd39638a --- /dev/null +++ b/dlls/ntdll/virtual.c @@ -0,0 +1,1535 @@ +/* + * Win32 virtual memory functions + * + * Copyright 1997, 2002 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#ifdef HAVE_SYS_ERRNO_H +#include +#endif +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#include "winternl.h" +#include "global.h" +#include "wine/library.h" +#include "wine/server.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(virtual); +WINE_DECLARE_DEBUG_CHANNEL(module); + +#ifndef MS_SYNC +#define MS_SYNC 0 +#endif + +/* File view */ +typedef struct _FV +{ + struct _FV *next; /* Next view */ + struct _FV *prev; /* Prev view */ + void *base; /* Base address */ + UINT size; /* Size in bytes */ + UINT flags; /* Allocation flags */ + HANDLE mapping; /* Handle to the file mapping */ + HANDLERPROC handlerProc; /* Fault handler */ + LPVOID handlerArg; /* Fault handler argument */ + BYTE protect; /* Protection for all pages at allocation time */ + BYTE prot[1]; /* Protection byte for each page */ +} FILE_VIEW; + +/* Per-view flags */ +#define VFLAG_SYSTEM 0x01 +#define VFLAG_VALLOC 0x02 /* allocated by VirtualAlloc */ + +/* Conversion from VPROT_* to Win32 flags */ +static const BYTE VIRTUAL_Win32Flags[16] = +{ + PAGE_NOACCESS, /* 0 */ + PAGE_READONLY, /* READ */ + PAGE_READWRITE, /* WRITE */ + PAGE_READWRITE, /* READ | WRITE */ + PAGE_EXECUTE, /* EXEC */ + PAGE_EXECUTE_READ, /* READ | EXEC */ + PAGE_EXECUTE_READWRITE, /* WRITE | EXEC */ + PAGE_EXECUTE_READWRITE, /* READ | WRITE | EXEC */ + PAGE_WRITECOPY, /* WRITECOPY */ + PAGE_WRITECOPY, /* READ | WRITECOPY */ + PAGE_WRITECOPY, /* WRITE | WRITECOPY */ + PAGE_WRITECOPY, /* READ | WRITE | WRITECOPY */ + PAGE_EXECUTE_WRITECOPY, /* EXEC | WRITECOPY */ + PAGE_EXECUTE_WRITECOPY, /* READ | EXEC | WRITECOPY */ + PAGE_EXECUTE_WRITECOPY, /* WRITE | EXEC | WRITECOPY */ + PAGE_EXECUTE_WRITECOPY /* READ | WRITE | EXEC | WRITECOPY */ +}; + + +static FILE_VIEW *VIRTUAL_FirstView; +static CRITICAL_SECTION csVirtual = CRITICAL_SECTION_INIT("csVirtual"); + +#ifdef __i386__ +/* These are always the same on an i386, and it will be faster this way */ +# define page_mask 0xfff +# define page_shift 12 +# define page_size 0x1000 +#else +static UINT page_shift; +static UINT page_mask; +static UINT page_size; +#endif /* __i386__ */ +#define granularity_mask 0xffff /* Allocation granularity (usually 64k) */ + +#define ADDRESS_SPACE_LIMIT ((void *)0xc0000000) /* top of the user address space */ + +#define ROUND_ADDR(addr,mask) \ + ((void *)((UINT_PTR)(addr) & ~(mask))) + +#define ROUND_SIZE(addr,size) \ + (((UINT)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask) + +#define VIRTUAL_DEBUG_DUMP_VIEW(view) \ + if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view) + +static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset_low, + DWORD offset_high, int prot, int flags, BOOL *removable ); + + +/*********************************************************************** + * VIRTUAL_GetProtStr + */ +static const char *VIRTUAL_GetProtStr( BYTE prot ) +{ + static char buffer[6]; + buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-'; + buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-'; + buffer[2] = (prot & VPROT_READ) ? 'r' : '-'; + buffer[3] = (prot & VPROT_WRITE) ? + ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-'; + buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-'; + buffer[5] = 0; + return buffer; +} + + +/*********************************************************************** + * VIRTUAL_DumpView + */ +static void VIRTUAL_DumpView( FILE_VIEW *view ) +{ + UINT i, count; + char *addr = view->base; + BYTE prot = view->prot[0]; + + DPRINTF( "View: %p - %p", addr, addr + view->size - 1 ); + if (view->flags & VFLAG_SYSTEM) + DPRINTF( " (system)\n" ); + else if (view->flags & VFLAG_VALLOC) + DPRINTF( " (valloc)\n" ); + else if (view->mapping) + DPRINTF( " %d\n", view->mapping ); + else + DPRINTF( " (anonymous)\n"); + + for (count = i = 1; i < view->size >> page_shift; i++, count++) + { + if (view->prot[i] == prot) continue; + DPRINTF( " %p - %p %s\n", + addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) ); + addr += (count << page_shift); + prot = view->prot[i]; + count = 0; + } + if (count) + DPRINTF( " %p - %p %s\n", + addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) ); +} + + +/*********************************************************************** + * VIRTUAL_Dump + */ +void VIRTUAL_Dump(void) +{ + FILE_VIEW *view; + DPRINTF( "\nDump of all virtual memory views:\n\n" ); + RtlEnterCriticalSection(&csVirtual); + view = VIRTUAL_FirstView; + while (view) + { + VIRTUAL_DumpView( view ); + view = view->next; + } + RtlLeaveCriticalSection(&csVirtual); +} + + +/*********************************************************************** + * VIRTUAL_FindView + * + * Find the view containing a given address. + * + * RETURNS + * View: Success + * NULL: Failure + */ +static FILE_VIEW *VIRTUAL_FindView( const void *addr ) /* [in] Address */ +{ + FILE_VIEW *view; + + RtlEnterCriticalSection(&csVirtual); + view = VIRTUAL_FirstView; + while (view) + { + if (view->base > addr) + { + view = NULL; + break; + } + if ((char*)view->base + view->size > (char*)addr) break; + view = view->next; + } + RtlLeaveCriticalSection(&csVirtual); + return view; +} + + +/*********************************************************************** + * VIRTUAL_CreateView + * + * Create a new view and add it in the linked list. + */ +static FILE_VIEW *VIRTUAL_CreateView( void *base, UINT size, UINT flags, + BYTE vprot, HANDLE mapping ) +{ + FILE_VIEW *view, *prev; + + /* Create the view structure */ + + assert( !((unsigned int)base & page_mask) ); + assert( !(size & page_mask) ); + size >>= page_shift; + if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL; + view->base = base; + view->size = size << page_shift; + view->flags = flags; + view->mapping = mapping; + view->protect = vprot; + view->handlerProc = NULL; + memset( view->prot, vprot, size ); + + /* Duplicate the mapping handle */ + + if (view->mapping && + NtDuplicateObject( GetCurrentProcess(), view->mapping, + GetCurrentProcess(), &view->mapping, + 0, 0, DUPLICATE_SAME_ACCESS )) + { + free( view ); + return NULL; + } + + /* Insert it in the linked list */ + + RtlEnterCriticalSection(&csVirtual); + if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base)) + { + view->next = VIRTUAL_FirstView; + view->prev = NULL; + if (view->next) view->next->prev = view; + VIRTUAL_FirstView = view; + } + else + { + prev = VIRTUAL_FirstView; + while (prev->next && (prev->next->base < base)) prev = prev->next; + view->next = prev->next; + view->prev = prev; + if (view->next) view->next->prev = view; + prev->next = view; + } + RtlLeaveCriticalSection(&csVirtual); + VIRTUAL_DEBUG_DUMP_VIEW( view ); + return view; +} + + +/*********************************************************************** + * VIRTUAL_DeleteView + * Deletes a view. + * + * RETURNS + * None + */ +static void VIRTUAL_DeleteView( FILE_VIEW *view ) /* [in] View */ +{ + if (!(view->flags & VFLAG_SYSTEM)) + munmap( (void *)view->base, view->size ); + RtlEnterCriticalSection(&csVirtual); + if (view->next) view->next->prev = view->prev; + if (view->prev) view->prev->next = view->next; + else VIRTUAL_FirstView = view->next; + RtlLeaveCriticalSection(&csVirtual); + if (view->mapping) NtClose( view->mapping ); + free( view ); +} + + +/*********************************************************************** + * VIRTUAL_GetUnixProt + * + * Convert page protections to protection for mmap/mprotect. + */ +static int VIRTUAL_GetUnixProt( BYTE vprot ) +{ + int prot = 0; + if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD)) + { + if (vprot & VPROT_READ) prot |= PROT_READ; + if (vprot & VPROT_WRITE) prot |= PROT_WRITE; + if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE; + if (vprot & VPROT_EXEC) prot |= PROT_EXEC; + } + return prot; +} + + +/*********************************************************************** + * VIRTUAL_GetWin32Prot + * + * Convert page protections to Win32 flags. + * + * RETURNS + * None + */ +static void VIRTUAL_GetWin32Prot( + BYTE vprot, /* [in] Page protection flags */ + DWORD *protect, /* [out] Location to store Win32 protection flags */ + DWORD *state ) /* [out] Location to store mem state flag */ +{ + if (protect) { + *protect = VIRTUAL_Win32Flags[vprot & 0x0f]; +/* if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/ + if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE; + + if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS; + } + + if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE; +} + + +/*********************************************************************** + * VIRTUAL_GetProt + * + * Build page protections from Win32 flags. + * + * RETURNS + * Value of page protection flags + */ +static BYTE VIRTUAL_GetProt( DWORD protect ) /* [in] Win32 protection flags */ +{ + BYTE vprot; + + switch(protect & 0xff) + { + case PAGE_READONLY: + vprot = VPROT_READ; + break; + case PAGE_READWRITE: + vprot = VPROT_READ | VPROT_WRITE; + break; + case PAGE_WRITECOPY: + /* MSDN CreateFileMapping() states that if PAGE_WRITECOPY is given, + * that the hFile must have been opened with GENERIC_READ and + * GENERIC_WRITE access. This is WRONG as tests show that you + * only need GENERIC_READ access (at least for Win9x, + * FIXME: what about NT?). Thus, we don't put VPROT_WRITE in + * PAGE_WRITECOPY and PAGE_EXECUTE_WRITECOPY. + */ + vprot = VPROT_READ | VPROT_WRITECOPY; + break; + case PAGE_EXECUTE: + vprot = VPROT_EXEC; + break; + case PAGE_EXECUTE_READ: + vprot = VPROT_EXEC | VPROT_READ; + break; + case PAGE_EXECUTE_READWRITE: + vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE; + break; + case PAGE_EXECUTE_WRITECOPY: + /* See comment for PAGE_WRITECOPY above */ + vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY; + break; + case PAGE_NOACCESS: + default: + vprot = 0; + break; + } + if (protect & PAGE_GUARD) vprot |= VPROT_GUARD; + if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE; + return vprot; +} + + +/*********************************************************************** + * VIRTUAL_SetProt + * + * Change the protection of a range of pages. + * + * RETURNS + * TRUE: Success + * FALSE: Failure + */ +static BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */ + void *base, /* [in] Starting address */ + UINT size, /* [in] Size in bytes */ + BYTE vprot ) /* [in] Protections to use */ +{ + TRACE("%p-%p %s\n", + base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) ); + + if (mprotect( base, size, VIRTUAL_GetUnixProt(vprot) )) + return FALSE; /* FIXME: last error */ + + memset( view->prot + (((char *)base - (char *)view->base) >> page_shift), + vprot, size >> page_shift ); + VIRTUAL_DEBUG_DUMP_VIEW( view ); + return TRUE; +} + + +/*********************************************************************** + * anon_mmap_aligned + * + * Create an anonymous mapping aligned to the allocation granularity. + */ +static NTSTATUS anon_mmap_aligned( void **addr, unsigned int size, int prot, int flags ) +{ + void *ptr, *base = *addr; + unsigned int view_size = size + (base ? 0 : granularity_mask + 1); + + if ((ptr = wine_anon_mmap( base, view_size, prot, flags )) == (void *)-1) + { + if (errno == ENOMEM) return STATUS_NO_MEMORY; + return STATUS_INVALID_PARAMETER; + } + + if (!base) + { + /* Release the extra memory while keeping the range + * starting on the granularity boundary. */ + if ((unsigned int)ptr & granularity_mask) + { + unsigned int extra = granularity_mask + 1 - ((unsigned int)ptr & granularity_mask); + munmap( ptr, extra ); + ptr = (char *)ptr + extra; + view_size -= extra; + } + if (view_size > size) + munmap( (char *)ptr + size, view_size - size ); + } + else if (ptr != base) + { + /* We couldn't get the address we wanted */ + munmap( ptr, view_size ); + return STATUS_CONFLICTING_ADDRESSES; + } + *addr = ptr; + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * do_relocations + * + * Apply the relocations to a mapped PE image + */ +static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir, + int delta, DWORD total_size ) +{ + IMAGE_BASE_RELOCATION *rel; + + TRACE_(module)( "relocating from %p-%p to %p-%p\n", + base - delta, base - delta + total_size, base, base + total_size ); + + for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress); + ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock; + rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) ) + { + char *page = base + rel->VirtualAddress; + WORD *TypeOffset = (WORD *)(rel + 1); + int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset); + + if (!count) continue; + + /* sanity checks */ + if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size || + page > base + total_size) + { + ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n", + rel, rel->VirtualAddress, rel->SizeOfBlock, + base, dir->VirtualAddress, dir->Size ); + return 0; + } + + TRACE_(module)("%ld relocations for page %lx\n", rel->SizeOfBlock, rel->VirtualAddress); + + /* patching in reverse order */ + for (i = 0 ; i < count; i++) + { + int offset = TypeOffset[i] & 0xFFF; + int type = TypeOffset[i] >> 12; + switch(type) + { + case IMAGE_REL_BASED_ABSOLUTE: + break; + case IMAGE_REL_BASED_HIGH: + *(short*)(page+offset) += HIWORD(delta); + break; + case IMAGE_REL_BASED_LOW: + *(short*)(page+offset) += LOWORD(delta); + break; + case IMAGE_REL_BASED_HIGHLOW: + *(int*)(page+offset) += delta; + /* FIXME: if this is an exported address, fire up enhanced logic */ + break; + default: + FIXME_(module)("Unknown/unsupported fixup type %d.\n", type); + break; + } + } + } + return 1; +} + + +/*********************************************************************** + * map_image + * + * Map an executable (PE format) image into memory. + */ +static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, DWORD total_size, + DWORD header_size, int shared_fd, DWORD shared_size, + BOOL removable, PVOID *addr_ptr ) +{ + IMAGE_DOS_HEADER *dos; + IMAGE_NT_HEADERS *nt; + IMAGE_SECTION_HEADER *sec; + IMAGE_DATA_DIRECTORY *imports; + NTSTATUS status = STATUS_INVALID_IMAGE_FORMAT; /* generic error (FIXME) */ + int i, pos; + FILE_VIEW *view; + char *ptr; + + /* zero-map the whole range */ + + if (base < (char *)0x110000 || /* make sure the DOS area remains free */ + (ptr = wine_anon_mmap( base, total_size, + PROT_READ | PROT_WRITE | PROT_EXEC, 0 )) == (char *)-1) + { + ptr = wine_anon_mmap( NULL, total_size, + PROT_READ | PROT_WRITE | PROT_EXEC, 0 ); + if (ptr == (char *)-1) + { + ERR_(module)("Not enough memory for module (%ld bytes)\n", total_size); + goto error; + } + } + TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size ); + + /* map the header */ + + if (VIRTUAL_mmap( fd, ptr, header_size, 0, 0, PROT_READ, + MAP_PRIVATE | MAP_FIXED, &removable ) == (char *)-1) goto error; + dos = (IMAGE_DOS_HEADER *)ptr; + nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew); + if ((char *)(nt + 1) > ptr + header_size) goto error; + + sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); + if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error; + + imports = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT; + if (!imports->Size || !imports->VirtualAddress) imports = NULL; + + /* check the architecture */ + + if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) + { + MESSAGE("Trying to load PE image for unsupported architecture ("); + switch (nt->FileHeader.Machine) + { + case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break; + case IMAGE_FILE_MACHINE_I860: MESSAGE("I860"); break; + case IMAGE_FILE_MACHINE_R3000: MESSAGE("R3000"); break; + case IMAGE_FILE_MACHINE_R4000: MESSAGE("R4000"); break; + case IMAGE_FILE_MACHINE_R10000: MESSAGE("R10000"); break; + case IMAGE_FILE_MACHINE_ALPHA: MESSAGE("Alpha"); break; + case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break; + default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break; + } + MESSAGE(")\n"); + goto error; + } + + /* map all the sections */ + + for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) + { + DWORD size; + + /* a few sanity checks */ + size = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize ); + if (sec->VirtualAddress > total_size || size > total_size || size < sec->VirtualAddress) + { + ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n", + sec->Name, sec->VirtualAddress, sec->Misc.VirtualSize, total_size ); + goto error; + } + + if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) && + (sec->Characteristics & IMAGE_SCN_MEM_WRITE)) + { + size = ROUND_SIZE( 0, sec->Misc.VirtualSize ); + TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n", + sec->Name, ptr + sec->VirtualAddress, + sec->PointerToRawData, pos, sec->SizeOfRawData, + size, sec->Characteristics ); + if (VIRTUAL_mmap( shared_fd, ptr + sec->VirtualAddress, size, + pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_SHARED|MAP_FIXED, NULL ) == (void *)-1) + { + ERR_(module)( "Could not map shared section %.8s\n", sec->Name ); + goto error; + } + + /* check if the import directory falls inside this section */ + if (imports && imports->VirtualAddress >= sec->VirtualAddress && + imports->VirtualAddress < sec->VirtualAddress + size) + { + UINT_PTR base = imports->VirtualAddress & ~page_mask; + UINT_PTR end = base + ROUND_SIZE( imports->VirtualAddress, imports->Size ); + if (end > sec->VirtualAddress + size) end = sec->VirtualAddress + size; + if (end > base) VIRTUAL_mmap( shared_fd, ptr + base, end - base, + pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE|MAP_FIXED, NULL ); + } + pos += size; + continue; + } + + TRACE_(module)( "mapping section %.8s at %p off %lx size %lx flags %lx\n", + sec->Name, ptr + sec->VirtualAddress, + sec->PointerToRawData, sec->SizeOfRawData, + sec->Characteristics ); + + if (sec->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue; + if (!sec->PointerToRawData || !sec->SizeOfRawData) continue; + + /* Note: if the section is not aligned properly VIRTUAL_mmap will magically + * fall back to read(), so we don't need to check anything here. + */ + if (VIRTUAL_mmap( fd, ptr + sec->VirtualAddress, sec->SizeOfRawData, + sec->PointerToRawData, 0, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE | MAP_FIXED, &removable ) == (void *)-1) + { + ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name ); + goto error; + } + + if ((sec->SizeOfRawData < sec->Misc.VirtualSize) && (sec->SizeOfRawData & page_mask)) + { + DWORD end = ROUND_SIZE( 0, sec->SizeOfRawData ); + if (end > sec->Misc.VirtualSize) end = sec->Misc.VirtualSize; + TRACE_(module)("clearing %p - %p\n", + ptr + sec->VirtualAddress + sec->SizeOfRawData, + ptr + sec->VirtualAddress + end ); + memset( ptr + sec->VirtualAddress + sec->SizeOfRawData, 0, + end - sec->SizeOfRawData ); + } + } + + + /* perform base relocation, if necessary */ + + if (ptr != base) + { + const IMAGE_DATA_DIRECTORY *relocs; + + relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if (!relocs->VirtualAddress || !relocs->Size) + { + if (nt->OptionalHeader.ImageBase == 0x400000) + ERR("Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ?\n"); + else + ERR( "FATAL: Need to relocate module from addr %lx, but there are no relocation records\n", + nt->OptionalHeader.ImageBase ); + goto error; + } + + /* FIXME: If we need to relocate a system DLL (base > 2GB) we should + * really make sure that the *new* base address is also > 2GB. + * Some DLLs really check the MSB of the module handle :-/ + */ + if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((DWORD)base & 0x80000000)) + ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" ); + + if (!do_relocations( ptr, relocs, ptr - base, total_size )) + { + goto error; + } + } + + if (removable) hmapping = 0; /* don't keep handle open on removable media */ + if (!(view = VIRTUAL_CreateView( ptr, total_size, 0, VPROT_COMMITTED|VPROT_READ, hmapping ))) + { + status = STATUS_NO_MEMORY; + goto error; + } + + /* set the image protections */ + + sec = (IMAGE_SECTION_HEADER*)((char *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) + { + DWORD size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize ); + BYTE vprot = VPROT_COMMITTED; + if (sec->Characteristics & IMAGE_SCN_MEM_READ) vprot |= VPROT_READ; + if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) vprot |= VPROT_WRITE|VPROT_WRITECOPY; + if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC; + + /* make sure the import directory is writable */ + if (imports && imports->VirtualAddress >= sec->VirtualAddress && + imports->VirtualAddress < sec->VirtualAddress + size) + vprot |= VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY; + + VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot ); + } + + close( fd ); + *addr_ptr = ptr; + return STATUS_SUCCESS; + + error: + if (ptr != (char *)-1) munmap( ptr, total_size ); + close( fd ); + return status; +} + + +/*********************************************************************** + * is_current_process + * + * Check whether a process handle is for the current process. + */ +static BOOL is_current_process( HANDLE handle ) +{ + BOOL ret = FALSE; + + if (handle == GetCurrentProcess()) return TRUE; + SERVER_START_REQ( get_process_info ) + { + req->handle = handle; + if (!wine_server_call( req )) + ret = ((DWORD)reply->pid == GetCurrentProcessId()); + } + SERVER_END_REQ; + return ret; +} + + +/*********************************************************************** + * VIRTUAL_Init + */ +#ifndef page_mask +DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init) +{ + page_size = getpagesize(); + page_mask = page_size - 1; + /* Make sure we have a power of 2 */ + assert( !(page_size & page_mask) ); + page_shift = 0; + while ((1 << page_shift) != page_size) page_shift++; +} +#endif /* page_mask */ + + +/*********************************************************************** + * VIRTUAL_SetFaultHandler + */ +BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg ) +{ + FILE_VIEW *view; + + if (!(view = VIRTUAL_FindView( addr ))) return FALSE; + view->handlerProc = proc; + view->handlerArg = arg; + return TRUE; +} + +/*********************************************************************** + * VIRTUAL_HandleFault + */ +DWORD VIRTUAL_HandleFault( LPCVOID addr ) +{ + FILE_VIEW *view = VIRTUAL_FindView( addr ); + DWORD ret = EXCEPTION_ACCESS_VIOLATION; + + if (view) + { + if (view->handlerProc) + { + if (view->handlerProc(view->handlerArg, addr)) ret = 0; /* handled */ + } + else + { + BYTE vprot = view->prot[((char *)addr - (char *)view->base) >> page_shift]; + void *page = (void *)((UINT_PTR)addr & ~page_mask); + char *stack = (char *)NtCurrentTeb()->stack_base + SIGNAL_STACK_SIZE + page_mask + 1; + if (vprot & VPROT_GUARD) + { + VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD ); + ret = STATUS_GUARD_PAGE_VIOLATION; + } + /* is it inside the stack guard pages? */ + if (((char *)addr >= stack) && ((char *)addr < stack + 2*(page_mask+1))) + ret = STATUS_STACK_OVERFLOW; + } + } + return ret; +} + + + +/*********************************************************************** + * unaligned_mmap + * + * Linux kernels before 2.4.x can support non page-aligned offsets, as + * long as the offset is aligned to the filesystem block size. This is + * a big performance gain so we want to take advantage of it. + * + * However, when we use 64-bit file support this doesn't work because + * glibc rejects unaligned offsets. Also glibc 2.1.3 mmap64 is broken + * in that it rounds unaligned offsets down to a page boundary. For + * these reasons we do a direct system call here. + */ +static void *unaligned_mmap( void *addr, size_t length, unsigned int prot, + unsigned int flags, int fd, unsigned int offset_low, + unsigned int offset_high ) +{ +#if defined(linux) && defined(__i386__) && defined(__GNUC__) + if (!offset_high && (offset_low & page_mask)) + { + int ret; + + struct + { + void *addr; + unsigned int length; + unsigned int prot; + unsigned int flags; + unsigned int fd; + unsigned int offset; + } args; + + args.addr = addr; + args.length = length; + args.prot = prot; + args.flags = flags; + args.fd = fd; + args.offset = offset_low; + + __asm__ __volatile__("push %%ebx\n\t" + "movl %2,%%ebx\n\t" + "int $0x80\n\t" + "popl %%ebx" + : "=a" (ret) + : "0" (90), /* SYS_mmap */ + "g" (&args) ); + if (ret < 0 && ret > -4096) + { + errno = -ret; + ret = -1; + } + return (void *)ret; + } +#endif + return mmap( addr, length, prot, flags, fd, ((off_t)offset_high << 32) | offset_low ); +} + + +/*********************************************************************** + * VIRTUAL_mmap + * + * Wrapper for mmap() that handles anonymous mappings portably, + * and falls back to read if mmap of a file fails. + */ +static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, + DWORD offset_low, DWORD offset_high, + int prot, int flags, BOOL *removable ) +{ + int pos; + LPVOID ret; + off_t offset; + BOOL is_shared_write = FALSE; + + if (fd == -1) return wine_anon_mmap( start, size, prot, flags ); + + if (prot & PROT_WRITE) + { +#ifdef MAP_SHARED + if (flags & MAP_SHARED) is_shared_write = TRUE; +#endif +#ifdef MAP_PRIVATE + if (!(flags & MAP_PRIVATE)) is_shared_write = TRUE; +#endif + } + + if (removable && *removable) + { + /* if on removable media, try using read instead of mmap */ + if (!is_shared_write) goto fake_mmap; + *removable = FALSE; + } + + if ((ret = unaligned_mmap( start, size, prot, flags, fd, + offset_low, offset_high )) != (LPVOID)-1) return ret; + + /* mmap() failed; if this is because the file offset is not */ + /* page-aligned (EINVAL), or because the underlying filesystem */ + /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */ + + if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return ret; + if (is_shared_write) return ret; /* we cannot fake shared write mappings */ + + fake_mmap: + /* Reserve the memory with an anonymous mmap */ + ret = wine_anon_mmap( start, size, PROT_READ | PROT_WRITE, flags ); + if (ret == (LPVOID)-1) return ret; + /* Now read in the file */ + offset = ((off_t)offset_high << 32) | offset_low; + if ((pos = lseek( fd, offset, SEEK_SET )) == -1) + { + munmap( ret, size ); + return (LPVOID)-1; + } + read( fd, ret, size ); + lseek( fd, pos, SEEK_SET ); /* Restore the file pointer */ + mprotect( ret, size, prot ); /* Set the right protection */ + return ret; +} + + +/*********************************************************************** + * NtAllocateVirtualMemory (NTDLL.@) + * ZwAllocateVirtualMemory (NTDLL.@) + */ +NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, PVOID addr, + ULONG *size_ptr, ULONG type, ULONG protect ) +{ + FILE_VIEW *view; + void *base; + BYTE vprot; + DWORD size = *size_ptr; + + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + + TRACE("%p %08lx %lx %08lx\n", addr, size, type, protect ); + + /* Round parameters to a page boundary */ + + if (size > 0x7fc00000) return STATUS_WORKING_SET_LIMIT_RANGE; /* 2Gb - 4Mb */ + + if (addr) + { + if (type & MEM_RESERVE) /* Round down to 64k boundary */ + base = ROUND_ADDR( addr, granularity_mask ); + else + base = ROUND_ADDR( addr, page_mask ); + size = (((UINT_PTR)addr + size + page_mask) & ~page_mask) - (UINT_PTR)base; + + /* disallow low 64k, wrap-around and kernel space */ + if (((char *)base <= (char *)granularity_mask) || + ((char *)base + size < (char *)base) || + ((char *)base + size > (char *)ADDRESS_SPACE_LIMIT)) + return STATUS_INVALID_PARAMETER; + } + else + { + base = NULL; + size = (size + page_mask) & ~page_mask; + } + + if (type & MEM_TOP_DOWN) { + /* FIXME: MEM_TOP_DOWN allocates the largest possible address. + * Is there _ANY_ way to do it with UNIX mmap()? + */ + WARN("MEM_TOP_DOWN ignored\n"); + type &= ~MEM_TOP_DOWN; + } + + /* Compute the alloc type flags */ + + if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)) || + (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM))) + { + ERR("called with wrong alloc type flags (%08lx) !\n", type); + return STATUS_INVALID_PARAMETER; + } + if (type & (MEM_COMMIT | MEM_SYSTEM)) + vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED; + else vprot = 0; + + /* Reserve the memory */ + + if ((type & MEM_RESERVE) || !base) + { + if (type & MEM_SYSTEM) + { + if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC | VFLAG_SYSTEM, vprot, 0 ))) + return STATUS_NO_MEMORY; + } + else + { + NTSTATUS res = anon_mmap_aligned( &base, size, VIRTUAL_GetUnixProt( vprot ), 0 ); + if (res) return res; + + if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC, vprot, 0 ))) + { + munmap( base, size ); + return STATUS_NO_MEMORY; + } + } + } + else + { + /* Commit the pages */ + + if (!(view = VIRTUAL_FindView( base )) || + ((char *)base + size > (char *)view->base + view->size)) return STATUS_NOT_MAPPED_VIEW; + + if (!VIRTUAL_SetProt( view, base, size, vprot )) return STATUS_ACCESS_DENIED; + } + + *ret = base; + *size_ptr = size; + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * NtFreeVirtualMemory (NTDLL.@) + * ZwFreeVirtualMemory (NTDLL.@) + */ +NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, ULONG *size_ptr, ULONG type ) +{ + FILE_VIEW *view; + char *base; + LPVOID addr = *addr_ptr; + DWORD size = *size_ptr; + + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + + TRACE("%p %08lx %lx\n", addr, size, type ); + + /* Fix the parameters */ + + size = ROUND_SIZE( addr, size ); + base = ROUND_ADDR( addr, page_mask ); + + if (!(view = VIRTUAL_FindView( base )) || + (base + size > (char *)view->base + view->size) || + !(view->flags & VFLAG_VALLOC)) + return STATUS_INVALID_PARAMETER; + + /* Check the type */ + + if (type & MEM_SYSTEM) + { + view->flags |= VFLAG_SYSTEM; + type &= ~MEM_SYSTEM; + } + + if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE)) + { + ERR("called with wrong free type flags (%08lx) !\n", type); + return STATUS_INVALID_PARAMETER; + } + + /* Free the pages */ + + if (type == MEM_RELEASE) + { + if (size || (base != view->base)) return STATUS_INVALID_PARAMETER; + VIRTUAL_DeleteView( view ); + } + else + { + /* Decommit the pages by remapping zero-pages instead */ + + if (wine_anon_mmap( (LPVOID)base, size, VIRTUAL_GetUnixProt(0), MAP_FIXED ) != (LPVOID)base) + ERR( "Could not remap pages, expect trouble\n" ); + if (!VIRTUAL_SetProt( view, base, size, 0 )) return STATUS_ACCESS_DENIED; /* FIXME */ + } + + *addr_ptr = base; + *size_ptr = size; + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * NtProtectVirtualMemory (NTDLL.@) + * ZwProtectVirtualMemory (NTDLL.@) + */ +NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, ULONG *size_ptr, + ULONG new_prot, ULONG *old_prot ) +{ + FILE_VIEW *view; + char *base; + UINT i; + BYTE vprot, *p; + DWORD prot, size = *size_ptr; + LPVOID addr = *addr_ptr; + + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + + TRACE("%p %08lx %08lx\n", addr, size, new_prot ); + + /* Fix the parameters */ + + size = ROUND_SIZE( addr, size ); + base = ROUND_ADDR( addr, page_mask ); + + if (!(view = VIRTUAL_FindView( base )) || + (base + size > (char *)view->base + view->size)) + return STATUS_INVALID_PARAMETER; + + /* Make sure all the pages are committed */ + + p = view->prot + ((base - (char *)view->base) >> page_shift); + VIRTUAL_GetWin32Prot( *p, &prot, NULL ); + for (i = size >> page_shift; i; i--, p++) + { + if (!(*p & VPROT_COMMITTED)) return STATUS_INVALID_PARAMETER; + } + + if (old_prot) *old_prot = prot; + vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED; + if (!VIRTUAL_SetProt( view, base, size, vprot )) return STATUS_ACCESS_DENIED; + + *addr_ptr = base; + *size_ptr = size; + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * NtQueryVirtualMemory (NTDLL.@) + * ZwQueryVirtualMemory (NTDLL.@) + */ +NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, + MEMORY_INFORMATION_CLASS info_class, PVOID buffer, + ULONG len, ULONG *res_len ) +{ + FILE_VIEW *view; + char *base, *alloc_base = 0; + UINT size = 0; + MEMORY_BASIC_INFORMATION *info = buffer; + + if (info_class != MemoryBasicInformation) return STATUS_INVALID_INFO_CLASS; + if (addr >= ADDRESS_SPACE_LIMIT) return STATUS_WORKING_SET_LIMIT_RANGE; /* FIXME */ + + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + + base = ROUND_ADDR( addr, page_mask ); + + /* Find the view containing the address */ + + RtlEnterCriticalSection(&csVirtual); + view = VIRTUAL_FirstView; + for (;;) + { + if (!view) + { + size = (char *)ADDRESS_SPACE_LIMIT - alloc_base; + break; + } + if ((char *)view->base > base) + { + size = (char *)view->base - alloc_base; + view = NULL; + break; + } + if ((char *)view->base + view->size > base) + { + alloc_base = view->base; + size = view->size; + break; + } + alloc_base = (char *)view->base + view->size; + view = view->next; + } + RtlLeaveCriticalSection(&csVirtual); + + /* Fill the info structure */ + + if (!view) + { + info->State = MEM_FREE; + info->Protect = 0; + info->AllocationProtect = 0; + info->Type = 0; + } + else + { + BYTE vprot = view->prot[(base - alloc_base) >> page_shift]; + VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State ); + for (size = base - alloc_base; size < view->size; size += page_mask+1) + if (view->prot[size >> page_shift] != vprot) break; + info->AllocationProtect = view->protect; + info->Type = MEM_PRIVATE; /* FIXME */ + } + + info->BaseAddress = (LPVOID)base; + info->AllocationBase = (LPVOID)alloc_base; + info->RegionSize = size - (base - alloc_base); + *res_len = sizeof(*info); + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * NtLockVirtualMemory (NTDLL.@) + * ZwLockVirtualMemory (NTDLL.@) + */ +NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown ) +{ + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * NtUnlockVirtualMemory (NTDLL.@) + * ZwUnlockVirtualMemory (NTDLL.@) + */ +NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown ) +{ + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * NtCreateSection (NTDLL.@) + * ZwCreateSection (NTDLL.@) + */ +NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, + const LARGE_INTEGER *size, ULONG protect, + ULONG sec_flags, HANDLE file ) +{ + NTSTATUS ret; + BYTE vprot; + DWORD len = attr->ObjectName ? attr->ObjectName->Length : 0; + + /* Check parameters */ + + if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG; + + vprot = VIRTUAL_GetProt( protect ); + if (sec_flags & SEC_RESERVE) + { + if (file) return STATUS_INVALID_PARAMETER; + } + else vprot |= VPROT_COMMITTED; + if (sec_flags & SEC_NOCACHE) vprot |= VPROT_NOCACHE; + if (sec_flags & SEC_IMAGE) vprot |= VPROT_IMAGE; + + /* Create the server object */ + + SERVER_START_REQ( create_mapping ) + { + req->file_handle = file; + req->size_high = size ? size->s.HighPart : 0; + req->size_low = size ? size->s.LowPart : 0; + req->protect = vprot; + req->access = access; + req->inherit = (attr->Attributes & OBJ_INHERIT) != 0; + if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len ); + ret = wine_server_call( req ); + *handle = reply->handle; + } + SERVER_END_REQ; + return ret; +} + + +/*********************************************************************** + * NtOpenSection (NTDLL.@) + * ZwOpenSection (NTDLL.@) + */ +NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) +{ + NTSTATUS ret; + DWORD len = attr->ObjectName->Length; + + if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG; + + SERVER_START_REQ( open_mapping ) + { + req->access = access; + req->inherit = (attr->Attributes & OBJ_INHERIT) != 0; + wine_server_add_data( req, attr->ObjectName->Buffer, len ); + if (!(ret = wine_server_call( req ))) *handle = reply->handle; + } + SERVER_END_REQ; + return ret; +} + + +/*********************************************************************** + * NtMapViewOfSection (NTDLL.@) + * ZwMapViewOfSection (NTDLL.@) + */ +NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_ptr, ULONG zero_bits, + ULONG commit_size, const LARGE_INTEGER *offset, ULONG *size_ptr, + SECTION_INHERIT inherit, ULONG alloc_type, ULONG protect ) +{ + FILE_VIEW *view; + NTSTATUS res; + UINT size = 0; + int flags = MAP_PRIVATE; + int unix_handle = -1; + int prot; + void *base, *ptr = (void *)-1, *ret; + DWORD size_low, size_high, header_size, shared_size; + HANDLE shared_file; + BOOL removable; + + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + + TRACE("handle=%x addr=%p off=%lx%08lx size=%x access=%lx\n", + handle, *addr_ptr, offset->s.HighPart, offset->s.LowPart, size, protect ); + + /* Check parameters */ + + if ((offset->s.LowPart & granularity_mask) || + (*addr_ptr && ((UINT_PTR)*addr_ptr & granularity_mask))) + return STATUS_INVALID_PARAMETER; + + SERVER_START_REQ( get_mapping_info ) + { + req->handle = handle; + res = wine_server_call( req ); + prot = reply->protect; + base = reply->base; + size_low = reply->size_low; + size_high = reply->size_high; + header_size = reply->header_size; + shared_file = reply->shared_file; + shared_size = reply->shared_size; + removable = (reply->drive_type == DRIVE_REMOVABLE || + reply->drive_type == DRIVE_CDROM); + } + SERVER_END_REQ; + if (res) goto error; + + if ((res = wine_server_handle_to_fd( handle, 0, &unix_handle, NULL, NULL ))) goto error; + + if (prot & VPROT_IMAGE) + { + int shared_fd = -1; + + if (shared_file) + { + if ((res = wine_server_handle_to_fd( shared_file, GENERIC_READ, &shared_fd, + NULL, NULL ))) goto error; + NtClose( shared_file ); /* we no longer need it */ + } + res = map_image( handle, unix_handle, base, size_low, header_size, + shared_fd, shared_size, removable, addr_ptr ); + if (shared_fd != -1) close( shared_fd ); + if (!res) *size_ptr = size_low; + return res; + } + + + if (size_high) + ERR("Sizes larger than 4Gb not supported\n"); + + if ((offset->s.LowPart >= size_low) || + (*size_ptr > size_low - offset->s.LowPart)) + { + res = STATUS_INVALID_PARAMETER; + goto error; + } + if (*size_ptr) size = ROUND_SIZE( offset->s.LowPart, *size_ptr ); + else size = size_low - offset->s.LowPart; + + switch(protect) + { + case PAGE_NOACCESS: + break; + case PAGE_READWRITE: + case PAGE_EXECUTE_READWRITE: + if (!(prot & VPROT_WRITE)) + { + res = STATUS_INVALID_PARAMETER; + goto error; + } + flags = MAP_SHARED; + /* fall through */ + case PAGE_READONLY: + case PAGE_WRITECOPY: + case PAGE_EXECUTE: + case PAGE_EXECUTE_READ: + case PAGE_EXECUTE_WRITECOPY: + if (prot & VPROT_READ) break; + /* fall through */ + default: + res = STATUS_INVALID_PARAMETER; + goto error; + } + + /* FIXME: If a mapping is created with SEC_RESERVE and a process, + * which has a view of this mapping commits some pages, they will + * appear commited in all other processes, which have the same + * view created. Since we don`t support this yet, we create the + * whole mapping commited. + */ + prot |= VPROT_COMMITTED; + + /* Reserve a properly aligned area */ + + if ((res = anon_mmap_aligned( addr_ptr, size, PROT_NONE, 0 ))) goto error; + ptr = *addr_ptr; + + /* Map the file */ + + TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset->s.LowPart ); + + ret = VIRTUAL_mmap( unix_handle, ptr, size, offset->s.LowPart, offset->s.HighPart, + VIRTUAL_GetUnixProt( prot ), flags | MAP_FIXED, &removable ); + if (ret != ptr) + { + ERR( "VIRTUAL_mmap %p %x %lx%08lx failed\n", + ptr, size, offset->s.HighPart, offset->s.LowPart ); + res = STATUS_NO_MEMORY; /* FIXME */ + goto error; + } + if (removable) handle = 0; /* don't keep handle open on removable media */ + + if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle ))) + { + res = STATUS_NO_MEMORY; + goto error; + } + if (unix_handle != -1) close( unix_handle ); + *size_ptr = size; + return STATUS_SUCCESS; + +error: + if (unix_handle != -1) close( unix_handle ); + if (ptr != (void *)-1) munmap( ptr, size ); + return res; +} + + +/*********************************************************************** + * NtUnmapViewOfSection (NTDLL.@) + * ZwUnmapViewOfSection (NTDLL.@) + */ +NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) +{ + FILE_VIEW *view; + void *base = ROUND_ADDR( addr, page_mask ); + + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + if (!(view = VIRTUAL_FindView( base )) || (base != view->base)) return STATUS_INVALID_PARAMETER; + VIRTUAL_DeleteView( view ); + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * NtFlushVirtualMemory (NTDLL.@) + * ZwFlushVirtualMemory (NTDLL.@) + */ +NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr, + ULONG *size_ptr, ULONG unknown ) +{ + FILE_VIEW *view; + void *addr = ROUND_ADDR( *addr_ptr, page_mask ); + + if (!is_current_process( process )) + { + ERR("Unsupported on other process\n"); + return STATUS_ACCESS_DENIED; + } + if (!(view = VIRTUAL_FindView( addr ))) return STATUS_INVALID_PARAMETER; + if (!*size_ptr) *size_ptr = view->size; + *addr_ptr = addr; + if (!msync( addr, *size_ptr, MS_SYNC )) return STATUS_SUCCESS; + return STATUS_NOT_MAPPED_DATA; +} diff --git a/include/winbase.h b/include/winbase.h index f65e7f3395..5d290af3a4 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -1500,10 +1500,11 @@ BOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW,DWORD,DWORDLONG); #define VerifyVersionInfo WINELIB_NAME_AW(VerifyVersionInfo) LPVOID WINAPI VirtualAlloc(LPVOID,DWORD,DWORD,DWORD); LPVOID WINAPI VirtualAllocEx(HANDLE,LPVOID,DWORD,DWORD,DWORD); -BOOL WINAPI VirtualFree(LPVOID,DWORD,DWORD); -BOOL WINAPI VirtualLock(LPVOID,DWORD); -BOOL WINAPI VirtualProtect(LPVOID,DWORD,DWORD,LPDWORD); -BOOL WINAPI VirtualProtectEx(HANDLE,LPVOID,DWORD,DWORD,LPDWORD); +BOOL WINAPI VirtualFree(LPVOID,DWORD,DWORD); +BOOL WINAPI VirtualFreeEx(HANDLE,LPVOID,DWORD,DWORD); +BOOL WINAPI VirtualLock(LPVOID,DWORD); +BOOL WINAPI VirtualProtect(LPVOID,DWORD,DWORD,LPDWORD); +BOOL WINAPI VirtualProtectEx(HANDLE,LPVOID,DWORD,DWORD,LPDWORD); DWORD WINAPI VirtualQuery(LPCVOID,LPMEMORY_BASIC_INFORMATION,DWORD); DWORD WINAPI VirtualQueryEx(HANDLE,LPCVOID,LPMEMORY_BASIC_INFORMATION,DWORD); BOOL WINAPI VirtualUnlock(LPVOID,DWORD); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index c5d991a0de..0b7c4fd4d6 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1418,6 +1418,7 @@ struct create_mapping_request int size_high; int size_low; int protect; + unsigned int access; int inherit; obj_handle_t file_handle; /* VARARG(name,unicode_str); */ @@ -3209,6 +3210,6 @@ union generic_reply struct get_window_properties_reply get_window_properties_reply; }; -#define SERVER_PROTOCOL_VERSION 81 +#define SERVER_PROTOCOL_VERSION 82 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/include/winnt.h b/include/winnt.h index 89bc8500f6..5a1cd1a930 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -3185,6 +3185,13 @@ typedef enum tagSID_NAME_USE { #define THREAD_BASE_PRIORITY_MIN -2 #define THREAD_BASE_PRIORITY_IDLE -15 +#define SECTION_QUERY 0x0001 +#define SECTION_MAP_WRITE 0x0002 +#define SECTION_MAP_READ 0x0004 +#define SECTION_MAP_EXECUTE 0x0008 +#define SECTION_EXTEND_SIZE 0x0010 +#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|0x01f) + #define FILE_READ_DATA 0x0001 /* file & pipe */ #define FILE_LIST_DIRECTORY 0x0001 /* directory */ #define FILE_WRITE_DATA 0x0002 /* file & pipe */ diff --git a/include/winternl.h b/include/winternl.h index 3568a36bc6..41279a4230 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -259,6 +259,11 @@ typedef enum _WINSTATIONINFOCLASS { WinStationInformation = 8 } WINSTATIONINFOCLASS; +typedef enum +{ + MemoryBasicInformation = 0 +} MEMORY_INFORMATION_CLASS; + /*********************************************************************** * IA64 specific types and data structures */ @@ -753,11 +758,13 @@ void WINAPIV DbgPrint(LPCSTR fmt, ...); NTSTATUS WINAPI NtAccessCheck(PSECURITY_DESCRIPTOR,HANDLE,ACCESS_MASK,PGENERIC_MAPPING,PPRIVILEGE_SET,PULONG,PULONG,PBOOLEAN); NTSTATUS WINAPI NtAdjustPrivilegesToken(HANDLE,BOOLEAN,PTOKEN_PRIVILEGES,DWORD,PTOKEN_PRIVILEGES,PDWORD); +NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE,PVOID*,PVOID,ULONG*,ULONG,ULONG); NTSTATUS WINAPI NtClearEvent(HANDLE); NTSTATUS WINAPI NtClose(HANDLE); NTSTATUS WINAPI NtCreateEvent(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *,BOOLEAN,BOOLEAN); NTSTATUS WINAPI NtCreateFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG); NTSTATUS WINAPI NtCreateKey(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,const UNICODE_STRING*,ULONG,PULONG); +NTSTATUS WINAPI NtCreateSection(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*,const LARGE_INTEGER*,ULONG,ULONG,HANDLE); NTSTATUS WINAPI NtCreateSemaphore(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,ULONG); NTSTATUS WINAPI NtDeleteKey(HANDLE); NTSTATUS WINAPI NtDeleteValueKey(HANDLE,const UNICODE_STRING *); @@ -766,13 +773,19 @@ NTSTATUS WINAPI NtDuplicateObject(HANDLE,HANDLE,HANDLE,PHANDLE,ACCESS_MASK,ULON NTSTATUS WINAPI NtEnumerateKey(HANDLE,ULONG,KEY_INFORMATION_CLASS,void *,DWORD,DWORD *); NTSTATUS WINAPI NtEnumerateValueKey(HANDLE,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG); NTSTATUS WINAPI NtFlushKey(HANDLE); +NTSTATUS WINAPI NtFlushVirtualMemory(HANDLE,LPCVOID*,ULONG*,ULONG); +NTSTATUS WINAPI NtFreeVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG); NTSTATUS WINAPI NtLoadKey(const OBJECT_ATTRIBUTES *,const OBJECT_ATTRIBUTES *); +NTSTATUS WINAPI NtLockVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG); +NTSTATUS WINAPI NtMapViewOfSection(HANDLE,HANDLE,PVOID*,ULONG,ULONG,const LARGE_INTEGER*,ULONG*,SECTION_INHERIT,ULONG,ULONG); NTSTATUS WINAPI NtNotifyChangeKey(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN); NTSTATUS WINAPI NtOpenEvent(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *); NTSTATUS WINAPI NtOpenFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG); NTSTATUS WINAPI NtOpenKey(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *); NTSTATUS WINAPI NtOpenProcessToken(HANDLE,DWORD,HANDLE *); +NTSTATUS WINAPI NtOpenSection(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*); NTSTATUS WINAPI NtOpenThreadToken(HANDLE,DWORD,BOOLEAN,HANDLE *); +NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG,ULONG*); NTSTATUS WINAPI NtPulseEvent(HANDLE,PULONG); NTSTATUS WINAPI NtQueryInformationProcess(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG); NTSTATUS WINAPI NtQueryInformationThread(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG); @@ -783,6 +796,7 @@ NTSTATUS WINAPI NtQuerySecurityObject(HANDLE,SECURITY_INFORMATION,PSECURITY_DES NTSTATUS WINAPI NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS,PVOID,ULONG,PULONG); NTSTATUS WINAPI NtQuerySystemTime(PLARGE_INTEGER); NTSTATUS WINAPI NtQueryValueKey(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *); +NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE,LPCVOID,MEMORY_INFORMATION_CLASS,PVOID,ULONG,ULONG*); void WINAPI NtRaiseException(PEXCEPTION_RECORD,PCONTEXT,BOOL); NTSTATUS WINAPI NtReadFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,PLARGE_INTEGER,PULONG); NTSTATUS WINAPI NtReleaseSemaphore(HANDLE,ULONG,PULONG); @@ -797,6 +811,8 @@ NTSTATUS WINAPI NtSetValueKey(HANDLE,const UNICODE_STRING *,ULONG,ULONG,const v NTSTATUS WINAPI NtTerminateProcess(HANDLE,LONG); NTSTATUS WINAPI NtTerminateThread(HANDLE,LONG); NTSTATUS WINAPI NtUnloadKey(HANDLE); +NTSTATUS WINAPI NtUnlockVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG); +NTSTATUS WINAPI NtUnmapViewOfSection(HANDLE,PVOID); NTSTATUS WINAPI NtWaitForSingleObject(HANDLE,BOOLEAN,PLARGE_INTEGER); void WINAPI RtlAcquirePebLock(void); diff --git a/memory/virtual.c b/memory/virtual.c index ab01a1e6a9..32f6c5d836 100644 --- a/memory/virtual.c +++ b/memory/virtual.c @@ -21,110 +21,25 @@ #include "config.h" #include "wine/port.h" -#include -#include -#ifdef HAVE_SYS_ERRNO_H -#include -#endif #include +#include +#include +#include #ifdef HAVE_UNISTD_H # include #endif -#include -#include -#include -#include -#ifdef HAVE_SYS_MMAN_H -#include -#endif + #include "winnls.h" #include "winbase.h" -#include "wine/exception.h" -#include "wine/unicode.h" -#include "wine/library.h" +#include "winternl.h" #include "winerror.h" -#include "file.h" -#include "global.h" -#include "wine/server.h" +#include "wine/exception.h" #include "msvcrt/excpt.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(virtual); -WINE_DECLARE_DEBUG_CHANNEL(module); -#ifndef MS_SYNC -#define MS_SYNC 0 -#endif - -/* File view */ -typedef struct _FV -{ - struct _FV *next; /* Next view */ - struct _FV *prev; /* Prev view */ - void *base; /* Base address */ - UINT size; /* Size in bytes */ - UINT flags; /* Allocation flags */ - HANDLE mapping; /* Handle to the file mapping */ - HANDLERPROC handlerProc; /* Fault handler */ - LPVOID handlerArg; /* Fault handler argument */ - BYTE protect; /* Protection for all pages at allocation time */ - BYTE prot[1]; /* Protection byte for each page */ -} FILE_VIEW; - -/* Per-view flags */ -#define VFLAG_SYSTEM 0x01 -#define VFLAG_VALLOC 0x02 /* allocated by VirtualAlloc */ - -/* Conversion from VPROT_* to Win32 flags */ -static const BYTE VIRTUAL_Win32Flags[16] = -{ - PAGE_NOACCESS, /* 0 */ - PAGE_READONLY, /* READ */ - PAGE_READWRITE, /* WRITE */ - PAGE_READWRITE, /* READ | WRITE */ - PAGE_EXECUTE, /* EXEC */ - PAGE_EXECUTE_READ, /* READ | EXEC */ - PAGE_EXECUTE_READWRITE, /* WRITE | EXEC */ - PAGE_EXECUTE_READWRITE, /* READ | WRITE | EXEC */ - PAGE_WRITECOPY, /* WRITECOPY */ - PAGE_WRITECOPY, /* READ | WRITECOPY */ - PAGE_WRITECOPY, /* WRITE | WRITECOPY */ - PAGE_WRITECOPY, /* READ | WRITE | WRITECOPY */ - PAGE_EXECUTE_WRITECOPY, /* EXEC | WRITECOPY */ - PAGE_EXECUTE_WRITECOPY, /* READ | EXEC | WRITECOPY */ - PAGE_EXECUTE_WRITECOPY, /* WRITE | EXEC | WRITECOPY */ - PAGE_EXECUTE_WRITECOPY /* READ | WRITE | EXEC | WRITECOPY */ -}; - - -static FILE_VIEW *VIRTUAL_FirstView; -static CRITICAL_SECTION csVirtual = CRITICAL_SECTION_INIT("csVirtual"); - -#ifdef __i386__ -/* These are always the same on an i386, and it will be faster this way */ -# define page_mask 0xfff -# define page_shift 12 -# define page_size 0x1000 -#else -static UINT page_shift; -static UINT page_mask; -static UINT page_size; -#endif /* __i386__ */ -#define granularity_mask 0xffff /* Allocation granularity (usually 64k) */ - -#define ADDRESS_SPACE_LIMIT ((void *)0xc0000000) /* top of the user address space */ - -#define ROUND_ADDR(addr,mask) \ - ((void *)((UINT_PTR)(addr) & ~(mask))) - -#define ROUND_SIZE(addr,size) \ - (((UINT)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask) - -#define VIRTUAL_DEBUG_DUMP_VIEW(view) \ - if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view) - -static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset_low, - DWORD offset_high, int prot, int flags, BOOL *removable ); +static unsigned int page_size; /* filter for page-fault exceptions */ static WINE_EXCEPTION_FILTER(page_fault) @@ -134,841 +49,6 @@ static WINE_EXCEPTION_FILTER(page_fault) return EXCEPTION_CONTINUE_SEARCH; } -/*********************************************************************** - * VIRTUAL_GetProtStr - */ -static const char *VIRTUAL_GetProtStr( BYTE prot ) -{ - static char buffer[6]; - buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-'; - buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-'; - buffer[2] = (prot & VPROT_READ) ? 'r' : '-'; - buffer[3] = (prot & VPROT_WRITE) ? - ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-'; - buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-'; - buffer[5] = 0; - return buffer; -} - - -/*********************************************************************** - * VIRTUAL_DumpView - */ -static void VIRTUAL_DumpView( FILE_VIEW *view ) -{ - UINT i, count; - char *addr = view->base; - BYTE prot = view->prot[0]; - - DPRINTF( "View: %p - %p", addr, addr + view->size - 1 ); - if (view->flags & VFLAG_SYSTEM) - DPRINTF( " (system)\n" ); - else if (view->flags & VFLAG_VALLOC) - DPRINTF( " (valloc)\n" ); - else if (view->mapping) - DPRINTF( " %d\n", view->mapping ); - else - DPRINTF( " (anonymous)\n"); - - for (count = i = 1; i < view->size >> page_shift; i++, count++) - { - if (view->prot[i] == prot) continue; - DPRINTF( " %p - %p %s\n", - addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) ); - addr += (count << page_shift); - prot = view->prot[i]; - count = 0; - } - if (count) - DPRINTF( " %p - %p %s\n", - addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) ); -} - - -/*********************************************************************** - * VIRTUAL_Dump - */ -void VIRTUAL_Dump(void) -{ - FILE_VIEW *view; - DPRINTF( "\nDump of all virtual memory views:\n\n" ); - EnterCriticalSection(&csVirtual); - view = VIRTUAL_FirstView; - while (view) - { - VIRTUAL_DumpView( view ); - view = view->next; - } - LeaveCriticalSection(&csVirtual); -} - - -/*********************************************************************** - * VIRTUAL_FindView - * - * Find the view containing a given address. - * - * RETURNS - * View: Success - * NULL: Failure - */ -static FILE_VIEW *VIRTUAL_FindView( const void *addr ) /* [in] Address */ -{ - FILE_VIEW *view; - - EnterCriticalSection(&csVirtual); - view = VIRTUAL_FirstView; - while (view) - { - if (view->base > addr) - { - view = NULL; - break; - } - if ((char*)view->base + view->size > (char*)addr) break; - view = view->next; - } - LeaveCriticalSection(&csVirtual); - return view; -} - - -/*********************************************************************** - * VIRTUAL_CreateView - * - * Create a new view and add it in the linked list. - */ -static FILE_VIEW *VIRTUAL_CreateView( void *base, UINT size, UINT flags, - BYTE vprot, HANDLE mapping ) -{ - FILE_VIEW *view, *prev; - - /* Create the view structure */ - - assert( !((unsigned int)base & page_mask) ); - assert( !(size & page_mask) ); - size >>= page_shift; - if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL; - view->base = base; - view->size = size << page_shift; - view->flags = flags; - view->mapping = mapping; - view->protect = vprot; - view->handlerProc = NULL; - memset( view->prot, vprot, size ); - - /* Duplicate the mapping handle */ - - if (view->mapping && - !DuplicateHandle( GetCurrentProcess(), view->mapping, - GetCurrentProcess(), &view->mapping, - 0, FALSE, DUPLICATE_SAME_ACCESS )) - { - free( view ); - return NULL; - } - - /* Insert it in the linked list */ - - EnterCriticalSection(&csVirtual); - if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base)) - { - view->next = VIRTUAL_FirstView; - view->prev = NULL; - if (view->next) view->next->prev = view; - VIRTUAL_FirstView = view; - } - else - { - prev = VIRTUAL_FirstView; - while (prev->next && (prev->next->base < base)) prev = prev->next; - view->next = prev->next; - view->prev = prev; - if (view->next) view->next->prev = view; - prev->next = view; - } - LeaveCriticalSection(&csVirtual); - VIRTUAL_DEBUG_DUMP_VIEW( view ); - return view; -} - - -/*********************************************************************** - * VIRTUAL_DeleteView - * Deletes a view. - * - * RETURNS - * None - */ -static void VIRTUAL_DeleteView( - FILE_VIEW *view /* [in] View */ -) { - if (!(view->flags & VFLAG_SYSTEM)) - munmap( (void *)view->base, view->size ); - EnterCriticalSection(&csVirtual); - if (view->next) view->next->prev = view->prev; - if (view->prev) view->prev->next = view->next; - else VIRTUAL_FirstView = view->next; - LeaveCriticalSection(&csVirtual); - if (view->mapping) NtClose( view->mapping ); - free( view ); -} - - -/*********************************************************************** - * VIRTUAL_GetUnixProt - * - * Convert page protections to protection for mmap/mprotect. - */ -static int VIRTUAL_GetUnixProt( BYTE vprot ) -{ - int prot = 0; - if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD)) - { - if (vprot & VPROT_READ) prot |= PROT_READ; - if (vprot & VPROT_WRITE) prot |= PROT_WRITE; - if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE; - if (vprot & VPROT_EXEC) prot |= PROT_EXEC; - } - return prot; -} - - -/*********************************************************************** - * VIRTUAL_GetWin32Prot - * - * Convert page protections to Win32 flags. - * - * RETURNS - * None - */ -static void VIRTUAL_GetWin32Prot( - BYTE vprot, /* [in] Page protection flags */ - DWORD *protect, /* [out] Location to store Win32 protection flags */ - DWORD *state /* [out] Location to store mem state flag */ -) { - if (protect) { - *protect = VIRTUAL_Win32Flags[vprot & 0x0f]; -/* if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/ - if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE; - - if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS; - } - - if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE; -} - - -/*********************************************************************** - * VIRTUAL_GetProt - * - * Build page protections from Win32 flags. - * - * RETURNS - * Value of page protection flags - */ -static BYTE VIRTUAL_GetProt( - DWORD protect /* [in] Win32 protection flags */ -) { - BYTE vprot; - - switch(protect & 0xff) - { - case PAGE_READONLY: - vprot = VPROT_READ; - break; - case PAGE_READWRITE: - vprot = VPROT_READ | VPROT_WRITE; - break; - case PAGE_WRITECOPY: - /* MSDN CreateFileMapping() states that if PAGE_WRITECOPY is given, - * that the hFile must have been opened with GENERIC_READ and - * GENERIC_WRITE access. This is WRONG as tests show that you - * only need GENERIC_READ access (at least for Win9x, - * FIXME: what about NT?). Thus, we don't put VPROT_WRITE in - * PAGE_WRITECOPY and PAGE_EXECUTE_WRITECOPY. - */ - vprot = VPROT_READ | VPROT_WRITECOPY; - break; - case PAGE_EXECUTE: - vprot = VPROT_EXEC; - break; - case PAGE_EXECUTE_READ: - vprot = VPROT_EXEC | VPROT_READ; - break; - case PAGE_EXECUTE_READWRITE: - vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE; - break; - case PAGE_EXECUTE_WRITECOPY: - /* See comment for PAGE_WRITECOPY above */ - vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY; - break; - case PAGE_NOACCESS: - default: - vprot = 0; - break; - } - if (protect & PAGE_GUARD) vprot |= VPROT_GUARD; - if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE; - return vprot; -} - - -/*********************************************************************** - * VIRTUAL_SetProt - * - * Change the protection of a range of pages. - * - * RETURNS - * TRUE: Success - * FALSE: Failure - */ -static BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */ - void *base, /* [in] Starting address */ - UINT size, /* [in] Size in bytes */ - BYTE vprot ) /* [in] Protections to use */ -{ - TRACE("%p-%p %s\n", - base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) ); - - if (mprotect( base, size, VIRTUAL_GetUnixProt(vprot) )) - return FALSE; /* FIXME: last error */ - - memset( view->prot + (((char *)base - (char *)view->base) >> page_shift), - vprot, size >> page_shift ); - VIRTUAL_DEBUG_DUMP_VIEW( view ); - return TRUE; -} - - -/*********************************************************************** - * anon_mmap_aligned - * - * Create an anonymous mapping aligned to the allocation granularity. - */ -static void *anon_mmap_aligned( void *base, unsigned int size, int prot, int flags ) -{ - void *ptr; - unsigned int view_size = size + (base ? 0 : granularity_mask + 1); - - if ((ptr = wine_anon_mmap( base, view_size, prot, flags )) == (void *)-1) - { - /* KB: Q125713, 25-SEP-1995, "Common File Mapping Problems and - * Platform Differences": - * Windows NT: ERROR_INVALID_PARAMETER - * Windows 95: ERROR_INVALID_ADDRESS. - */ - if (errno == ENOMEM) SetLastError( ERROR_OUTOFMEMORY ); - else - { - if (GetVersion() & 0x80000000) /* win95 */ - SetLastError( ERROR_INVALID_ADDRESS ); - else - SetLastError( ERROR_INVALID_PARAMETER ); - } - return ptr; - } - - if (!base) - { - /* Release the extra memory while keeping the range - * starting on the granularity boundary. */ - if ((unsigned int)ptr & granularity_mask) - { - unsigned int extra = granularity_mask + 1 - ((unsigned int)ptr & granularity_mask); - munmap( ptr, extra ); - ptr = (char *)ptr + extra; - view_size -= extra; - } - if (view_size > size) - munmap( (char *)ptr + size, view_size - size ); - } - else if (ptr != base) - { - /* We couldn't get the address we wanted */ - munmap( ptr, view_size ); - SetLastError( ERROR_INVALID_ADDRESS ); - ptr = (void *)-1; - } - return ptr; -} - - -/*********************************************************************** - * do_relocations - * - * Apply the relocations to a mapped PE image - */ -static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir, - int delta, DWORD total_size ) -{ - IMAGE_BASE_RELOCATION *rel; - - TRACE_(module)( "relocating from %p-%p to %p-%p\n", - base - delta, base - delta + total_size, base, base + total_size ); - - for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress); - ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock; - rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) ) - { - char *page = base + rel->VirtualAddress; - WORD *TypeOffset = (WORD *)(rel + 1); - int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset); - - if (!count) continue; - - /* sanity checks */ - if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size || - page > base + total_size) - { - ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n", - rel, rel->VirtualAddress, rel->SizeOfBlock, - base, dir->VirtualAddress, dir->Size ); - return 0; - } - - TRACE_(module)("%ld relocations for page %lx\n", rel->SizeOfBlock, rel->VirtualAddress); - - /* patching in reverse order */ - for (i = 0 ; i < count; i++) - { - int offset = TypeOffset[i] & 0xFFF; - int type = TypeOffset[i] >> 12; - switch(type) - { - case IMAGE_REL_BASED_ABSOLUTE: - break; - case IMAGE_REL_BASED_HIGH: - *(short*)(page+offset) += HIWORD(delta); - break; - case IMAGE_REL_BASED_LOW: - *(short*)(page+offset) += LOWORD(delta); - break; - case IMAGE_REL_BASED_HIGHLOW: - *(int*)(page+offset) += delta; - /* FIXME: if this is an exported address, fire up enhanced logic */ - break; - default: - FIXME_(module)("Unknown/unsupported fixup type %d.\n", type); - break; - } - } - } - return 1; -} - - -/*********************************************************************** - * map_image - * - * Map an executable (PE format) image into memory. - */ -static LPVOID map_image( HANDLE hmapping, int fd, char *base, DWORD total_size, - DWORD header_size, HANDLE shared_file, DWORD shared_size, - BOOL removable ) -{ - IMAGE_DOS_HEADER *dos; - IMAGE_NT_HEADERS *nt; - IMAGE_SECTION_HEADER *sec; - IMAGE_DATA_DIRECTORY *imports; - int i, pos; - DWORD err = GetLastError(); - FILE_VIEW *view; - char *ptr; - int shared_fd = -1; - - SetLastError( ERROR_BAD_EXE_FORMAT ); /* generic error */ - - /* zero-map the whole range */ - - if (base < (char *)0x110000 || /* make sure the DOS area remains free */ - (ptr = wine_anon_mmap( base, total_size, - PROT_READ | PROT_WRITE | PROT_EXEC, 0 )) == (char *)-1) - { - ptr = wine_anon_mmap( NULL, total_size, - PROT_READ | PROT_WRITE | PROT_EXEC, 0 ); - if (ptr == (char *)-1) - { - ERR_(module)("Not enough memory for module (%ld bytes)\n", total_size); - goto error; - } - } - TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size ); - - /* map the header */ - - if (VIRTUAL_mmap( fd, ptr, header_size, 0, 0, PROT_READ, - MAP_PRIVATE | MAP_FIXED, &removable ) == (char *)-1) goto error; - dos = (IMAGE_DOS_HEADER *)ptr; - nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew); - if ((char *)(nt + 1) > ptr + header_size) goto error; - - sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); - if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error; - - imports = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT; - if (!imports->Size || !imports->VirtualAddress) imports = NULL; - - /* check the architecture */ - - if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) - { - MESSAGE("Trying to load PE image for unsupported architecture ("); - switch (nt->FileHeader.Machine) - { - case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break; - case IMAGE_FILE_MACHINE_I860: MESSAGE("I860"); break; - case IMAGE_FILE_MACHINE_R3000: MESSAGE("R3000"); break; - case IMAGE_FILE_MACHINE_R4000: MESSAGE("R4000"); break; - case IMAGE_FILE_MACHINE_R10000: MESSAGE("R10000"); break; - case IMAGE_FILE_MACHINE_ALPHA: MESSAGE("Alpha"); break; - case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break; - default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break; - } - MESSAGE(")\n"); - goto error; - } - - /* retrieve the shared sections file */ - - if (shared_size) - { - if ((shared_fd = FILE_GetUnixHandle( shared_file, GENERIC_READ )) == -1) goto error; - CloseHandle( shared_file ); /* we no longer need it */ - shared_file = 0; - } - - /* map all the sections */ - - for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) - { - DWORD size; - - /* a few sanity checks */ - size = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize ); - if (sec->VirtualAddress > total_size || size > total_size || size < sec->VirtualAddress) - { - ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n", - sec->Name, sec->VirtualAddress, sec->Misc.VirtualSize, total_size ); - goto error; - } - - if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) && - (sec->Characteristics & IMAGE_SCN_MEM_WRITE)) - { - size = ROUND_SIZE( 0, sec->Misc.VirtualSize ); - TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n", - sec->Name, ptr + sec->VirtualAddress, - sec->PointerToRawData, pos, sec->SizeOfRawData, - size, sec->Characteristics ); - if (VIRTUAL_mmap( shared_fd, ptr + sec->VirtualAddress, size, - pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_SHARED|MAP_FIXED, NULL ) == (void *)-1) - { - ERR_(module)( "Could not map shared section %.8s\n", sec->Name ); - goto error; - } - - /* check if the import directory falls inside this section */ - if (imports && imports->VirtualAddress >= sec->VirtualAddress && - imports->VirtualAddress < sec->VirtualAddress + size) - { - UINT_PTR base = imports->VirtualAddress & ~page_mask; - UINT_PTR end = base + ROUND_SIZE( imports->VirtualAddress, imports->Size ); - if (end > sec->VirtualAddress + size) end = sec->VirtualAddress + size; - if (end > base) VIRTUAL_mmap( shared_fd, ptr + base, end - base, - pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_PRIVATE|MAP_FIXED, NULL ); - } - pos += size; - continue; - } - - TRACE_(module)( "mapping section %.8s at %p off %lx size %lx flags %lx\n", - sec->Name, ptr + sec->VirtualAddress, - sec->PointerToRawData, sec->SizeOfRawData, - sec->Characteristics ); - - if (sec->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue; - if (!sec->PointerToRawData || !sec->SizeOfRawData) continue; - - /* Note: if the section is not aligned properly VIRTUAL_mmap will magically - * fall back to read(), so we don't need to check anything here. - */ - if (VIRTUAL_mmap( fd, ptr + sec->VirtualAddress, sec->SizeOfRawData, - sec->PointerToRawData, 0, PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_PRIVATE | MAP_FIXED, &removable ) == (void *)-1) - { - ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name ); - goto error; - } - - if ((sec->SizeOfRawData < sec->Misc.VirtualSize) && (sec->SizeOfRawData & page_mask)) - { - DWORD end = ROUND_SIZE( 0, sec->SizeOfRawData ); - if (end > sec->Misc.VirtualSize) end = sec->Misc.VirtualSize; - TRACE_(module)("clearing %p - %p\n", - ptr + sec->VirtualAddress + sec->SizeOfRawData, - ptr + sec->VirtualAddress + end ); - memset( ptr + sec->VirtualAddress + sec->SizeOfRawData, 0, - end - sec->SizeOfRawData ); - } - } - - - /* perform base relocation, if necessary */ - - if (ptr != base) - { - const IMAGE_DATA_DIRECTORY *relocs; - - relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; - if (!relocs->VirtualAddress || !relocs->Size) - { - if (nt->OptionalHeader.ImageBase == 0x400000) - ERR("Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ?\n"); - else - ERR( "FATAL: Need to relocate module from addr %lx, but there are no relocation records\n", - nt->OptionalHeader.ImageBase ); - SetLastError( ERROR_BAD_EXE_FORMAT ); - goto error; - } - - /* FIXME: If we need to relocate a system DLL (base > 2GB) we should - * really make sure that the *new* base address is also > 2GB. - * Some DLLs really check the MSB of the module handle :-/ - */ - if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((DWORD)base & 0x80000000)) - ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" ); - - if (!do_relocations( ptr, relocs, ptr - base, total_size )) - { - SetLastError( ERROR_BAD_EXE_FORMAT ); - goto error; - } - } - - if (removable) hmapping = 0; /* don't keep handle open on removable media */ - if (!(view = VIRTUAL_CreateView( ptr, total_size, 0, VPROT_COMMITTED|VPROT_READ, hmapping ))) - { - SetLastError( ERROR_OUTOFMEMORY ); - goto error; - } - - /* set the image protections */ - - sec = (IMAGE_SECTION_HEADER*)((char *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); - for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) - { - DWORD size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize ); - BYTE vprot = VPROT_COMMITTED; - if (sec->Characteristics & IMAGE_SCN_MEM_READ) vprot |= VPROT_READ; - if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) vprot |= VPROT_WRITE|VPROT_WRITECOPY; - if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC; - - /* make sure the import directory is writable */ - if (imports && imports->VirtualAddress >= sec->VirtualAddress && - imports->VirtualAddress < sec->VirtualAddress + size) - vprot |= VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY; - - VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot ); - } - - SetLastError( err ); /* restore last error */ - close( fd ); - if (shared_fd != -1) close( shared_fd ); - return ptr; - - error: - if (ptr != (char *)-1) munmap( ptr, total_size ); - close( fd ); - if (shared_fd != -1) close( shared_fd ); - if (shared_file) CloseHandle( shared_file ); - return NULL; -} - - -/*********************************************************************** - * VIRTUAL_Init - */ -#ifndef page_mask -DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init) -{ - page_size = getpagesize(); - page_mask = page_size - 1; - /* Make sure we have a power of 2 */ - assert( !(page_size & page_mask) ); - page_shift = 0; - while ((1 << page_shift) != page_size) page_shift++; -} -#endif /* page_mask */ - - -/*********************************************************************** - * VIRTUAL_SetFaultHandler - */ -BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg ) -{ - FILE_VIEW *view; - - if (!(view = VIRTUAL_FindView( addr ))) return FALSE; - view->handlerProc = proc; - view->handlerArg = arg; - return TRUE; -} - -/*********************************************************************** - * VIRTUAL_HandleFault - */ -DWORD VIRTUAL_HandleFault( LPCVOID addr ) -{ - FILE_VIEW *view = VIRTUAL_FindView( addr ); - DWORD ret = EXCEPTION_ACCESS_VIOLATION; - - if (view) - { - if (view->handlerProc) - { - if (view->handlerProc(view->handlerArg, addr)) ret = 0; /* handled */ - } - else - { - BYTE vprot = view->prot[((char *)addr - (char *)view->base) >> page_shift]; - void *page = (void *)((UINT_PTR)addr & ~page_mask); - char *stack = (char *)NtCurrentTeb()->stack_base + SIGNAL_STACK_SIZE + page_mask + 1; - if (vprot & VPROT_GUARD) - { - VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD ); - ret = STATUS_GUARD_PAGE_VIOLATION; - } - /* is it inside the stack guard pages? */ - if (((char *)addr >= stack) && ((char *)addr < stack + 2*(page_mask+1))) - ret = STATUS_STACK_OVERFLOW; - } - } - return ret; -} - - - -/*********************************************************************** - * unaligned_mmap - * - * Linux kernels before 2.4.x can support non page-aligned offsets, as - * long as the offset is aligned to the filesystem block size. This is - * a big performance gain so we want to take advantage of it. - * - * However, when we use 64-bit file support this doesn't work because - * glibc rejects unaligned offsets. Also glibc 2.1.3 mmap64 is broken - * in that it rounds unaligned offsets down to a page boundary. For - * these reasons we do a direct system call here. - */ -static void *unaligned_mmap( void *addr, size_t length, unsigned int prot, - unsigned int flags, int fd, unsigned int offset_low, - unsigned int offset_high ) -{ -#if defined(linux) && defined(__i386__) && defined(__GNUC__) - if (!offset_high && (offset_low & page_mask)) - { - int ret; - - struct - { - void *addr; - unsigned int length; - unsigned int prot; - unsigned int flags; - unsigned int fd; - unsigned int offset; - } args; - - args.addr = addr; - args.length = length; - args.prot = prot; - args.flags = flags; - args.fd = fd; - args.offset = offset_low; - - __asm__ __volatile__("push %%ebx\n\t" - "movl %2,%%ebx\n\t" - "int $0x80\n\t" - "popl %%ebx" - : "=a" (ret) - : "0" (90), /* SYS_mmap */ - "g" (&args) ); - if (ret < 0 && ret > -4096) - { - errno = -ret; - ret = -1; - } - return (void *)ret; - } -#endif - return mmap( addr, length, prot, flags, fd, ((off_t)offset_high << 32) | offset_low ); -} - - -/*********************************************************************** - * VIRTUAL_mmap - * - * Wrapper for mmap() that handles anonymous mappings portably, - * and falls back to read if mmap of a file fails. - */ -static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, - DWORD offset_low, DWORD offset_high, - int prot, int flags, BOOL *removable ) -{ - int pos; - LPVOID ret; - off_t offset; - BOOL is_shared_write = FALSE; - - if (fd == -1) return wine_anon_mmap( start, size, prot, flags ); - - if (prot & PROT_WRITE) - { -#ifdef MAP_SHARED - if (flags & MAP_SHARED) is_shared_write = TRUE; -#endif -#ifdef MAP_PRIVATE - if (!(flags & MAP_PRIVATE)) is_shared_write = TRUE; -#endif - } - - if (removable && *removable) - { - /* if on removable media, try using read instead of mmap */ - if (!is_shared_write) goto fake_mmap; - *removable = FALSE; - } - - if ((ret = unaligned_mmap( start, size, prot, flags, fd, - offset_low, offset_high )) != (LPVOID)-1) return ret; - - /* mmap() failed; if this is because the file offset is not */ - /* page-aligned (EINVAL), or because the underlying filesystem */ - /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */ - - if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return ret; - if (is_shared_write) return ret; /* we cannot fake shared write mappings */ - - fake_mmap: - /* Reserve the memory with an anonymous mmap */ - ret = wine_anon_mmap( start, size, PROT_READ | PROT_WRITE, flags ); - if (ret == (LPVOID)-1) return ret; - /* Now read in the file */ - offset = ((off_t)offset_high << 32) | offset_low; - if ((pos = lseek( fd, offset, SEEK_SET )) == -1) - { - munmap( ret, size ); - return (LPVOID)-1; - } - read( fd, ret, size ); - lseek( fd, pos, SEEK_SET ); /* Restore the file pointer */ - mprotect( ret, size, prot ); /* Set the right protection */ - return ret; -} - /*********************************************************************** * VirtualAlloc (KERNEL32.@) @@ -984,98 +64,7 @@ LPVOID WINAPI VirtualAlloc( DWORD type, /* [in] Type of allocation */ DWORD protect)/* [in] Type of access protection */ { - FILE_VIEW *view; - char *ptr, *base; - BYTE vprot; - - TRACE("%p %08lx %lx %08lx\n", addr, size, type, protect ); - - /* Round parameters to a page boundary */ - - if (size > 0x7fc00000) /* 2Gb - 4Mb */ - { - SetLastError( ERROR_OUTOFMEMORY ); - return NULL; - } - if (addr) - { - if (type & MEM_RESERVE) /* Round down to 64k boundary */ - base = ROUND_ADDR( addr, granularity_mask ); - else - base = ROUND_ADDR( addr, page_mask ); - size = (((UINT_PTR)addr + size + page_mask) & ~page_mask) - (UINT_PTR)base; - - /* disallow low 64k, wrap-around and kernel space */ - if ((base <= (char *)granularity_mask) || - (base + size < base) || - (base + size > (char *)ADDRESS_SPACE_LIMIT)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return NULL; - } - } - else - { - base = 0; - size = (size + page_mask) & ~page_mask; - } - - if (type & MEM_TOP_DOWN) { - /* FIXME: MEM_TOP_DOWN allocates the largest possible address. - * Is there _ANY_ way to do it with UNIX mmap()? - */ - WARN("MEM_TOP_DOWN ignored\n"); - type &= ~MEM_TOP_DOWN; - } - /* Compute the alloc type flags */ - - if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)) || - (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM))) - { - ERR("called with wrong alloc type flags (%08lx) !\n", type); - SetLastError( ERROR_INVALID_PARAMETER ); - return NULL; - } - if (type & (MEM_COMMIT | MEM_SYSTEM)) - vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED; - else vprot = 0; - - /* Reserve the memory */ - - if ((type & MEM_RESERVE) || !base) - { - if (type & MEM_SYSTEM) - { - if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC | VFLAG_SYSTEM, vprot, 0 ))) - { - SetLastError( ERROR_OUTOFMEMORY ); - return NULL; - } - return (LPVOID)base; - } - ptr = anon_mmap_aligned( base, size, VIRTUAL_GetUnixProt( vprot ), 0 ); - if (ptr == (void *)-1) return NULL; - - if (!(view = VIRTUAL_CreateView( ptr, size, VFLAG_VALLOC, vprot, 0 ))) - { - munmap( ptr, size ); - SetLastError( ERROR_OUTOFMEMORY ); - return NULL; - } - return ptr; - } - - /* Commit the pages */ - - if (!(view = VIRTUAL_FindView( base )) || - (base + size > (char *)view->base + view->size)) - { - SetLastError( ERROR_INVALID_ADDRESS ); - return NULL; - } - - if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL; - return (LPVOID)base; + return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect ); } @@ -1086,15 +75,20 @@ LPVOID WINAPI VirtualAlloc( */ LPVOID WINAPI VirtualAllocEx( HANDLE hProcess, /* [in] Handle of process to do mem operation */ - LPVOID addr, /* [in] Address of region to reserve or commit */ - DWORD size, /* [in] Size of region */ - DWORD type, /* [in] Type of allocation */ - DWORD protect /* [in] Type of access protection */ -) { - if (MapProcessHandle( hProcess ) == GetCurrentProcessId()) - return VirtualAlloc( addr, size, type, protect ); - ERR("Unsupported on other process\n"); - return NULL; + LPVOID addr, /* [in] Address of region to reserve or commit */ + DWORD size, /* [in] Size of region */ + DWORD type, /* [in] Type of allocation */ + DWORD protect ) /* [in] Type of access protection */ +{ + LPVOID ret; + NTSTATUS status; + + if ((status = NtAllocateVirtualMemory( hProcess, &ret, addr, &size, type, protect ))) + { + SetLastError( RtlNtStatusToDosError(status) ); + ret = NULL; + } + return ret; } @@ -1111,57 +105,23 @@ BOOL WINAPI VirtualFree( DWORD size, /* [in] Size of region */ DWORD type /* [in] Type of operation */ ) { - FILE_VIEW *view; - char *base; + return VirtualFreeEx( GetCurrentProcess(), addr, size, type ); +} - TRACE("%p %08lx %lx\n", addr, size, type ); - /* Fix the parameters */ - - size = ROUND_SIZE( addr, size ); - base = ROUND_ADDR( addr, page_mask ); - - if (!(view = VIRTUAL_FindView( base )) || - (base + size > (char *)view->base + view->size) || - !(view->flags & VFLAG_VALLOC)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - - /* Check the type */ - - if (type & MEM_SYSTEM) - { - view->flags |= VFLAG_SYSTEM; - type &= ~MEM_SYSTEM; - } - - if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE)) - { - ERR("called with wrong free type flags (%08lx) !\n", type); - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - - /* Free the pages */ - - if (type == MEM_RELEASE) - { - if (size || (base != view->base)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - VIRTUAL_DeleteView( view ); - return TRUE; - } - - /* Decommit the pages by remapping zero-pages instead */ - - if (wine_anon_mmap( (LPVOID)base, size, VIRTUAL_GetUnixProt(0), MAP_FIXED ) != (LPVOID)base) - ERR( "Could not remap pages, expect trouble\n" ); - return VIRTUAL_SetProt( view, base, size, 0 ); +/*********************************************************************** + * VirtualFreeEx (KERNEL32.@) + * Release or decommits a region of pages in virtual address space. + * + * RETURNS + * TRUE: Success + * FALSE: Failure + */ +BOOL WINAPI VirtualFreeEx( HANDLE process, LPVOID addr, DWORD size, DWORD type ) +{ + NTSTATUS status = NtFreeVirtualMemory( process, &addr, &size, type ); + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; } @@ -1176,11 +136,12 @@ BOOL WINAPI VirtualFree( * TRUE: Success * FALSE: Failure */ -BOOL WINAPI VirtualLock( - LPVOID addr, /* [in] Address of first byte of range to lock */ - DWORD size /* [in] Number of bytes in range to lock */ -) { - return TRUE; +BOOL WINAPI VirtualLock( LPVOID addr, /* [in] Address of first byte of range to lock */ + DWORD size ) /* [in] Number of bytes in range to lock */ +{ + NTSTATUS status = NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ); + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; } @@ -1195,11 +156,12 @@ BOOL WINAPI VirtualLock( * TRUE: Success * FALSE: Failure */ -BOOL WINAPI VirtualUnlock( - LPVOID addr, /* [in] Address of first byte of range */ - DWORD size /* [in] Number of bytes in range */ -) { - return TRUE; +BOOL WINAPI VirtualUnlock( LPVOID addr, /* [in] Address of first byte of range */ + DWORD size ) /* [in] Number of bytes in range */ +{ + NTSTATUS status = NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ); + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; } @@ -1217,42 +179,7 @@ BOOL WINAPI VirtualProtect( DWORD new_prot, /* [in] Desired access protection */ LPDWORD old_prot /* [out] Address of variable to get old protection */ ) { - FILE_VIEW *view; - char *base; - UINT i; - BYTE vprot, *p; - DWORD prot; - - TRACE("%p %08lx %08lx\n", addr, size, new_prot ); - - /* Fix the parameters */ - - size = ROUND_SIZE( addr, size ); - base = ROUND_ADDR( addr, page_mask ); - - if (!(view = VIRTUAL_FindView( base )) || - (base + size > (char *)view->base + view->size)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - - /* Make sure all the pages are committed */ - - p = view->prot + ((base - (char *)view->base) >> page_shift); - VIRTUAL_GetWin32Prot( *p, &prot, NULL ); - for (i = size >> page_shift; i; i--, p++) - { - if (!(*p & VPROT_COMMITTED)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - } - - if (old_prot) *old_prot = prot; - vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED; - return VIRTUAL_SetProt( view, base, size, vprot ); + return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot ); } @@ -1266,16 +193,15 @@ BOOL WINAPI VirtualProtect( * FALSE: Failure */ BOOL WINAPI VirtualProtectEx( - HANDLE handle, /* [in] Handle of process */ + HANDLE process, /* [in] Handle of process */ LPVOID addr, /* [in] Address of region of committed pages */ DWORD size, /* [in] Size of region */ DWORD new_prot, /* [in] Desired access protection */ LPDWORD old_prot /* [out] Address of variable to get old protection */ ) { - if (MapProcessHandle( handle ) == GetCurrentProcessId()) - return VirtualProtect( addr, size, new_prot, old_prot ); - ERR("Unsupported on other process\n"); - return FALSE; + NTSTATUS status = NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot ); + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; } @@ -1292,65 +218,7 @@ DWORD WINAPI VirtualQuery( LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */ DWORD len /* [in] Size of buffer */ ) { - FILE_VIEW *view; - char *base, *alloc_base = 0; - UINT size = 0; - - if (addr >= ADDRESS_SPACE_LIMIT) return 0; - - base = ROUND_ADDR( addr, page_mask ); - - /* Find the view containing the address */ - - EnterCriticalSection(&csVirtual); - view = VIRTUAL_FirstView; - for (;;) - { - if (!view) - { - size = (char *)ADDRESS_SPACE_LIMIT - alloc_base; - break; - } - if ((char *)view->base > base) - { - size = (char *)view->base - alloc_base; - view = NULL; - break; - } - if ((char *)view->base + view->size > base) - { - alloc_base = view->base; - size = view->size; - break; - } - alloc_base = (char *)view->base + view->size; - view = view->next; - } - LeaveCriticalSection(&csVirtual); - - /* Fill the info structure */ - - if (!view) - { - info->State = MEM_FREE; - info->Protect = 0; - info->AllocationProtect = 0; - info->Type = 0; - } - else - { - BYTE vprot = view->prot[(base - alloc_base) >> page_shift]; - VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State ); - for (size = base - alloc_base; size < view->size; size += page_mask+1) - if (view->prot[size >> page_shift] != vprot) break; - info->AllocationProtect = view->protect; - info->Type = MEM_PRIVATE; /* FIXME */ - } - - info->BaseAddress = (LPVOID)base; - info->AllocationBase = (LPVOID)alloc_base; - info->RegionSize = size - (base - alloc_base); - return sizeof(*info); + return VirtualQueryEx( GetCurrentProcess(), addr, info, len ); } @@ -1363,15 +231,277 @@ DWORD WINAPI VirtualQuery( * Number of bytes returned in information buffer */ DWORD WINAPI VirtualQueryEx( - HANDLE handle, /* [in] Handle of process */ + HANDLE process, /* [in] Handle of process */ LPCVOID addr, /* [in] Address of region */ LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */ DWORD len /* [in] Size of buffer */ ) { - if (MapProcessHandle( handle ) == GetCurrentProcessId()) - return VirtualQuery( addr, info, len ); - ERR("Unsupported on other process\n"); - return 0; + DWORD ret; + NTSTATUS status; + + if ((status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret ))) + { + SetLastError( RtlNtStatusToDosError(status) ); + ret = 0; + } + return ret; +} + + +/*********************************************************************** + * CreateFileMappingA (KERNEL32.@) + * Creates a named or unnamed file-mapping object for the specified file + * + * RETURNS + * Handle: Success + * 0: Mapping object does not exist + * NULL: Failure + */ +HANDLE WINAPI CreateFileMappingA( + HANDLE hFile, /* [in] Handle of file to map */ + SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/ + DWORD protect, /* [in] Protection for mapping object */ + DWORD size_high, /* [in] High-order 32 bits of object size */ + DWORD size_low, /* [in] Low-order 32 bits of object size */ + LPCSTR name /* [in] Name of file-mapping object */ ) +{ + WCHAR buffer[MAX_PATH]; + + if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL ); + + if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) + { + SetLastError( ERROR_FILENAME_EXCED_RANGE ); + return 0; + } + return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer ); +} + + +/*********************************************************************** + * CreateFileMappingW (KERNEL32.@) + * See CreateFileMappingA + */ +HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa, + DWORD protect, DWORD size_high, + DWORD size_low, LPCWSTR name ) +{ + static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE; + + HANDLE ret; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + NTSTATUS status; + DWORD access, sec_type; + LARGE_INTEGER size; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = NULL; + attr.Attributes = (sa && sa->bInheritHandle) ? OBJ_INHERIT : 0; + attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL; + attr.SecurityQualityOfService = NULL; + + if (name) + { + RtlInitUnicodeString( &nameW, name ); + attr.ObjectName = &nameW; + } + + sec_type = protect & sec_flags; + protect &= ~sec_flags; + if (!sec_type) sec_type = SEC_COMMIT; + + switch(protect) + { + case 0: + case PAGE_READONLY: + case PAGE_WRITECOPY: + access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ; + break; + case PAGE_READWRITE: + access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE; + break; + default: + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + + if (hFile == INVALID_HANDLE_VALUE) + { + hFile = 0; + if (!size_low && !size_high) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + } + + size.s.LowPart = size_low; + size.s.HighPart = size_high; + + status = NtCreateSection( &ret, access, &attr, &size, protect, sec_type, hFile ); + SetLastError( RtlNtStatusToDosError(status) ); + return ret; +} + + +/*********************************************************************** + * OpenFileMappingA (KERNEL32.@) + * Opens a named file-mapping object. + * + * RETURNS + * Handle: Success + * NULL: Failure + */ +HANDLE WINAPI OpenFileMappingA( + DWORD access, /* [in] Access mode */ + BOOL inherit, /* [in] Inherit flag */ + LPCSTR name ) /* [in] Name of file-mapping object */ +{ + WCHAR buffer[MAX_PATH]; + + if (!name) return OpenFileMappingW( access, inherit, NULL ); + + if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) + { + SetLastError( ERROR_FILENAME_EXCED_RANGE ); + return 0; + } + return OpenFileMappingW( access, inherit, buffer ); +} + + +/*********************************************************************** + * OpenFileMappingW (KERNEL32.@) + * See OpenFileMappingA + */ +HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + HANDLE ret; + NTSTATUS status; + + if (!name) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &nameW; + attr.Attributes = inherit ? OBJ_INHERIT : 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &nameW, name ); + + if (access == FILE_MAP_COPY) access = FILE_MAP_READ; + + if ((status = NtOpenSection( &ret, access, &attr ))) + { + SetLastError( RtlNtStatusToDosError(status) ); + ret = 0; + } + return ret; +} + + +/*********************************************************************** + * MapViewOfFile (KERNEL32.@) + * Maps a view of a file into the address space + * + * RETURNS + * Starting address of mapped view + * NULL: Failure + */ +LPVOID WINAPI MapViewOfFile( + HANDLE mapping, /* [in] File-mapping object to map */ + DWORD access, /* [in] Access mode */ + DWORD offset_high, /* [in] High-order 32 bits of file offset */ + DWORD offset_low, /* [in] Low-order 32 bits of file offset */ + DWORD count /* [in] Number of bytes to map */ +) { + return MapViewOfFileEx( mapping, access, offset_high, + offset_low, count, NULL ); +} + + +/*********************************************************************** + * MapViewOfFileEx (KERNEL32.@) + * Maps a view of a file into the address space + * + * RETURNS + * Starting address of mapped view + * NULL: Failure + */ +LPVOID WINAPI MapViewOfFileEx( + HANDLE handle, /* [in] File-mapping object to map */ + DWORD access, /* [in] Access mode */ + DWORD offset_high, /* [in] High-order 32 bits of file offset */ + DWORD offset_low, /* [in] Low-order 32 bits of file offset */ + DWORD count, /* [in] Number of bytes to map */ + LPVOID addr /* [in] Suggested starting address for mapped view */ +) { + NTSTATUS status; + LARGE_INTEGER offset; + ULONG protect; + + offset.s.LowPart = offset_low; + offset.s.HighPart = offset_high; + + if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE; + else if (access & FILE_MAP_READ) protect = PAGE_READONLY; + else if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY; + else protect = PAGE_NOACCESS; + + if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset, + &count, ViewShare, 0, protect ))) + { + SetLastError( RtlNtStatusToDosError(status) ); + addr = NULL; + } + return addr; +} + + +/*********************************************************************** + * UnmapViewOfFile (KERNEL32.@) + * Unmaps a mapped view of a file. + * + * NOTES + * Should addr be an LPCVOID? + * + * RETURNS + * TRUE: Success + * FALSE: Failure + */ +BOOL WINAPI UnmapViewOfFile( LPVOID addr ) /* [in] Address where mapped view begins */ +{ + NTSTATUS status = NtUnmapViewOfSection( GetCurrentProcess(), addr ); + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; +} + + +/*********************************************************************** + * FlushViewOfFile (KERNEL32.@) + * Writes to the disk a byte range within a mapped view of a file + * + * RETURNS + * TRUE: Success + * FALSE: Failure + */ +BOOL WINAPI FlushViewOfFile( LPCVOID base, /* [in] Start address of byte range to flush */ + DWORD size ) /* [in] Number of bytes in range */ +{ + NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 ); + if (status) + { + if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS; + else SetLastError( RtlNtStatusToDosError(status) ); + } + return !status; } @@ -1387,6 +517,7 @@ BOOL WINAPI IsBadReadPtr( UINT size ) /* [in] Size of block */ { if (!size) return FALSE; /* handle 0 size case w/o reference */ + if (!page_size) page_size = getpagesize(); __TRY { volatile const char *p = ptr; @@ -1420,6 +551,7 @@ BOOL WINAPI IsBadWritePtr( UINT size ) /* [in] Size of block in bytes */ { if (!size) return FALSE; /* handle 0 size case w/o reference */ + if (!page_size) page_size = getpagesize(); __TRY { volatile char *p = ptr; @@ -1518,350 +650,3 @@ BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max ) __ENDTRY return FALSE; } - - -/*********************************************************************** - * CreateFileMappingA (KERNEL32.@) - * Creates a named or unnamed file-mapping object for the specified file - * - * RETURNS - * Handle: Success - * 0: Mapping object does not exist - * NULL: Failure - */ -HANDLE WINAPI CreateFileMappingA( - HANDLE hFile, /* [in] Handle of file to map */ - SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/ - DWORD protect, /* [in] Protection for mapping object */ - DWORD size_high, /* [in] High-order 32 bits of object size */ - DWORD size_low, /* [in] Low-order 32 bits of object size */ - LPCSTR name /* [in] Name of file-mapping object */ ) -{ - WCHAR buffer[MAX_PATH]; - - if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL ); - - if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) - { - SetLastError( ERROR_FILENAME_EXCED_RANGE ); - return 0; - } - return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer ); -} - - -/*********************************************************************** - * CreateFileMappingW (KERNEL32.@) - * See CreateFileMappingA - */ -HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa, - DWORD protect, DWORD size_high, - DWORD size_low, LPCWSTR name ) -{ - HANDLE ret; - BYTE vprot; - DWORD len = name ? strlenW(name) : 0; - - /* Check parameters */ - - TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n", - hFile, sa, protect, size_high, size_low, debugstr_w(name) ); - - if (len > MAX_PATH) - { - SetLastError( ERROR_FILENAME_EXCED_RANGE ); - return 0; - } - - vprot = VIRTUAL_GetProt( protect ); - if (protect & SEC_RESERVE) - { - if (hFile != INVALID_HANDLE_VALUE) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - } - else vprot |= VPROT_COMMITTED; - if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE; - if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE; - - /* Create the server object */ - - if (hFile == INVALID_HANDLE_VALUE) hFile = 0; - SERVER_START_REQ( create_mapping ) - { - req->file_handle = hFile; - req->size_high = size_high; - req->size_low = size_low; - req->protect = vprot; - req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); - wine_server_add_data( req, name, len * sizeof(WCHAR) ); - SetLastError(0); - wine_server_call_err( req ); - ret = reply->handle; - } - SERVER_END_REQ; - return ret; -} - - -/*********************************************************************** - * OpenFileMappingA (KERNEL32.@) - * Opens a named file-mapping object. - * - * RETURNS - * Handle: Success - * NULL: Failure - */ -HANDLE WINAPI OpenFileMappingA( - DWORD access, /* [in] Access mode */ - BOOL inherit, /* [in] Inherit flag */ - LPCSTR name ) /* [in] Name of file-mapping object */ -{ - WCHAR buffer[MAX_PATH]; - - if (!name) return OpenFileMappingW( access, inherit, NULL ); - - if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) - { - SetLastError( ERROR_FILENAME_EXCED_RANGE ); - return 0; - } - return OpenFileMappingW( access, inherit, buffer ); -} - - -/*********************************************************************** - * OpenFileMappingW (KERNEL32.@) - * See OpenFileMappingA - */ -HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name) -{ - HANDLE ret; - DWORD len = name ? strlenW(name) : 0; - if (len >= MAX_PATH) - { - SetLastError( ERROR_FILENAME_EXCED_RANGE ); - return 0; - } - SERVER_START_REQ( open_mapping ) - { - req->access = access; - req->inherit = inherit; - wine_server_add_data( req, name, len * sizeof(WCHAR) ); - wine_server_call_err( req ); - ret = reply->handle; - } - SERVER_END_REQ; - return ret; -} - - -/*********************************************************************** - * MapViewOfFile (KERNEL32.@) - * Maps a view of a file into the address space - * - * RETURNS - * Starting address of mapped view - * NULL: Failure - */ -LPVOID WINAPI MapViewOfFile( - HANDLE mapping, /* [in] File-mapping object to map */ - DWORD access, /* [in] Access mode */ - DWORD offset_high, /* [in] High-order 32 bits of file offset */ - DWORD offset_low, /* [in] Low-order 32 bits of file offset */ - DWORD count /* [in] Number of bytes to map */ -) { - return MapViewOfFileEx( mapping, access, offset_high, - offset_low, count, NULL ); -} - - -/*********************************************************************** - * MapViewOfFileEx (KERNEL32.@) - * Maps a view of a file into the address space - * - * RETURNS - * Starting address of mapped view - * NULL: Failure - */ -LPVOID WINAPI MapViewOfFileEx( - HANDLE handle, /* [in] File-mapping object to map */ - DWORD access, /* [in] Access mode */ - DWORD offset_high, /* [in] High-order 32 bits of file offset */ - DWORD offset_low, /* [in] Low-order 32 bits of file offset */ - DWORD count, /* [in] Number of bytes to map */ - LPVOID addr /* [in] Suggested starting address for mapped view */ -) { - FILE_VIEW *view; - UINT size = 0; - int flags = MAP_PRIVATE; - int unix_handle = -1; - int prot, res; - void *base, *ptr = (void *)-1, *ret; - DWORD size_low, size_high, header_size, shared_size; - HANDLE shared_file; - BOOL removable; - - /* Check parameters */ - - if ((offset_low & granularity_mask) || - (addr && ((UINT_PTR)addr & granularity_mask))) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return NULL; - } - - SERVER_START_REQ( get_mapping_info ) - { - req->handle = handle; - res = wine_server_call_err( req ); - prot = reply->protect; - base = reply->base; - size_low = reply->size_low; - size_high = reply->size_high; - header_size = reply->header_size; - shared_file = reply->shared_file; - shared_size = reply->shared_size; - removable = (reply->drive_type == DRIVE_REMOVABLE || - reply->drive_type == DRIVE_CDROM); - } - SERVER_END_REQ; - if (res) goto error; - - if ((unix_handle = FILE_GetUnixHandle( handle, 0 )) == -1) goto error; - - if (prot & VPROT_IMAGE) - return map_image( handle, unix_handle, base, size_low, header_size, - shared_file, shared_size, removable ); - - - if (size_high) - ERR("Sizes larger than 4Gb not supported\n"); - - if ((offset_low >= size_low) || - (count > size_low - offset_low)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - goto error; - } - if (count) size = ROUND_SIZE( offset_low, count ); - else size = size_low - offset_low; - - switch(access) - { - case FILE_MAP_ALL_ACCESS: - case FILE_MAP_WRITE: - case FILE_MAP_WRITE | FILE_MAP_READ: - if (!(prot & VPROT_WRITE)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - goto error; - } - flags = MAP_SHARED; - /* fall through */ - case FILE_MAP_READ: - case FILE_MAP_COPY: - case FILE_MAP_COPY | FILE_MAP_READ: - if (prot & VPROT_READ) break; - /* fall through */ - default: - SetLastError( ERROR_INVALID_PARAMETER ); - goto error; - } - - /* FIXME: If a mapping is created with SEC_RESERVE and a process, - * which has a view of this mapping commits some pages, they will - * appear commited in all other processes, which have the same - * view created. Since we don`t support this yet, we create the - * whole mapping commited. - */ - prot |= VPROT_COMMITTED; - - /* Reserve a properly aligned area */ - - if ((ptr = anon_mmap_aligned( addr, size, PROT_NONE, 0 )) == (void *)-1) goto error; - - /* Map the file */ - - TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset_low ); - - ret = VIRTUAL_mmap( unix_handle, ptr, size, offset_low, offset_high, - VIRTUAL_GetUnixProt( prot ), flags | MAP_FIXED, &removable ); - if (ret != ptr) - { - ERR( "VIRTUAL_mmap %p %x %lx%08lx failed\n", ptr, size, offset_high, offset_low ); - goto error; - } - if (removable) handle = 0; /* don't keep handle open on removable media */ - - if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle ))) - { - SetLastError( ERROR_OUTOFMEMORY ); - goto error; - } - if (unix_handle != -1) close( unix_handle ); - return ptr; - -error: - if (unix_handle != -1) close( unix_handle ); - if (ptr != (void *)-1) munmap( ptr, size ); - return NULL; -} - - -/*********************************************************************** - * FlushViewOfFile (KERNEL32.@) - * Writes to the disk a byte range within a mapped view of a file - * - * RETURNS - * TRUE: Success - * FALSE: Failure - */ -BOOL WINAPI FlushViewOfFile( - LPCVOID base, /* [in] Start address of byte range to flush */ - DWORD cbFlush /* [in] Number of bytes in range */ -) { - FILE_VIEW *view; - void *addr = ROUND_ADDR( base, page_mask ); - - TRACE("FlushViewOfFile at %p for %ld bytes\n", - base, cbFlush ); - - if (!(view = VIRTUAL_FindView( addr ))) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - if (!cbFlush) cbFlush = view->size; - if (!msync( addr, cbFlush, MS_SYNC )) return TRUE; - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; -} - - -/*********************************************************************** - * UnmapViewOfFile (KERNEL32.@) - * Unmaps a mapped view of a file. - * - * NOTES - * Should addr be an LPCVOID? - * - * RETURNS - * TRUE: Success - * FALSE: Failure - */ -BOOL WINAPI UnmapViewOfFile( - LPVOID addr /* [in] Address where mapped view begins */ -) { - FILE_VIEW *view; - void *base = ROUND_ADDR( addr, page_mask ); - if (!(view = VIRTUAL_FindView( base )) || (base != view->base)) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - VIRTUAL_DeleteView( view ); - return TRUE; -} diff --git a/server/mapping.c b/server/mapping.c index 0c7e4d96fc..d9e79c6156 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -375,9 +375,7 @@ DECL_HANDLER(create_mapping) req->protect, req->file_handle, get_req_data(), get_req_data_size() ))) { - int access = FILE_MAP_ALL_ACCESS; - if (!(req->protect & VPROT_WRITE)) access &= ~FILE_MAP_WRITE; - reply->handle = alloc_handle( current->process, obj, access, req->inherit ); + reply->handle = alloc_handle( current->process, obj, req->access, req->inherit ); release_object( obj ); } } diff --git a/server/protocol.def b/server/protocol.def index 9d4f8f37a7..fd526e69ab 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1043,6 +1043,7 @@ enum char_info_mode int size_high; /* mapping size */ int size_low; /* mapping size */ int protect; /* protection flags (see below) */ + unsigned int access; /* wanted access rights */ int inherit; /* inherit flag */ obj_handle_t file_handle; /* file handle */ VARARG(name,unicode_str); /* object name */ diff --git a/server/trace.c b/server/trace.c index c96863d1a7..864e146e9f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1213,6 +1213,7 @@ static void dump_create_mapping_request( const struct create_mapping_request *re fprintf( stderr, " size_high=%d,", req->size_high ); fprintf( stderr, " size_low=%d,", req->size_low ); fprintf( stderr, " protect=%d,", req->protect ); + fprintf( stderr, " access=%08x,", req->access ); fprintf( stderr, " inherit=%d,", req->inherit ); fprintf( stderr, " file_handle=%d,", req->file_handle ); fprintf( stderr, " name=" );