190075Sobrien/*-
2132718Skan * Copyright (c) 2003
3169689Skan *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
490075Sobrien *
590075Sobrien * Redistribution and use in source and binary forms, with or without
6132718Skan * modification, are permitted provided that the following conditions
790075Sobrien * are met:
8132718Skan * 1. Redistributions of source code must retain the above copyright
9132718Skan *    notice, this list of conditions and the following disclaimer.
10132718Skan * 2. Redistributions in binary form must reproduce the above copyright
11132718Skan *    notice, this list of conditions and the following disclaimer in the
1290075Sobrien *    documentation and/or other materials provided with the distribution.
13132718Skan * 3. All advertising materials mentioning features or use of this software
14132718Skan *    must display the following acknowledgement:
15132718Skan *	This product includes software developed by Bill Paul.
16132718Skan * 4. Neither the name of the author nor the names of any co-contributors
1790075Sobrien *    may be used to endorse or promote products derived from this software
18132718Skan *    without specific prior written permission.
19132718Skan *
20169689Skan * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2290075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23117395Skan * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24169689Skan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25117395Skan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26117395Skan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2790075Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2890075Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2990075Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3090075Sobrien * THE POSSIBILITY OF SUCH DAMAGE.
3190075Sobrien */
3290075Sobrien
3390075Sobrien#include <sys/cdefs.h>
3490075Sobrien__FBSDID("$FreeBSD$");
3590075Sobrien
3690075Sobrien/*
3790075Sobrien * This file contains routines for relocating and dynamically linking
3890075Sobrien * executable object code files in the Windows(r) PE (Portable Executable)
3990075Sobrien * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
4090075Sobrien * considered an executable, and all such files have some structures in
4190075Sobrien * common. The PE format was apparently based largely on COFF but has
4290075Sobrien * mutated significantly over time. We are mainly concerned with .SYS files,
4390075Sobrien * so this module implements only enough routines to be able to parse the
4490075Sobrien * headers and sections of a .SYS object file and perform the necessary
4590075Sobrien * relocations and jump table patching to allow us to call into it
4690075Sobrien * (and to have it call back to us). Note that while this module
4790075Sobrien * can handle fixups for imported symbols, it knows nothing about
4890075Sobrien * exporting them.
4990075Sobrien */
5090075Sobrien
5190075Sobrien#include <sys/param.h>
5290075Sobrien#include <sys/types.h>
5390075Sobrien#include <sys/errno.h>
5490075Sobrien#ifdef _KERNEL
5590075Sobrien#include <sys/systm.h>
5690075Sobrien#else
5790075Sobrien#include <stdio.h>
5890075Sobrien#include <stddef.h>
5990075Sobrien#include <stdlib.h>
6090075Sobrien#include <unistd.h>
6190075Sobrien#include <string.h>
62169689Skan#endif
63169689Skan
64169689Skan#include <compat/ndis/pe_var.h>
65169689Skan
66169689Skanstatic vm_offset_t pe_functbl_match(image_patch_table *, char *);
6790075Sobrien
6890075Sobrien/*
69132718Skan * Check for an MS-DOS executable header. All Windows binaries
7090075Sobrien * have a small MS-DOS executable prepended to them to print out
7190075Sobrien * the "This program requires Windows" message. Even .SYS files
7290075Sobrien * have this header, in spite of the fact that you're can't actually
7390075Sobrien * run them directly.
7490075Sobrien */
7590075Sobrien
7690075Sobrienint
7790075Sobrienpe_get_dos_header(imgbase, hdr)
7890075Sobrien	vm_offset_t		imgbase;
7990075Sobrien	image_dos_header	*hdr;
8090075Sobrien{
8190075Sobrien	uint16_t		signature;
8290075Sobrien
8390075Sobrien	if (imgbase == 0 || hdr == NULL)
8490075Sobrien		return (EINVAL);
8590075Sobrien
8690075Sobrien	signature = *(uint16_t *)imgbase;
87132718Skan	if (signature != IMAGE_DOS_SIGNATURE)
88132718Skan		return (ENOEXEC);
89132718Skan
9090075Sobrien	bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
9190075Sobrien
9290075Sobrien	return (0);
9390075Sobrien}
9490075Sobrien
9590075Sobrien/*
9690075Sobrien * Verify that this image has a Windows NT PE signature.
9790075Sobrien */
9890075Sobrien
9990075Sobrienint
10090075Sobrienpe_is_nt_image(imgbase)
10190075Sobrien	vm_offset_t		imgbase;
10290075Sobrien{
10390075Sobrien	uint32_t		signature;
10490075Sobrien	image_dos_header	*dos_hdr;
10590075Sobrien
10690075Sobrien	if (imgbase == 0)
10790075Sobrien		return (EINVAL);
108169689Skan
109169689Skan	signature = *(uint16_t *)imgbase;
110169689Skan	if (signature == IMAGE_DOS_SIGNATURE) {
111169689Skan		dos_hdr = (image_dos_header *)imgbase;
112169689Skan		signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
113169689Skan		if (signature == IMAGE_NT_SIGNATURE)
11496263Sobrien			return (0);
11596263Sobrien	}
11690075Sobrien
11790075Sobrien	return (ENOEXEC);
118132718Skan}
119132718Skan
12090075Sobrien/*
12190075Sobrien * Return a copy of the optional header. This contains the
12290075Sobrien * executable entry point and the directory listing which we
12390075Sobrien * need to find the relocations and imports later.
12490075Sobrien */
12590075Sobrien
12690075Sobrienint
12790075Sobrienpe_get_optional_header(imgbase, hdr)
12890075Sobrien	vm_offset_t		imgbase;
12990075Sobrien	image_optional_header	*hdr;
13090075Sobrien{
13190075Sobrien	image_dos_header	*dos_hdr;
13290075Sobrien	image_nt_header		*nt_hdr;
13390075Sobrien
13490075Sobrien	if (imgbase == 0 || hdr == NULL)
13590075Sobrien		return (EINVAL);
13690075Sobrien
13790075Sobrien	if (pe_is_nt_image(imgbase))
13890075Sobrien		return (EINVAL);
13990075Sobrien
14090075Sobrien	dos_hdr = (image_dos_header *)(imgbase);
14190075Sobrien	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
14290075Sobrien
14390075Sobrien	bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
14490075Sobrien	    nt_hdr->inh_filehdr.ifh_optionalhdrlen);
14590075Sobrien
14690075Sobrien	return (0);
14790075Sobrien}
14890075Sobrien
14990075Sobrien/*
15090075Sobrien * Return a copy of the file header. Contains the number of
15190075Sobrien * sections in this image.
15290075Sobrien */
15390075Sobrien
15490075Sobrienint
15590075Sobrienpe_get_file_header(imgbase, hdr)
15690075Sobrien	vm_offset_t		imgbase;
15790075Sobrien	image_file_header	*hdr;
15890075Sobrien{
15990075Sobrien	image_dos_header	*dos_hdr;
16090075Sobrien	image_nt_header		*nt_hdr;
16190075Sobrien
16290075Sobrien	if (imgbase == 0 || hdr == NULL)
16390075Sobrien		return (EINVAL);
16490075Sobrien
16590075Sobrien	if (pe_is_nt_image(imgbase))
16690075Sobrien		return (EINVAL);
167132718Skan
168132718Skan	dos_hdr = (image_dos_header *)imgbase;
169132718Skan	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
17090075Sobrien
17190075Sobrien	/*
17290075Sobrien	 * Note: the size of the nt_header is variable since it
17390075Sobrien	 * can contain optional fields, as indicated by ifh_optionalhdrlen.
17490075Sobrien	 * However it happens we're only interested in fields in the
17590075Sobrien	 * non-variant portion of the nt_header structure, so we don't
17690075Sobrien	 * bother copying the optional parts here.
177117395Skan	 */
178117395Skan
17990075Sobrien	bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
18090075Sobrien	    sizeof(image_file_header));
18190075Sobrien
18290075Sobrien	return (0);
18390075Sobrien}
18490075Sobrien
185117395Skan/*
186117395Skan * Return the header of the first section in this image (usually
18790075Sobrien * .text).
18890075Sobrien */
18990075Sobrien
19090075Sobrienint
19190075Sobrienpe_get_section_header(imgbase, hdr)
19290075Sobrien	vm_offset_t		imgbase;
19390075Sobrien	image_section_header	*hdr;
19490075Sobrien{
19590075Sobrien	image_dos_header	*dos_hdr;
19690075Sobrien	image_nt_header		*nt_hdr;
19790075Sobrien	image_section_header	*sect_hdr;
19890075Sobrien
19990075Sobrien	if (imgbase == 0 || hdr == NULL)
200132718Skan		return (EINVAL);
20190075Sobrien
20290075Sobrien	if (pe_is_nt_image(imgbase))
20390075Sobrien		return (EINVAL);
20490075Sobrien
20590075Sobrien	dos_hdr = (image_dos_header *)imgbase;
20690075Sobrien	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
20790075Sobrien	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
20890075Sobrien
20990075Sobrien	bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
21090075Sobrien
21190075Sobrien	return (0);
21290075Sobrien}
213169689Skan
214169689Skan/*
215169689Skan * Return the number of sections in this executable, or 0 on error.
216169689Skan */
217169689Skan
21890075Sobrienint
219132718Skanpe_numsections(imgbase)
220169689Skan	vm_offset_t		imgbase;
221169689Skan{
222169689Skan	image_file_header	file_hdr;
223169689Skan
22490075Sobrien	if (pe_get_file_header(imgbase, &file_hdr))
22590075Sobrien		return (0);
22690075Sobrien
22790075Sobrien	return (file_hdr.ifh_numsections);
22890075Sobrien}
229132718Skan
230132718Skan/*
231132718Skan * Return the base address that this image was linked for.
232132718Skan * This helps us calculate relocation addresses later.
233132718Skan */
234132718Skan
235132718Skanvm_offset_t
236132718Skanpe_imagebase(imgbase)
23790075Sobrien	vm_offset_t		imgbase;
23890075Sobrien{
23990075Sobrien	image_optional_header	optional_hdr;
24090075Sobrien
24190075Sobrien	if (pe_get_optional_header(imgbase, &optional_hdr))
24290075Sobrien		return (0);
24390075Sobrien
24490075Sobrien	return (optional_hdr.ioh_imagebase);
24590075Sobrien}
246169689Skan
247169689Skan/*
248169689Skan * Return the offset of a given directory structure within the
249169689Skan * image. Directories reside within sections.
25090075Sobrien */
25190075Sobrien
25290075Sobrienvm_offset_t
25390075Sobrienpe_directory_offset(imgbase, diridx)
25490075Sobrien	vm_offset_t		imgbase;
25590075Sobrien	uint32_t		diridx;
25690075Sobrien{
25790075Sobrien	image_optional_header	opt_hdr;
25890075Sobrien	vm_offset_t		dir;
25990075Sobrien
26090075Sobrien	if (pe_get_optional_header(imgbase, &opt_hdr))
26190075Sobrien		return (0);
26290075Sobrien
263117395Skan	if (diridx >= opt_hdr.ioh_rva_size_cnt)
26490075Sobrien		return (0);
26590075Sobrien
26690075Sobrien	dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
26790075Sobrien
26890075Sobrien	return (pe_translate_addr(imgbase, dir));
26990075Sobrien}
27090075Sobrien
27190075Sobrienvm_offset_t
27290075Sobrienpe_translate_addr(imgbase, rva)
27390075Sobrien	vm_offset_t		imgbase;
27490075Sobrien	vm_offset_t		rva;
27590075Sobrien{
27690075Sobrien	image_optional_header	opt_hdr;
27790075Sobrien	image_section_header	*sect_hdr;
27890075Sobrien	image_dos_header	*dos_hdr;
27990075Sobrien	image_nt_header		*nt_hdr;
28090075Sobrien	int			i = 0, sections, fixedlen;
28190075Sobrien
28290075Sobrien	if (pe_get_optional_header(imgbase, &opt_hdr))
28390075Sobrien		return (0);
28490075Sobrien
28590075Sobrien	sections = pe_numsections(imgbase);
28690075Sobrien
28790075Sobrien	dos_hdr = (image_dos_header *)imgbase;
28890075Sobrien	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
28990075Sobrien	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
29090075Sobrien
29190075Sobrien	/*
29290075Sobrien	 * The test here is to see if the RVA falls somewhere
29390075Sobrien	 * inside the section, based on the section's start RVA
29490075Sobrien	 * and its length. However it seems sometimes the
29590075Sobrien	 * virtual length isn't enough to cover the entire
29690075Sobrien	 * area of the section. We fudge by taking into account
29790075Sobrien	 * the section alignment and rounding the section length
29890075Sobrien	 * up to a page boundary.
29990075Sobrien	 */
30090075Sobrien	while (i++ < sections) {
30190075Sobrien		fixedlen = sect_hdr->ish_misc.ish_vsize;
30290075Sobrien		fixedlen += ((opt_hdr.ioh_sectalign - 1) -
30390075Sobrien		    sect_hdr->ish_misc.ish_vsize) &
30490075Sobrien		    (opt_hdr.ioh_sectalign - 1);
30590075Sobrien		if (sect_hdr->ish_vaddr <= (uint32_t)rva &&
30690075Sobrien		    (sect_hdr->ish_vaddr + fixedlen) >
30790075Sobrien		    (uint32_t)rva)
30890075Sobrien			break;
30990075Sobrien		sect_hdr++;
31090075Sobrien	}
311122180Skan
312122180Skan	if (i > sections)
313122180Skan		return (0);
314122180Skan
315122180Skan	return ((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
316122180Skan	    sect_hdr->ish_rawdataaddr));
317122180Skan}
318122180Skan
319122180Skan/*
320122180Skan * Get the section header for a particular section. Note that
321122180Skan * section names can be anything, but there are some standard
322122180Skan * ones (.text, .data, .rdata, .reloc).
323122180Skan */
324122180Skan
325122180Skanint
32690075Sobrienpe_get_section(imgbase, hdr, name)
327132718Skan	vm_offset_t		imgbase;
328132718Skan	image_section_header	*hdr;
32990075Sobrien	const char		*name;
33090075Sobrien{
33190075Sobrien	image_dos_header	*dos_hdr;
33290075Sobrien	image_nt_header		*nt_hdr;
33390075Sobrien	image_section_header	*sect_hdr;
33490075Sobrien
33590075Sobrien	int			i, sections;
33690075Sobrien
33790075Sobrien	if (imgbase == 0 || hdr == NULL)
33890075Sobrien		return (EINVAL);
33990075Sobrien
34090075Sobrien	if (pe_is_nt_image(imgbase))
34190075Sobrien		return (EINVAL);
34290075Sobrien
34390075Sobrien	sections = pe_numsections(imgbase);
34490075Sobrien
34590075Sobrien	dos_hdr = (image_dos_header *)imgbase;
34690075Sobrien	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
34790075Sobrien	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
34890075Sobrien
34990075Sobrien	for (i = 0; i < sections; i++) {
35090075Sobrien		if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
35190075Sobrien			bcopy((char *)sect_hdr, (char *)hdr,
35290075Sobrien			    sizeof(image_section_header));
35390075Sobrien			return (0);
35490075Sobrien		} else
35590075Sobrien			sect_hdr++;
35690075Sobrien	}
35790075Sobrien
358132718Skan	return (ENOEXEC);
359132718Skan}
36090075Sobrien
36190075Sobrien/*
36290075Sobrien * Apply the base relocations to this image. The relocation table
36390075Sobrien * resides within the .reloc section. Relocations are specified in
36490075Sobrien * blocks which refer to a particular page. We apply the relocations
365117395Skan * one page block at a time.
366169689Skan */
367169689Skan
368169689Skanint
369117395Skanpe_relocate(imgbase)
370117395Skan	vm_offset_t		imgbase;
37190075Sobrien{
372117395Skan	image_section_header	sect;
37390075Sobrien	image_base_reloc	*relhdr;
37490075Sobrien	uint16_t		rel, *sloc;
37590075Sobrien	vm_offset_t		base;
37690075Sobrien	vm_size_t		delta;
37790075Sobrien	uint32_t		*lloc;
37890075Sobrien	uint64_t		*qloc;
37990075Sobrien	int			i, count;
38090075Sobrien	vm_offset_t		txt;
38190075Sobrien
38290075Sobrien	base = pe_imagebase(imgbase);
38390075Sobrien	pe_get_section(imgbase, &sect, ".text");
38490075Sobrien	txt = pe_translate_addr(imgbase, sect.ish_vaddr);
38590075Sobrien	delta = (uint32_t)(txt) - base - sect.ish_vaddr;
38690075Sobrien
38790075Sobrien	pe_get_section(imgbase, &sect, ".reloc");
38890075Sobrien
38990075Sobrien	relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
39090075Sobrien
39190075Sobrien	do {
39290075Sobrien		count = (relhdr->ibr_blocksize -
39390075Sobrien		    (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
39490075Sobrien		for (i = 0; i < count; i++) {
395169689Skan			rel = relhdr->ibr_rel[i];
39690075Sobrien			switch (IMR_RELTYPE(rel)) {
39790075Sobrien			case IMAGE_REL_BASED_ABSOLUTE:
39890075Sobrien				break;
39990075Sobrien			case IMAGE_REL_BASED_HIGHLOW:
40090075Sobrien				lloc = (uint32_t *)pe_translate_addr(imgbase,
40190075Sobrien				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
40290075Sobrien				*lloc = pe_translate_addr(imgbase,
40390075Sobrien				    (*lloc - base));
40490075Sobrien				break;
40590075Sobrien			case IMAGE_REL_BASED_HIGH:
40690075Sobrien				sloc = (uint16_t *)pe_translate_addr(imgbase,
40790075Sobrien				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
40890075Sobrien				*sloc += (delta & 0xFFFF0000) >> 16;
40990075Sobrien				break;
41090075Sobrien			case IMAGE_REL_BASED_LOW:
41190075Sobrien				sloc = (uint16_t *)pe_translate_addr(imgbase,
412132718Skan				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
41390075Sobrien				*sloc += (delta & 0xFFFF);
41490075Sobrien				break;
41590075Sobrien			case IMAGE_REL_BASED_DIR64:
41690075Sobrien				qloc = (uint64_t *)pe_translate_addr(imgbase,
41790075Sobrien				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
41890075Sobrien				*qloc = pe_translate_addr(imgbase,
41990075Sobrien				    (*qloc - base));
420132718Skan				break;
42190075Sobrien
42290075Sobrien			default:
42390075Sobrien				printf("[%d]reloc type: %d\n",i,
42490075Sobrien				    IMR_RELTYPE(rel));
425117395Skan				break;
426117395Skan			}
42790075Sobrien		}
42890075Sobrien		relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
42990075Sobrien		    relhdr->ibr_blocksize);
43090075Sobrien	} while (relhdr->ibr_blocksize);
43190075Sobrien
43290075Sobrien	return (0);
43390075Sobrien}
43490075Sobrien
43590075Sobrien/*
43690075Sobrien * Return the import descriptor for a particular module. An image
437169689Skan * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
438169689Skan * and NDIS.SYS. For each module, there is a list of imported function
43990075Sobrien * names and their addresses.
440169689Skan *
44190075Sobrien * Note: module names are case insensitive!
442169689Skan */
44390075Sobrien
44490075Sobrienint
44590075Sobrienpe_get_import_descriptor(imgbase, desc, module)
44690075Sobrien	vm_offset_t		imgbase;
447117395Skan	image_import_descriptor	*desc;
44890075Sobrien	char			*module;
44990075Sobrien{
45090075Sobrien	vm_offset_t		offset;
45190075Sobrien	image_import_descriptor	*imp_desc;
45290075Sobrien	char			*modname;
453132718Skan
454132718Skan	if (imgbase == 0 || module == NULL || desc == NULL)
45590075Sobrien		return (EINVAL);
456117395Skan
45790075Sobrien	offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
45890075Sobrien	if (offset == 0)
45990075Sobrien		return (ENOENT);
46090075Sobrien
46190075Sobrien	imp_desc = (void *)offset;
462169689Skan
46390075Sobrien	while (imp_desc->iid_nameaddr) {
46490075Sobrien		modname = (char *)pe_translate_addr(imgbase,
465132718Skan		    imp_desc->iid_nameaddr);
466132718Skan		if (!strncasecmp(module, modname, strlen(module))) {
467132718Skan			bcopy((char *)imp_desc, (char *)desc,
468132718Skan			    sizeof(image_import_descriptor));
469132718Skan			return (0);
470132718Skan		}
471132718Skan		imp_desc++;
472132718Skan	}
473132718Skan
474132718Skan	return (ENOENT);
475132718Skan}
476132718Skan
477132718Skanint
478132718Skanpe_get_messagetable(imgbase, md)
479103445Skan	vm_offset_t		imgbase;
480103445Skan	message_resource_data	**md;
481103445Skan{
482103445Skan	image_resource_directory	*rdir, *rtype;
483103445Skan	image_resource_directory_entry	*dent, *dent2;
484103445Skan	image_resource_data_entry	*rent;
485103445Skan	vm_offset_t		offset;
486103445Skan	int			i;
487103445Skan
488103445Skan	if (imgbase == 0)
489103445Skan		return (EINVAL);
490117395Skan
491103445Skan	offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
492103445Skan	if (offset == 0)
493103445Skan		return (ENOENT);
494103445Skan
495103445Skan	rdir = (image_resource_directory *)offset;
496103445Skan
497103445Skan	dent = (image_resource_directory_entry *)(offset +
498103445Skan	    sizeof(image_resource_directory));
499103445Skan
500103445Skan	for (i = 0; i < rdir->ird_id_entries; i++){
501103445Skan		if (dent->irde_name != RT_MESSAGETABLE)	{
502117395Skan			dent++;
503103445Skan			continue;
504103445Skan		}
505103445Skan		dent2 = dent;
506103445Skan		while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
50790075Sobrien			rtype = (image_resource_directory *)(offset +
50890075Sobrien			    (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
50990075Sobrien			dent2 = (image_resource_directory_entry *)
51090075Sobrien			    ((uintptr_t)rtype +
51190075Sobrien			     sizeof(image_resource_directory));
51290075Sobrien		}
51390075Sobrien		rent = (image_resource_data_entry *)(offset +
51490075Sobrien		    dent2->irde_dataoff);
51590075Sobrien		*md = (message_resource_data *)pe_translate_addr(imgbase,
51690075Sobrien		    rent->irde_offset);
51790075Sobrien		return (0);
51890075Sobrien	}
51990075Sobrien
52090075Sobrien	return (ENOENT);
52190075Sobrien}
52290075Sobrien
52390075Sobrienint
52490075Sobrienpe_get_message(imgbase, id, str, len, flags)
52590075Sobrien	vm_offset_t		imgbase;
52690075Sobrien	uint32_t		id;
527117395Skan	char			**str;
528117395Skan	int			*len;
52990075Sobrien	uint16_t		*flags;
53090075Sobrien{
531117395Skan	message_resource_data	*md = NULL;
53290075Sobrien	message_resource_block	*mb;
533117395Skan	message_resource_entry	*me;
534117395Skan	uint32_t		i;
53590075Sobrien
53690075Sobrien	pe_get_messagetable(imgbase, &md);
53790075Sobrien
53890075Sobrien	if (md == NULL)
53990075Sobrien		return (ENOENT);
54090075Sobrien
541132718Skan	mb = (message_resource_block *)((uintptr_t)md +
542132718Skan	    sizeof(message_resource_data));
54390075Sobrien
54490075Sobrien	for (i = 0; i < md->mrd_numblocks; i++) {
54590075Sobrien		if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
54690075Sobrien			me = (message_resource_entry *)((uintptr_t)md +
54790075Sobrien			    mb->mrb_entryoff);
54890075Sobrien			for (i = id - mb->mrb_lowid; i > 0; i--)
54990075Sobrien				me = (message_resource_entry *)((uintptr_t)me +
55090075Sobrien				    me->mre_len);
55190075Sobrien			*str = me->mre_text;
552169689Skan			*len = me->mre_len;
553169689Skan			*flags = me->mre_flags;
554169689Skan			return (0);
555169689Skan		}
556169689Skan		mb++;
557169689Skan	}
558169689Skan
559132718Skan	return (ENOENT);
560132718Skan}
561117395Skan
562169689Skan/*
563169689Skan * Find the function that matches a particular name. This doesn't
564169689Skan * need to be particularly speedy since it's only run when loading
565169689Skan * a module for the first time.
566169689Skan */
567169689Skan
568169689Skanstatic vm_offset_t
569169689Skanpe_functbl_match(functbl, name)
570169689Skan	image_patch_table	*functbl;
571169689Skan	char			*name;
572169689Skan{
573169689Skan	image_patch_table	*p;
574117395Skan
57590075Sobrien	if (functbl == NULL || name == NULL)
57690075Sobrien		return (0);
57790075Sobrien
57890075Sobrien	p = functbl;
57990075Sobrien
58090075Sobrien	while (p->ipt_name != NULL) {
58190075Sobrien		if (!strcmp(p->ipt_name, name))
58290075Sobrien			return ((vm_offset_t)p->ipt_wrap);
583132718Skan		p++;
584132718Skan	}
585132718Skan	printf("no match for %s\n", name);
586132718Skan
587132718Skan	/*
588132718Skan	 * Return the wrapper pointer for this routine.
589132718Skan	 * For x86, this is the same as the funcptr.
590132718Skan	 * For amd64, this points to a wrapper routine
591132718Skan	 * that does calling convention translation and
592132718Skan	 * then invokes the underlying routine.
593132718Skan	 */
59490075Sobrien	return ((vm_offset_t)p->ipt_wrap);
59590075Sobrien}
59690075Sobrien
59790075Sobrien/*
59890075Sobrien * Patch the imported function addresses for a given module.
59990075Sobrien * The caller must specify the module name and provide a table
60090075Sobrien * of function pointers that will be patched into the jump table.
60190075Sobrien * Note that there are actually two copies of the jump table: one
60290075Sobrien * copy is left alone. In a .SYS file, the jump tables are usually
60390075Sobrien * merged into the INIT segment.
60496263Sobrien */
60590075Sobrien
606169689Skanint
607169689Skanpe_patch_imports(imgbase, module, functbl)
608169689Skan	vm_offset_t		imgbase;
609169689Skan	char			*module;
61090075Sobrien	image_patch_table	*functbl;
61190075Sobrien{
612132718Skan	image_import_descriptor	imp_desc;
613132718Skan	char			*fname;
614132718Skan	vm_offset_t		*nptr, *fptr;
615132718Skan	vm_offset_t		func;
616132718Skan
617132718Skan	if (imgbase == 0 || module == NULL || functbl == NULL)
618132718Skan		return (EINVAL);
619132718Skan
620132718Skan	if (pe_get_import_descriptor(imgbase, &imp_desc, module))
621132718Skan		return (ENOEXEC);
62290075Sobrien
62390075Sobrien	nptr = (vm_offset_t *)pe_translate_addr(imgbase,
62490075Sobrien	    imp_desc.iid_import_name_table_addr);
62590075Sobrien	fptr = (vm_offset_t *)pe_translate_addr(imgbase,
62690075Sobrien	    imp_desc.iid_import_address_table_addr);
62790075Sobrien
62896263Sobrien	while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
629132718Skan		fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
630132718Skan		func = pe_functbl_match(functbl, fname);
63190075Sobrien		if (func)
63290075Sobrien			*fptr = func;
633169689Skan#ifdef notdef
63490075Sobrien		if (*fptr == 0)
63590075Sobrien			return (ENOENT);
63690075Sobrien#endif
637259563Spfg		nptr++;
63890075Sobrien		fptr++;
63990075Sobrien	}
64090075Sobrien
64190075Sobrien	return (0);
64290075Sobrien}
64390075Sobrien