ntdll: Store reserved areas in the Unix library.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Alexandre Julliard 2020-05-17 11:05:02 +02:00
parent 625209433f
commit aaa654abd6
2 changed files with 151 additions and 17 deletions

View File

@ -528,6 +528,13 @@ void __wine_main( int argc, char *argv[], char *envp[] )
__wine_set_unix_funcs( NTDLL_UNIXLIB_VERSION, &unix_funcs );
}
static int add_area( void *base, size_t size, void *arg )
{
mmap_add_reserved_area( base, size );
return 0;
}
/***********************************************************************
* __wine_init_unix_lib
*
@ -540,6 +547,7 @@ NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, const void *ptr_in, void
map_so_dll( nt, module );
fixup_ntdll_imports( &__wine_spec_nt_header, module );
*(struct unix_funcs **)ptr_out = &unix_funcs;
wine_mmap_enum_reserved_areas( add_area, NULL, 0 );
return STATUS_SUCCESS;
}

View File

@ -45,7 +45,7 @@
#include "winnt.h"
#include "winternl.h"
#include "unix_private.h"
#include "wine/library.h"
#include "wine/list.h"
struct preload_info
{
@ -53,6 +53,15 @@ struct preload_info
size_t size;
};
struct reserved_area
{
struct list entry;
void *base;
size_t size;
};
static struct list reserved_areas = LIST_INIT(reserved_areas);
static const unsigned int granularity_mask = 0xffff; /* reserved areas have 64k granularity */
extern IMAGE_NT_HEADERS __wine_spec_nt_header;
@ -202,36 +211,153 @@ static void mmap_init( const struct preload_info *preload_info )
void CDECL mmap_add_reserved_area( void *addr, SIZE_T size )
{
wine_mmap_add_reserved_area( addr, size );
struct reserved_area *area;
struct list *ptr;
if (!((char *)addr + size)) size--; /* avoid wrap-around */
LIST_FOR_EACH( ptr, &reserved_areas )
{
area = LIST_ENTRY( ptr, struct reserved_area, entry );
if (area->base > addr)
{
/* try to merge with the next one */
if ((char *)addr + size == (char *)area->base)
{
area->base = addr;
area->size += size;
return;
}
break;
}
else if ((char *)area->base + area->size == (char *)addr)
{
/* merge with the previous one */
area->size += size;
/* try to merge with the next one too */
if ((ptr = list_next( &reserved_areas, ptr )))
{
struct reserved_area *next = LIST_ENTRY( ptr, struct reserved_area, entry );
if ((char *)addr + size == (char *)next->base)
{
area->size += next->size;
list_remove( &next->entry );
free( next );
}
}
return;
}
}
if ((area = malloc( sizeof(*area) )))
{
area->base = addr;
area->size = size;
list_add_before( ptr, &area->entry );
}
}
void CDECL mmap_remove_reserved_area( void *addr, SIZE_T size )
{
wine_mmap_remove_reserved_area( addr, size, 0 );
struct reserved_area *area;
struct list *ptr;
if (!((char *)addr + size)) size--; /* avoid wrap-around */
ptr = list_head( &reserved_areas );
/* find the first area covering address */
while (ptr)
{
area = LIST_ENTRY( ptr, struct reserved_area, entry );
if ((char *)area->base >= (char *)addr + size) break; /* outside the range */
if ((char *)area->base + area->size > (char *)addr) /* overlaps range */
{
if (area->base >= addr)
{
if ((char *)area->base + area->size > (char *)addr + size)
{
/* range overlaps beginning of area only -> shrink area */
area->size -= (char *)addr + size - (char *)area->base;
area->base = (char *)addr + size;
break;
}
else
{
/* range contains the whole area -> remove area completely */
ptr = list_next( &reserved_areas, ptr );
list_remove( &area->entry );
free( area );
continue;
}
}
else
{
if ((char *)area->base + area->size > (char *)addr + size)
{
/* range is in the middle of area -> split area in two */
struct reserved_area *new_area = malloc( sizeof(*new_area) );
if (new_area)
{
new_area->base = (char *)addr + size;
new_area->size = (char *)area->base + area->size - (char *)new_area->base;
list_add_after( ptr, &new_area->entry );
}
else size = (char *)area->base + area->size - (char *)addr;
area->size = (char *)addr - (char *)area->base;
break;
}
else
{
/* range overlaps end of area only -> shrink area */
area->size = (char *)addr - (char *)area->base;
}
}
}
ptr = list_next( &reserved_areas, ptr );
}
}
int CDECL mmap_is_in_reserved_area( void *addr, SIZE_T size )
{
return wine_mmap_is_in_reserved_area( addr, size );
}
struct reserved_area *area;
struct list *ptr;
struct enum_data
{
int (CDECL *enum_func)( void *base, SIZE_T size, void *arg );
void *arg;
};
static int enum_wrapper( void *base, size_t size, void *arg )
{
struct enum_data *data = arg;
return data->enum_func( base, size, data->arg );
LIST_FOR_EACH( ptr, &reserved_areas )
{
area = LIST_ENTRY( ptr, struct reserved_area, entry );
if (area->base > addr) break;
if ((char *)area->base + area->size <= (char *)addr) continue;
/* area must contain block completely */
if ((char *)area->base + area->size < (char *)addr + size) return -1;
return 1;
}
return 0;
}
int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T size, void *arg),
void *arg, int top_down )
{
struct enum_data data = { enum_func, arg };
return wine_mmap_enum_reserved_areas( enum_wrapper, &data, top_down );
int ret = 0;
struct list *ptr;
if (top_down)
{
for (ptr = reserved_areas.prev; ptr != &reserved_areas; ptr = ptr->prev)
{
struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry );
if ((ret = enum_func( area->base, area->size, arg ))) break;
}
}
else
{
for (ptr = reserved_areas.next; ptr != &reserved_areas; ptr = ptr->next)
{
struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry );
if ((ret = enum_func( area->base, area->size, arg ))) break;
}
}
return ret;
}
void virtual_init(void)