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 *)§_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, §, ".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, §, ".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