void NaClVmmapMakeSorted(struct NaClVmmap *self) { if (self->is_sorted) return; NaClVmmapRemoveMarked(self); qsort(self->vmentry, self->nvalid, sizeof *self->vmentry, NaClVmmapCmpEntries); self->is_sorted = 1; #if REMOVE_MARKED_DEBUG NaClVmmapDebug(self, "After Sort"); #endif }
/* * Update the virtual memory map. Deletion is handled by a remove * flag, since a NULL nmop just means that the memory is backed by the * system paging file. */ void NaClVmmapUpdate(struct NaClVmmap *self, uintptr_t page_num, size_t npages, int prot, struct NaClMemObj *nmop, int remove) { /* update existing entries or create new entry as needed */ size_t i; uintptr_t new_region_end_page = page_num + npages; NaClLog(2, ("NaClVmmapUpdate(0x%08"NACL_PRIxPTR", " "0x%"NACL_PRIxPTR", 0x%"NACL_PRIxS", " "0x%x, 0x%08"NACL_PRIxPTR", %d)\n"), (uintptr_t) self, page_num, npages, prot, (uintptr_t) nmop, remove); NaClVmmapMakeSorted(self); CHECK(npages > 0); for (i = 0; i < self->nvalid; i++) { struct NaClVmmapEntry *ent = self->vmentry[i]; uintptr_t ent_end_page = ent->page_num + ent->npages; nacl_off64_t additional_offset = (new_region_end_page - ent->page_num) << NACL_PAGESHIFT; if (ent->page_num < page_num && new_region_end_page < ent_end_page) { /* * Split existing mapping into two parts, with new mapping in * the middle. */ if (!NaClVmmapAdd(self, new_region_end_page, ent_end_page - new_region_end_page, ent->prot, NaClMemObjSplit(ent->nmop, additional_offset))) { NaClLog(LOG_FATAL, "NaClVmmapUpdate: could not split entry\n"); } ent->npages = page_num - ent->page_num; break; } else if (ent->page_num < page_num && page_num < ent_end_page) { /* New mapping overlaps end of existing mapping. */ ent->npages = page_num - ent->page_num; } else if (ent->page_num < new_region_end_page && new_region_end_page < ent_end_page) { /* New mapping overlaps start of existing mapping. */ NaClMemObjIncOffset(ent->nmop, additional_offset); ent->page_num = new_region_end_page; ent->npages = ent_end_page - new_region_end_page; break; } else if (page_num <= ent->page_num && ent_end_page <= new_region_end_page) { /* New mapping covers all of the existing mapping. */ ent->removed = 1; } else { /* No overlap */ assert(new_region_end_page <= ent->page_num || ent_end_page <= page_num); } } if (!remove) { if (!NaClVmmapAdd(self, page_num, npages, prot, nmop)) { NaClLog(LOG_FATAL, "NaClVmmapUpdate: could not add entry\n"); } } NaClVmmapRemoveMarked(self); }
/* * Update the virtual memory map. Deletion is handled by a remove * flag, since a NULL desc just means that the memory is backed by the * system paging file. */ static void NaClVmmapUpdate(struct NaClVmmap *self, uintptr_t page_num, size_t npages, int prot, int flags, int remove, struct NaClDesc *desc, nacl_off64_t offset, nacl_off64_t file_size) { /* update existing entries or create new entry as needed */ size_t i; uintptr_t new_region_end_page = page_num + npages; NaClLog(2, ("NaClVmmapUpdate(0x%08"NACL_PRIxPTR", 0x%"NACL_PRIxPTR", " "0x%"NACL_PRIxS", 0x%x, 0x%x, %d, 0x%"NACL_PRIxPTR", " "0x%"NACL_PRIx64")\n"), (uintptr_t) self, page_num, npages, prot, flags, remove, (uintptr_t) desc, offset); NaClVmmapMakeSorted(self); CHECK(npages > 0); for (i = 0; i < self->nvalid; i++) { struct NaClVmmapEntry *ent = self->vmentry[i]; uintptr_t ent_end_page = ent->page_num + ent->npages; nacl_off64_t additional_offset = (new_region_end_page - ent->page_num) << NACL_PAGESHIFT; if (ent->page_num < page_num && new_region_end_page < ent_end_page) { /* * Split existing mapping into two parts, with new mapping in * the middle. */ NaClVmmapAdd(self, new_region_end_page, ent_end_page - new_region_end_page, ent->prot, ent->flags, ent->desc, ent->offset + additional_offset, ent->file_size); ent->npages = page_num - ent->page_num; break; } else if (ent->page_num < page_num && page_num < ent_end_page) { /* New mapping overlaps end of existing mapping. */ ent->npages = page_num - ent->page_num; } else if (ent->page_num < new_region_end_page && new_region_end_page < ent_end_page) { /* New mapping overlaps start of existing mapping. */ ent->page_num = new_region_end_page; ent->npages = ent_end_page - new_region_end_page; ent->offset += additional_offset; break; } else if (page_num <= ent->page_num && ent_end_page <= new_region_end_page) { /* New mapping covers all of the existing mapping. */ ent->removed = 1; } else { /* No overlap */ assert(new_region_end_page <= ent->page_num || ent_end_page <= page_num); } } if (!remove) { NaClVmmapAdd(self, page_num, npages, prot, flags, desc, offset, file_size); } NaClVmmapRemoveMarked(self); }