* mmap.cc: Restructure. Add, remove and rewrite comments throughout
for better readability. Change function names for better understanding. (MAP_SET): Accomodate name change from map_map_ to page_map_. (MAP_CLR): Ditto. (MAP_ISSET): Ditto. (mmap_record::page_map_): Rename from page_map_. (mmap_record::get_map): Remove. (mmap_record::alloc_page_map): Rename from alloc_map. Return bool indicating success of cygheap memory allocation. (mmap_record::free_page_map): Rename from free_map. (mmap_record::fixup_page_map): Rename from fixup_map. (mmap_record::find_unused_pages): Rename from find_empty. (mmap_record::map_pages): Rename from map_map. (mmap_record::unmap_pages): Rename from unmap_map. (class list): Make all class members private. (list::list): Remove. (list::~list): Remove. (list::get_fd): New attribute reader. (list::get_hash): Ditto. (list::get_record): Ditto. (list::add_record): Manage all allocation for mmap_records. Check for failed memory allocation and return NULL if so. (list::set): New function. (list::del_record): Rename from erase. Return true if last mmap_record has been deleted, false otherwise. Check for legal incoming index value. (list::erase): Remove erase/0. (list::search_record): Rename from match. (map::map): Remove. (map::~map): Remove. (map::add_list): Manage all allocation for lists. Check for failed memory allocation and return NULL if so. (map::get_list): New method. (map::del_list): Rename from erase. Check for legal incoming index value. (mmap64): Check for failed mmap_record memory allocation. Return with MAP_FAILED and errno set to ENOMEM if so. (munmap): Rearrange loop using new list and mmap_record accessor functions. Rename loop index variables for better understanding. Check if list can be deleted after last mmap_record in it has been deleted. (msync): Rearrange loop using new list and mmap_record accessor functions. Rename loop index variables for better understanding. (fixup_mmaps_after_fork): Ditto.
This commit is contained in:
		| @@ -1,3 +1,51 @@ | ||||
