subr_pe.c revision 124165
1145132Sanholt/*
2145132Sanholt * Copyright (c) 2003
3145132Sanholt *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4145132Sanholt *
5145132Sanholt * Redistribution and use in source and binary forms, with or without
6145132Sanholt * modification, are permitted provided that the following conditions
7145132Sanholt * are met:
8145132Sanholt * 1. Redistributions of source code must retain the above copyright
9145132Sanholt *    notice, this list of conditions and the following disclaimer.
10145132Sanholt * 2. Redistributions in binary form must reproduce the above copyright
11145132Sanholt *    notice, this list of conditions and the following disclaimer in the
12145132Sanholt *    documentation and/or other materials provided with the distribution.
13145132Sanholt * 3. All advertising materials mentioning features or use of this software
14145132Sanholt *    must display the following acknowledgement:
15145132Sanholt *	This product includes software developed by Bill Paul.
16145132Sanholt * 4. Neither the name of the author nor the names of any co-contributors
17145132Sanholt *    may be used to endorse or promote products derived from this software
18145132Sanholt *    without specific prior written permission.
19145132Sanholt *
20145132Sanholt * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21145132Sanholt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22145132Sanholt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23145132Sanholt * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24145132Sanholt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25145132Sanholt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26145132Sanholt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27145132Sanholt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28145132Sanholt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29145132Sanholt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30145132Sanholt * THE POSSIBILITY OF SUCH DAMAGE.
31152909Sanholt */
32152909Sanholt
33152909Sanholt#include <sys/cdefs.h>
34182080Srnoland__FBSDID("$FreeBSD: head/sys/compat/ndis/subr_pe.c 124165 2004-01-06 07:09:26Z wpaul $");
35182080Srnoland
36182080Srnoland/*
37182080Srnoland * This file contains routines for relocating and dynamically linking
38152909Sanholt * executable object code files in the Windows(r) PE (Portable Executable)
39152909Sanholt * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
40145132Sanholt * considered an executable, and all such files have some structures in
41145132Sanholt * common. The PE format was apparently based largely on COFF but has
42152909Sanholt * mutated significantly over time. We are mainly concerned with .SYS files,
43152909Sanholt * so this module implements only enough routines to be able to parse the
44152909Sanholt * headers and sections of a .SYS object file and perform the necessary
45152909Sanholt * relocations and jump table patching to allow us to call into it
46182080Srnoland * (and to have it call back to us). Note that while this module
47145132Sanholt * can handle fixups for imported symbols, it knows nothing about
48152909Sanholt * exporting them.
49152909Sanholt */
50152909Sanholt
51152909Sanholt#include <sys/param.h>
52145132Sanholt#include <sys/types.h>
53152909Sanholt#include <sys/errno.h>
54152909Sanholt#ifdef _KERNEL
55152909Sanholt#include <sys/systm.h>
56145132Sanholt#else
57145132Sanholt#include <stdio.h>
58145132Sanholt#include <stdlib.h>
59152909Sanholt#include <unistd.h>
60152909Sanholt#include <string.h>
61152909Sanholt#endif
62152909Sanholt
63145132Sanholt#include <compat/ndis/pe_var.h>
64152909Sanholt#ifdef _KERNEL
65152909Sanholt#include <machine/bus.h>
66152909Sanholt#include <machine/resource.h>
67152909Sanholt#include <sys/bus.h>
68145132Sanholt#include <sys/rman.h>
69152909Sanholt#include <compat/ndis/resource_var.h>
70145132Sanholt#include <compat/ndis/ntoskrnl_var.h>
71145132Sanholt#include <compat/ndis/ndis_var.h>
72182080Srnoland#endif
73182080Srnoland
74145132Sanholtstatic u_int32_t pe_functbl_match(image_patch_table *, char *);
75152909Sanholt
76152909Sanholt/*
77145132Sanholt * Check for an MS-DOS executable header. All Windows binaries
78152909Sanholt * have a small MS-DOS executable prepended to them to print out
79145132Sanholt * the "This program requires Windows" message. Even .SYS files
80145132Sanholt * have this header, in spite of the fact that you're can't actually
81182080Srnoland * run them directly.
82182080Srnoland */
83145132Sanholt
84152909Sanholtint
85152909Sanholtpe_get_dos_header(imgbase, hdr)
86145132Sanholt	vm_offset_t		imgbase;
87152909Sanholt	image_dos_header	*hdr;
88145132Sanholt{
89145132Sanholt	uint16_t		signature;
90182080Srnoland
91182080Srnoland	if (imgbase == 0 || hdr == NULL)
92183573Srnoland		return (EINVAL);
93145132Sanholt
94145132Sanholt	signature = *(uint16_t *)imgbase;
95152909Sanholt	if (signature != IMAGE_DOS_SIGNATURE)
96152909Sanholt		return (ENOEXEC);
97152909Sanholt
98145132Sanholt	bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
99145132Sanholt
100145132Sanholt	return(0);
101145132Sanholt}
102145132Sanholt
103152909Sanholt/*
104152909Sanholt * Verify that this image has a Windows NT PE signature.
105145132Sanholt */
106152909Sanholt
107152909Sanholtint
108152909Sanholtpe_is_nt_image(imgbase)
109152909Sanholt	vm_offset_t		imgbase;
110145132Sanholt{
111152909Sanholt	uint32_t		signature;
112152909Sanholt	image_dos_header	*dos_hdr;
113152909Sanholt
114152909Sanholt	if (imgbase == 0)
115145132Sanholt		return (EINVAL);
116152909Sanholt
117145132Sanholt	signature = *(uint16_t *)imgbase;
118152909Sanholt	if (signature == IMAGE_DOS_SIGNATURE) {
119152909Sanholt		dos_hdr = (image_dos_header *)imgbase;
120145132Sanholt		signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
121145132Sanholt		if (signature == IMAGE_NT_SIGNATURE)
122145132Sanholt			return(0);
123145132Sanholt	}
124152909Sanholt
125152909Sanholt	return(ENOEXEC);
126145132Sanholt}
127152909Sanholt
128152909Sanholt/*
129152909Sanholt * Return a copy of the optional header. This contains the
130152909Sanholt * executable entry point and the directory listing which we
131152909Sanholt * need to find the relocations and imports later.
132145132Sanholt */
133145132Sanholt
134145132Sanholtint
135145132Sanholtpe_get_optional_header(imgbase, hdr)
136152909Sanholt	vm_offset_t		imgbase;
137145132Sanholt	image_optional_header	*hdr;
138145132Sanholt{
139145132Sanholt	image_dos_header	*dos_hdr;
140145132Sanholt	image_nt_header		*nt_hdr;
141145132Sanholt
142183573Srnoland	if (imgbase == 0 || hdr == NULL)
143182080Srnoland		return(EINVAL);
144182080Srnoland
145182080Srnoland	if (pe_is_nt_image(imgbase))
146145132Sanholt		return (EINVAL);
147152909Sanholt
148152909Sanholt	dos_hdr = (image_dos_header *)(imgbase);
149152909Sanholt	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
150152909Sanholt
151145132Sanholt	bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
152183573Srnoland	    sizeof(image_optional_header));
153145132Sanholt
154145478Sanholt	return(0);
155145132Sanholt}
156145132Sanholt
157145132Sanholt/*
158145132Sanholt * Return a copy of the file header. Contains the number of
159145132Sanholt * sections in this image.
160145132Sanholt */
161145132Sanholt
162145132Sanholtint
163145132Sanholtpe_get_file_header(imgbase, hdr)
164183573Srnoland	vm_offset_t		imgbase;
165183573Srnoland	image_file_header	*hdr;
166183573Srnoland{
167145132Sanholt	image_dos_header	*dos_hdr;
168182080Srnoland	image_nt_header		*nt_hdr;
169182080Srnoland
170145132Sanholt	if (imgbase == 0 || hdr == NULL)
171145132Sanholt		return(EINVAL);
172183573Srnoland
173145132Sanholt	if (pe_is_nt_image(imgbase))
174145132Sanholt		return (EINVAL);
175145132Sanholt
176145132Sanholt	dos_hdr = (image_dos_header *)imgbase;
177145132Sanholt	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
178145132Sanholt
179182080Srnoland	bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
180145132Sanholt	    sizeof(image_file_header));
181145132Sanholt
182145132Sanholt	return(0);
183145132Sanholt}
184145132Sanholt
185145132Sanholt/*
186152909Sanholt * Return the header of the first section in this image (usually
187182080Srnoland * .text).
188182080Srnoland */
189182080Srnoland
190182080Srnolandint
191182080Srnolandpe_get_section_header(imgbase, hdr)
192182080Srnoland	vm_offset_t		imgbase;
193182080Srnoland	image_section_header	*hdr;
194182080Srnoland{
195182080Srnoland	image_dos_header	*dos_hdr;
196182080Srnoland	image_nt_header		*nt_hdr;
197182080Srnoland	image_section_header	*sect_hdr;
198145132Sanholt
199152909Sanholt	if (imgbase == 0 || hdr == NULL)
200152909Sanholt		return(EINVAL);
201152909Sanholt
202152909Sanholt	if (pe_is_nt_image(imgbase))
203152909Sanholt		return (EINVAL);
204152909Sanholt
205152909Sanholt	dos_hdr = (image_dos_header *)imgbase;
206152909Sanholt	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
207152909Sanholt	sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
208152909Sanholt	    sizeof(image_nt_header));
209182080Srnoland
210182080Srnoland	bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
211152909Sanholt
212145132Sanholt	return(0);
213145132Sanholt}
214145132Sanholt
215145132Sanholt/*
216182080Srnoland * Return the number of sections in this executable, or 0 on error.
217182080Srnoland */
218145132Sanholt
219145132Sanholtint
220145132Sanholtpe_numsections(imgbase)
221145132Sanholt	vm_offset_t		imgbase;
222152909Sanholt{
223152909Sanholt	image_file_header	file_hdr;
224152909Sanholt
225152909Sanholt	if (pe_get_file_header(imgbase, &file_hdr))
226152909Sanholt		return(0);
227152909Sanholt
228152909Sanholt	return (file_hdr.ifh_numsections);
229152909Sanholt}
230152909Sanholt
231152909Sanholt/*
232152909Sanholt * Return the base address that this image was linked for.
233145132Sanholt * This helps us calculate relocation addresses later.
234182080Srnoland */
235182080Srnoland
236145132Sanholtvm_offset_t
237152909Sanholtpe_imagebase(imgbase)
238152909Sanholt	vm_offset_t		imgbase;
239145132Sanholt{
240145132Sanholt	image_optional_header	optional_hdr;
241152909Sanholt
242145132Sanholt	if (pe_get_optional_header(imgbase, &optional_hdr))
243182080Srnoland		return(0);
244182080Srnoland
245145132Sanholt	return (optional_hdr.ioh_imagebase);
246145132Sanholt}
247145132Sanholt
248145132Sanholt/*
249145132Sanholt * Return the offset of a given directory structure within the
250145132Sanholt * image. Directories reside within sections.
251145132Sanholt */
252152909Sanholt
253152909Sanholtvm_offset_t
254152909Sanholtpe_directory_offset(imgbase, diridx)
255152909Sanholt	vm_offset_t		imgbase;
256152909Sanholt	uint32_t		diridx;
257152909Sanholt{
258152909Sanholt	image_optional_header	opt_hdr;
259152909Sanholt	vm_offset_t		dir;
260152909Sanholt
261182080Srnoland	if (pe_get_optional_header(imgbase, &opt_hdr))
262182080Srnoland		return(0);
263152909Sanholt
264183573Srnoland	if (diridx >= opt_hdr.ioh_rva_size_cnt)
265152909Sanholt		return(0);
266152909Sanholt
267152909Sanholt	dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
268152909Sanholt
269182080Srnoland	return(pe_translate_addr(imgbase, dir));
270152909Sanholt}
271182080Srnoland
272182080Srnolandvm_offset_t
273152909Sanholtpe_translate_addr(imgbase, rva)
274152909Sanholt	vm_offset_t		imgbase;
275182080Srnoland	uint32_t		rva;
276182080Srnoland{
277152909Sanholt	image_optional_header	opt_hdr;
278152909Sanholt	image_section_header	*sect_hdr;
279152909Sanholt	image_dos_header	*dos_hdr;
280152909Sanholt	image_nt_header		*nt_hdr;
281182080Srnoland	int			i = 0, sections, fixedlen;
282182080Srnoland
283182080Srnoland	if (pe_get_optional_header(imgbase, &opt_hdr))
284182080Srnoland		return(0);
285182080Srnoland
286182080Srnoland	sections = pe_numsections(imgbase);
287145132Sanholt
288182080Srnoland	dos_hdr = (image_dos_header *)imgbase;
289182080Srnoland	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
290145132Sanholt	sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
291145132Sanholt	    sizeof(image_nt_header));
292145132Sanholt
293145132Sanholt	/*
294145132Sanholt	 * The test here is to see if the RVA falls somewhere
295182080Srnoland	 * inside the section, based on the section's start RVA
296145132Sanholt	 * and its length. However it seems sometimes the
297145132Sanholt	 * virtual length isn't enough to cover the entire
298145132Sanholt	 * area of the section. We fudge by taking into account
299145132Sanholt	 * the section alignment and rounding the section length
300145132Sanholt	 * up to a page boundary.
301145132Sanholt	 */
302145132Sanholt	while (i++ < sections) {
303145132Sanholt		fixedlen = sect_hdr->ish_misc.ish_vsize;
304145132Sanholt		fixedlen += ((opt_hdr.ioh_sectalign - 1) -
305145132Sanholt		    sect_hdr->ish_misc.ish_vsize) &
306145132Sanholt		    (opt_hdr.ioh_sectalign - 1);
307145132Sanholt		if (sect_hdr->ish_vaddr <= (u_int32_t)rva &&
308145132Sanholt		    (sect_hdr->ish_vaddr + fixedlen) >
309145132Sanholt		    (u_int32_t)rva)
310152909Sanholt			break;
311145132Sanholt		sect_hdr++;
312145132Sanholt	}
313145132Sanholt
314145132Sanholt	if (i > sections)
315145132Sanholt		return(0);
316145132Sanholt
317145132Sanholt	return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
318145132Sanholt	    sect_hdr->ish_rawdataaddr));
319145132Sanholt}
320145132Sanholt
321145132Sanholt/*
322152909Sanholt * Get the section header for a particular section. Note that
323145132Sanholt * section names can be anything, but there are some standard
324182080Srnoland * ones (.text, .data, .rdata, .reloc).
325182080Srnoland */
326182080Srnoland
327145132Sanholtint
328145132Sanholtpe_get_section(imgbase, hdr, name)
329145132Sanholt	vm_offset_t		imgbase;
330145132Sanholt	image_section_header	*hdr;
331145132Sanholt	const char		*name;
332145132Sanholt{
333145132Sanholt	image_dos_header	*dos_hdr;
334145132Sanholt	image_nt_header		*nt_hdr;
335145132Sanholt	image_section_header	*sect_hdr;
336145132Sanholt
337145132Sanholt	int			i, sections;
338145132Sanholt
339145132Sanholt	if (imgbase == 0 || hdr == NULL)
340145132Sanholt		return(EINVAL);
341182080Srnoland
342182080Srnoland	if (pe_is_nt_image(imgbase))
343145132Sanholt		return (EINVAL);
344145132Sanholt
345183573Srnoland	sections = pe_numsections(imgbase);
346145132Sanholt
347145132Sanholt	dos_hdr = (image_dos_header *)imgbase;
348145132Sanholt	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
349182080Srnoland	sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
350145132Sanholt	    sizeof(image_nt_header));
351145132Sanholt
352145132Sanholt	for (i = 0; i < sections; i++) {
353145132Sanholt		if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
354145132Sanholt			bcopy((char *)sect_hdr, (char *)hdr,
355145132Sanholt			    sizeof(image_section_header));
356145132Sanholt			return(0);
357182080Srnoland		} else
358145132Sanholt			sect_hdr++;
359145132Sanholt	}
360152909Sanholt
361145132Sanholt	return (ENOEXEC);
362145132Sanholt}
363145132Sanholt
364145132Sanholt/*
365145132Sanholt * Apply the base relocations to this image. The relocation table
366145132Sanholt * resides within the .reloc section. Relocations are specified in
367145132Sanholt * blocks which refer to a particular page. We apply the relocations
368182080Srnoland * one page block at a time.
369182080Srnoland */
370145132Sanholt
371145132Sanholtint
372145132Sanholtpe_relocate(imgbase)
373145132Sanholt	vm_offset_t		imgbase;
374145132Sanholt{
375152909Sanholt	image_section_header	sect;
376145132Sanholt	image_base_reloc	*relhdr;
377145132Sanholt	uint16_t		rel, *sloc;
378145132Sanholt	uint32_t		base, delta, *lloc;
379145132Sanholt	int			i, count;
380145132Sanholt	vm_offset_t		txt;
381145132Sanholt
382145132Sanholt	base = pe_imagebase(imgbase);
383145132Sanholt	pe_get_section(imgbase, &sect, ".text");
384145132Sanholt	txt = pe_translate_addr(imgbase, sect.ish_vaddr);
385145132Sanholt	delta = (uint32_t)(txt) - base - sect.ish_vaddr;
386145132Sanholt
387145132Sanholt	pe_get_section(imgbase, &sect, ".reloc");
388145132Sanholt
389145132Sanholt	relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
390145132Sanholt
391145132Sanholt	do {
392183573Srnoland		count = (relhdr->ibr_blocksize -
393145132Sanholt		    (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
394145132Sanholt		for (i = 0; i < count; i++) {
395145132Sanholt			rel = relhdr->ibr_rel[i];
396152909Sanholt			switch (IMR_RELTYPE(rel)) {
397152909Sanholt			case IMAGE_REL_BASED_ABSOLUTE:
398145132Sanholt				break;
399145132Sanholt			case IMAGE_REL_BASED_HIGHLOW:
400145132Sanholt				lloc = (uint32_t *)pe_translate_addr(imgbase,
401145132Sanholt				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
402145132Sanholt				*lloc = pe_translate_addr(imgbase,
403145132Sanholt				    (*lloc - base));
404145132Sanholt				break;
405145132Sanholt			case IMAGE_REL_BASED_HIGH:
406145132Sanholt				sloc = (uint16_t *)pe_translate_addr(imgbase,
407145132Sanholt				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
408145132Sanholt				*sloc += (delta & 0xFFFF0000) >> 16;
409145132Sanholt				break;
410145132Sanholt			case IMAGE_REL_BASED_LOW:
411145132Sanholt				sloc = (uint16_t *)pe_translate_addr(imgbase,
412145132Sanholt				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
413145132Sanholt				*sloc += (delta & 0xFFFF);
414145132Sanholt				break;
415145132Sanholt			default:
416183573Srnoland				printf ("[%d]reloc type: %d\n",i,
417145132Sanholt				    IMR_RELTYPE(rel));
418145132Sanholt				break;
419145132Sanholt			}
420145132Sanholt		}
421145132Sanholt		relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
422145132Sanholt		    relhdr->ibr_blocksize);
423183573Srnoland	} while (relhdr->ibr_blocksize);
424183573Srnoland
425183573Srnoland	return(0);
426183573Srnoland}
427183573Srnoland
428183573Srnoland/*
429183573Srnoland * Return the import descriptor for a particular module. An image
430145132Sanholt * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
431152909Sanholt * and NDIS.SYS. For each module, there is a list of imported function
432152909Sanholt * names and their addresses.
433152909Sanholt */
434152909Sanholt
435152909Sanholtint
436152909Sanholtpe_get_import_descriptor(imgbase, desc, module)
437152909Sanholt	vm_offset_t		imgbase;
438152909Sanholt	image_import_descriptor	*desc;
439152909Sanholt	char			*module;
440152909Sanholt{
441152909Sanholt	vm_offset_t		offset;
442152909Sanholt	image_import_descriptor	*imp_desc;
443152909Sanholt	char			*modname;
444152909Sanholt
445152909Sanholt	if (imgbase == 0 || module == NULL || desc == NULL)
446152909Sanholt		return(EINVAL);
447152909Sanholt
448182080Srnoland	offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
449152909Sanholt	if (offset == 0)
450152909Sanholt		return (ENOENT);
451145132Sanholt
452145132Sanholt	imp_desc = (void *)offset;
453145132Sanholt
454145132Sanholt	while (imp_desc->iid_nameaddr) {
455183573Srnoland		modname = (char *)pe_translate_addr(imgbase,
456182080Srnoland		    imp_desc->iid_nameaddr);
457145132Sanholt		if (!strncmp(module, modname, strlen(module))) {
458145132Sanholt			bcopy((char *)imp_desc, (char *)desc,
459145132Sanholt			    sizeof(image_import_descriptor));
460145132Sanholt			return(0);
461145132Sanholt		}
462145132Sanholt		imp_desc++;
463145132Sanholt	}
464183573Srnoland
465145132Sanholt	return (ENOENT);
466145132Sanholt}
467145132Sanholt
468145132Sanholt#ifdef _KERNEL
469145132Sanholtint
470145132Sanholtpe_get_messagetable(imgbase, md)
471145132Sanholt	vm_offset_t		imgbase;
472145132Sanholt	message_resource_data	**md;
473145132Sanholt{
474145132Sanholt	image_resource_directory	*rdir, *rtype;
475145132Sanholt	image_resource_directory_entry	*dent, *dent2;
476182080Srnoland	image_resource_data_entry	*rent;
477145132Sanholt	vm_offset_t		offset;
478183573Srnoland	int			i;
479145132Sanholt
480145132Sanholt	if (imgbase == 0)
481145132Sanholt		return(EINVAL);
482145132Sanholt
483145132Sanholt	offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
484145132Sanholt	if (offset == 0)
485182080Srnoland		return (ENOENT);
486145132Sanholt
487145132Sanholt	rdir = (image_resource_directory *)offset;
488145132Sanholt
489145132Sanholt	dent = (image_resource_directory_entry *)(offset +
490145132Sanholt	    sizeof(image_resource_directory));
491145132Sanholt
492145132Sanholt	for (i = 0; i < rdir->ird_id_entries; i++){
493183573Srnoland		if (dent->irde_name != RT_MESSAGETABLE)	{
494145132Sanholt			dent++;
495145132Sanholt			continue;
496145132Sanholt		}
497145132Sanholt		dent2 = dent;
498145132Sanholt		while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
499145132Sanholt			rtype = (image_resource_directory *)(offset +
500145132Sanholt			    (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
501182080Srnoland			dent2 = (image_resource_directory_entry *)
502145132Sanholt			    ((uintptr_t)rtype +
503145132Sanholt			     sizeof(image_resource_directory));
504145132Sanholt		}
505183573Srnoland		rent = (image_resource_data_entry *)(offset +
506145132Sanholt		    dent2->irde_dataoff);
507145132Sanholt		*md = (message_resource_data *)pe_translate_addr(imgbase,
508145132Sanholt		    rent->irde_offset);
509145132Sanholt		return(0);
510145132Sanholt	}
511145132Sanholt
512183573Srnoland	return(ENOENT);
513183573Srnoland}
514145132Sanholt
515145132Sanholtint
516145132Sanholtpe_get_message(imgbase, id, str, len)
517145132Sanholt	vm_offset_t		imgbase;
518145132Sanholt	uint32_t		id;
519145132Sanholt	char			**str;
520145132Sanholt	int			*len;
521145132Sanholt{
522145132Sanholt	message_resource_data	*md = NULL;
523183573Srnoland	message_resource_block	*mb;
524145132Sanholt	message_resource_entry	*me;
525145132Sanholt	int			i;
526145132Sanholt	char			m[1024], *msg;
527145132Sanholt
528145132Sanholt	pe_get_messagetable(imgbase, &md);
529145132Sanholt
530145132Sanholt	if (md == NULL)
531145132Sanholt		return(ENOENT);
532145132Sanholt
533145132Sanholt	mb = (message_resource_block *)((uintptr_t)md +
534145132Sanholt	    sizeof(message_resource_data));
535145132Sanholt
536145132Sanholt	for (i = 0; i < md->mrd_numblocks; i++) {
537145132Sanholt		if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
538145132Sanholt			me = (message_resource_entry *)((uintptr_t)md +
539145132Sanholt			    mb->mrb_entryoff);
540145132Sanholt			for (i = id - mb->mrb_lowid; i > 0; i--)
541145132Sanholt				me = (message_resource_entry *)((uintptr_t)me +
542145132Sanholt				    me->mre_len);
543145132Sanholt			if (me->mre_flags == MESSAGE_RESOURCE_UNICODE) {
544145132Sanholt				msg = m;
545183573Srnoland				ndis_unicode_to_ascii((uint16_t *)me->mre_text,
546183573Srnoland				    me->mre_len, &msg);
547145132Sanholt				*str = m;
548145132Sanholt			} else
549183573Srnoland				*str = me->mre_text;
550145132Sanholt			*len = me->mre_len;
551145132Sanholt			return(0);
552145132Sanholt		}
553145132Sanholt		mb++;
554145132Sanholt	}
555145132Sanholt
556145132Sanholt	return(ENOENT);
557145132Sanholt}
558145132Sanholt#endif
559145132Sanholt
560145132Sanholt/*
561145132Sanholt * Find the function that matches a particular name. This doesn't
562145132Sanholt * need to be particularly speedy since it's only run when loading
563145132Sanholt * a module for the first time.
564145132Sanholt */
565145132Sanholt
566145132Sanholtstatic vm_offset_t
567152909Sanholtpe_functbl_match(functbl, name)
568183573Srnoland	image_patch_table	*functbl;
569183573Srnoland	char			*name;
570145132Sanholt{
571182080Srnoland	image_patch_table	*p;
572145132Sanholt
573183573Srnoland	if (functbl == NULL || name == NULL)
574145132Sanholt		return(0);
575145132Sanholt
576145132Sanholt	p = functbl;
577183573Srnoland
578183573Srnoland	while (p->ipt_name != NULL) {
579145132Sanholt		if (!strcmp(p->ipt_name, name))
580145132Sanholt			return((uint32_t)p->ipt_func);
581145132Sanholt		p++;
582145132Sanholt	}
583145132Sanholt	printf ("no match for %s\n", name);
584145132Sanholt	return((vm_offset_t)p->ipt_func);
585183573Srnoland}
586182883Srnoland
587152909Sanholt/*
588152909Sanholt * Patch the imported function addresses for a given module.
589182883Srnoland * The caller must specify the module name and provide a table
590152909Sanholt * of function pointers that will be patched into the jump table.
591145132Sanholt * Note that there are actually two copies of the jump table: one
592145132Sanholt * copy is left alone. In a .SYS file, the jump tables are usually
593145132Sanholt * merged into the INIT segment.
594145132Sanholt *
595145132Sanholt * Note: Windows uses the _stdcall calling convention. This means
596182080Srnoland * that the callback functions provided in the function table must
597145132Sanholt * be declared using __attribute__((__stdcall__)), otherwise the
598152909Sanholt * Windows code will likely screw up the %esp register and cause
599152909Sanholt * us to jump to an invalid address when it returns.
600183573Srnoland */
601183573Srnoland
602183573Srnolandint
603183573Srnolandpe_patch_imports(imgbase, module, functbl)
604145132Sanholt	vm_offset_t		imgbase;
605152909Sanholt	char			*module;
606145132Sanholt	image_patch_table	*functbl;
607183573Srnoland{
608183573Srnoland	image_import_descriptor	imp_desc;
609183573Srnoland	char			*fname;
610145132Sanholt	vm_offset_t		*nptr, *fptr;
611145132Sanholt	vm_offset_t		func;
612145132Sanholt
613145132Sanholt	if (imgbase == 0 || module == NULL || functbl == NULL)
614145132Sanholt		return(EINVAL);
615145132Sanholt
616152909Sanholt	if (pe_get_import_descriptor(imgbase, &imp_desc, module))
617152909Sanholt		return(ENOEXEC);
618145132Sanholt
619145132Sanholt	nptr = (vm_offset_t *)pe_translate_addr(imgbase,
620182080Srnoland	    imp_desc.iid_import_name_table_addr);
621145132Sanholt	fptr = (vm_offset_t *)pe_translate_addr(imgbase,
622183573Srnoland	    imp_desc.iid_import_address_table_addr);
623145132Sanholt
624145132Sanholt	while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
625145132Sanholt		fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
626145132Sanholt		func = pe_functbl_match(functbl, fname);
627145132Sanholt		if (func)
628145132Sanholt			*fptr = func;
629145132Sanholt#ifdef notdef
630145132Sanholt		if (*fptr == 0)
631182080Srnoland			return(ENOENT);
632145132Sanholt#endif
633145132Sanholt		nptr++;
634183573Srnoland		fptr++;
635183573Srnoland	}
636145132Sanholt
637145132Sanholt	return(0);
638145132Sanholt}
639145132Sanholt