Sync ndis(4) and tools with FreeBSD and hook it all back into the build.
[dragonfly.git] / sys / emulation / ndis / subr_pe.c
1 /*-
2  * Copyright (c) 2003
3  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * $FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.15 2009/11/02 11:07:42 rpaulo Exp $
33  */
34
35 /*
36  * This file contains routines for relocating and dynamically linking
37  * executable object code files in the Windows(r) PE (Portable Executable)
38  * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
39  * considered an executable, and all such files have some structures in
40  * common. The PE format was apparently based largely on COFF but has
41  * mutated significantly over time. We are mainly concerned with .SYS files,
42  * so this module implements only enough routines to be able to parse the
43  * headers and sections of a .SYS object file and perform the necessary
44  * relocations and jump table patching to allow us to call into it
45  * (and to have it call back to us). Note that while this module
46  * can handle fixups for imported symbols, it knows nothing about
47  * exporting them.
48  */
49
50 #include <sys/param.h>
51 #include <sys/types.h>
52 #include <sys/errno.h>
53 #ifdef _KERNEL
54 #include <sys/systm.h>
55 #else
56 #include <stdio.h>
57 #include <stddef.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <string.h>
61 #define kprintf         printf  /* ndiscvt(8) uses this file */
62 #endif
63
64 #include <emulation/ndis/pe_var.h>
65
66 static vm_offset_t pe_functbl_match(image_patch_table *, char *);
67
68 /*
69  * Check for an MS-DOS executable header. All Windows binaries
70  * have a small MS-DOS executable prepended to them to print out
71  * the "This program requires Windows" message. Even .SYS files
72  * have this header, in spite of the fact that you're can't actually
73  * run them directly.
74  */
75
76 int
77 pe_get_dos_header(vm_offset_t imgbase, image_dos_header *hdr)
78 {
79         uint16_t                signature;
80
81         if (imgbase == 0 || hdr == NULL)
82                 return (EINVAL);
83
84         signature = *(uint16_t *)imgbase;
85         if (signature != IMAGE_DOS_SIGNATURE)
86                 return (ENOEXEC);
87
88         bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
89
90         return (0);
91 }
92
93 /*
94  * Verify that this image has a Windows NT PE signature.
95  */
96
97 int
98 pe_is_nt_image(vm_offset_t imgbase)
99 {
100         uint32_t                signature;
101         image_dos_header        *dos_hdr;
102
103         if (imgbase == 0)
104                 return (EINVAL);
105
106         signature = *(uint16_t *)imgbase;
107         if (signature == IMAGE_DOS_SIGNATURE) {
108                 dos_hdr = (image_dos_header *)imgbase;
109                 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
110                 if (signature == IMAGE_NT_SIGNATURE)
111                         return (0);
112         }
113
114         return (ENOEXEC);
115 }
116
117 /*
118  * Return a copy of the optional header. This contains the
119  * executable entry point and the directory listing which we
120  * need to find the relocations and imports later.
121  */
122
123 int
124 pe_get_optional_header(vm_offset_t imgbase, image_optional_header *hdr)
125 {
126         image_dos_header        *dos_hdr;
127         image_nt_header         *nt_hdr;
128
129         if (imgbase == 0 || hdr == NULL)
130                 return (EINVAL);
131
132         if (pe_is_nt_image(imgbase))
133                 return (EINVAL);
134
135         dos_hdr = (image_dos_header *)(imgbase);
136         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
137
138         bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
139             nt_hdr->inh_filehdr.ifh_optionalhdrlen);
140
141         return (0);
142 }
143
144 /*
145  * Return a copy of the file header. Contains the number of
146  * sections in this image.
147  */
148
149 int
150 pe_get_file_header(vm_offset_t imgbase, image_file_header *hdr)
151 {
152         image_dos_header        *dos_hdr;
153         image_nt_header         *nt_hdr;
154
155         if (imgbase == 0 || hdr == NULL)
156                 return (EINVAL);
157
158         if (pe_is_nt_image(imgbase))
159                 return (EINVAL);
160
161         dos_hdr = (image_dos_header *)imgbase;
162         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
163
164         /*
165          * Note: the size of the nt_header is variable since it
166          * can contain optional fields, as indicated by ifh_optionalhdrlen.
167          * However it happens we're only interested in fields in the
168          * non-variant portion of the nt_header structure, so we don't
169          * bother copying the optional parts here.
170          */
171
172         bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
173             sizeof(image_file_header));
174
175         return (0);
176 }
177
178 /*
179  * Return the header of the first section in this image (usually
180  * .text).
181  */
182
183 int
184 pe_get_section_header(vm_offset_t imgbase, image_section_header *hdr)
185 {
186         image_dos_header        *dos_hdr;
187         image_nt_header         *nt_hdr;
188         image_section_header    *sect_hdr;
189
190         if (imgbase == 0 || hdr == NULL)
191                 return (EINVAL);
192
193         if (pe_is_nt_image(imgbase))
194                 return (EINVAL);
195
196         dos_hdr = (image_dos_header *)imgbase;
197         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
198         sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
199
200         bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
201
202         return (0);
203 }
204
205 /*
206  * Return the number of sections in this executable, or 0 on error.
207  */
208
209 int
210 pe_numsections(vm_offset_t imgbase)
211 {
212         image_file_header       file_hdr;
213
214         if (pe_get_file_header(imgbase, &file_hdr))
215                 return (0);
216
217         return (file_hdr.ifh_numsections);
218 }
219
220 /*
221  * Return the base address that this image was linked for.
222  * This helps us calculate relocation addresses later.
223  */
224
225 vm_offset_t
226 pe_imagebase(vm_offset_t imgbase)
227 {
228         image_optional_header   optional_hdr;
229
230         if (pe_get_optional_header(imgbase, &optional_hdr))
231                 return (0);
232
233         return (optional_hdr.ioh_imagebase);
234 }
235
236 /*
237  * Return the offset of a given directory structure within the
238  * image. Directories reside within sections.
239  */
240
241 vm_offset_t
242 pe_directory_offset(vm_offset_t imgbase, uint32_t diridx)
243 {
244         image_optional_header   opt_hdr;
245         vm_offset_t             dir;
246
247         if (pe_get_optional_header(imgbase, &opt_hdr))
248                 return (0);
249
250         if (diridx >= opt_hdr.ioh_rva_size_cnt)
251                 return (0);
252
253         dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
254
255         return (pe_translate_addr(imgbase, dir));
256 }
257
258 vm_offset_t
259 pe_translate_addr(vm_offset_t imgbase, vm_offset_t rva)
260 {
261         image_optional_header   opt_hdr;
262         image_section_header    *sect_hdr;
263         image_dos_header        *dos_hdr;
264         image_nt_header         *nt_hdr;
265         int                     i = 0, sections, fixedlen;
266
267         if (pe_get_optional_header(imgbase, &opt_hdr))
268                 return (0);
269
270         sections = pe_numsections(imgbase);
271
272         dos_hdr = (image_dos_header *)imgbase;
273         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
274         sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
275
276         /*
277          * The test here is to see if the RVA falls somewhere
278          * inside the section, based on the section's start RVA
279          * and its length. However it seems sometimes the
280          * virtual length isn't enough to cover the entire
281          * area of the section. We fudge by taking into account
282          * the section alignment and rounding the section length
283          * up to a page boundary.
284          */
285         while (i++ < sections) {
286                 fixedlen = sect_hdr->ish_misc.ish_vsize;
287                 fixedlen += ((opt_hdr.ioh_sectalign - 1) -
288                     sect_hdr->ish_misc.ish_vsize) &
289                     (opt_hdr.ioh_sectalign - 1);
290                 if (sect_hdr->ish_vaddr <= (uint32_t)rva &&
291                     (sect_hdr->ish_vaddr + fixedlen) >
292                     (uint32_t)rva)
293                         break;
294                 sect_hdr++;
295         }
296
297         if (i > sections)
298                 return (0);
299
300         return ((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
301             sect_hdr->ish_rawdataaddr));
302 }
303
304 /*
305  * Get the section header for a particular section. Note that
306  * section names can be anything, but there are some standard
307  * ones (.text, .data, .rdata, .reloc).
308  */
309
310 int
311 pe_get_section(vm_offset_t imgbase, image_section_header *hdr,
312     const char *name)
313 {
314         image_dos_header        *dos_hdr;
315         image_nt_header         *nt_hdr;
316         image_section_header    *sect_hdr;
317
318         int                     i, sections;
319
320         if (imgbase == 0 || hdr == NULL)
321                 return (EINVAL);
322
323         if (pe_is_nt_image(imgbase))
324                 return (EINVAL);
325
326         sections = pe_numsections(imgbase);
327
328         dos_hdr = (image_dos_header *)imgbase;
329         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
330         sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
331
332         for (i = 0; i < sections; i++) {
333                 if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
334                         bcopy((char *)sect_hdr, (char *)hdr,
335                             sizeof(image_section_header));
336                         return (0);
337                 } else
338                         sect_hdr++;
339         }
340
341         return (ENOEXEC);
342 }
343
344 /*
345  * Apply the base relocations to this image. The relocation table
346  * resides within the .reloc section. Relocations are specified in
347  * blocks which refer to a particular page. We apply the relocations
348  * one page block at a time.
349  */
350
351 int
352 pe_relocate(vm_offset_t imgbase)
353 {
354         image_section_header    sect;
355         image_base_reloc        *relhdr;
356         uint16_t                rel, *sloc;
357         vm_offset_t             base;
358         vm_size_t               delta;
359         uint32_t                *lloc;
360         uint64_t                *qloc;
361         int                     i, count;
362         vm_offset_t             txt;
363
364         base = pe_imagebase(imgbase);
365         pe_get_section(imgbase, &sect, ".text");
366         txt = pe_translate_addr(imgbase, sect.ish_vaddr);
367         delta = (uint32_t)(txt) - base - sect.ish_vaddr;
368
369         pe_get_section(imgbase, &sect, ".reloc");
370
371         relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
372
373         do {
374                 count = (relhdr->ibr_blocksize -
375                     (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
376                 for (i = 0; i < count; i++) {
377                         rel = relhdr->ibr_rel[i];
378                         switch (IMR_RELTYPE(rel)) {
379                         case IMAGE_REL_BASED_ABSOLUTE:
380                                 break;
381                         case IMAGE_REL_BASED_HIGHLOW:
382                                 lloc = (uint32_t *)pe_translate_addr(imgbase,
383                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
384                                 *lloc = pe_translate_addr(imgbase,
385                                     (*lloc - base));
386                                 break;
387                         case IMAGE_REL_BASED_HIGH:
388                                 sloc = (uint16_t *)pe_translate_addr(imgbase,
389                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
390                                 *sloc += (delta & 0xFFFF0000) >> 16;
391                                 break;
392                         case IMAGE_REL_BASED_LOW:
393                                 sloc = (uint16_t *)pe_translate_addr(imgbase,
394                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
395                                 *sloc += (delta & 0xFFFF);
396                                 break;
397                         case IMAGE_REL_BASED_DIR64:
398                                 qloc = (uint64_t *)pe_translate_addr(imgbase,
399                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
400                                 *qloc = pe_translate_addr(imgbase,
401                                     (*qloc - base));
402                                 break;
403
404                         default:
405                                 kprintf("[%d]reloc type: %d\n", i,
406                                     IMR_RELTYPE(rel));
407                                 break;
408                         }
409                 }
410                 relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
411                     relhdr->ibr_blocksize);
412         } while (relhdr->ibr_blocksize);
413
414         return (0);
415 }
416
417 /*
418  * Return the import descriptor for a particular module. An image
419  * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
420  * and NDIS.SYS. For each module, there is a list of imported function
421  * names and their addresses.
422  *
423  * Note: module names are case insensitive!
424  */
425
426 int
427 pe_get_import_descriptor(vm_offset_t imgbase, image_import_descriptor *desc,
428     char *module)
429 {       
430         vm_offset_t             offset;
431         image_import_descriptor *imp_desc;
432         char                    *modname;
433
434         if (imgbase == 0 || module == NULL || desc == NULL)
435                 return (EINVAL);
436
437         offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
438         if (offset == 0)
439                 return (ENOENT);
440
441         imp_desc = (void *)offset;
442
443         while (imp_desc->iid_nameaddr) {
444                 modname = (char *)pe_translate_addr(imgbase,
445                     imp_desc->iid_nameaddr);
446                 if (!strncasecmp(module, modname, strlen(module))) {
447                         bcopy((char *)imp_desc, (char *)desc,
448                             sizeof(image_import_descriptor));
449                         return (0);
450                 }
451                 imp_desc++;
452         }
453
454         return (ENOENT);
455 }
456
457 int
458 pe_get_messagetable(vm_offset_t imgbase, message_resource_data **md)
459 {
460         image_resource_directory        *rdir, *rtype;
461         image_resource_directory_entry  *dent, *dent2;
462         image_resource_data_entry       *rent;
463         vm_offset_t             offset;
464         int                     i;
465
466         if (imgbase == 0)
467                 return (EINVAL);
468
469         offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
470         if (offset == 0)
471                 return (ENOENT);
472
473         rdir = (image_resource_directory *)offset;
474
475         dent = (image_resource_directory_entry *)(offset +
476             sizeof(image_resource_directory));
477
478         for (i = 0; i < rdir->ird_id_entries; i++){
479                 if (dent->irde_name != RT_MESSAGETABLE) {
480                         dent++;
481                         continue;
482                 }
483                 dent2 = dent;
484                 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
485                         rtype = (image_resource_directory *)(offset +
486                             (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
487                         dent2 = (image_resource_directory_entry *)
488                             ((uintptr_t)rtype +
489                              sizeof(image_resource_directory));
490                 }
491                 rent = (image_resource_data_entry *)(offset +
492                     dent2->irde_dataoff);
493                 *md = (message_resource_data *)pe_translate_addr(imgbase,
494                     rent->irde_offset);
495                 return (0);
496         }
497
498         return (ENOENT);
499 }
500
501 int
502 pe_get_message(vm_offset_t imgbase, uint32_t id, char **str, int *len,
503     uint16_t *flags)
504 {
505         message_resource_data   *md = NULL;
506         message_resource_block  *mb;
507         message_resource_entry  *me;
508         uint32_t                i;
509
510         pe_get_messagetable(imgbase, &md);
511
512         if (md == NULL)
513                 return (ENOENT);
514
515         mb = (message_resource_block *)((uintptr_t)md +
516             sizeof(message_resource_data));
517
518         for (i = 0; i < md->mrd_numblocks; i++) {
519                 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
520                         me = (message_resource_entry *)((uintptr_t)md +
521                             mb->mrb_entryoff);
522                         for (i = id - mb->mrb_lowid; i > 0; i--)
523                                 me = (message_resource_entry *)((uintptr_t)me +
524                                     me->mre_len);
525                         *str = me->mre_text;
526                         *len = me->mre_len;
527                         *flags = me->mre_flags;
528                         return (0);
529                 }
530                 mb++;
531         }
532
533         return (ENOENT);
534 }
535
536 /*
537  * Find the function that matches a particular name. This doesn't
538  * need to be particularly speedy since it's only run when loading
539  * a module for the first time.
540  */
541
542 static vm_offset_t
543 pe_functbl_match(image_patch_table *functbl, char *name)
544 {
545         image_patch_table       *p;
546
547         if (functbl == NULL || name == NULL)
548                 return (0);
549
550         p = functbl;
551
552         while (p->ipt_name != NULL) {
553                 if (!strcmp(p->ipt_name, name))
554                         return ((vm_offset_t)p->ipt_wrap);
555                 p++;
556         }
557         kprintf("no match for %s\n", name);
558
559         /*
560          * Return the wrapper pointer for this routine.
561          * For x86, this is the same as the funcptr.
562          * For amd64, this points to a wrapper routine
563          * that does calling convention translation and
564          * then invokes the underlying routine.
565          */
566         return ((vm_offset_t)p->ipt_wrap);
567 }
568
569 /*
570  * Patch the imported function addresses for a given module.
571  * The caller must specify the module name and provide a table
572  * of function pointers that will be patched into the jump table.
573  * Note that there are actually two copies of the jump table: one
574  * copy is left alone. In a .SYS file, the jump tables are usually
575  * merged into the INIT segment.
576  */
577
578 int
579 pe_patch_imports(vm_offset_t imgbase, char *module, image_patch_table *functbl)
580 {
581         image_import_descriptor imp_desc;
582         char                    *fname;
583         vm_offset_t             *nptr, *fptr;
584         vm_offset_t             func;
585
586         if (imgbase == 0 || module == NULL || functbl == NULL)
587                 return (EINVAL);
588
589         if (pe_get_import_descriptor(imgbase, &imp_desc, module))
590                 return (ENOEXEC);
591
592         nptr = (vm_offset_t *)pe_translate_addr(imgbase,
593             imp_desc.iid_import_name_table_addr);
594         fptr = (vm_offset_t *)pe_translate_addr(imgbase,
595             imp_desc.iid_import_address_table_addr);
596
597         while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
598                 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
599                 func = pe_functbl_match(functbl, fname);
600                 if (func)
601                         *fptr = func;
602 #ifdef notdef
603                 if (*fptr == 0)
604                         return (ENOENT);
605 #endif
606                 nptr++;
607                 fptr++;
608         }
609
610         return (0);
611 }