📄 mmap.cc
字号:
else if (fh->get_device () == FH_ZERO) /* mmap /dev/zero is like MAP_ANONYMOUS. */ fd = -1; } if (fd == -1) { fh_paging_file.set_io_handle (INVALID_HANDLE_VALUE); fh = &fh_paging_file; } list *l = mmapped_areas->get_list_by_fd (fd); /* First check if this mapping matches into the chunk of another already performed mapping. Only valid for MAP_ANON in a special case of MAP_PRIVATE. */ if (l && fd == -1 && off == 0 && !(flags & MAP_FIXED)) { mmap_record *rec; if ((rec = l->match (off, len)) != NULL) { if ((off = rec->map_map (off, len)) == (__off64_t)-1) { syscall_printf ("-1 = mmap()"); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK, "mmap"); return MAP_FAILED; } caddr_t ret = rec->get_address () + off; syscall_printf ("%x = mmap() succeeded", ret); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); return ret; } } DWORD access = (prot & PROT_WRITE) ? FILE_MAP_WRITE : FILE_MAP_READ; /* copy-on-write doesn't work at all on 9x using anonymous maps. Workaround: Anonymous mappings always use normal READ or WRITE access and don't use named file mapping. copy-on-write doesn't also work properly on 9x with real files. While the changes are not propagated to the file, they are visible to other processes sharing the same file mapping object. Workaround: Don't use named file mapping. That should work since sharing file mappings only works reliable using named file mapping on 9x. */ if ((flags & MAP_PRIVATE) && (wincap.has_working_copy_on_write () || fd != -1)) access = FILE_MAP_COPY; h = fh->mmap (&base, gran_len, access, flags, gran_off); if (h == INVALID_HANDLE_VALUE) { ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); return MAP_FAILED; } /* Now we should have a successfully mmapped area. Need to save it so forked children can reproduce it. */ if (fd == -1) gran_len = PAGE_CNT (gran_len) * getpagesize (); mmap_record mmap_rec (fd, h, access, gran_off, gran_len, base); /* Get list of mmapped areas for this fd, create a new one if one does not exist yet. */ if (l == 0) { /* Create a new one */ l = new list; if (l == 0) { 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; } l = mmapped_areas->add_list (l, fd); } /* Insert into the list */ mmap_record *rec = l->add_record (mmap_rec); if ((off = rec->map_map (off, len)) == (__off64_t)-1) { fh->munmap (h, base, gran_len); l->erase (); syscall_printf ("-1 = mmap()"); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); return MAP_FAILED; } caddr_t ret = rec->get_address () + off; syscall_printf ("%x = mmap() succeeded", ret); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); return ret;}extern "C"caddr_tmmap (caddr_t addr, size_t len, int prot, int flags, int fd, __off32_t off){ return mmap64 (addr, len, prot, flags, fd, (__off64_t)off);}/* munmap () removes an mmapped area. It insists that base area requested is the same as that mmapped, error if not. */extern "C"intmunmap (caddr_t addr, size_t len){ syscall_printf ("munmap (addr %x, len %d)", addr, len); /* Error conditions according to SUSv2 */ if (((DWORD)addr % getpagesize ()) || !len) { set_errno (EINVAL); syscall_printf ("-1 = munmap(): Invalid parameters"); return -1; } SetResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); /* Check if a mmap'ed area was ever created */ if (mmapped_areas == NULL) { syscall_printf ("-1 = munmap(): mmapped_areas == NULL"); set_errno (EINVAL); ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); return -1; } /* Iterate through the map, looking for the mmapped area. Error if not found. */ for (int it = 0; it < mmapped_areas->nlists; ++it) { list *l = mmapped_areas->lists[it]; if (l) { long li = -1; if ((li = l->match(addr, len, li)) >= 0) { mmap_record *rec = l->recs + li; if (rec->unmap_map (addr, len)) { fhandler_base *fh = rec->alloc_fh (); fh->munmap (rec->get_handle (), addr, len); rec->free_fh (fh); /* Delete the entry. */ l->erase (li); } syscall_printf ("0 = munmap(): %x", addr); ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); return 0; } } } set_errno (EINVAL); syscall_printf ("-1 = munmap(): EINVAL"); ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); return -1;}/* Sync file with memory. Ignore flags for now. */extern "C"intmsync (caddr_t addr, size_t len, int flags){ syscall_printf ("addr = %x, len = %d, flags = %x", addr, len, flags); /* However, check flags for validity. */ if ((flags & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE)) || ((flags & MS_ASYNC) && (flags & MS_SYNC))) { syscall_printf ("-1 = msync(): Invalid flags"); set_errno (EINVAL); return -1; } SetResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync"); /* Check if a mmap'ed area was ever created */ if (mmapped_areas == NULL) { syscall_printf ("-1 = msync(): mmapped_areas == NULL"); set_errno (EINVAL); ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync"); return -1; } /* Iterate through the map, looking for the mmapped area. Error if not found. */ for (int it = 0; it < mmapped_areas->nlists; ++it) { list *l = mmapped_areas->lists[it]; if (l != 0) { for (int li = 0; li < l->nrecs; ++li) { mmap_record *rec = l->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); if (ret) syscall_printf ("%d = msync(): %E", ret); else syscall_printf ("0 = msync()"); ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync"); return 0; } } } }invalid_address_range: /* SUSv2: Return code if indicated memory was not mapped is ENOMEM. */ set_errno (ENOMEM); syscall_printf ("-1 = msync(): ENOMEM"); ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync"); return -1;}/* * Base implementation: * * `mmap' returns ENODEV as documented in SUSv2. * In contrast to the global function implementation, the member function * `mmap' has to return the mapped base address in `addr' and the handle to * the mapping object as return value. In case of failure, the fhandler * mmap has to close that handle by itself and return INVALID_HANDLE_VALUE. * * `munmap' and `msync' get the handle to the mapping object as first parameter * additionally.*/HANDLEfhandler_base::mmap (caddr_t *addr, size_t len, DWORD access, int flags, __off64_t off){ set_errno (ENODEV); return INVALID_HANDLE_VALUE;}intfhandler_base::munmap (HANDLE h, caddr_t addr, size_t len){ set_errno (ENODEV); return -1;}intfhandler_base::msync (HANDLE h, caddr_t addr, size_t len, int flags){ set_errno (ENODEV); return -1;}BOOLfhandler_base::fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset, DWORD size, void *address){ set_errno (ENODEV); return -1;}/* Implementation for disk files. */HANDLEfhandler_disk_file::mmap (caddr_t *addr, size_t len, DWORD access, int flags, __off64_t off){ DWORD protect; if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY; else if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE; else protect = PAGE_READONLY; HANDLE h; /* On 9x/ME try first to open the mapping by name when opening a shared file object. This is needed since 9x/ME only shares objects between processes by name. What a mess... */ if (wincap.share_mmaps_only_by_name () && get_handle () != INVALID_HANDLE_VALUE && !(access & FILE_MAP_COPY)) { /* Grrr, the whole stuff is just needed to try to get a reliable mapping of the same file. Even that uprising isn't bullet proof but it does it's best... */ char namebuf[MAX_PATH]; cygwin_conv_to_full_posix_path (get_name (), namebuf); for (int i = strlen (namebuf) - 1; i >= 0; --i) namebuf[i] = cyg_tolower (namebuf [i]); debug_printf ("named sharing"); if (!(h = OpenFileMapping (access, TRUE, namebuf))) h = CreateFileMapping (get_handle (), &sec_none, protect, 0, 0, namebuf); } else h = CreateFileMapping (get_handle (), &sec_none, protect, 0, get_handle () == INVALID_HANDLE_VALUE ? len : 0, NULL); if (!h) { __seterrno (); syscall_printf ("-1 = mmap(): CreateFileMapping failed with %E"); return INVALID_HANDLE_VALUE; } DWORD high = off >> 32, low = off & 0xffffffff; void *base = MapViewOfFileEx (h, access, high, low, len, (flags & MAP_FIXED) ? *addr : NULL); debug_printf ("%x = MapViewOfFileEx (h:%x, access:%x, 0, off:%D, len:%d, addr:%x)", base, h, access, off, len, (flags & MAP_FIXED) ? *addr : NULL); if (!base || ((flags & MAP_FIXED) && base != *addr)) { if (!base) { __seterrno (); syscall_printf ("-1 = mmap(): MapViewOfFileEx failed with %E"); } else { set_errno (EINVAL); syscall_printf ("-1 = mmap(): address shift with MAP_FIXED given"); } CloseHandle (h); return INVALID_HANDLE_VALUE; } *addr = (caddr_t) base; return h;}intfhandler_disk_file::munmap (HANDLE h, caddr_t addr, size_t len){ UnmapViewOfFile (addr); CloseHandle (h); return 0;}intfhandler_disk_file::msync (HANDLE h, caddr_t addr, size_t len, int flags){ if (FlushViewOfFile (addr, len) == 0) { __seterrno (); return -1; } return 0;}BOOLfhandler_disk_file::fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset, DWORD size, void *address){ /* Re-create the MapViewOfFileEx call */ void *base = MapViewOfFileEx (h, access, 0, offset, size, address); if (base != address) { MEMORY_BASIC_INFORMATION m; (void) VirtualQuery (address, &m, sizeof (m)); system_printf ("requested %p != %p mem alloc base %p, state %p, size %d, %E", address, base, m.AllocationBase, m.State, m.RegionSize); } return base == address;}/* Set memory protection */extern "C"intmprotect (caddr_t addr, size_t len, int prot){ DWORD old_prot; DWORD new_prot = 0; syscall_printf ("mprotect (addr %x, len %d, prot %x)", addr, len, prot); if (prot == PROT_NONE) new_prot = PAGE_NOACCESS; else { switch (prot) { case PROT_READ | PROT_WRITE | PROT_EXEC: new_prot = PAGE_EXECUTE_READWRITE; break; case PROT_READ | PROT_WRITE: new_prot = PAGE_READWRITE; break; case PROT_READ | PROT_EXEC: new_prot = PAGE_EXECUTE_READ; break; case PROT_READ: new_prot = PAGE_READONLY; break; default: syscall_printf ("-1 = mprotect (): invalid prot value"); set_errno (EINVAL); return -1; } } if (VirtualProtect (addr, len, new_prot, &old_prot) == 0) { __seterrno (); syscall_printf ("-1 = mprotect (): %E"); return -1; } syscall_printf ("0 = mprotect ()"); return 0;}/* * Call to re-create all the file mappings in a forked * child. Called from the child in initialization. At this * point we are passed a valid mmapped_areas map, and all the * HANDLE's are valid for the child, but none of the * mapped areas are in our address space. We need to iterate * through the map, doing the MapViewOfFile calls. */int __stdcallfixup_mmaps_after_fork (HANDLE parent){ debug_printf ("recreate_mmaps_after_fork, mmapped_areas %p", mmapped_areas); /* Check if a mmapped area was ever created */ if (mmapped_areas == NULL) return 0; /* Iterate through the map */ for (int it = 0; it < mmapped_areas->nlists; ++it) { list *l = mmapped_areas->lists[it]; if (l != 0) { int li; for (li = 0; li < l->nrecs; ++li) { mmap_record *rec = l->recs + li; debug_printf ("fd %d, h %x, access %x, offset %d, size %d, 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)) { system_printf ("ReadProcessMemory failed for MAP_PRIVATE address %p, %E", rec->get_address ()); return -1; } } rec->fixup_map (); } } } debug_printf ("succeeded"); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -