1139743Simp/*-
2123474Swpaul * Copyright (c) 2003
3123474Swpaul *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4123474Swpaul *
5123474Swpaul * Redistribution and use in source and binary forms, with or without
6123474Swpaul * modification, are permitted provided that the following conditions
7123474Swpaul * are met:
8123474Swpaul * 1. Redistributions of source code must retain the above copyright
9123474Swpaul *    notice, this list of conditions and the following disclaimer.
10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright
11123474Swpaul *    notice, this list of conditions and the following disclaimer in the
12123474Swpaul *    documentation and/or other materials provided with the distribution.
13123474Swpaul * 3. All advertising materials mentioning features or use of this software
14123474Swpaul *    must display the following acknowledgement:
15123474Swpaul *	This product includes software developed by Bill Paul.
16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors
17123474Swpaul *    may be used to endorse or promote products derived from this software
18123474Swpaul *    without specific prior written permission.
19123474Swpaul *
20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23123474Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
31123474Swpaul */
32123474Swpaul
33123474Swpaul#include <sys/cdefs.h>
34123474Swpaul__FBSDID("$FreeBSD$");
35123474Swpaul
36123474Swpaul/*
37123474Swpaul * This file contains routines for relocating and dynamically linking
38123474Swpaul * executable object code files in the Windows(r) PE (Portable Executable)
39123474Swpaul * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
40123474Swpaul * considered an executable, and all such files have some structures in
41123474Swpaul * common. The PE format was apparently based largely on COFF but has
42123474Swpaul * mutated significantly over time. We are mainly concerned with .SYS files,
43123474Swpaul * so this module implements only enough routines to be able to parse the
44123474Swpaul * headers and sections of a .SYS object file and perform the necessary
45123474Swpaul * relocations and jump table patching to allow us to call into it
46123474Swpaul * (and to have it call back to us). Note that while this module
47123474Swpaul * can handle fixups for imported symbols, it knows nothing about
48123474Swpaul * exporting them.
49123474Swpaul */
50123474Swpaul
51123474Swpaul#include <sys/param.h>
52123474Swpaul#include <sys/types.h>
53123474Swpaul#include <sys/errno.h>
54123474Swpaul#ifdef _KERNEL
55123474Swpaul#include <sys/systm.h>
56123474Swpaul#else
57123474Swpaul#include <stdio.h>
58151703Swpaul#include <stddef.h>
59123474Swpaul#include <stdlib.h>
60123474Swpaul#include <unistd.h>
61123474Swpaul#include <string.h>
62123474Swpaul#endif
63123474Swpaul
64123474Swpaul#include <compat/ndis/pe_var.h>
65123474Swpaul
66124502Sobrienstatic vm_offset_t pe_functbl_match(image_patch_table *, char *);
67123474Swpaul
68123474Swpaul/*
69123474Swpaul * Check for an MS-DOS executable header. All Windows binaries
70123474Swpaul * have a small MS-DOS executable prepended to them to print out
71123474Swpaul * the "This program requires Windows" message. Even .SYS files
72123474Swpaul * have this header, in spite of the fact that you're can't actually
73123474Swpaul * run them directly.
74123474Swpaul */
75123474Swpaul
76123474Swpaulint
77123474Swpaulpe_get_dos_header(imgbase, hdr)
78123474Swpaul	vm_offset_t		imgbase;
79123474Swpaul	image_dos_header	*hdr;
80123474Swpaul{
81123474Swpaul	uint16_t		signature;
82123474Swpaul
83123821Swpaul	if (imgbase == 0 || hdr == NULL)
84123474Swpaul		return (EINVAL);
85123474Swpaul
86123474Swpaul	signature = *(uint16_t *)imgbase;
87123474Swpaul	if (signature != IMAGE_DOS_SIGNATURE)
88123474Swpaul		return (ENOEXEC);
89123474Swpaul
90123474Swpaul	bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
91123474Swpaul
92198786Srpaulo	return (0);
93123474Swpaul}
94123474Swpaul
95123474Swpaul/*
96123474Swpaul * Verify that this image has a Windows NT PE signature.
97123474Swpaul */
98123474Swpaul
99123474Swpaulint
100123474Swpaulpe_is_nt_image(imgbase)
101123474Swpaul	vm_offset_t		imgbase;
102123474Swpaul{
103123474Swpaul	uint32_t		signature;
104123474Swpaul	image_dos_header	*dos_hdr;
105123474Swpaul
106123821Swpaul	if (imgbase == 0)
107123474Swpaul		return (EINVAL);
108123474Swpaul
109123474Swpaul	signature = *(uint16_t *)imgbase;
110123474Swpaul	if (signature == IMAGE_DOS_SIGNATURE) {
111123474Swpaul		dos_hdr = (image_dos_header *)imgbase;
112123474Swpaul		signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
113123474Swpaul		if (signature == IMAGE_NT_SIGNATURE)
114198786Srpaulo			return (0);
115123474Swpaul	}
116123474Swpaul
117198786Srpaulo	return (ENOEXEC);
118123474Swpaul}
119123474Swpaul
120123474Swpaul/*
121123474Swpaul * Return a copy of the optional header. This contains the
122123474Swpaul * executable entry point and the directory listing which we
123123474Swpaul * need to find the relocations and imports later.
124123474Swpaul */
125123474Swpaul
126123474Swpaulint
127123474Swpaulpe_get_optional_header(imgbase, hdr)
128123474Swpaul	vm_offset_t		imgbase;
129123474Swpaul	image_optional_header	*hdr;
130123474Swpaul{
131123474Swpaul	image_dos_header	*dos_hdr;
132123474Swpaul	image_nt_header		*nt_hdr;
133123474Swpaul
134123821Swpaul	if (imgbase == 0 || hdr == NULL)
135198786Srpaulo		return (EINVAL);
136123474Swpaul
137123474Swpaul	if (pe_is_nt_image(imgbase))
138123474Swpaul		return (EINVAL);
139123474Swpaul
140123474Swpaul	dos_hdr = (image_dos_header *)(imgbase);
141123474Swpaul	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
142123474Swpaul
143123474Swpaul	bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
144151703Swpaul	    nt_hdr->inh_filehdr.ifh_optionalhdrlen);
145123474Swpaul
146198786Srpaulo	return (0);
147123474Swpaul}
148123474Swpaul
149123474Swpaul/*
150123474Swpaul * Return a copy of the file header. Contains the number of
151123474Swpaul * sections in this image.
152123474Swpaul */
153123474Swpaul
154123474Swpaulint
155123474Swpaulpe_get_file_header(imgbase, hdr)
156123474Swpaul	vm_offset_t		imgbase;
157123474Swpaul	image_file_header	*hdr;
158123474Swpaul{
159123474Swpaul	image_dos_header	*dos_hdr;
160123474Swpaul	image_nt_header		*nt_hdr;
161123474Swpaul
162123821Swpaul	if (imgbase == 0 || hdr == NULL)
163198786Srpaulo		return (EINVAL);
164123474Swpaul
165123474Swpaul	if (pe_is_nt_image(imgbase))
166123474Swpaul		return (EINVAL);
167123474Swpaul
168123474Swpaul	dos_hdr = (image_dos_header *)imgbase;
169123474Swpaul	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
170123474Swpaul
171151703Swpaul	/*
172151703Swpaul	 * Note: the size of the nt_header is variable since it
173151703Swpaul	 * can contain optional fields, as indicated by ifh_optionalhdrlen.
174151703Swpaul	 * However it happens we're only interested in fields in the
175151703Swpaul	 * non-variant portion of the nt_header structure, so we don't
176151703Swpaul	 * bother copying the optional parts here.
177151703Swpaul	 */
178151703Swpaul
179123474Swpaul	bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
180123474Swpaul	    sizeof(image_file_header));
181123474Swpaul
182198786Srpaulo	return (0);
183123474Swpaul}
184123474Swpaul
185123474Swpaul/*
186123474Swpaul * Return the header of the first section in this image (usually
187123474Swpaul * .text).
188123474Swpaul */
189123474Swpaul
190123474Swpaulint
191123474Swpaulpe_get_section_header(imgbase, hdr)
192123474Swpaul	vm_offset_t		imgbase;
193123474Swpaul	image_section_header	*hdr;
194123474Swpaul{
195123474Swpaul	image_dos_header	*dos_hdr;
196123474Swpaul	image_nt_header		*nt_hdr;
197123474Swpaul	image_section_header	*sect_hdr;
198123474Swpaul
199123821Swpaul	if (imgbase == 0 || hdr == NULL)
200198786Srpaulo		return (EINVAL);
201123474Swpaul
202123474Swpaul	if (pe_is_nt_image(imgbase))
203123474Swpaul		return (EINVAL);
204123474Swpaul
205123474Swpaul	dos_hdr = (image_dos_header *)imgbase;
206123474Swpaul	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
207151703Swpaul	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
208123474Swpaul
209123474Swpaul	bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
210123474Swpaul
211198786Srpaulo	return (0);
212123474Swpaul}
213123474Swpaul
214123474Swpaul/*
215123474Swpaul * Return the number of sections in this executable, or 0 on error.
216123474Swpaul */
217123474Swpaul
218123474Swpaulint
219123474Swpaulpe_numsections(imgbase)
220123474Swpaul	vm_offset_t		imgbase;
221123474Swpaul{
222123474Swpaul	image_file_header	file_hdr;
223123474Swpaul
224123474Swpaul	if (pe_get_file_header(imgbase, &file_hdr))
225198786Srpaulo		return (0);
226123474Swpaul
227123474Swpaul	return (file_hdr.ifh_numsections);
228123474Swpaul}
229123474Swpaul
230123474Swpaul/*
231123474Swpaul * Return the base address that this image was linked for.
232123474Swpaul * This helps us calculate relocation addresses later.
233123474Swpaul */
234123474Swpaul
235123474Swpaulvm_offset_t
236123474Swpaulpe_imagebase(imgbase)
237123474Swpaul	vm_offset_t		imgbase;
238123474Swpaul{
239123474Swpaul	image_optional_header	optional_hdr;
240123474Swpaul
241123474Swpaul	if (pe_get_optional_header(imgbase, &optional_hdr))
242198786Srpaulo		return (0);
243123474Swpaul
244123474Swpaul	return (optional_hdr.ioh_imagebase);
245123474Swpaul}
246123474Swpaul
247123474Swpaul/*
248123474Swpaul * Return the offset of a given directory structure within the
249123474Swpaul * image. Directories reside within sections.
250123474Swpaul */
251123474Swpaul
252123474Swpaulvm_offset_t
253123474Swpaulpe_directory_offset(imgbase, diridx)
254123474Swpaul	vm_offset_t		imgbase;
255123474Swpaul	uint32_t		diridx;
256123474Swpaul{
257123474Swpaul	image_optional_header	opt_hdr;
258123474Swpaul	vm_offset_t		dir;
259123474Swpaul
260123474Swpaul	if (pe_get_optional_header(imgbase, &opt_hdr))
261198786Srpaulo		return (0);
262123474Swpaul
263123474Swpaul	if (diridx >= opt_hdr.ioh_rva_size_cnt)
264198786Srpaulo		return (0);
265123474Swpaul
266123474Swpaul	dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
267123474Swpaul
268198786Srpaulo	return (pe_translate_addr(imgbase, dir));
269123474Swpaul}
270123474Swpaul
271123474Swpaulvm_offset_t
272123474Swpaulpe_translate_addr(imgbase, rva)
273123474Swpaul	vm_offset_t		imgbase;
274141963Swpaul	vm_offset_t		rva;
275123474Swpaul{
276123474Swpaul	image_optional_header	opt_hdr;
277123474Swpaul	image_section_header	*sect_hdr;
278123474Swpaul	image_dos_header	*dos_hdr;
279123474Swpaul	image_nt_header		*nt_hdr;
280123474Swpaul	int			i = 0, sections, fixedlen;
281123474Swpaul
282123474Swpaul	if (pe_get_optional_header(imgbase, &opt_hdr))
283198786Srpaulo		return (0);
284123474Swpaul
285123474Swpaul	sections = pe_numsections(imgbase);
286123474Swpaul
287123474Swpaul	dos_hdr = (image_dos_header *)imgbase;
288123474Swpaul	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
289151703Swpaul	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
290123474Swpaul
291123474Swpaul	/*
292123474Swpaul	 * The test here is to see if the RVA falls somewhere
293123474Swpaul	 * inside the section, based on the section's start RVA
294123474Swpaul	 * and its length. However it seems sometimes the
295123474Swpaul	 * virtual length isn't enough to cover the entire
296123474Swpaul	 * area of the section. We fudge by taking into account
297123474Swpaul	 * the section alignment and rounding the section length
298123474Swpaul	 * up to a page boundary.
299123474Swpaul	 */
300123474Swpaul	while (i++ < sections) {
301123474Swpaul		fixedlen = sect_hdr->ish_misc.ish_vsize;
302123474Swpaul		fixedlen += ((opt_hdr.ioh_sectalign - 1) -
303123474Swpaul		    sect_hdr->ish_misc.ish_vsize) &
304123474Swpaul		    (opt_hdr.ioh_sectalign - 1);
305142037Swpaul		if (sect_hdr->ish_vaddr <= (uint32_t)rva &&
306123474Swpaul		    (sect_hdr->ish_vaddr + fixedlen) >
307142037Swpaul		    (uint32_t)rva)
308123474Swpaul			break;
309123474Swpaul		sect_hdr++;
310123474Swpaul	}
311123474Swpaul
312123474Swpaul	if (i > sections)
313198786Srpaulo		return (0);
314123474Swpaul
315198786Srpaulo	return ((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
316123474Swpaul	    sect_hdr->ish_rawdataaddr));
317123474Swpaul}
318123474Swpaul
319123474Swpaul/*
320123474Swpaul * Get the section header for a particular section. Note that
321123474Swpaul * section names can be anything, but there are some standard
322123474Swpaul * ones (.text, .data, .rdata, .reloc).
323123474Swpaul */
324123474Swpaul
325123474Swpaulint
326123474Swpaulpe_get_section(imgbase, hdr, name)
327123474Swpaul	vm_offset_t		imgbase;
328123474Swpaul	image_section_header	*hdr;
329123474Swpaul	const char		*name;
330123474Swpaul{
331123474Swpaul	image_dos_header	*dos_hdr;
332123474Swpaul	image_nt_header		*nt_hdr;
333123474Swpaul	image_section_header	*sect_hdr;
334123474Swpaul
335123474Swpaul	int			i, sections;
336123474Swpaul
337123821Swpaul	if (imgbase == 0 || hdr == NULL)
338198786Srpaulo		return (EINVAL);
339123474Swpaul
340123474Swpaul	if (pe_is_nt_image(imgbase))
341123474Swpaul		return (EINVAL);
342123474Swpaul
343123474Swpaul	sections = pe_numsections(imgbase);
344123474Swpaul
345123474Swpaul	dos_hdr = (image_dos_header *)imgbase;
346123474Swpaul	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
347151703Swpaul	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
348123474Swpaul
349123474Swpaul	for (i = 0; i < sections; i++) {
350123474Swpaul		if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
351123474Swpaul			bcopy((char *)sect_hdr, (char *)hdr,
352123474Swpaul			    sizeof(image_section_header));
353198786Srpaulo			return (0);
354123474Swpaul		} else
355123474Swpaul			sect_hdr++;
356123474Swpaul	}
357123474Swpaul
358123474Swpaul	return (ENOEXEC);
359123474Swpaul}
360123474Swpaul
361123474Swpaul/*
362123474Swpaul * Apply the base relocations to this image. The relocation table
363123474Swpaul * resides within the .reloc section. Relocations are specified in
364123474Swpaul * blocks which refer to a particular page. We apply the relocations
365123474Swpaul * one page block at a time.
366123474Swpaul */
367123474Swpaul
368123474Swpaulint
369123474Swpaulpe_relocate(imgbase)
370123474Swpaul	vm_offset_t		imgbase;
371123474Swpaul{
372123474Swpaul	image_section_header	sect;
373123474Swpaul	image_base_reloc	*relhdr;
374123474Swpaul	uint16_t		rel, *sloc;
375141963Swpaul	vm_offset_t		base;
376141963Swpaul	vm_size_t		delta;
377141963Swpaul	uint32_t		*lloc;
378141963Swpaul	uint64_t		*qloc;
379123474Swpaul	int			i, count;
380123474Swpaul	vm_offset_t		txt;
381123474Swpaul
382123474Swpaul	base = pe_imagebase(imgbase);
383123474Swpaul	pe_get_section(imgbase, &sect, ".text");
384123474Swpaul	txt = pe_translate_addr(imgbase, sect.ish_vaddr);
385123474Swpaul	delta = (uint32_t)(txt) - base - sect.ish_vaddr;
386123474Swpaul
387123474Swpaul	pe_get_section(imgbase, &sect, ".reloc");
388123474Swpaul
389123474Swpaul	relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
390123474Swpaul
391123474Swpaul	do {
392123474Swpaul		count = (relhdr->ibr_blocksize -
393123474Swpaul		    (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
394123474Swpaul		for (i = 0; i < count; i++) {
395123474Swpaul			rel = relhdr->ibr_rel[i];
396123474Swpaul			switch (IMR_RELTYPE(rel)) {
397123474Swpaul			case IMAGE_REL_BASED_ABSOLUTE:
398123474Swpaul				break;
399123474Swpaul			case IMAGE_REL_BASED_HIGHLOW:
400123474Swpaul				lloc = (uint32_t *)pe_translate_addr(imgbase,
401123474Swpaul				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
402123474Swpaul				*lloc = pe_translate_addr(imgbase,
403123474Swpaul				    (*lloc - base));
404123474Swpaul				break;
405123474Swpaul			case IMAGE_REL_BASED_HIGH:
406123474Swpaul				sloc = (uint16_t *)pe_translate_addr(imgbase,
407123474Swpaul				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
408123474Swpaul				*sloc += (delta & 0xFFFF0000) >> 16;
409123474Swpaul				break;
410123474Swpaul			case IMAGE_REL_BASED_LOW:
411123474Swpaul				sloc = (uint16_t *)pe_translate_addr(imgbase,
412123474Swpaul				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
413123474Swpaul				*sloc += (delta & 0xFFFF);
414123474Swpaul				break;
415141963Swpaul			case IMAGE_REL_BASED_DIR64:
416141963Swpaul				qloc = (uint64_t *)pe_translate_addr(imgbase,
417141963Swpaul				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
418141963Swpaul				*qloc = pe_translate_addr(imgbase,
419141963Swpaul				    (*qloc - base));
420189488Sweongyo				break;
421141963Swpaul
422123474Swpaul			default:
423198786Srpaulo				printf("[%d]reloc type: %d\n",i,
424123474Swpaul				    IMR_RELTYPE(rel));
425123474Swpaul				break;
426123474Swpaul			}
427123474Swpaul		}
428123474Swpaul		relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
429123474Swpaul		    relhdr->ibr_blocksize);
430123474Swpaul	} while (relhdr->ibr_blocksize);
431123474Swpaul
432198786Srpaulo	return (0);
433123474Swpaul}
434123474Swpaul
435123474Swpaul/*
436123474Swpaul * Return the import descriptor for a particular module. An image
437123474Swpaul * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
438123474Swpaul * and NDIS.SYS. For each module, there is a list of imported function
439123474Swpaul * names and their addresses.
440142387Swpaul *
441142387Swpaul * Note: module names are case insensitive!
442123474Swpaul */
443123474Swpaul
444123474Swpaulint
445123474Swpaulpe_get_import_descriptor(imgbase, desc, module)
446123474Swpaul	vm_offset_t		imgbase;
447123474Swpaul	image_import_descriptor	*desc;
448123474Swpaul	char			*module;
449189488Sweongyo{
450123474Swpaul	vm_offset_t		offset;
451123474Swpaul	image_import_descriptor	*imp_desc;
452123474Swpaul	char			*modname;
453123474Swpaul
454123821Swpaul	if (imgbase == 0 || module == NULL || desc == NULL)
455198786Srpaulo		return (EINVAL);
456123474Swpaul
457123474Swpaul	offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
458123474Swpaul	if (offset == 0)
459123474Swpaul		return (ENOENT);
460123474Swpaul
461123474Swpaul	imp_desc = (void *)offset;
462123474Swpaul
463123474Swpaul	while (imp_desc->iid_nameaddr) {
464123474Swpaul		modname = (char *)pe_translate_addr(imgbase,
465123474Swpaul		    imp_desc->iid_nameaddr);
466142387Swpaul		if (!strncasecmp(module, modname, strlen(module))) {
467123474Swpaul			bcopy((char *)imp_desc, (char *)desc,
468123474Swpaul			    sizeof(image_import_descriptor));
469198786Srpaulo			return (0);
470123474Swpaul		}
471123474Swpaul		imp_desc++;
472123474Swpaul	}
473123474Swpaul
474123474Swpaul	return (ENOENT);
475123474Swpaul}
476123474Swpaul
477124165Swpaulint
478124165Swpaulpe_get_messagetable(imgbase, md)
479124165Swpaul	vm_offset_t		imgbase;
480124165Swpaul	message_resource_data	**md;
481124165Swpaul{
482124165Swpaul	image_resource_directory	*rdir, *rtype;
483124165Swpaul	image_resource_directory_entry	*dent, *dent2;
484124165Swpaul	image_resource_data_entry	*rent;
485124165Swpaul	vm_offset_t		offset;
486124165Swpaul	int			i;
487124165Swpaul
488124165Swpaul	if (imgbase == 0)
489198786Srpaulo		return (EINVAL);
490124165Swpaul
491124165Swpaul	offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
492124165Swpaul	if (offset == 0)
493124165Swpaul		return (ENOENT);
494124165Swpaul
495124165Swpaul	rdir = (image_resource_directory *)offset;
496124165Swpaul
497124165Swpaul	dent = (image_resource_directory_entry *)(offset +
498124165Swpaul	    sizeof(image_resource_directory));
499124165Swpaul
500124165Swpaul	for (i = 0; i < rdir->ird_id_entries; i++){
501124165Swpaul		if (dent->irde_name != RT_MESSAGETABLE)	{
502124165Swpaul			dent++;
503124165Swpaul			continue;
504124165Swpaul		}
505124165Swpaul		dent2 = dent;
506124165Swpaul		while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
507124165Swpaul			rtype = (image_resource_directory *)(offset +
508124165Swpaul			    (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
509124165Swpaul			dent2 = (image_resource_directory_entry *)
510124165Swpaul			    ((uintptr_t)rtype +
511124165Swpaul			     sizeof(image_resource_directory));
512124165Swpaul		}
513124165Swpaul		rent = (image_resource_data_entry *)(offset +
514124165Swpaul		    dent2->irde_dataoff);
515124165Swpaul		*md = (message_resource_data *)pe_translate_addr(imgbase,
516124165Swpaul		    rent->irde_offset);
517198786Srpaulo		return (0);
518124165Swpaul	}
519124165Swpaul
520198786Srpaulo	return (ENOENT);
521124165Swpaul}
522124165Swpaul
523124165Swpaulint
524124173Swpaulpe_get_message(imgbase, id, str, len, flags)
525124165Swpaul	vm_offset_t		imgbase;
526124165Swpaul	uint32_t		id;
527124165Swpaul	char			**str;
528124165Swpaul	int			*len;
529124173Swpaul	uint16_t		*flags;
530124165Swpaul{
531124165Swpaul	message_resource_data	*md = NULL;
532124165Swpaul	message_resource_block	*mb;
533124165Swpaul	message_resource_entry	*me;
534124173Swpaul	uint32_t		i;
535124165Swpaul
536124165Swpaul	pe_get_messagetable(imgbase, &md);
537124165Swpaul
538124165Swpaul	if (md == NULL)
539198786Srpaulo		return (ENOENT);
540124165Swpaul
541124165Swpaul	mb = (message_resource_block *)((uintptr_t)md +
542124165Swpaul	    sizeof(message_resource_data));
543124165Swpaul
544124165Swpaul	for (i = 0; i < md->mrd_numblocks; i++) {
545124165Swpaul		if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
546124165Swpaul			me = (message_resource_entry *)((uintptr_t)md +
547124165Swpaul			    mb->mrb_entryoff);
548124165Swpaul			for (i = id - mb->mrb_lowid; i > 0; i--)
549124165Swpaul				me = (message_resource_entry *)((uintptr_t)me +
550124165Swpaul				    me->mre_len);
551124173Swpaul			*str = me->mre_text;
552124165Swpaul			*len = me->mre_len;
553124173Swpaul			*flags = me->mre_flags;
554198786Srpaulo			return (0);
555124165Swpaul		}
556124165Swpaul		mb++;
557124165Swpaul	}
558124165Swpaul
559198786Srpaulo	return (ENOENT);
560124165Swpaul}
561124165Swpaul
562123474Swpaul/*
563123474Swpaul * Find the function that matches a particular name. This doesn't
564123474Swpaul * need to be particularly speedy since it's only run when loading
565123474Swpaul * a module for the first time.
566123474Swpaul */
567123474Swpaul
568123474Swpaulstatic vm_offset_t
569123474Swpaulpe_functbl_match(functbl, name)
570123474Swpaul	image_patch_table	*functbl;
571123474Swpaul	char			*name;
572123474Swpaul{
573123474Swpaul	image_patch_table	*p;
574123474Swpaul
575123474Swpaul	if (functbl == NULL || name == NULL)
576198786Srpaulo		return (0);
577123474Swpaul
578123474Swpaul	p = functbl;
579123474Swpaul
580123474Swpaul	while (p->ipt_name != NULL) {
581123474Swpaul		if (!strcmp(p->ipt_name, name))
582198786Srpaulo			return ((vm_offset_t)p->ipt_wrap);
583123474Swpaul		p++;
584123474Swpaul	}
585198786Srpaulo	printf("no match for %s\n", name);
586141963Swpaul
587141963Swpaul	/*
588141963Swpaul	 * Return the wrapper pointer for this routine.
589141963Swpaul	 * For x86, this is the same as the funcptr.
590141963Swpaul	 * For amd64, this points to a wrapper routine
591141963Swpaul	 * that does calling convention translation and
592141963Swpaul	 * then invokes the underlying routine.
593141963Swpaul	 */
594198786Srpaulo	return ((vm_offset_t)p->ipt_wrap);
595123474Swpaul}
596123474Swpaul
597123474Swpaul/*
598123474Swpaul * Patch the imported function addresses for a given module.
599123474Swpaul * The caller must specify the module name and provide a table
600123474Swpaul * of function pointers that will be patched into the jump table.
601123474Swpaul * Note that there are actually two copies of the jump table: one
602123474Swpaul * copy is left alone. In a .SYS file, the jump tables are usually
603123474Swpaul * merged into the INIT segment.
604123474Swpaul */
605123474Swpaul
606123474Swpaulint
607123474Swpaulpe_patch_imports(imgbase, module, functbl)
608123474Swpaul	vm_offset_t		imgbase;
609123474Swpaul	char			*module;
610123474Swpaul	image_patch_table	*functbl;
611123474Swpaul{
612123474Swpaul	image_import_descriptor	imp_desc;
613123474Swpaul	char			*fname;
614123474Swpaul	vm_offset_t		*nptr, *fptr;
615123474Swpaul	vm_offset_t		func;
616123474Swpaul
617123821Swpaul	if (imgbase == 0 || module == NULL || functbl == NULL)
618198786Srpaulo		return (EINVAL);
619123474Swpaul
620123474Swpaul	if (pe_get_import_descriptor(imgbase, &imp_desc, module))
621198786Srpaulo		return (ENOEXEC);
622123474Swpaul
623123474Swpaul	nptr = (vm_offset_t *)pe_translate_addr(imgbase,
624123474Swpaul	    imp_desc.iid_import_name_table_addr);
625123474Swpaul	fptr = (vm_offset_t *)pe_translate_addr(imgbase,
626123474Swpaul	    imp_desc.iid_import_address_table_addr);
627123474Swpaul
628123848Swpaul	while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
629123474Swpaul		fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
630123474Swpaul		func = pe_functbl_match(functbl, fname);
631123474Swpaul		if (func)
632123474Swpaul			*fptr = func;
633123474Swpaul#ifdef notdef
634123474Swpaul		if (*fptr == 0)
635198786Srpaulo			return (ENOENT);
636123474Swpaul#endif
637123474Swpaul		nptr++;
638123474Swpaul		fptr++;
639123474Swpaul	}
640123474Swpaul
641198786Srpaulo	return (0);
642123474Swpaul}
643