[PATCH 1/3] ntdll: Implement NtQueryVirtualMemory(MemoryWorkingSetExInformation).

Andrew Wesie awesie at gmail.com
Tue Dec 17 18:34:26 CST 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45667
Signed-off-by: Andrew Wesie <awesie at gmail.com>
---
 dlls/ntdll/virtual.c | 78 +++++++++++++++++++++++++++++++++++++++++---
 include/winternl.h   | 21 +++++++++++-
 2 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index cb869feff0..fecc2d601d 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -84,6 +84,7 @@ struct file_view
 #define VPROT_GUARD      0x10
 #define VPROT_COMMITTED  0x20
 #define VPROT_WRITEWATCH 0x40
+#define VPROT_DEFERRED   0x80
 /* per-mapping protection flags */
 #define VPROT_SYSTEM     0x0200  /* system view (underlying mmap not under our control) */
 
@@ -319,7 +320,7 @@ static const char *VIRTUAL_GetProtStr( BYTE prot )
 static int VIRTUAL_GetUnixProt( BYTE vprot )
 {
     int prot = 0;
-    if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
+    if ((vprot & VPROT_COMMITTED) && !(vprot & (VPROT_GUARD | VPROT_DEFERRED)))
     {
         if (vprot & VPROT_READ) prot |= PROT_READ;
         if (vprot & VPROT_WRITE) prot |= PROT_WRITE | PROT_READ;
@@ -952,7 +953,7 @@ static BOOL VIRTUAL_SetProt( struct file_view *view, /* [in] Pointer to view */
  *
  * Set page protections on a range of pages
  */
-static NTSTATUS set_protection( struct file_view *view, void *base, SIZE_T size, ULONG protect )
+static NTSTATUS set_protection( struct file_view *view, void *base, SIZE_T size, ULONG protect, BOOL apply )
 {
     unsigned int vprot;
     NTSTATUS status;
@@ -968,6 +969,8 @@ static NTSTATUS set_protection( struct file_view *view, void *base, SIZE_T size,
         if ((view->protect & access) != access) return STATUS_INVALID_PAGE_PROTECTION;
     }
 
+    if (!apply)
+        vprot |= VPROT_DEFERRED;
     if (!VIRTUAL_SetProt( view, base, size, vprot | VPROT_COMMITTED )) return STATUS_ACCESS_DENIED;
     return STATUS_SUCCESS;
 }
@@ -2109,10 +2112,16 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack )
     vprot = get_page_vprot( page );
     if (!on_signal_stack && (vprot & VPROT_GUARD))
     {
-        set_page_vprot_bits( page, page_size, 0, VPROT_GUARD );
+        set_page_vprot_bits( page, page_size, 0, VPROT_GUARD | VPROT_DEFERRED );
         mprotect_range( page, page_size, 0, 0 );
         ret = STATUS_GUARD_PAGE_VIOLATION;
     }
+    else if (vprot & VPROT_DEFERRED)
+    {
+        set_page_vprot_bits( page, page_size, 0, VPROT_DEFERRED );
+        mprotect_range( page, page_size, 0, 0 );
+        ret = STATUS_SUCCESS;
+    }
     else if (err & EXCEPTION_WRITE_FAULT)
     {
         if (vprot & VPROT_WRITEWATCH)
@@ -2684,7 +2693,7 @@ NTSTATUS virtual_alloc_aligned( PVOID *ret, unsigned short zero_bits_64, SIZE_T
     {
         if (!(view = VIRTUAL_FindView( base, size ))) status = STATUS_NOT_MAPPED_VIEW;
         else if (view->protect & SEC_FILE) status = STATUS_ALREADY_COMMITTED;
-        else if (!(status = set_protection( view, base, size, protect )) && (view->protect & SEC_RESERVE))
+        else if (!(status = set_protection( view, base, size, protect, TRUE )) && (view->protect & SEC_RESERVE))
         {
             SERVER_START_REQ( add_mapping_committed_range )
             {
@@ -2850,7 +2859,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH NtProtectVirtualMemory( HANDLE process, PVOID
         if (get_committed_size( view, base, &vprot ) >= size && (vprot & VPROT_COMMITTED))
         {
             old = VIRTUAL_GetWin32Prot( vprot, view->protect );
-            status = set_protection( view, base, size, new_prot );
+            status = set_protection( view, base, size, new_prot, VIRTUAL_GetUnixProt(vprot) != PROT_NONE );
         }
         else status = STATUS_NOT_COMMITTED;
     }
@@ -2906,6 +2915,62 @@ static int get_free_mem_state_callback( void *start, size_t size, void *arg )
     return 1;
 }
 
+static NTSTATUS get_working_set_ex( HANDLE process, LPCVOID addr,
+                                    MEMORY_WORKING_SET_EX_INFORMATION *info,
+                                    SIZE_T len, SIZE_T *res_len )
+{
+    MEMORY_WORKING_SET_EX_INFORMATION *p;
+    char pagemap_path[128];
+    FILE *f;
+    sigset_t sigset;
+
+    if (process != NtCurrentProcess())
+    {
+        FIXME("(process=%p,addr=%p) Unimplemented information class: MemoryWorkingSetExInformation\n", process, addr);
+        return STATUS_INVALID_INFO_CLASS;
+    }
+
+    snprintf(pagemap_path, sizeof(pagemap_path), "/proc/%u/pagemap", getpid());
+    f = fopen(pagemap_path, "rb");
+
+    server_enter_uninterrupted_section( &csVirtual, &sigset );
+    for (p = info; (UINT_PTR)(p + 1) <= (UINT_PTR)info + len; p++)
+    {
+        BYTE vprot;
+        UINT64 pagemap;
+        struct file_view *view;
+
+        memset(&p->VirtualAttributes, 0, sizeof(p->VirtualAttributes));
+        /* If we don't have pagemap information, default to invalid. */
+        if (f == NULL ||
+            fseek(f, ((UINT_PTR)p->VirtualAddress >> 12) * sizeof(pagemap), SEEK_SET) == -1 ||
+            fread(&pagemap, sizeof(pagemap), 1, f) != 1)
+        {
+            continue;
+        }
+
+        if ((view = VIRTUAL_FindView( p->VirtualAddress, 0 )) &&
+            get_committed_size( view, p->VirtualAddress, &vprot ) &&
+            (vprot & VPROT_COMMITTED))
+        {
+            p->VirtualAttributes.Valid = !(vprot & (VPROT_GUARD | VPROT_DEFERRED)) && (vprot & 0x0f) && (pagemap >> 62);
+            p->VirtualAttributes.Shared = (view->protect & (VPROT_SYSTEM | SEC_IMAGE | SEC_FILE | SEC_RESERVE | SEC_COMMIT)) != 0;
+            if (p->VirtualAttributes.Shared && p->VirtualAttributes.Valid)
+                p->VirtualAttributes.ShareCount = 1; /* FIXME */
+            if (p->VirtualAttributes.Valid)
+                p->VirtualAttributes.Win32Protection = VIRTUAL_GetWin32Prot( vprot, view->protect );
+        }
+    }
+    server_leave_uninterrupted_section( &csVirtual, &sigset );
+
+    if (f)
+        fclose(f);
+    if (res_len)
+        *res_len = (UINT_PTR)p - (UINT_PTR)info;
+    return STATUS_SUCCESS;
+}
+
+
 #define UNIMPLEMENTED_INFO_CLASS(c) \
     case c: \
         FIXME("(process=%p,addr=%p) Unimplemented information class: " #c "\n", process, addr); \
@@ -2933,6 +2998,9 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
             UNIMPLEMENTED_INFO_CLASS(MemorySectionName);
             UNIMPLEMENTED_INFO_CLASS(MemoryBasicVlmInformation);
 
+            case MemoryWorkingSetExInformation:
+                return get_working_set_ex( process, addr, buffer, len, res_len );
+
             default:
                 FIXME("(%p,%p,info_class=%d,%p,%ld,%p) Unknown information class\n", 
                       process, addr, info_class, buffer, len, res_len);
diff --git a/include/winternl.h b/include/winternl.h
index 0122684483..eef42be5b3 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1049,7 +1049,8 @@ typedef enum _MEMORY_INFORMATION_CLASS {
     MemoryBasicInformation,
     MemoryWorkingSetList,
     MemorySectionName,
-    MemoryBasicVlmInformation
+    MemoryBasicVlmInformation,
+    MemoryWorkingSetExInformation
 } MEMORY_INFORMATION_CLASS;
 
 typedef struct _MEMORY_SECTION_NAME
@@ -1057,6 +1058,24 @@ typedef struct _MEMORY_SECTION_NAME
     UNICODE_STRING SectionFileName;
 } MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;
 
+typedef union _MEMORY_WORKING_SET_EX_BLOCK {
+    ULONG_PTR Flags;
+    struct {
+        ULONG_PTR Valid  :1;
+        ULONG_PTR ShareCount  :3;
+        ULONG_PTR Win32Protection  :11;
+        ULONG_PTR Shared  :1;
+        ULONG_PTR Node  :6;
+        ULONG_PTR Locked  :1;
+        ULONG_PTR LargePage  :1;
+    } DUMMYSTRUCTNAME;
+} MEMORY_WORKING_SET_EX_BLOCK, *PMEMORY_WORKING_SET_EX_BLOCK;
+
+typedef struct _MEMORY_WORKING_SET_EX_INFORMATION {
+    PVOID                       VirtualAddress;
+    MEMORY_WORKING_SET_EX_BLOCK VirtualAttributes;
+} MEMORY_WORKING_SET_EX_INFORMATION, *PMEMORY_WORKING_SET_EX_INFORMATION;
+
 typedef enum _MUTANT_INFORMATION_CLASS
 {
     MutantBasicInformation
-- 
2.17.1




More information about the wine-devel mailing list