Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
341b7dce
Commit
341b7dce
authored
Sep 17, 2002
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented the ntdll virtual memory functions, and made the kernel
functions use them.
parent
4131aaa9
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1965 additions
and
1686 deletions
+1965
-1686
kernel32.spec
dlls/kernel/kernel32.spec
+1
-1
Makefile.in
dlls/ntdll/Makefile.in
+1
-0
heap.c
dlls/ntdll/heap.c
+28
-22
nt.c
dlls/ntdll/nt.c
+0
-73
ntdll.spec
dlls/ntdll/ntdll.spec
+22
-22
virtual.c
dlls/ntdll/virtual.c
+1535
-0
winbase.h
include/winbase.h
+5
-4
server_protocol.h
include/wine/server_protocol.h
+2
-1
winnt.h
include/winnt.h
+7
-0
winternl.h
include/winternl.h
+16
-0
virtual.c
memory/virtual.c
+345
-1560
mapping.c
server/mapping.c
+1
-3
protocol.def
server/protocol.def
+1
-0
trace.c
server/trace.c
+1
-0
No files found.
dlls/kernel/kernel32.spec
View file @
341b7dce
...
...
@@ -940,7 +940,7 @@ init MAIN_KernelInit
@ stdcall SwitchToThread() SwitchToThread
@ forward TryEnterCriticalSection ntdll.RtlTryEnterCriticalSection
@ stdcall VirtualAllocEx(long ptr long long long) VirtualAllocEx
@ st
ub
VirtualFreeEx
@ st
dcall VirtualFreeEx(long ptr long long)
VirtualFreeEx
@ stub WriteFileGather
#Win98 and higher
...
...
dlls/ntdll/Makefile.in
View file @
341b7dce
...
...
@@ -111,6 +111,7 @@ C_SRCS = \
signal_powerpc.c
\
signal_sparc.c
\
sync.c
\
virtual.c
\
time.c
\
wcstring.c
...
...
dlls/ntdll/heap.c
View file @
341b7dce
...
...
@@ -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
;
...
...
dlls/ntdll/nt.c
View file @
341b7dce
...
...
@@ -418,41 +418,6 @@ NTSTATUS WINAPI NtQueryInformationToken(
*/
/******************************************************************************
* 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.@]
*/
NTSTATUS
WINAPI
NtQuerySection
(
...
...
@@ -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
*/
...
...
dlls/ntdll/ntdll.spec
View file @
341b7dce
...
...
@@ -63,7 +63,7 @@
@ stub NtAlertThread
@ stdcall NtAllocateLocallyUniqueId(ptr) NtAllocateLocallyUniqueId
@ stdcall NtAllocateUuids(ptr ptr ptr) NtAllocateUuids
@ st
ub
NtAllocateVirtualMemory
@ st
dcall 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
@ st
ub
NtFlushVirtualMemory
@ st
dcall NtFlushVirtualMemory(long ptr ptr long)
NtFlushVirtualMemory
@ stub NtFlushWriteBuffer
@ st
ub
NtFreeVirtualMemory
@ st
dcall 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
@ st
ub
NtLockVirtualMemory
@ st
dcall 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
@ st
ub
NtProtectVirtualMemory
@ st
dcall 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
@ st
ub
NtQueryVirtualMemory
@ st
dcall 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
@ st
ub
NtUnlockVirtualMemory
@ st
ub
NtUnmapViewOfSection
@ st
dcall NtUnlockVirtualMemory(long ptr ptr long)
NtUnlockVirtualMemory
@ st
dcall NtUnmapViewOfSection(long ptr)
NtUnmapViewOfSection
@ stub NtVdmControl
@ stub NtW32Call
@ stub NtWaitForMultipleObjects
...
...
@@ -581,7 +581,7 @@
@ stub ZwAlertThread
@ stub ZwAllocateLocallyUniqueId
@ stub ZwAllocateUuids
@ st
ub Zw
AllocateVirtualMemory
@ st
dcall ZwAllocateVirtualMemory(long ptr ptr ptr long long) Nt
AllocateVirtualMemory
@ 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
@ st
ub Zw
FlushVirtualMemory
@ st
dcall ZwFlushVirtualMemory(long ptr ptr long) Nt
FlushVirtualMemory
@ stub ZwFlushWriteBuffer
@ st
ub Zw
FreeVirtualMemory
@ st
dcall ZwFreeVirtualMemory(long ptr ptr long) Nt
FreeVirtualMemory
@ 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
@ st
ub Zw
LockVirtualMemory
@ st
dcall ZwLockVirtualMemory(long ptr ptr long) Nt
LockVirtualMemory
@ 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
@ st
ub Zw
ProtectVirtualMemory
@ st
dcall ZwProtectVirtualMemory(long ptr ptr long ptr) Nt
ProtectVirtualMemory
@ stub ZwPulseEvent
@ stub ZwQueryAttributesFile
@ stub ZwQueryDefaultLocale
...
...
@@ -693,7 +693,7 @@
@ stub ZwQueryTimer
@ stub ZwQueryTimerResolution
@ stdcall ZwQueryValueKey(long ptr long ptr long ptr) NtQueryValueKey
@ st
ub Zw
QueryVirtualMemory
@ st
dcall ZwQueryVirtualMemory(long ptr long ptr long ptr) Nt
QueryVirtualMemory
@ stdcall ZwQueryVolumeInformationFile(long ptr ptr long long) NtQueryVolumeInformationFile
@ stub ZwRaiseException
@ stub ZwRaiseHardError
...
...
@@ -756,8 +756,8 @@
@ stub ZwUnloadDriver
@ stdcall ZwUnloadKey(long) NtUnloadKey
@ stub ZwUnlockFile
@ st
ub Zw
UnlockVirtualMemory
@ st
ub Zw
UnmapViewOfSection
@ st
dcall ZwUnlockVirtualMemory(long ptr ptr long) Nt
UnlockVirtualMemory
@ st
dcall ZwUnmapViewOfSection(long ptr) Nt
UnmapViewOfSection
@ stub ZwVdmControl
@ stub ZwW32Call
@ stub ZwWaitForMultipleObjects
...
...
dlls/ntdll/virtual.c
0 → 100644
View file @
341b7dce
/*
* 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 <assert.h>
#include <errno.h>
#ifdef HAVE_SYS_ERRNO_H
#include <sys/errno.h>
#endif
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#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
(
"
\n
Dump 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
;
}
include/winbase.h
View file @
341b7dce
...
...
@@ -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
);
...
...
include/wine/server_protocol.h
View file @
341b7dce
...
...
@@ -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 8
1
#define SERVER_PROTOCOL_VERSION 8
2
#endif
/* __WINE_WINE_SERVER_PROTOCOL_H */
include/winnt.h
View file @
341b7dce
...
...
@@ -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 */
...
...
include/winternl.h
View file @
341b7dce
...
...
@@ -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
);
...
...
memory/virtual.c
View file @
341b7dce
...
...
@@ -21,110 +21,25 @@
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <errno.h>
#ifdef HAVE_SYS_ERRNO_H
#include <sys/errno.h>
#endif
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_
SYS_MMAN
_H
#
include <sys/mman
.h>
#ifdef HAVE_
UNISTD
_H
#
include <unistd
.h>
#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,1389 +49,202 @@ 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
(
"
\n
Dump 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.
* VirtualAlloc (KERNEL32.@)
* Reserves or commits a region of pages in virtual address space
*
* RETURNS
*
View: Succes
s
*
Base address of allocated region of page
s
* NULL: Failure
*/
static
FILE_VIEW
*
VIRTUAL_FindView
(
const
void
*
addr
)
/* [in] Address */
LPVOID
WINAPI
VirtualAlloc
(
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 */
{
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
;
return
VirtualAllocEx
(
GetCurrentProcess
(),
addr
,
size
,
type
,
protect
);
}
/***********************************************************************
*
VIRTUAL_CreateView
*
VirtualAllocEx (KERNEL32.@)
*
*
Create a new view and add it in the linked list
.
*
Seems to be just as VirtualAlloc, but with process handle
.
*/
static
FILE_VIEW
*
VIRTUAL_CreateView
(
void
*
base
,
UINT
size
,
UINT
flags
,
BYTE
vprot
,
HANDLE
mapping
)
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 */
{
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
);
}
LPVOID
ret
;
NTSTATUS
status
;
/***********************************************************************
* 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
((
status
=
NtAllocateVirtualMemory
(
hProcess
,
&
ret
,
addr
,
&
size
,
type
,
protect
)))
{
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
;
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
ret
=
NULL
;
}
return
pro
t
;
return
re
t
;
}
/***********************************************************************
* VIRTUAL_GetWin32Prot
*
* Convert page protections to Win32 flags.
* VirtualFree (KERNEL32.@)
* Release or decommits a region of pages in virtual address space.
*
* RETURNS
* None
* TRUE: Success
* FALSE: Failure
*/
static
void
VIRTUAL_GetWin32Prot
(
BYTE
vprot
,
/* [in] Page protection flag
s */
DWORD
*
protect
,
/* [out] Location to store Win32 protection flags
*/
DWORD
*
state
/* [out] Location to store mem state flag
*/
BOOL
WINAPI
VirtualFree
(
LPVOID
addr
,
/* [in] Address of region of committed page
s */
DWORD
size
,
/* [in] Size of region
*/
DWORD
type
/* [in] Type of operation
*/
)
{
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
;
return
VirtualFreeEx
(
GetCurrentProcess
(),
addr
,
size
,
type
);
}
/***********************************************************************
* VIRTUAL_GetProt
*
* Build page protections from Win32 flags.
* VirtualFreeEx (KERNEL32.@)
* Release or decommits a region of pages in virtual address space.
*
* RETURNS
* Value of page protection flags
* TRUE: Success
* FALSE: Failure
*/
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
;
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
;
}
/***********************************************************************
* VIRTUAL_SetProt
* VirtualLock (KERNEL32.@)
* Locks the specified region of virtual address space
*
* Change the protection of a range of pages.
* NOTE
* Always returns TRUE
*
* 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
)
BOOL
WINAPI
VirtualLock
(
LPVOID
addr
,
/* [in] Address of first byte of range to lock */
DWORD
size
)
/* [in] Number of bytes in range to lock */
{
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
;
NTSTATUS
status
=
NtLockVirtualMemory
(
GetCurrentProcess
(),
&
addr
,
&
size
,
1
);
if
(
status
)
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
return
!
status
;
}
/***********************************************************************
* do_relocations
* VirtualUnlock (KERNEL32.@)
* Unlocks a range of pages in the virtual address space
*
* 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
* NOTE
* Always returns TRUE
*
* 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
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
DWORD
VIRTUAL_HandleFault
(
LPCVOID
addr
)
BOOL
WINAPI
VirtualUnlock
(
LPVOID
addr
,
/* [in] Address of first byte of range */
DWORD
size
)
/* [in] Number of bytes in range */
{
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
;
NTSTATUS
status
=
NtUnlockVirtualMemory
(
GetCurrentProcess
(),
&
addr
,
&
size
,
1
);
if
(
status
)
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
return
!
status
;
}
/***********************************************************************
* 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.@)
* Reserves or commits a region of pages in virtual address space
*
* RETURNS
* Base address of allocated region of pages
* NULL: Failure
*/
LPVOID
WINAPI
VirtualAlloc
(
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 */
{
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
;
}
/***********************************************************************
* VirtualAllocEx (KERNEL32.@)
*
* Seems to be just as VirtualAlloc, but with process handle.
*/
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
;
}
/***********************************************************************
* VirtualFree (KERNEL32.@)
* Release or decommits a region of pages in virtual address space.
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL
WINAPI
VirtualFree
(
LPVOID
addr
,
/* [in] Address of region of committed pages */
DWORD
size
,
/* [in] Size of region */
DWORD
type
/* [in] Type of operation */
)
{
FILE_VIEW
*
view
;
char
*
base
;
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
);
}
/***********************************************************************
* VirtualLock (KERNEL32.@)
* Locks the specified region of virtual address space
*
* NOTE
* Always returns TRUE
*
* RETURNS
* 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
;
}
/***********************************************************************
* VirtualUnlock (KERNEL32.@)
* Unlocks a range of pages in the virtual address space
*
* NOTE
* Always returns TRUE
*
* RETURNS
* 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
;
}
/***********************************************************************
* VirtualProtect (KERNEL32.@)
* Changes the access protection on a region of committed pages
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL
WINAPI
VirtualProtect
(
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 */
)
{
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
);
}
/***********************************************************************
* VirtualProtectEx (KERNEL32.@)
* Changes the access protection on a region of committed pages in the
* virtual address space of a specified process
* VirtualProtect (KERNEL32.@)
* Changes the access protection on a region of committed pages
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL
WINAPI
VirtualProtectEx
(
HANDLE
handle
,
/* [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
;
}
/***********************************************************************
* VirtualQuery (KERNEL32.@)
* Provides info about a range of pages in virtual address space
*
* RETURNS
* Number of bytes returned in information buffer
* or 0 if addr is >= 0xc0000000 (kernel space).
*/
DWORD
WINAPI
VirtualQuery
(
LPCVOID
addr
,
/* [in] Address of region */
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
);
}
/***********************************************************************
* VirtualQueryEx (KERNEL32.@)
* Provides info about a range of pages in virtual address space of a
* specified process
*
* RETURNS
* Number of bytes returned in information buffer
*/
DWORD
WINAPI
VirtualQueryEx
(
HANDLE
handle
,
/* [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
;
}
/***********************************************************************
* IsBadReadPtr (KERNEL32.@)
*
* RETURNS
* FALSE: Process has read access to entire block
* TRUE: Otherwise
*/
BOOL
WINAPI
IsBadReadPtr
(
LPCVOID
ptr
,
/* [in] Address of memory block */
UINT
size
)
/* [in] Size of block */
{
if
(
!
size
)
return
FALSE
;
/* handle 0 size case w/o reference */
__TRY
{
volatile
const
char
*
p
=
ptr
;
char
dummy
;
UINT
count
=
size
;
while
(
count
>
page_size
)
{
dummy
=
*
p
;
p
+=
page_size
;
count
-=
page_size
;
}
dummy
=
p
[
0
];
dummy
=
p
[
count
-
1
];
}
__EXCEPT
(
page_fault
)
{
return
TRUE
;
}
__ENDTRY
return
FALSE
;
}
/***********************************************************************
* IsBadWritePtr (KERNEL32.@)
*
* RETURNS
* FALSE: Process has write access to entire block
* TRUE: Otherwise
*/
BOOL
WINAPI
IsBadWritePtr
(
LPVOID
ptr
,
/* [in] Address of memory block */
UINT
size
)
/* [in] Size of block in bytes */
{
if
(
!
size
)
return
FALSE
;
/* handle 0 size case w/o reference */
__TRY
{
volatile
char
*
p
=
ptr
;
UINT
count
=
size
;
while
(
count
>
page_size
)
{
*
p
|=
0
;
p
+=
page_size
;
count
-=
page_size
;
}
p
[
0
]
|=
0
;
p
[
count
-
1
]
|=
0
;
}
__EXCEPT
(
page_fault
)
{
return
TRUE
;
}
__ENDTRY
return
FALSE
;
}
/***********************************************************************
* IsBadHugeReadPtr (KERNEL32.@)
* RETURNS
* FALSE: Process has read access to entire block
* TRUE: Otherwise
*/
BOOL
WINAPI
IsBadHugeReadPtr
(
LPCVOID
ptr
,
/* [in] Address of memory block */
UINT
size
/* [in] Size of block */
)
{
return
IsBadReadPtr
(
ptr
,
size
);
}
/***********************************************************************
* IsBadHugeWritePtr (KERNEL32.@)
* RETURNS
* FALSE: Process has write access to entire block
* TRUE: Otherwise
*/
BOOL
WINAPI
IsBadHugeWritePtr
(
LPVOID
ptr
,
/* [in] Address of memory block */
UINT
size
/* [in] Size of block */
* FALSE: Failure
*/
BOOL
WINAPI
VirtualProtect
(
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 */
)
{
return
IsBadWritePtr
(
ptr
,
size
);
return
VirtualProtectEx
(
GetCurrentProcess
(),
addr
,
size
,
new_prot
,
old_prot
);
}
/***********************************************************************
* IsBadCodePtr (KERNEL32.@)
* VirtualProtectEx (KERNEL32.@)
* Changes the access protection on a region of committed pages in the
* virtual address space of a specified process
*
* RETURNS
*
FALSE: Process has read access to specified memory
*
TRUE: Otherwis
e
*
TRUE: Success
*
FALSE: Failur
e
*/
BOOL
WINAPI
IsBadCodePtr
(
FARPROC
ptr
)
/* [in] Address of function */
BOOL
WINAPI
VirtualProtectEx
(
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 */
)
{
return
IsBadReadPtr
(
ptr
,
1
);
NTSTATUS
status
=
NtProtectVirtualMemory
(
process
,
&
addr
,
&
size
,
new_prot
,
old_prot
);
if
(
status
)
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
return
!
status
;
}
/***********************************************************************
* IsBadStringPtrA (KERNEL32.@)
* VirtualQuery (KERNEL32.@)
* Provides info about a range of pages in virtual address space
*
* RETURNS
*
FALSE: Read access to all bytes in string
*
TRUE: Else
*
Number of bytes returned in information buffer
*
or 0 if addr is >= 0xc0000000 (kernel space).
*/
BOOL
WINAPI
IsBadStringPtrA
(
LPCSTR
str
,
/* [in] Address of string */
UINT
max
)
/* [in] Maximum size of string */
{
__TRY
{
volatile
const
char
*
p
=
str
;
while
(
p
!=
str
+
max
)
if
(
!*
p
++
)
break
;
}
__EXCEPT
(
page_fault
)
{
return
TRUE
;
}
__ENDTRY
return
FALSE
;
DWORD
WINAPI
VirtualQuery
(
LPCVOID
addr
,
/* [in] Address of region */
LPMEMORY_BASIC_INFORMATION
info
,
/* [out] Address of info buffer */
DWORD
len
/* [in] Size of buffer */
)
{
return
VirtualQueryEx
(
GetCurrentProcess
(),
addr
,
info
,
len
);
}
/***********************************************************************
* IsBadStringPtrW (KERNEL32.@)
* See IsBadStringPtrA
* VirtualQueryEx (KERNEL32.@)
* Provides info about a range of pages in virtual address space of a
* specified process
*
* RETURNS
* Number of bytes returned in information buffer
*/
BOOL
WINAPI
IsBadStringPtrW
(
LPCWSTR
str
,
UINT
max
)
DWORD
WINAPI
VirtualQueryEx
(
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 */
)
{
__TRY
DWORD
ret
;
NTSTATUS
status
;
if
((
status
=
NtQueryVirtualMemory
(
process
,
addr
,
MemoryBasicInformation
,
info
,
len
,
&
ret
)))
{
volatile
const
WCHAR
*
p
=
str
;
while
(
p
!=
str
+
max
)
if
(
!*
p
++
)
break
;
SetLastError
(
RtlNtStatusToDosError
(
status
)
)
;
ret
=
0
;
}
__EXCEPT
(
page_fault
)
{
return
TRUE
;
}
__ENDTRY
return
FALSE
;
return
ret
;
}
...
...
@@ -1558,50 +286,62 @@ 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
;
BYTE
vprot
;
DWORD
len
=
name
?
strlenW
(
name
)
:
0
;
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
;
/* Check parameters */
if
(
name
)
{
RtlInitUnicodeString
(
&
nameW
,
name
);
attr
.
ObjectName
=
&
nameW
;
}
TRACE
(
"(%x,%p,%08lx,%08lx%08lx,%s)
\n
"
,
hFile
,
sa
,
protect
,
size_high
,
size_low
,
debugstr_w
(
name
)
);
sec_type
=
protect
&
sec_flags
;
protect
&=
~
sec_flags
;
if
(
!
sec_type
)
sec_type
=
SEC_COMMIT
;
if
(
len
>
MAX_PATH
)
switch
(
protect
)
{
SetLastError
(
ERROR_FILENAME_EXCED_RANGE
);
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
;
}
vprot
=
VIRTUAL_GetProt
(
protect
);
if
(
protect
&
SEC_RESERVE
)
if
(
hFile
==
INVALID_HANDLE_VALUE
)
{
if
(
hFile
!=
INVALID_HANDLE_VALUE
)
hFile
=
0
;
if
(
!
size_low
&&
!
size_high
)
{
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 */
size
.
s
.
LowPart
=
size_low
;
size
.
s
.
HighPart
=
size_high
;
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
;
status
=
NtCreateSection
(
&
ret
,
access
,
&
attr
,
&
size
,
protect
,
sec_type
,
hFile
);
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
return
ret
;
}
...
...
@@ -1638,22 +378,31 @@ HANDLE WINAPI OpenFileMappingA(
*/
HANDLE
WINAPI
OpenFileMappingW
(
DWORD
access
,
BOOL
inherit
,
LPCWSTR
name
)
{
OBJECT_ATTRIBUTES
attr
;
UNICODE_STRING
nameW
;
HANDLE
ret
;
DWORD
len
=
name
?
strlenW
(
name
)
:
0
;
if
(
len
>=
MAX_PATH
)
NTSTATUS
status
;
if
(
!
name
)
{
SetLastError
(
ERROR_
FILENAME_EXCED_RANGE
);
SetLastError
(
ERROR_
INVALID_PARAMETER
);
return
0
;
}
SERVER_START_REQ
(
open_mapping
)
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
)))
{
req
->
access
=
access
;
req
->
inherit
=
inherit
;
wine_server_add_data
(
req
,
name
,
len
*
sizeof
(
WCHAR
)
);
wine_server_call_err
(
req
);
ret
=
reply
->
handle
;
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
ret
=
0
;
}
SERVER_END_REQ
;
return
ret
;
}
...
...
@@ -1694,174 +443,210 @@ LPVOID WINAPI MapViewOfFileEx(
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
;
}
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
;
SERVER_START_REQ
(
get_mapping_info
)
if
((
status
=
NtMapViewOfSection
(
handle
,
GetCurrentProcess
(),
&
addr
,
0
,
0
,
&
offset
,
&
count
,
ViewShare
,
0
,
protect
)))
{
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
);
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
addr
=
NULL
;
}
SERVER_END_REQ
;
if
(
res
)
goto
error
;
if
((
unix_handle
=
FILE_GetUnixHandle
(
handle
,
0
))
==
-
1
)
goto
error
;
return
addr
;
}
if
(
prot
&
VPROT_IMAGE
)
return
map_image
(
handle
,
unix_handle
,
base
,
size_low
,
header_size
,
shared_file
,
shared_size
,
removable
);
/***********************************************************************
* 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
;
}
if
(
size_high
)
ERR
(
"Sizes larger than 4Gb not supported
\n
"
);
if
((
offset_low
>=
size_low
)
||
(
count
>
size_low
-
offset_low
))
/***********************************************************************
* 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
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
)
;
goto
error
;
if
(
status
==
STATUS_NOT_MAPPED_DATA
)
status
=
STATUS_SUCCESS
;
else
SetLastError
(
RtlNtStatusToDosError
(
status
)
)
;
}
if
(
count
)
size
=
ROUND_SIZE
(
offset_low
,
count
)
;
else
size
=
size_low
-
offset_low
;
return
!
status
;
}
switch
(
access
)
/***********************************************************************
* IsBadReadPtr (KERNEL32.@)
*
* RETURNS
* FALSE: Process has read access to entire block
* TRUE: Otherwise
*/
BOOL
WINAPI
IsBadReadPtr
(
LPCVOID
ptr
,
/* [in] Address of memory block */
UINT
size
)
/* [in] Size of block */
{
if
(
!
size
)
return
FALSE
;
/* handle 0 size case w/o reference */
if
(
!
page_size
)
page_size
=
getpagesize
();
__TRY
{
case
FILE_MAP_ALL_ACCESS
:
case
FILE_MAP_WRITE
:
case
FILE_MAP_WRITE
|
FILE_MAP_READ
:
if
(
!
(
prot
&
VPROT_WRITE
))
volatile
const
char
*
p
=
ptr
;
char
dummy
;
UINT
count
=
size
;
while
(
count
>
page_size
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
goto
error
;
dummy
=
*
p
;
p
+=
page_size
;
count
-=
page_size
;
}
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
;
dummy
=
p
[
0
];
dummy
=
p
[
count
-
1
];
}
__EXCEPT
(
page_fault
)
{
return
TRUE
;
}
__ENDTRY
return
FALSE
;
}
/* 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
;
/***********************************************************************
* IsBadWritePtr (KERNEL32.@)
*
* RETURNS
* FALSE: Process has write access to entire block
* TRUE: Otherwise
*/
BOOL
WINAPI
IsBadWritePtr
(
LPVOID
ptr
,
/* [in] Address of memory block */
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
;
UINT
count
=
size
;
/* Map the file */
while
(
count
>
page_size
)
{
*
p
|=
0
;
p
+=
page_size
;
count
-=
page_size
;
}
p
[
0
]
|=
0
;
p
[
count
-
1
]
|=
0
;
}
__EXCEPT
(
page_fault
)
{
return
TRUE
;
}
__ENDTRY
return
FALSE
;
}
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 */
/***********************************************************************
* IsBadHugeReadPtr (KERNEL32.@)
* RETURNS
* FALSE: Process has read access to entire block
* TRUE: Otherwise
*/
BOOL
WINAPI
IsBadHugeReadPtr
(
LPCVOID
ptr
,
/* [in] Address of memory block */
UINT
size
/* [in] Size of block */
)
{
return
IsBadReadPtr
(
ptr
,
size
);
}
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
;
/***********************************************************************
* IsBadHugeWritePtr (KERNEL32.@)
* RETURNS
* FALSE: Process has write access to entire block
* TRUE: Otherwise
*/
BOOL
WINAPI
IsBadHugeWritePtr
(
LPVOID
ptr
,
/* [in] Address of memory block */
UINT
size
/* [in] Size of block */
)
{
return
IsBadWritePtr
(
ptr
,
size
);
}
/***********************************************************************
* FlushViewOfFile (KERNEL32.@)
* Writes to the disk a byte range within a mapped view of a file
* IsBadCodePtr (KERNEL32.@)
*
* RETURNS
*
TRUE: Success
*
FALSE: Failur
e
*
FALSE: Process has read access to specified memory
*
TRUE: Otherwis
e
*/
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
);
BOOL
WINAPI
IsBadCodePtr
(
FARPROC
ptr
)
/* [in] Address of function */
{
return
IsBadReadPtr
(
ptr
,
1
);
}
TRACE
(
"FlushViewOfFile at %p for %ld bytes
\n
"
,
base
,
cbFlush
);
if
(
!
(
view
=
VIRTUAL_FindView
(
addr
)))
/***********************************************************************
* IsBadStringPtrA (KERNEL32.@)
*
* RETURNS
* FALSE: Read access to all bytes in string
* TRUE: Else
*/
BOOL
WINAPI
IsBadStringPtrA
(
LPCSTR
str
,
/* [in] Address of string */
UINT
max
)
/* [in] Maximum size of string */
{
__TRY
{
SetLastError
(
ERROR_INVALID_PARAMETER
)
;
return
FALSE
;
volatile
const
char
*
p
=
str
;
while
(
p
!=
str
+
max
)
if
(
!*
p
++
)
break
;
}
if
(
!
cbFlush
)
cbFlush
=
view
->
size
;
if
(
!
msync
(
addr
,
cbFlush
,
MS_SYNC
))
return
TRUE
;
SetLastError
(
ERROR_INVALID_PARAMETER
);
__EXCEPT
(
page_fault
)
{
return
TRUE
;
}
__ENDTRY
return
FALSE
;
}
/***********************************************************************
* UnmapViewOfFile (KERNEL32.@)
* Unmaps a mapped view of a file.
*
* NOTES
* Should addr be an LPCVOID?
*
* RETURNS
* TRUE: Success
* FALSE: Failure
* IsBadStringPtrW (KERNEL32.@)
* See IsBadStringPtrA
*/
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
))
BOOL
WINAPI
IsBadStringPtrW
(
LPCWSTR
str
,
UINT
max
)
{
__TRY
{
SetLastError
(
ERROR_INVALID_PARAMETER
)
;
return
FALSE
;
volatile
const
WCHAR
*
p
=
str
;
while
(
p
!=
str
+
max
)
if
(
!*
p
++
)
break
;
}
VIRTUAL_DeleteView
(
view
);
return
TRUE
;
__EXCEPT
(
page_fault
)
{
return
TRUE
;
}
__ENDTRY
return
FALSE
;
}
server/mapping.c
View file @
341b7dce
...
...
@@ -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
);
}
}
...
...
server/protocol.def
View file @
341b7dce
...
...
@@ -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 */
...
...
server/trace.c
View file @
341b7dce
...
...
@@ -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="
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment