Rename printf -> kprintf in sys/ and add some defines where necessary
[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  * $DragonFly: src/sys/emulation/ndis/subr_pe.c,v 1.3 2006/12/23 00:27:02 swildner Exp $
33  * $FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.7 2004/01/13 22:49:45 obrien Exp $
34  */
35
36 /*
37  * This file contains routines for relocating and dynamically linking
38  * executable object code files in the Windows(r) PE (Portable Executable)
39  * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
40  * considered an executable, and all such files have some structures in
41  * common. The PE format was apparently based largely on COFF but has
42  * mutated significantly over time. We are mainly concerned with .SYS files,
43  * so this module implements only enough routines to be able to parse the
44  * headers and sections of a .SYS object file and perform the necessary
45  * relocations and jump table patching to allow us to call into it
46  * (and to have it call back to us). Note that while this module
47  * can handle fixups for imported symbols, it knows nothing about
48  * exporting them.
49  */
50
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/errno.h>
54 #ifdef _KERNEL
55 #include <sys/systm.h>
56 #else
57 #include <stdio.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 "regcall.h"
65 #include "pe_var.h"
66
67 static vm_offset_t pe_functbl_match(image_patch_table *, char *);
68
69 /*
70  * Check for an MS-DOS executable header. All Windows binaries
71  * have a small MS-DOS executable prepended to them to print out
72  * the "This program requires Windows" message. Even .SYS files
73  * have this header, in spite of the fact that you're can't actually
74  * run them directly.
75  */
76
77 int
78 pe_get_dos_header(vm_offset_t imgbase, image_dos_header *hdr)
79 {
80         uint16_t                signature;
81
82         if (imgbase == 0 || hdr == NULL)
83                 return (EINVAL);
84
85         signature = *(uint16_t *)imgbase;
86         if (signature != IMAGE_DOS_SIGNATURE)
87                 return (ENOEXEC);
88
89         bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
90
91         return(0);
92 }
93
94 /*
95  * Verify that this image has a Windows NT PE signature.
96  */
97
98 int
99 pe_is_nt_image(vm_offset_t imgbase)
100 {
101         uint32_t                signature;
102         image_dos_header        *dos_hdr;
103
104         if (imgbase == 0)
105                 return (EINVAL);
106
107         signature = *(uint16_t *)imgbase;
108         if (signature == IMAGE_DOS_SIGNATURE) {
109                 dos_hdr = (image_dos_header *)imgbase;
110                 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
111                 if (signature == IMAGE_NT_SIGNATURE)
112                         return(0);
113         }
114
115         return(ENOEXEC);
116 }
117
118 /*
119  * Return a copy of the optional header. This contains the
120  * executable entry point and the directory listing which we
121  * need to find the relocations and imports later.
122  */
123
124 int
125 pe_get_optional_header(vm_offset_t imgbase, image_optional_header *hdr)
126 {
127         image_dos_header        *dos_hdr;
128         image_nt_header         *nt_hdr;
129
130         if (imgbase == 0 || hdr == NULL)
131                 return(EINVAL);
132
133         if (pe_is_nt_image(imgbase))
134                 return (EINVAL);
135
136         dos_hdr = (image_dos_header *)(imgbase);
137         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
138
139         bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
140             sizeof(image_optional_header));
141
142         return(0);
143 }
144
145 /*
146  * Return a copy of the file header. Contains the number of
147  * sections in this image.
148  */
149
150 int
151 pe_get_file_header(vm_offset_t imgbase, image_file_header *hdr)
152 {
153         image_dos_header        *dos_hdr;
154         image_nt_header         *nt_hdr;
155
156         if (imgbase == 0 || hdr == NULL)
157                 return(EINVAL);
158
159         if (pe_is_nt_image(imgbase))
160                 return (EINVAL);
161
162         dos_hdr = (image_dos_header *)imgbase;
163         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
164
165         bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
166             sizeof(image_file_header));
167
168         return(0);
169 }
170
171 /*
172  * Return the header of the first section in this image (usually
173  * .text).
174  */
175
176 int
177 pe_get_section_header(vm_offset_t imgbase, image_section_header *hdr)
178 {
179         image_dos_header        *dos_hdr;
180         image_nt_header         *nt_hdr;
181         image_section_header    *sect_hdr;
182
183         if (imgbase == 0 || hdr == NULL)
184                 return(EINVAL);
185
186         if (pe_is_nt_image(imgbase))
187                 return (EINVAL);
188
189         dos_hdr = (image_dos_header *)imgbase;
190         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
191         sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
192             sizeof(image_nt_header));
193
194         bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
195
196         return(0);
197 }
198
199 /*
200  * Return the number of sections in this executable, or 0 on error.
201  */
202
203 int
204 pe_numsections(vm_offset_t imgbase)
205 {
206         image_file_header       file_hdr;
207
208         if (pe_get_file_header(imgbase, &file_hdr))
209                 return(0);
210
211         return (file_hdr.ifh_numsections);
212 }
213
214 /*
215  * Return the base address that this image was linked for.
216  * This helps us calculate relocation addresses later.
217  */
218
219 vm_offset_t
220 pe_imagebase(vm_offset_t imgbase)
221 {
222         image_optional_header   optional_hdr;
223
224         if (pe_get_optional_header(imgbase, &optional_hdr))
225                 return(0);
226
227         return (optional_hdr.ioh_imagebase);
228 }
229
230 /*
231  * Return the offset of a given directory structure within the
232  * image. Directories reside within sections.
233  */
234
235 vm_offset_t
236 pe_directory_offset(vm_offset_t imgbase, uint32_t diridx)
237 {
238         image_optional_header   opt_hdr;
239         vm_offset_t             dir;
240
241         if (pe_get_optional_header(imgbase, &opt_hdr))
242                 return(0);
243
244         if (diridx >= opt_hdr.ioh_rva_size_cnt)
245                 return(0);
246
247         dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
248
249         return(pe_translate_addr(imgbase, dir));
250 }
251
252 vm_offset_t
253 pe_translate_addr(vm_offset_t imgbase, uint32_t rva)
254 {
255         image_optional_header   opt_hdr;
256         image_section_header    *sect_hdr;
257         image_dos_header        *dos_hdr;
258         image_nt_header         *nt_hdr;
259         int                     i = 0, sections, fixedlen;
260
261         if (pe_get_optional_header(imgbase, &opt_hdr))
262                 return(0);
263
264         sections = pe_numsections(imgbase);
265
266         dos_hdr = (image_dos_header *)imgbase;
267         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
268         sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
269             sizeof(image_nt_header));
270
271         /*
272          * The test here is to see if the RVA falls somewhere
273          * inside the section, based on the section's start RVA
274          * and its length. However it seems sometimes the
275          * virtual length isn't enough to cover the entire
276          * area of the section. We fudge by taking into account
277          * the section alignment and rounding the section length
278          * up to a page boundary.
279          */
280         while (i++ < sections) {
281                 fixedlen = sect_hdr->ish_misc.ish_vsize;
282                 fixedlen += ((opt_hdr.ioh_sectalign - 1) -
283                     sect_hdr->ish_misc.ish_vsize) &
284                     (opt_hdr.ioh_sectalign - 1);
285                 if (sect_hdr->ish_vaddr <= (u_int32_t)rva &&
286                     (sect_hdr->ish_vaddr + fixedlen) >
287                     (u_int32_t)rva)
288                         break;
289                 sect_hdr++;
290         }
291
292         if (i > sections)
293                 return(0);
294
295         return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
296             sect_hdr->ish_rawdataaddr));
297 }
298
299 /*
300  * Get the section header for a particular section. Note that
301  * section names can be anything, but there are some standard
302  * ones (.text, .data, .rdata, .reloc).
303  */
304
305 int
306 pe_get_section(vm_offset_t imgbase, image_section_header *hdr,
307                const char *name)
308 {
309         image_dos_header        *dos_hdr;
310         image_nt_header         *nt_hdr;
311         image_section_header    *sect_hdr;
312
313         int                     i, sections;
314
315         if (imgbase == 0 || hdr == NULL)
316                 return(EINVAL);
317
318         if (pe_is_nt_image(imgbase))
319                 return (EINVAL);
320
321         sections = pe_numsections(imgbase);
322
323         dos_hdr = (image_dos_header *)imgbase;
324         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
325         sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
326             sizeof(image_nt_header));
327
328         for (i = 0; i < sections; i++) {
329                 if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
330                         bcopy((char *)sect_hdr, (char *)hdr,
331                             sizeof(image_section_header));
332                         return(0);
333                 } else
334                         sect_hdr++;
335         }
336
337         return (ENOEXEC);
338 }
339
340 /*
341  * Apply the base relocations to this image. The relocation table
342  * resides within the .reloc section. Relocations are specified in
343  * blocks which refer to a particular page. We apply the relocations
344  * one page block at a time.
345  */
346
347 int
348 pe_relocate(vm_offset_t imgbase)
349 {
350         image_section_header    sect;
351         image_base_reloc        *relhdr;
352         uint16_t                rel, *sloc;
353         uint32_t                base, delta, *lloc;
354         int                     i, count;
355         vm_offset_t             txt;
356
357         base = pe_imagebase(imgbase);
358         pe_get_section(imgbase, &sect, ".text");
359         txt = pe_translate_addr(imgbase, sect.ish_vaddr);
360         delta = (uint32_t)(txt) - base - sect.ish_vaddr;
361
362         pe_get_section(imgbase, &sect, ".reloc");
363
364         relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
365
366         do {
367                 count = (relhdr->ibr_blocksize -
368                     (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
369                 for (i = 0; i < count; i++) {
370                         rel = relhdr->ibr_rel[i];
371                         switch (IMR_RELTYPE(rel)) {
372                         case IMAGE_REL_BASED_ABSOLUTE:
373                                 break;
374                         case IMAGE_REL_BASED_HIGHLOW:
375                                 lloc = (uint32_t *)pe_translate_addr(imgbase,
376                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
377                                 *lloc = pe_translate_addr(imgbase,
378                                     (*lloc - base));
379                                 break;
380                         case IMAGE_REL_BASED_HIGH:
381                                 sloc = (uint16_t *)pe_translate_addr(imgbase,
382                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
383                                 *sloc += (delta & 0xFFFF0000) >> 16;
384                                 break;
385                         case IMAGE_REL_BASED_LOW:
386                                 sloc = (uint16_t *)pe_translate_addr(imgbase,
387                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
388                                 *sloc += (delta & 0xFFFF);
389                                 break;
390                         default:
391                                 kprintf ("[%d]reloc type: %d\n",i,
392                                     IMR_RELTYPE(rel));
393                                 break;
394                         }
395                 }
396                 relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
397                     relhdr->ibr_blocksize);
398         } while (relhdr->ibr_blocksize);
399
400         return(0);
401 }
402
403 /*
404  * Return the import descriptor for a particular module. An image
405  * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
406  * and NDIS.SYS. For each module, there is a list of imported function
407  * names and their addresses.
408  */
409
410 int
411 pe_get_import_descriptor(vm_offset_t imgbase, image_import_descriptor *desc,
412                          char *module)
413 {       
414         vm_offset_t             offset;
415         image_import_descriptor *imp_desc;
416         char                    *modname;
417
418         if (imgbase == 0 || module == NULL || desc == NULL)
419                 return(EINVAL);
420
421         offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
422         if (offset == 0)
423                 return (ENOENT);
424
425         imp_desc = (void *)offset;
426
427         while (imp_desc->iid_nameaddr) {
428                 modname = (char *)pe_translate_addr(imgbase,
429                     imp_desc->iid_nameaddr);
430                 if (!strncmp(module, modname, strlen(module))) {
431                         bcopy((char *)imp_desc, (char *)desc,
432                             sizeof(image_import_descriptor));
433                         return(0);
434                 }
435                 imp_desc++;
436         }
437
438         return (ENOENT);
439 }
440
441 int
442 pe_get_messagetable(vm_offset_t imgbase, message_resource_data **md)
443 {
444         image_resource_directory        *rdir, *rtype;
445         image_resource_directory_entry  *dent, *dent2;
446         image_resource_data_entry       *rent;
447         vm_offset_t             offset;
448         int                     i;
449
450         if (imgbase == 0)
451                 return(EINVAL);
452
453         offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
454         if (offset == 0)
455                 return (ENOENT);
456
457         rdir = (image_resource_directory *)offset;
458
459         dent = (image_resource_directory_entry *)(offset +
460             sizeof(image_resource_directory));
461
462         for (i = 0; i < rdir->ird_id_entries; i++){
463                 if (dent->irde_name != RT_MESSAGETABLE) {
464                         dent++;
465                         continue;
466                 }
467                 dent2 = dent;
468                 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
469                         rtype = (image_resource_directory *)(offset +
470                             (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
471                         dent2 = (image_resource_directory_entry *)
472                             ((uintptr_t)rtype +
473                              sizeof(image_resource_directory));
474                 }
475                 rent = (image_resource_data_entry *)(offset +
476                     dent2->irde_dataoff);
477                 *md = (message_resource_data *)pe_translate_addr(imgbase,
478                     rent->irde_offset);
479                 return(0);
480         }
481
482         return(ENOENT);
483 }
484
485 int
486 pe_get_message(vm_offset_t imgbase, uint32_t id, char **str, int *len,
487                uint16_t *flags)
488 {
489         message_resource_data   *md = NULL;
490         message_resource_block  *mb;
491         message_resource_entry  *me;
492         uint32_t                i;
493
494         pe_get_messagetable(imgbase, &md);
495
496         if (md == NULL)
497                 return(ENOENT);
498
499         mb = (message_resource_block *)((uintptr_t)md +
500             sizeof(message_resource_data));
501
502         for (i = 0; i < md->mrd_numblocks; i++) {
503                 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
504                         me = (message_resource_entry *)((uintptr_t)md +
505                             mb->mrb_entryoff);
506                         for (i = id - mb->mrb_lowid; i > 0; i--)
507                                 me = (message_resource_entry *)((uintptr_t)me +
508                                     me->mre_len);
509                         *str = me->mre_text;
510                         *len = me->mre_len;
511                         *flags = me->mre_flags;
512                         return(0);
513                 }
514                 mb++;
515         }
516
517         return(ENOENT);
518 }
519
520 /*
521  * Find the function that matches a particular name. This doesn't
522  * need to be particularly speedy since it's only run when loading
523  * a module for the first time.
524  */
525
526 static vm_offset_t
527 pe_functbl_match(image_patch_table *functbl, char *name)
528 {
529         image_patch_table       *p;
530
531         if (functbl == NULL || name == NULL)
532                 return(0);
533
534         p = functbl;
535
536         while (p->ipt_name != NULL) {
537                 if (!strcmp(p->ipt_name, name))
538                         return((vm_offset_t)p->ipt_func);
539                 p++;
540         }
541         kprintf ("no match for %s\n", name);
542         return((vm_offset_t)p->ipt_func);
543 }
544
545 /*
546  * Patch the imported function addresses for a given module.
547  * The caller must specify the module name and provide a table
548  * of function pointers that will be patched into the jump table.
549  * Note that there are actually two copies of the jump table: one
550  * copy is left alone. In a .SYS file, the jump tables are usually
551  * merged into the INIT segment.
552  */
553
554 int
555 pe_patch_imports(vm_offset_t imgbase, char *module,
556                  image_patch_table *functbl)
557 {
558         image_import_descriptor imp_desc;
559         char                    *fname;
560         vm_offset_t             *nptr, *fptr;
561         vm_offset_t             func;
562
563         if (imgbase == 0 || module == NULL || functbl == NULL)
564                 return(EINVAL);
565
566         if (pe_get_import_descriptor(imgbase, &imp_desc, module))
567                 return(ENOEXEC);
568
569         nptr = (vm_offset_t *)pe_translate_addr(imgbase,
570             imp_desc.iid_import_name_table_addr);
571         fptr = (vm_offset_t *)pe_translate_addr(imgbase,
572             imp_desc.iid_import_address_table_addr);
573
574         while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
575                 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
576                 func = pe_functbl_match(functbl, fname);
577                 if (func)
578                         *fptr = func;
579 #ifdef notdef
580                 if (*fptr == 0)
581                         return(ENOENT);
582 #endif
583                 nptr++;
584                 fptr++;
585         }
586
587         return(0);
588 }