| 2003-09-04  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* mmap.cc: Restructure. Add, remove and rewrite comments throughout | ||||
| 	for better readability.  Change function names for better | ||||
| 	understanding. | ||||
| 	(MAP_SET): Accomodate name change from map_map_ to page_map_. | ||||
| 	(MAP_CLR): Ditto. | ||||
| 	(MAP_ISSET): Ditto. | ||||
| 	(mmap_record::page_map_): Rename from page_map_. | ||||
| 	(mmap_record::get_map): Remove. | ||||
| 	(mmap_record::alloc_page_map): Rename from alloc_map. Return bool | ||||
| 	indicating success of cygheap memory allocation. | ||||
| 	(mmap_record::free_page_map): Rename from free_map. | ||||
| 	(mmap_record::fixup_page_map): Rename from fixup_map. | ||||
| 	(mmap_record::find_unused_pages): Rename from find_empty. | ||||
| 	(mmap_record::map_pages): Rename from map_map. | ||||
| 	(mmap_record::unmap_pages): Rename from unmap_map. | ||||
| 	(class list): Make all class members private. | ||||
| 	(list::list): Remove. | ||||
| 	(list::~list): Remove. | ||||
| 	(list::get_fd): New attribute reader. | ||||
| 	(list::get_hash): Ditto. | ||||
| 	(list::get_record): Ditto. | ||||
| 	(list::add_record): Manage all allocation for mmap_records.  Check | ||||
| 	for failed memory allocation and return NULL if so. | ||||
| 	(list::set): New function. | ||||
| 	(list::del_record): Rename from erase. Return true if last mmap_record | ||||
| 	has been deleted, false otherwise. Check for legal incoming index | ||||
| 	value. | ||||
| 	(list::erase): Remove erase/0. | ||||
| 	(list::search_record): Rename from match. | ||||
| 	(map::map): Remove. | ||||
| 	(map::~map): Remove. | ||||
| 	(map::add_list): Manage all allocation for lists.  Check for failed | ||||
| 	memory allocation and return NULL if so. | ||||
| 	(map::get_list): New method. | ||||
| 	(map::del_list): Rename from erase. Check for legal incoming index | ||||
| 	value. | ||||
| 	(mmap64): Check for failed mmap_record memory allocation.  Return | ||||
| 	with MAP_FAILED and errno set to ENOMEM if so. | ||||
| 	(munmap): Rearrange loop using new list and mmap_record accessor | ||||
| 	functions.  Rename loop index variables for better understanding. | ||||
| 	Check if list can be deleted after last mmap_record in it has been | ||||
| 	deleted. | ||||
| 	(msync): Rearrange loop using new list and mmap_record accessor | ||||
| 	functions.  Rename loop index variables for better understanding. | ||||
| 	(fixup_mmaps_after_fork): Ditto. | ||||
|  | ||||
| 2003-09-03  Christopher Faylor  <cgf@redhat.com> | ||||
|  | ||||
| 	* cxx.cc (new): Fix formatting.  Just return result of ccalloc rather | ||||
|   | ||||
| @@ -27,15 +27,29 @@ details. */ | ||||
| #define PGBITS		(sizeof (DWORD)*8) | ||||
| #define MAPSIZE(pages)	howmany ((pages), PGBITS) | ||||
|  | ||||
| #define MAP_SET(n)	(map_map_[(n)/PGBITS] |= (1L << ((n) % PGBITS))) | ||||
| #define MAP_CLR(n)	(map_map_[(n)/PGBITS] &= ~(1L << ((n) % PGBITS))) | ||||
| #define MAP_ISSET(n)	(map_map_[(n)/PGBITS] & (1L << ((n) % PGBITS))) | ||||
| #define MAP_SET(n)	(page_map_[(n)/PGBITS] |= (1L << ((n) % PGBITS))) | ||||
| #define MAP_CLR(n)	(page_map_[(n)/PGBITS] &= ~(1L << ((n) % PGBITS))) | ||||
| #define MAP_ISSET(n)	(page_map_[(n)/PGBITS] & (1L << ((n) % PGBITS))) | ||||
|  | ||||
| /* | ||||
|  * Simple class used to keep a record of all current | ||||
|  * mmap areas in a process. Needed so that | ||||
|  * they can be duplicated after a fork(). | ||||
|  */ | ||||
| /* Used for accessing the page file (anonymous mmaps). */ | ||||
| static fhandler_disk_file fh_paging_file; | ||||
|  | ||||
| /* Class structure used to keep a record of all current mmap areas | ||||
|    in a process.  Needed for bookkeeping all mmaps in a process and | ||||
|    for duplicating all mmaps after fork() since mmaps are not propagated | ||||
|    to child processes by Windows.  All information must be duplicated | ||||
|    by hand, see fixup_mmaps_after_fork(). | ||||
|    | ||||
|    The class structure: | ||||
|    | ||||
|    One member of class map per process, global variable mmapped_areas. | ||||
|    Contains a dynamic class list array.  Each list entry represents all | ||||
|    mapping to a file, keyed by file descriptor and file name hash. | ||||
|    Each list entry contains a dynamic class mmap_record array.  Each | ||||
|    mmap_record represents exactly one mapping.  For each mapping, there's | ||||
|    an additional so called `page_map'.  It's an array of bits, one bit | ||||
|    per mapped memory page.  The bit is set if the page is accessible, | ||||
|    unset otherwise. */ | ||||
|  | ||||
| class mmap_record | ||||
| { | ||||
| @@ -47,7 +61,7 @@ class mmap_record | ||||
|     _off64_t offset_; | ||||
|     DWORD size_to_map_; | ||||
|     caddr_t base_address_; | ||||
|     DWORD *map_map_; | ||||
|     DWORD *page_map_; | ||||
|  | ||||
|   public: | ||||
|     mmap_record (int fd, HANDLE h, DWORD ac, _off64_t o, DWORD s, caddr_t b) : | ||||
| @@ -58,15 +72,12 @@ class mmap_record | ||||
|        offset_ (o), | ||||
|        size_to_map_ (s), | ||||
|        base_address_ (b), | ||||
|        map_map_ (NULL) | ||||
|        page_map_ (NULL) | ||||
|       { | ||||
| 	if (fd >= 0 && !cygheap->fdtab.not_open (fd)) | ||||
| 	  devtype_ = cygheap->fdtab[fd]->get_device (); | ||||
|       } | ||||
|  | ||||
|     /* Default Copy constructor/operator=/destructor are ok */ | ||||
|  | ||||
|     /* Simple accessors */ | ||||
|     int get_fd () const { return fdesc_; } | ||||
|     HANDLE get_handle () const { return mapping_handle_; } | ||||
|     DWORD get_device () const { return devtype_; } | ||||
| @@ -74,22 +85,61 @@ class mmap_record | ||||
|     DWORD get_offset () const { return offset_; } | ||||
|     DWORD get_size () const { return size_to_map_; } | ||||
|     caddr_t get_address () const { return base_address_; } | ||||
|     DWORD *get_map () const { return map_map_; } | ||||
|     void alloc_map (_off64_t off, DWORD len); | ||||
|     void free_map () { if (map_map_) cfree (map_map_); } | ||||
|  | ||||
|     DWORD find_empty (DWORD pages); | ||||
|     _off64_t map_map (_off64_t off, DWORD len); | ||||
|     BOOL unmap_map (caddr_t addr, DWORD len); | ||||
|     void fixup_map (void); | ||||
|     bool alloc_page_map (_off64_t off, DWORD len); | ||||
|     void free_page_map () { if (page_map_) cfree (page_map_); } | ||||
|     void fixup_page_map (void); | ||||
|  | ||||
|     DWORD find_unused_pages (DWORD pages); | ||||
|     _off64_t map_pages (_off64_t off, DWORD len); | ||||
|     BOOL unmap_pages (caddr_t addr, DWORD len); | ||||
|     int access (caddr_t address); | ||||
|  | ||||
|     fhandler_base *alloc_fh (); | ||||
|     void free_fh (fhandler_base *fh); | ||||
| }; | ||||
|  | ||||
| class list | ||||
| { | ||||
|   private: | ||||
|     mmap_record *recs; | ||||
|     int nrecs, maxrecs; | ||||
|     int fd; | ||||
|     DWORD hash; | ||||
|  | ||||
|   public: | ||||
|     int get_fd () const { return fd; } | ||||
|     DWORD get_hash () const { return hash; } | ||||
|     mmap_record *get_record (int i) { return i >= nrecs ? NULL : recs + i; } | ||||
|  | ||||
|     void set (int nfd); | ||||
|     mmap_record *add_record (mmap_record r, _off64_t off, DWORD len); | ||||
|     bool del_record (int i); | ||||
|     void free_recs () { if (recs) cfree (recs); } | ||||
|     mmap_record *search_record (_off64_t off, DWORD len); | ||||
|     long search_record (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, | ||||
| 		long start); | ||||
| }; | ||||
|  | ||||
| class map | ||||
| { | ||||
|   private: | ||||
|     list *lists; | ||||
|     int nlists, maxlists; | ||||
|  | ||||
|   public: | ||||
|     list *get_list (int i) { return i >= nlists ? NULL : lists + i; } | ||||
|     list *get_list_by_fd (int fd); | ||||
|     list *add_list (int fd); | ||||
|     void del_list (int i); | ||||
| }; | ||||
|  | ||||
| /* This is the global map structure pointer.  It's allocated once on the | ||||
|    first call to mmap64(). */ | ||||
| static map *mmapped_areas; | ||||
|  | ||||
| DWORD | ||||
| mmap_record::find_empty (DWORD pages) | ||||
| mmap_record::find_unused_pages (DWORD pages) | ||||
| { | ||||
|   DWORD mapped_pages = PAGE_CNT (size_to_map_); | ||||
|   DWORD start; | ||||
| @@ -109,12 +159,15 @@ mmap_record::find_empty (DWORD pages) | ||||
|   return (DWORD)-1; | ||||
| } | ||||
|  | ||||
| void | ||||
| mmap_record::alloc_map (_off64_t off, DWORD len) | ||||
| bool | ||||
| mmap_record::alloc_page_map (_off64_t off, DWORD len) | ||||
| { | ||||
|   /* Allocate one bit per page */ | ||||
|   map_map_ = (DWORD *) ccalloc (HEAP_MMAP, MAPSIZE (PAGE_CNT (size_to_map_)), | ||||
| 			        sizeof (DWORD)); | ||||
|   if (!(page_map_ = (DWORD *) ccalloc (HEAP_MMAP, | ||||
| 				       MAPSIZE (PAGE_CNT (size_to_map_)), | ||||
| 				       sizeof (DWORD)))) | ||||
|     return false; | ||||
|  | ||||
|   if (wincap.virtual_protect_works_on_shared_pages ()) | ||||
|     { | ||||
|       DWORD old_prot; | ||||
| @@ -135,15 +188,16 @@ mmap_record::alloc_map (_off64_t off, DWORD len) | ||||
|       while (len-- > 0) | ||||
| 	MAP_SET (off + len); | ||||
|     } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| _off64_t | ||||
| mmap_record::map_map (_off64_t off, DWORD len) | ||||
| mmap_record::map_pages (_off64_t off, DWORD len) | ||||
| { | ||||
|   /* Used ONLY if this mapping matches into the chunk of another already | ||||
|      performed mapping in a special case of MAP_ANON|MAP_PRIVATE. | ||||
|  | ||||
|      Otherwise it's job is now done by alloc_map(). */ | ||||
|      Otherwise it's job is now done by alloc_page_map(). */ | ||||
|   DWORD prot, old_prot; | ||||
|   switch (access_mode_) | ||||
|     { | ||||
| @@ -158,10 +212,10 @@ mmap_record::map_map (_off64_t off, DWORD len) | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|   debug_printf ("map_map (fd=%d, off=%D, len=%u)", fdesc_, off, len); | ||||
|   debug_printf ("map_pages (fd=%d, off=%D, len=%u)", fdesc_, off, len); | ||||
|   len = PAGE_CNT (len); | ||||
|  | ||||
|   if ((off = find_empty (len)) == (DWORD)-1) | ||||
|   if ((off = find_unused_pages (len)) == (DWORD)-1) | ||||
|     return 0L; | ||||
|   if (wincap.virtual_protect_works_on_shared_pages () | ||||
|       && !VirtualProtect (base_address_ + off * getpagesize (), | ||||
| @@ -177,7 +231,7 @@ mmap_record::map_map (_off64_t off, DWORD len) | ||||
| } | ||||
|  | ||||
| BOOL | ||||
| mmap_record::unmap_map (caddr_t addr, DWORD len) | ||||
| mmap_record::unmap_pages (caddr_t addr, DWORD len) | ||||
| { | ||||
|   DWORD old_prot; | ||||
|   DWORD off = addr - base_address_; | ||||
| @@ -186,20 +240,20 @@ mmap_record::unmap_map (caddr_t addr, DWORD len) | ||||
|   if (wincap.virtual_protect_works_on_shared_pages () | ||||
|       && !VirtualProtect (base_address_ + off * getpagesize (), | ||||
| 			  len * getpagesize (), PAGE_NOACCESS, &old_prot)) | ||||
|     syscall_printf ("-1 = unmap_map (): %E"); | ||||
|     syscall_printf ("-1 = unmap_pages (): %E"); | ||||
|  | ||||
|   for (; len-- > 0; ++off) | ||||
|     MAP_CLR (off); | ||||
|   /* Return TRUE if all pages are free'd which may result in unmapping | ||||
|      the whole chunk. */ | ||||
|   for (len = MAPSIZE (PAGE_CNT (size_to_map_)); len > 0; ) | ||||
|     if (map_map_[--len]) | ||||
|     if (page_map_[--len]) | ||||
|       return FALSE; | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| void | ||||
| mmap_record::fixup_map () | ||||
| mmap_record::fixup_page_map () | ||||
| { | ||||
|   if (!wincap.virtual_protect_works_on_shared_pages ()) | ||||
|     return; | ||||
| @@ -232,8 +286,6 @@ mmap_record::access (caddr_t address) | ||||
|   return MAP_ISSET (off); | ||||
| } | ||||
|  | ||||
| static fhandler_disk_file fh_paging_file; | ||||
|  | ||||
| fhandler_base * | ||||
| mmap_record::alloc_fh () | ||||
| { | ||||
| @@ -258,57 +310,38 @@ mmap_record::free_fh (fhandler_base *fh) | ||||
|     cfree (fh); | ||||
| } | ||||
|  | ||||
| class list { | ||||
| public: | ||||
|   mmap_record *recs; | ||||
|   int nrecs, maxrecs; | ||||
|   int fd; | ||||
|   DWORD hash; | ||||
|   list (); | ||||
|   ~list (); | ||||
|   mmap_record *add_record (mmap_record r, _off64_t off, DWORD len); | ||||
|   void erase (int i); | ||||
|   void erase (); | ||||
|   mmap_record *match (_off64_t off, DWORD len); | ||||
|   long match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, | ||||
| 	      long start); | ||||
| }; | ||||
|  | ||||
| list::list () | ||||
| : nrecs (0), maxrecs (10), fd (0), hash (0) | ||||
| { | ||||
|   recs = (mmap_record *) cmalloc (HEAP_MMAP, 10 * sizeof (mmap_record)); | ||||
| } | ||||
|  | ||||
| list::~list () | ||||
| { | ||||
|   for (mmap_record *rec = recs; nrecs-- > 0; ++rec) | ||||
|     rec->free_map (); | ||||
|   cfree (recs); | ||||
| } | ||||
|  | ||||
| mmap_record * | ||||
| list::add_record (mmap_record r, _off64_t off, DWORD len) | ||||
| { | ||||
|   if (nrecs == maxrecs) | ||||
|     { | ||||
|       mmap_record *new_recs; | ||||
|       if (maxrecs == 0) | ||||
|         new_recs = (mmap_record *) | ||||
| 			cmalloc (HEAP_MMAP, 5 * sizeof (mmap_record)); | ||||
|       else | ||||
| 	new_recs = (mmap_record *) | ||||
| 			crealloc (recs, (maxrecs + 5) * sizeof (mmap_record)); | ||||
|       if (!new_recs) | ||||
|         return NULL; | ||||
|       maxrecs += 5; | ||||
|       recs = (mmap_record *) crealloc (recs, maxrecs * sizeof (mmap_record)); | ||||
|       recs = new_recs; | ||||
|     } | ||||
|   recs[nrecs] = r; | ||||
|   recs[nrecs].alloc_map (off, len); | ||||
|   if (!recs[nrecs].alloc_page_map (off, len)) | ||||
|     return NULL; | ||||
|   return recs + nrecs++; | ||||
| } | ||||
|  | ||||
| /* Used in mmap() */ | ||||
| mmap_record * | ||||
| list::match (_off64_t off, DWORD len) | ||||
| list::search_record (_off64_t off, DWORD len) | ||||
| { | ||||
|   if (fd == -1 && !off) | ||||
|     { | ||||
|       len = PAGE_CNT (len); | ||||
|       for (int i = 0; i < nrecs; ++i) | ||||
| 	if (recs[i].find_empty (len) != (DWORD)-1) | ||||
| 	if (recs[i].find_unused_pages (len) != (DWORD)-1) | ||||
| 	  return recs + i; | ||||
|     } | ||||
|   else | ||||
| @@ -324,7 +357,7 @@ list::match (_off64_t off, DWORD len) | ||||
|  | ||||
| /* Used in munmap() */ | ||||
| long | ||||
| list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, | ||||
| list::search_record (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, | ||||
| 	     _off_t start) | ||||
| { | ||||
|   caddr_t low, high; | ||||
| @@ -346,41 +379,27 @@ list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, | ||||
| } | ||||
|  | ||||
| void | ||||
| list::erase (int i) | ||||
| list::set (int nfd) | ||||
| { | ||||
|   recs[i].free_map (); | ||||
|   for (; i < nrecs-1; i++) | ||||
|     recs[i] = recs[i+1]; | ||||
|   nrecs--; | ||||
|   if ((fd = nfd) != -1) | ||||
|     hash = cygheap->fdtab[fd]->get_namehash (); | ||||
|   nrecs = maxrecs = 0; | ||||
|   recs = NULL; | ||||
| } | ||||
|  | ||||
| void | ||||
| list::erase () | ||||
| bool | ||||
| list::del_record (int i) | ||||
| { | ||||
|   erase (nrecs-1); | ||||
| } | ||||
|  | ||||
| class map { | ||||
| public: | ||||
|   list **lists; | ||||
|   int nlists, maxlists; | ||||
|   map (); | ||||
|   ~map (); | ||||
|   list *get_list_by_fd (int fd); | ||||
|   list *add_list (list *l, int fd); | ||||
|   void erase (int i); | ||||
| }; | ||||
|  | ||||
| map::map () | ||||
| { | ||||
|   lists = (list **) cmalloc (HEAP_MMAP, 10 * sizeof (list *)); | ||||
|   nlists = 0; | ||||
|   maxlists = 10; | ||||
| } | ||||
|  | ||||
| map::~map () | ||||
| { | ||||
|   cfree (lists); | ||||
|   if (i < nrecs) | ||||
|     { | ||||
|       recs[i].free_page_map (); | ||||
|       for (; i < nrecs - 1; i++) | ||||
| 	recs[i] = recs[i + 1]; | ||||
|       nrecs--; | ||||
|     } | ||||
|   /* Return true if the list is empty which allows the caller to remove | ||||
|      this list from the list array. */ | ||||
|   return !nrecs; | ||||
| } | ||||
|  | ||||
| list * | ||||
| @@ -388,50 +407,47 @@ map::get_list_by_fd (int fd) | ||||
| { | ||||
|   int i; | ||||
|   for (i=0; i<nlists; i++) | ||||
| #if 0 /* The fd isn't sufficient since it could already be another file. */ | ||||
|     if (lists[i]->fd == fd | ||||
| #else /* so we use the name hash value to identify the file unless | ||||
| 	 it's not an anonymous mapping. */ | ||||
|     if ((fd == -1 && lists[i]->fd == -1) | ||||
| 	|| (fd != -1 && lists[i]->hash == cygheap->fdtab[fd]->get_namehash ())) | ||||
| #endif | ||||
|       return lists[i]; | ||||
|     /* The fd isn't sufficient since it could already be the fd of another | ||||
|        file.  So we use the name hash value to identify the file unless | ||||
|        it's an anonymous mapping in which case the fd (-1) is sufficient. */ | ||||
|     if ((fd == -1 && lists[i].get_fd () == -1) | ||||
| 	|| (fd != -1 | ||||
| 	    && lists[i].get_hash () == cygheap->fdtab[fd]->get_namehash ())) | ||||
|       return lists + i; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| list * | ||||
| map::add_list (list *l, int fd) | ||||
| map::add_list (int fd) | ||||
| { | ||||
|   l->fd = fd; | ||||
|   if (fd != -1) | ||||
|     l->hash = cygheap->fdtab[fd]->get_namehash (); | ||||
|   if (nlists == maxlists) | ||||
|     { | ||||
|       list *new_lists; | ||||
|       if (maxlists == 0) | ||||
|         new_lists = (list *) cmalloc (HEAP_MMAP, 5 * sizeof (list)); | ||||
|       else | ||||
| 	new_lists = (list *) crealloc (lists, (maxlists + 5) * sizeof (list)); | ||||
|       if (!new_lists) | ||||
|         return NULL; | ||||
|       maxlists += 5; | ||||
|       lists = (list **) crealloc (lists, maxlists * sizeof (list *)); | ||||
|       lists = new_lists; | ||||
|     } | ||||
|   lists[nlists++] = l; | ||||
|   return lists[nlists-1]; | ||||
|   lists[nlists].set (fd); | ||||
|   return lists + nlists++; | ||||
| } | ||||
|  | ||||
| void | ||||
| map::erase (int i) | ||||
| map::del_list (int i) | ||||
| { | ||||
|   for (; i < nlists-1; i++) | ||||
|     lists[i] = lists[i+1]; | ||||
|   nlists--; | ||||
|   if (i < nlists) | ||||
|     { | ||||
|       lists[i].free_recs (); | ||||
|       for (; i < nlists - 1; i++) | ||||
|         lists[i] = lists[i + 1]; | ||||
|       nlists--; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Code to keep a record of all mmap'ed areas in a process. | ||||
|  * Needed to duplicate tham in a child of fork(). | ||||
|  * mmap_record classes are kept in an STL list in an STL map, keyed | ||||
|  * by file descriptor. This is *NOT* duplicated across a fork(), it | ||||
|  * needs to be specially handled by the fork code. | ||||
|  */ | ||||
|  | ||||
| static map *mmapped_areas; | ||||
|  | ||||
| extern "C" caddr_t | ||||
| mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) | ||||
| { | ||||
| @@ -463,7 +479,7 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) | ||||
|   if (mmapped_areas == NULL) | ||||
|     { | ||||
|       /* First mmap call, create STL map */ | ||||
|       mmapped_areas = new map; | ||||
|       mmapped_areas = (map *) ccalloc (HEAP_MMAP, 1, sizeof (map)); | ||||
|       if (mmapped_areas == NULL) | ||||
| 	{ | ||||
| 	  set_errno (ENOMEM); | ||||
| @@ -530,9 +546,9 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) | ||||
|   if (map_list && fd == -1 && off == 0 && !(flags & MAP_FIXED)) | ||||
|     { | ||||
|       mmap_record *rec; | ||||
|       if ((rec = map_list->match (off, len)) != NULL) | ||||
|       if ((rec = map_list->search_record (off, len)) != NULL) | ||||
| 	{ | ||||
| 	  if ((off = rec->map_map (off, len)) == (_off64_t)-1) | ||||
| 	  if ((off = rec->map_pages (off, len)) == (_off64_t)-1) | ||||
| 	    { | ||||
| 	      syscall_printf ("-1 = mmap()"); | ||||
| 	      ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK, "mmap"); | ||||
| @@ -574,9 +590,8 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) | ||||
|       return MAP_FAILED; | ||||
|     } | ||||
|  | ||||
|   /* Now we should have a successfully mmapped area. | ||||
|      Need to save it so forked children can reproduce it. | ||||
|   */ | ||||
|   /* At this point we should have a successfully mmapped area. | ||||
|      Now it's time for bookkeeping stuff. */ | ||||
|   if (fd == -1) | ||||
|     gran_len = PAGE_CNT (gran_len) * getpagesize (); | ||||
|   mmap_record mmap_rec (fd, h, access, gran_off, gran_len, base); | ||||
| @@ -587,7 +602,7 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) | ||||
|   if (!map_list) | ||||
|     { | ||||
|       /* Create a new one */ | ||||
|       map_list = new list; | ||||
|       map_list = mmapped_areas->add_list (fd); | ||||
|       if (!map_list) | ||||
| 	{ | ||||
| 	  fh->munmap (h, base, gran_len); | ||||
| @@ -596,11 +611,20 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) | ||||
| 	  ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); | ||||
| 	  return MAP_FAILED; | ||||
| 	} | ||||
|       map_list = mmapped_areas->add_list (map_list, fd); | ||||
|   } | ||||
|  | ||||
|   /* Insert into the list */ | ||||
|   mmap_record *rec = map_list->add_record (mmap_rec, off, len > gran_len ? gran_len : len); | ||||
|   mmap_record *rec = map_list->add_record (mmap_rec, off, | ||||
| 					   len > gran_len ? gran_len : len); | ||||
|   if (!rec) | ||||
|     { | ||||
|       fh->munmap (h, base, gran_len); | ||||
|       set_errno (ENOMEM); | ||||
|       syscall_printf ("-1 = mmap(): ENOMEM"); | ||||
|       ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); | ||||
|       return MAP_FAILED; | ||||
|     } | ||||
|  | ||||
|   caddr_t ret = rec->get_address () + (off - gran_off); | ||||
|   syscall_printf ("%x = mmap() succeeded", ret); | ||||
|   ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); | ||||
| @@ -639,27 +663,33 @@ munmap (caddr_t addr, size_t len) | ||||
|  | ||||
|   /* Iterate through the map, unmap pages between addr and addr+len | ||||
|      in all maps. */ | ||||
|  | ||||
|   for (int it = 0; it < mmapped_areas->nlists; ++it) | ||||
|   list *map_list; | ||||
|   for (int list_idx = 0; | ||||
|        (map_list = mmapped_areas->get_list (list_idx)); | ||||
|        ++list_idx) | ||||
|     { | ||||
|       list *map_list = mmapped_areas->lists[it]; | ||||
|       if (map_list) | ||||
|       long record_idx = -1; | ||||
|       caddr_t u_addr; | ||||
|       DWORD u_len; | ||||
|  | ||||
|       while ((record_idx = map_list->search_record(addr, len, u_addr, | ||||
|       						   u_len, record_idx)) >= 0) | ||||
| 	{ | ||||
| 	  long li = -1; | ||||
| 	  caddr_t u_addr; | ||||
| 	  DWORD u_len; | ||||
|  | ||||
| 	  while ((li = map_list->match(addr, len, u_addr, u_len, li)) >= 0) | ||||
| 	  mmap_record *rec = map_list->get_record (record_idx); | ||||
| 	  if (rec->unmap_pages (u_addr, u_len)) | ||||
| 	    { | ||||
| 	      mmap_record *rec = map_list->recs + li; | ||||
| 	      if (rec->unmap_map (u_addr, u_len)) | ||||
| 		{ | ||||
| 		  fhandler_base *fh = rec->alloc_fh (); | ||||
| 		  fh->munmap (rec->get_handle (), addr, len); | ||||
| 		  rec->free_fh (fh); | ||||
| 	      /* The whole record has been unmapped, so... */ | ||||
| 	      fhandler_base *fh = rec->alloc_fh (); | ||||
| 	      fh->munmap (rec->get_handle (), addr, len); | ||||
| 	      rec->free_fh (fh); | ||||
|  | ||||
| 		  /* Delete the entry. */ | ||||
| 		  map_list->erase (li); | ||||
| 	      /* ...delete the record. */ | ||||
| 	      if (map_list->del_record (record_idx--)) | ||||
| 		{ | ||||
| 		  /* Yay, the last record has been removed from the list, | ||||
| 		     we can remove the list now, too. */ | ||||
| 		  mmapped_areas->del_list (list_idx--); | ||||
| 		  break; | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
| @@ -700,33 +730,34 @@ msync (caddr_t addr, size_t len, int flags) | ||||
|   /* Iterate through the map, looking for the mmapped area. | ||||
|      Error if not found. */ | ||||
|  | ||||
|   for (int it = 0; it < mmapped_areas->nlists; ++it) | ||||
|   list *map_list; | ||||
|   for (int list_idx = 0; | ||||
|        (map_list = mmapped_areas->get_list (list_idx)); | ||||
|        ++list_idx) | ||||
|     { | ||||
|       list *map_list = mmapped_areas->lists[it]; | ||||
|       if (map_list != 0) | ||||
|       mmap_record *rec; | ||||
|       for (int record_idx = 0; | ||||
|       	   (rec = map_list->get_record (record_idx)); | ||||
| 	   ++record_idx) | ||||
| 	{ | ||||
| 	  for (int li = 0; li < map_list->nrecs; ++li) | ||||
| 	  if (rec->access (addr)) | ||||
| 	    { | ||||
| 	      mmap_record *rec = map_list->recs + li; | ||||
| 	      if (rec->access (addr)) | ||||
| 		{ | ||||
| 		  /* Check whole area given by len. */ | ||||
| 		  for (DWORD i = getpagesize (); i < len; ++i) | ||||
| 		    if (!rec->access (addr + i)) | ||||
| 		      goto invalid_address_range; | ||||
| 		  fhandler_base *fh = rec->alloc_fh (); | ||||
| 		  int ret = fh->msync (rec->get_handle (), addr, len, flags); | ||||
| 		  rec->free_fh (fh); | ||||
| 	      /* Check whole area given by len. */ | ||||
| 	      for (DWORD i = getpagesize (); i < len; ++i) | ||||
| 		if (!rec->access (addr + i)) | ||||
| 		  goto invalid_address_range; | ||||
| 	      fhandler_base *fh = rec->alloc_fh (); | ||||
| 	      int ret = fh->msync (rec->get_handle (), addr, len, flags); | ||||
| 	      rec->free_fh (fh); | ||||
|  | ||||
| 		  if (ret) | ||||
| 		    syscall_printf ("%d = msync(): %E", ret); | ||||
| 		  else | ||||
| 		    syscall_printf ("0 = msync()"); | ||||
| 	      if (ret) | ||||
| 		syscall_printf ("%d = msync(): %E", ret); | ||||
| 	      else | ||||
| 		syscall_printf ("0 = msync()"); | ||||
|  | ||||
| 		  ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, | ||||
| 				       "msync"); | ||||
| 		  return 0; | ||||
| 		} | ||||
| 	      ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, | ||||
| 				   "msync"); | ||||
| 	      return 0; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| @@ -975,94 +1006,94 @@ fixup_mmaps_after_fork (HANDLE parent) | ||||
|     return 0; | ||||
|  | ||||
|   /* Iterate through the map */ | ||||
|   for (int it = 0; it < mmapped_areas->nlists; ++it) | ||||
|   list *map_list; | ||||
|   for (int list_idx = 0; | ||||
|        (map_list = mmapped_areas->get_list (list_idx)); | ||||
|        ++list_idx) | ||||
|     { | ||||
|       list *map_list = mmapped_areas->lists[it]; | ||||
|       if (map_list) | ||||
|       mmap_record *rec; | ||||
|       for (int record_idx = 0; | ||||
|       	   (rec = map_list->get_record (record_idx)); | ||||
| 	   ++record_idx) | ||||
| 	{ | ||||
| 	  int li; | ||||
| 	  for (li = 0; li < map_list->nrecs; ++li) | ||||
|  | ||||
| 	  debug_printf ("fd %d, h %x, access %x, offset %D, size %u, address %p", | ||||
| 	      rec->get_fd (), rec->get_handle (), rec->get_access (), | ||||
| 	      rec->get_offset (), rec->get_size (), rec->get_address ()); | ||||
|  | ||||
| 	  fhandler_base *fh = rec->alloc_fh (); | ||||
| 	  BOOL ret = fh->fixup_mmap_after_fork (rec->get_handle (), | ||||
| 						rec->get_access (), | ||||
| 						rec->get_offset (), | ||||
| 						rec->get_size (), | ||||
| 						rec->get_address ()); | ||||
| 	  rec->free_fh (fh); | ||||
|  | ||||
| 	  if (!ret) | ||||
| 	    return -1; | ||||
| 	  if (rec->get_access () == FILE_MAP_COPY) | ||||
| 	    { | ||||
| 	      mmap_record *rec = map_list->recs + li; | ||||
| 	      for (char *address = rec->get_address (); | ||||
| 		   address < rec->get_address () + rec->get_size (); | ||||
| 		   address += getpagesize ()) | ||||
| 		if (rec->access (address) | ||||
| 		    && !ReadProcessMemory (parent, address, address, | ||||
| 					   getpagesize (), NULL)) | ||||
| 		  { | ||||
| 		    DWORD old_prot; | ||||
| 		    DWORD last_error = GetLastError (); | ||||
|  | ||||
| 	      debug_printf ("fd %d, h %x, access %x, offset %D, size %u, address %p", | ||||
| 		  rec->get_fd (), rec->get_handle (), rec->get_access (), | ||||
| 		  rec->get_offset (), rec->get_size (), rec->get_address ()); | ||||
|  | ||||
| 	      fhandler_base *fh = rec->alloc_fh (); | ||||
| 	      BOOL ret = fh->fixup_mmap_after_fork (rec->get_handle (), | ||||
| 						    rec->get_access (), | ||||
| 						    rec->get_offset (), | ||||
| 						    rec->get_size (), | ||||
| 						    rec->get_address ()); | ||||
| 	      rec->free_fh (fh); | ||||
|  | ||||
| 	      if (!ret) | ||||
| 		return -1; | ||||
| 	      if (rec->get_access () == FILE_MAP_COPY) | ||||
| 		{ | ||||
| 		  for (char *address = rec->get_address (); | ||||
| 		       address < rec->get_address () + rec->get_size (); | ||||
| 		       address += getpagesize ()) | ||||
| 		    if (rec->access (address) | ||||
| 			&& !ReadProcessMemory (parent, address, address, | ||||
| 					       getpagesize (), NULL)) | ||||
| 		    if (last_error != ERROR_PARTIAL_COPY | ||||
| 			&& last_error != ERROR_NOACCESS | ||||
| 			|| !wincap.virtual_protect_works_on_shared_pages ()) | ||||
| 		      { | ||||
| 			DWORD old_prot; | ||||
| 			DWORD last_error = GetLastError (); | ||||
| 			system_printf ("ReadProcessMemory failed for " | ||||
| 				       "MAP_PRIVATE address %p, %E", | ||||
| 				       rec->get_address ()); | ||||
| 			return -1; | ||||
| 		      } | ||||
| 		    if (!VirtualProtectEx (parent, | ||||
| 					   address, getpagesize (), | ||||
| 					   PAGE_READONLY, &old_prot)) | ||||
| 		      { | ||||
| 			system_printf ("VirtualProtectEx failed for " | ||||
| 				       "MAP_PRIVATE address %p, %E", | ||||
| 				       rec->get_address ()); | ||||
| 			return -1; | ||||
| 		      } | ||||
| 		    else | ||||
| 		      { | ||||
| 			BOOL ret; | ||||
| 			DWORD dummy_prot; | ||||
|  | ||||
| 			if (last_error != ERROR_PARTIAL_COPY | ||||
| 			    && last_error != ERROR_NOACCESS | ||||
| 			    || !wincap.virtual_protect_works_on_shared_pages ()) | ||||
| 			ret = ReadProcessMemory (parent, address, address, | ||||
| 						 getpagesize (), NULL); | ||||
| 			if (!VirtualProtectEx(parent, | ||||
| 					      address, getpagesize (), | ||||
| 					      old_prot, &dummy_prot)) | ||||
| 			  system_printf ("WARNING: VirtualProtectEx to " | ||||
| 					 "return to previous state " | ||||
| 					 "in parent failed for " | ||||
| 					 "MAP_PRIVATE address %p, %E", | ||||
| 					 rec->get_address ()); | ||||
| 			if (!VirtualProtect (address, getpagesize (), | ||||
| 					     old_prot, &dummy_prot)) | ||||
| 			  system_printf ("WARNING: VirtualProtect to copy " | ||||
| 					 "protection to child failed for" | ||||
| 					 "MAP_PRIVATE address %p, %E", | ||||
| 					 rec->get_address ()); | ||||
| 			if (!ret) | ||||
| 			  { | ||||
| 			    system_printf ("ReadProcessMemory failed for " | ||||
| 			    system_printf ("ReadProcessMemory (2nd try) " | ||||
| 					   "failed for " | ||||
| 					   "MAP_PRIVATE address %p, %E", | ||||
| 					   rec->get_address ()); | ||||
| 			    return -1; | ||||
| 			  } | ||||
| 			if (!VirtualProtectEx (parent, | ||||
| 					       address, getpagesize (), | ||||
| 					       PAGE_READONLY, &old_prot)) | ||||
| 			  { | ||||
| 			    system_printf ("VirtualProtectEx failed for " | ||||
| 					   "MAP_PRIVATE address %p, %E", | ||||
| 					   rec->get_address ()); | ||||
| 			    return -1; | ||||
| 			  } | ||||
| 			else | ||||
| 			  { | ||||
| 			    BOOL ret; | ||||
| 			    DWORD dummy_prot; | ||||
|  | ||||
| 			    ret = ReadProcessMemory (parent, address, address, | ||||
| 						     getpagesize (), NULL); | ||||
| 			    if (!VirtualProtectEx(parent, | ||||
| 						  address, getpagesize (), | ||||
| 						  old_prot, &dummy_prot)) | ||||
| 			      system_printf ("WARNING: VirtualProtectEx to " | ||||
| 					     "return to previous state " | ||||
| 					     "in parent failed for " | ||||
| 					     "MAP_PRIVATE address %p, %E", | ||||
| 					     rec->get_address ()); | ||||
| 			    if (!VirtualProtect (address, getpagesize (), | ||||
| 						 old_prot, &dummy_prot)) | ||||
| 			      system_printf ("WARNING: VirtualProtect to copy " | ||||
| 					     "protection to child failed for" | ||||
| 					     "MAP_PRIVATE address %p, %E", | ||||
| 					     rec->get_address ()); | ||||
| 			    if (!ret) | ||||
| 			      { | ||||
| 				system_printf ("ReadProcessMemory (2nd try) " | ||||
| 					       "failed for " | ||||
| 					       "MAP_PRIVATE address %p, %E", | ||||
| 					       rec->get_address ()); | ||||
| 				return -1; | ||||
| 			      } | ||||
| 			  } | ||||
| 		      } | ||||
| 		} | ||||
| 	      rec->fixup_map (); | ||||
| 		  } | ||||
| 	    } | ||||
| 	  rec->fixup_page_map (); | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user