+struct pe_module_info
+{
+ struct image_file_map fmap;
+};
+
+static void* pe_map_full(struct image_file_map* fmap, IMAGE_NT_HEADERS** nth)
+{
+ if (!fmap->u.pe.full_map)
+ {
+ fmap->u.pe.full_map = MapViewOfFile(fmap->u.pe.hMap, FILE_MAP_READ, 0, 0, 0);
+ }
+ if (fmap->u.pe.full_map)
+ {
+ if (nth) *nth = RtlImageNtHeader(fmap->u.pe.full_map);
+ fmap->u.pe.full_count++;
+ return fmap->u.pe.full_map;
+ }
+ return IMAGE_NO_MAP;
+}
+
+static void pe_unmap_full(struct image_file_map* fmap)
+{
+ if (fmap->u.pe.full_count && !--fmap->u.pe.full_count)
+ {
+ UnmapViewOfFile(fmap->u.pe.full_map);
+ fmap->u.pe.full_map = NULL;
+ }
+}
+
+/******************************************************************
+ * pe_map_section
+ *
+ * Maps a single section into memory from an PE file
+ */
+const char* pe_map_section(struct image_section_map* ism)
+{
+ void* mapping;
+ struct pe_file_map* fmap = &ism->fmap->u.pe;
+
+ if (ism->sidx >= 0 && ism->sidx < fmap->ntheader.FileHeader.NumberOfSections &&
+ fmap->sect[ism->sidx].mapped == IMAGE_NO_MAP)
+ {
+ IMAGE_NT_HEADERS* nth;
+ /* FIXME: that's rather drastic, but that will do for now
+ * that's ok if the full file map exists, but we could be less agressive otherwise and
+ * only map the relevant section
+ */
+ if ((mapping = pe_map_full(ism->fmap, &nth)))
+ {
+ fmap->sect[ism->sidx].mapped = RtlImageRvaToVa(nth, mapping,
+ fmap->sect[ism->sidx].shdr.VirtualAddress,
+ NULL);
+ return fmap->sect[ism->sidx].mapped;
+ }
+ }
+ return IMAGE_NO_MAP;
+}
+
+/******************************************************************
+ * pe_find_section
+ *
+ * Finds a section by name (and type) into memory from an PE file
+ * or its alternate if any
+ */
+BOOL pe_find_section(struct image_file_map* fmap, const char* name,
+ struct image_section_map* ism)
+{
+ const char* sectname;
+ unsigned i;
+ char tmp[IMAGE_SIZEOF_SHORT_NAME + 1];
+
+ for (i = 0; i < fmap->u.pe.ntheader.FileHeader.NumberOfSections; i++)
+ {
+ sectname = (const char*)fmap->u.pe.sect[i].shdr.Name;
+ /* long section names start with a '/' (at least on MinGW32) */
+ if (sectname[0] == '/' && fmap->u.pe.strtable)
+ sectname = fmap->u.pe.strtable + atoi(sectname + 1);
+ else
+ {
+ /* the section name may not be null terminated */
+ sectname = memcpy(tmp, sectname, IMAGE_SIZEOF_SHORT_NAME);
+ tmp[IMAGE_SIZEOF_SHORT_NAME] = '\0';
+ }
+ if (!strcasecmp(sectname, name))
+ {
+ ism->fmap = fmap;
+ ism->sidx = i;
+ return TRUE;
+ }
+ }
+ ism->fmap = NULL;
+ ism->sidx = -1;
+
+ return FALSE;
+}
+
+/******************************************************************
+ * pe_unmap_section
+ *
+ * Unmaps a single section from memory
+ */
+void pe_unmap_section(struct image_section_map* ism)
+{
+ if (ism->sidx >= 0 && ism->sidx < ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections &&
+ ism->fmap->u.pe.sect[ism->sidx].mapped != IMAGE_NO_MAP)
+ {
+ pe_unmap_full(ism->fmap);
+ ism->fmap->u.pe.sect[ism->sidx].mapped = IMAGE_NO_MAP;
+ }
+}
+
+/******************************************************************
+ * pe_get_map_rva
+ *
+ * Get the RVA of an PE section
+ */
+DWORD_PTR pe_get_map_rva(const struct image_section_map* ism)
+{
+ if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections)
+ return 0;
+ return ism->fmap->u.pe.sect[ism->sidx].shdr.VirtualAddress;
+}
+
+/******************************************************************
+ * pe_get_map_size
+ *
+ * Get the size of an PE section
+ */
+unsigned pe_get_map_size(const struct image_section_map* ism)
+{
+ if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections)
+ return 0;
+ return ism->fmap->u.pe.sect[ism->sidx].shdr.SizeOfRawData;
+}
+
+/******************************************************************
+ * pe_map_file
+ *
+ * Maps an PE file into memory (and checks it's a real PE file)
+ */
+static BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_type mt)
+{
+ void* mapping;
+
+ fmap->modtype = mt;
+ fmap->u.pe.hMap = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (fmap->u.pe.hMap == 0) return FALSE;
+ fmap->u.pe.full_count = 0;
+ fmap->u.pe.full_map = NULL;
+ if (!(mapping = pe_map_full(fmap, NULL))) goto error;
+
+ switch (mt)
+ {
+ case DMT_PE:
+ {
+ IMAGE_NT_HEADERS* nthdr;
+ IMAGE_SECTION_HEADER* section;
+ unsigned i;
+
+ if (!(nthdr = RtlImageNtHeader(mapping))) goto error;
+ memcpy(&fmap->u.pe.ntheader, nthdr, sizeof(fmap->u.pe.ntheader));
+ section = (IMAGE_SECTION_HEADER*)
+ ((char*)&nthdr->OptionalHeader + nthdr->FileHeader.SizeOfOptionalHeader);
+ fmap->u.pe.sect = HeapAlloc(GetProcessHeap(), 0,
+ nthdr->FileHeader.NumberOfSections * sizeof(fmap->u.pe.sect[0]));
+ if (!fmap->u.pe.sect) goto error;
+ for (i = 0; i < nthdr->FileHeader.NumberOfSections; i++)
+ {
+ memcpy(&fmap->u.pe.sect[i].shdr, section + i, sizeof(IMAGE_SECTION_HEADER));
+ fmap->u.pe.sect[i].mapped = IMAGE_NO_MAP;
+ }
+ if (nthdr->FileHeader.PointerToSymbolTable && nthdr->FileHeader.NumberOfSymbols)
+ {
+ /* FIXME ugly: should rather map the relevant content instead of copying it */
+ const char* src = (const char*)mapping +
+ nthdr->FileHeader.PointerToSymbolTable +
+ nthdr->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL);
+ char* dst;
+ DWORD sz = *(DWORD*)src;
+
+ if ((dst = HeapAlloc(GetProcessHeap(), 0, sz)))
+ memcpy(dst, src, sz);
+ fmap->u.pe.strtable = dst;
+ }
+ else fmap->u.pe.strtable = NULL;
+ }
+ break;
+ default: assert(0); goto error;
+ }
+ pe_unmap_full(fmap);
+
+ return TRUE;
+error:
+ pe_unmap_full(fmap);
+ CloseHandle(fmap->u.pe.hMap);
+ return FALSE;
+}
+
+/******************************************************************
+ * pe_unmap_file
+ *
+ * Unmaps an PE file from memory (previously mapped with pe_map_file)
+ */
+static void pe_unmap_file(struct image_file_map* fmap)
+{
+ if (fmap->u.pe.hMap != 0)
+ {
+ struct image_section_map ism;
+ ism.fmap = fmap;
+ for (ism.sidx = 0; ism.sidx < fmap->u.pe.ntheader.FileHeader.NumberOfSections; ism.sidx++)
+ {
+ pe_unmap_section(&ism);
+ }
+ while (fmap->u.pe.full_count) pe_unmap_full(fmap);
+ HeapFree(GetProcessHeap(), 0, fmap->u.pe.sect);
+ HeapFree(GetProcessHeap(), 0, (void*)fmap->u.pe.strtable); /* FIXME ugly (see pe_map_file) */
+ CloseHandle(fmap->u.pe.hMap);
+ fmap->u.pe.hMap = NULL;
+ }
+}
+
+static void pe_module_remove(struct process* pcs, struct module_format* modfmt)
+{
+ pe_unmap_file(&modfmt->u.pe_info->fmap);
+ HeapFree(GetProcessHeap(), 0, modfmt);
+}
+