1139743Simp/*- 2123474Swpaul * Copyright (c) 2003 3123474Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4123474Swpaul * 5123474Swpaul * Redistribution and use in source and binary forms, with or without 6123474Swpaul * modification, are permitted provided that the following conditions 7123474Swpaul * are met: 8123474Swpaul * 1. Redistributions of source code must retain the above copyright 9123474Swpaul * notice, this list of conditions and the following disclaimer. 10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11123474Swpaul * notice, this list of conditions and the following disclaimer in the 12123474Swpaul * documentation and/or other materials provided with the distribution. 13123474Swpaul * 3. All advertising materials mentioning features or use of this software 14123474Swpaul * must display the following acknowledgement: 15123474Swpaul * This product includes software developed by Bill Paul. 16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17123474Swpaul * may be used to endorse or promote products derived from this software 18123474Swpaul * without specific prior written permission. 19123474Swpaul * 20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23123474Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31123474Swpaul */ 32123474Swpaul 33123474Swpaul#include <sys/cdefs.h> 34123474Swpaul__FBSDID("$FreeBSD$"); 35123474Swpaul 36123474Swpaul/* 37123474Swpaul * This file contains routines for relocating and dynamically linking 38123474Swpaul * executable object code files in the Windows(r) PE (Portable Executable) 39123474Swpaul * format. In Windows, anything with a .EXE, .DLL or .SYS extention is 40123474Swpaul * considered an executable, and all such files have some structures in 41123474Swpaul * common. The PE format was apparently based largely on COFF but has 42123474Swpaul * mutated significantly over time. We are mainly concerned with .SYS files, 43123474Swpaul * so this module implements only enough routines to be able to parse the 44123474Swpaul * headers and sections of a .SYS object file and perform the necessary 45123474Swpaul * relocations and jump table patching to allow us to call into it 46123474Swpaul * (and to have it call back to us). Note that while this module 47123474Swpaul * can handle fixups for imported symbols, it knows nothing about 48123474Swpaul * exporting them. 49123474Swpaul */ 50123474Swpaul 51123474Swpaul#include <sys/param.h> 52123474Swpaul#include <sys/types.h> 53123474Swpaul#include <sys/errno.h> 54123474Swpaul#ifdef _KERNEL 55123474Swpaul#include <sys/systm.h> 56123474Swpaul#else 57123474Swpaul#include <stdio.h> 58151703Swpaul#include <stddef.h> 59123474Swpaul#include <stdlib.h> 60123474Swpaul#include <unistd.h> 61123474Swpaul#include <string.h> 62123474Swpaul#endif 63123474Swpaul 64123474Swpaul#include <compat/ndis/pe_var.h> 65123474Swpaul 66124502Sobrienstatic vm_offset_t pe_functbl_match(image_patch_table *, char *); 67123474Swpaul 68123474Swpaul/* 69123474Swpaul * Check for an MS-DOS executable header. All Windows binaries 70123474Swpaul * have a small MS-DOS executable prepended to them to print out 71123474Swpaul * the "This program requires Windows" message. Even .SYS files 72123474Swpaul * have this header, in spite of the fact that you're can't actually 73123474Swpaul * run them directly. 74123474Swpaul */ 75123474Swpaul 76123474Swpaulint 77123474Swpaulpe_get_dos_header(imgbase, hdr) 78123474Swpaul vm_offset_t imgbase; 79123474Swpaul image_dos_header *hdr; 80123474Swpaul{ 81123474Swpaul uint16_t signature; 82123474Swpaul 83123821Swpaul if (imgbase == 0 || hdr == NULL) 84123474Swpaul return (EINVAL); 85123474Swpaul 86123474Swpaul signature = *(uint16_t *)imgbase; 87123474Swpaul if (signature != IMAGE_DOS_SIGNATURE) 88123474Swpaul return (ENOEXEC); 89123474Swpaul 90123474Swpaul bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header)); 91123474Swpaul 92198786Srpaulo return (0); 93123474Swpaul} 94123474Swpaul 95123474Swpaul/* 96123474Swpaul * Verify that this image has a Windows NT PE signature. 97123474Swpaul */ 98123474Swpaul 99123474Swpaulint 100123474Swpaulpe_is_nt_image(imgbase) 101123474Swpaul vm_offset_t imgbase; 102123474Swpaul{ 103123474Swpaul uint32_t signature; 104123474Swpaul image_dos_header *dos_hdr; 105123474Swpaul 106123821Swpaul if (imgbase == 0) 107123474Swpaul return (EINVAL); 108123474Swpaul 109123474Swpaul signature = *(uint16_t *)imgbase; 110123474Swpaul if (signature == IMAGE_DOS_SIGNATURE) { 111123474Swpaul dos_hdr = (image_dos_header *)imgbase; 112123474Swpaul signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew); 113123474Swpaul if (signature == IMAGE_NT_SIGNATURE) 114198786Srpaulo return (0); 115123474Swpaul } 116123474Swpaul 117198786Srpaulo return (ENOEXEC); 118123474Swpaul} 119123474Swpaul 120123474Swpaul/* 121123474Swpaul * Return a copy of the optional header. This contains the 122123474Swpaul * executable entry point and the directory listing which we 123123474Swpaul * need to find the relocations and imports later. 124123474Swpaul */ 125123474Swpaul 126123474Swpaulint 127123474Swpaulpe_get_optional_header(imgbase, hdr) 128123474Swpaul vm_offset_t imgbase; 129123474Swpaul image_optional_header *hdr; 130123474Swpaul{ 131123474Swpaul image_dos_header *dos_hdr; 132123474Swpaul image_nt_header *nt_hdr; 133123474Swpaul 134123821Swpaul if (imgbase == 0 || hdr == NULL) 135198786Srpaulo return (EINVAL); 136123474Swpaul 137123474Swpaul if (pe_is_nt_image(imgbase)) 138123474Swpaul return (EINVAL); 139123474Swpaul 140123474Swpaul dos_hdr = (image_dos_header *)(imgbase); 141123474Swpaul nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 142123474Swpaul 143123474Swpaul bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr, 144151703Swpaul nt_hdr->inh_filehdr.ifh_optionalhdrlen); 145123474Swpaul 146198786Srpaulo return (0); 147123474Swpaul} 148123474Swpaul 149123474Swpaul/* 150123474Swpaul * Return a copy of the file header. Contains the number of 151123474Swpaul * sections in this image. 152123474Swpaul */ 153123474Swpaul 154123474Swpaulint 155123474Swpaulpe_get_file_header(imgbase, hdr) 156123474Swpaul vm_offset_t imgbase; 157123474Swpaul image_file_header *hdr; 158123474Swpaul{ 159123474Swpaul image_dos_header *dos_hdr; 160123474Swpaul image_nt_header *nt_hdr; 161123474Swpaul 162123821Swpaul if (imgbase == 0 || hdr == NULL) 163198786Srpaulo return (EINVAL); 164123474Swpaul 165123474Swpaul if (pe_is_nt_image(imgbase)) 166123474Swpaul return (EINVAL); 167123474Swpaul 168123474Swpaul dos_hdr = (image_dos_header *)imgbase; 169123474Swpaul nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 170123474Swpaul 171151703Swpaul /* 172151703Swpaul * Note: the size of the nt_header is variable since it 173151703Swpaul * can contain optional fields, as indicated by ifh_optionalhdrlen. 174151703Swpaul * However it happens we're only interested in fields in the 175151703Swpaul * non-variant portion of the nt_header structure, so we don't 176151703Swpaul * bother copying the optional parts here. 177151703Swpaul */ 178151703Swpaul 179123474Swpaul bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr, 180123474Swpaul sizeof(image_file_header)); 181123474Swpaul 182198786Srpaulo return (0); 183123474Swpaul} 184123474Swpaul 185123474Swpaul/* 186123474Swpaul * Return the header of the first section in this image (usually 187123474Swpaul * .text). 188123474Swpaul */ 189123474Swpaul 190123474Swpaulint 191123474Swpaulpe_get_section_header(imgbase, hdr) 192123474Swpaul vm_offset_t imgbase; 193123474Swpaul image_section_header *hdr; 194123474Swpaul{ 195123474Swpaul image_dos_header *dos_hdr; 196123474Swpaul image_nt_header *nt_hdr; 197123474Swpaul image_section_header *sect_hdr; 198123474Swpaul 199123821Swpaul if (imgbase == 0 || hdr == NULL) 200198786Srpaulo return (EINVAL); 201123474Swpaul 202123474Swpaul if (pe_is_nt_image(imgbase)) 203123474Swpaul return (EINVAL); 204123474Swpaul 205123474Swpaul dos_hdr = (image_dos_header *)imgbase; 206123474Swpaul nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 207151703Swpaul sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); 208123474Swpaul 209123474Swpaul bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header)); 210123474Swpaul 211198786Srpaulo return (0); 212123474Swpaul} 213123474Swpaul 214123474Swpaul/* 215123474Swpaul * Return the number of sections in this executable, or 0 on error. 216123474Swpaul */ 217123474Swpaul 218123474Swpaulint 219123474Swpaulpe_numsections(imgbase) 220123474Swpaul vm_offset_t imgbase; 221123474Swpaul{ 222123474Swpaul image_file_header file_hdr; 223123474Swpaul 224123474Swpaul if (pe_get_file_header(imgbase, &file_hdr)) 225198786Srpaulo return (0); 226123474Swpaul 227123474Swpaul return (file_hdr.ifh_numsections); 228123474Swpaul} 229123474Swpaul 230123474Swpaul/* 231123474Swpaul * Return the base address that this image was linked for. 232123474Swpaul * This helps us calculate relocation addresses later. 233123474Swpaul */ 234123474Swpaul 235123474Swpaulvm_offset_t 236123474Swpaulpe_imagebase(imgbase) 237123474Swpaul vm_offset_t imgbase; 238123474Swpaul{ 239123474Swpaul image_optional_header optional_hdr; 240123474Swpaul 241123474Swpaul if (pe_get_optional_header(imgbase, &optional_hdr)) 242198786Srpaulo return (0); 243123474Swpaul 244123474Swpaul return (optional_hdr.ioh_imagebase); 245123474Swpaul} 246123474Swpaul 247123474Swpaul/* 248123474Swpaul * Return the offset of a given directory structure within the 249123474Swpaul * image. Directories reside within sections. 250123474Swpaul */ 251123474Swpaul 252123474Swpaulvm_offset_t 253123474Swpaulpe_directory_offset(imgbase, diridx) 254123474Swpaul vm_offset_t imgbase; 255123474Swpaul uint32_t diridx; 256123474Swpaul{ 257123474Swpaul image_optional_header opt_hdr; 258123474Swpaul vm_offset_t dir; 259123474Swpaul 260123474Swpaul if (pe_get_optional_header(imgbase, &opt_hdr)) 261198786Srpaulo return (0); 262123474Swpaul 263123474Swpaul if (diridx >= opt_hdr.ioh_rva_size_cnt) 264198786Srpaulo return (0); 265123474Swpaul 266123474Swpaul dir = opt_hdr.ioh_datadir[diridx].idd_vaddr; 267123474Swpaul 268198786Srpaulo return (pe_translate_addr(imgbase, dir)); 269123474Swpaul} 270123474Swpaul 271123474Swpaulvm_offset_t 272123474Swpaulpe_translate_addr(imgbase, rva) 273123474Swpaul vm_offset_t imgbase; 274141963Swpaul vm_offset_t rva; 275123474Swpaul{ 276123474Swpaul image_optional_header opt_hdr; 277123474Swpaul image_section_header *sect_hdr; 278123474Swpaul image_dos_header *dos_hdr; 279123474Swpaul image_nt_header *nt_hdr; 280123474Swpaul int i = 0, sections, fixedlen; 281123474Swpaul 282123474Swpaul if (pe_get_optional_header(imgbase, &opt_hdr)) 283198786Srpaulo return (0); 284123474Swpaul 285123474Swpaul sections = pe_numsections(imgbase); 286123474Swpaul 287123474Swpaul dos_hdr = (image_dos_header *)imgbase; 288123474Swpaul nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 289151703Swpaul sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); 290123474Swpaul 291123474Swpaul /* 292123474Swpaul * The test here is to see if the RVA falls somewhere 293123474Swpaul * inside the section, based on the section's start RVA 294123474Swpaul * and its length. However it seems sometimes the 295123474Swpaul * virtual length isn't enough to cover the entire 296123474Swpaul * area of the section. We fudge by taking into account 297123474Swpaul * the section alignment and rounding the section length 298123474Swpaul * up to a page boundary. 299123474Swpaul */ 300123474Swpaul while (i++ < sections) { 301123474Swpaul fixedlen = sect_hdr->ish_misc.ish_vsize; 302123474Swpaul fixedlen += ((opt_hdr.ioh_sectalign - 1) - 303123474Swpaul sect_hdr->ish_misc.ish_vsize) & 304123474Swpaul (opt_hdr.ioh_sectalign - 1); 305142037Swpaul if (sect_hdr->ish_vaddr <= (uint32_t)rva && 306123474Swpaul (sect_hdr->ish_vaddr + fixedlen) > 307142037Swpaul (uint32_t)rva) 308123474Swpaul break; 309123474Swpaul sect_hdr++; 310123474Swpaul } 311123474Swpaul 312123474Swpaul if (i > sections) 313198786Srpaulo return (0); 314123474Swpaul 315198786Srpaulo return ((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr + 316123474Swpaul sect_hdr->ish_rawdataaddr)); 317123474Swpaul} 318123474Swpaul 319123474Swpaul/* 320123474Swpaul * Get the section header for a particular section. Note that 321123474Swpaul * section names can be anything, but there are some standard 322123474Swpaul * ones (.text, .data, .rdata, .reloc). 323123474Swpaul */ 324123474Swpaul 325123474Swpaulint 326123474Swpaulpe_get_section(imgbase, hdr, name) 327123474Swpaul vm_offset_t imgbase; 328123474Swpaul image_section_header *hdr; 329123474Swpaul const char *name; 330123474Swpaul{ 331123474Swpaul image_dos_header *dos_hdr; 332123474Swpaul image_nt_header *nt_hdr; 333123474Swpaul image_section_header *sect_hdr; 334123474Swpaul 335123474Swpaul int i, sections; 336123474Swpaul 337123821Swpaul if (imgbase == 0 || hdr == NULL) 338198786Srpaulo return (EINVAL); 339123474Swpaul 340123474Swpaul if (pe_is_nt_image(imgbase)) 341123474Swpaul return (EINVAL); 342123474Swpaul 343123474Swpaul sections = pe_numsections(imgbase); 344123474Swpaul 345123474Swpaul dos_hdr = (image_dos_header *)imgbase; 346123474Swpaul nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 347151703Swpaul sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); 348123474Swpaul 349123474Swpaul for (i = 0; i < sections; i++) { 350123474Swpaul if (!strcmp ((char *)§_hdr->ish_name, name)) { 351123474Swpaul bcopy((char *)sect_hdr, (char *)hdr, 352123474Swpaul sizeof(image_section_header)); 353198786Srpaulo return (0); 354123474Swpaul } else 355123474Swpaul sect_hdr++; 356123474Swpaul } 357123474Swpaul 358123474Swpaul return (ENOEXEC); 359123474Swpaul} 360123474Swpaul 361123474Swpaul/* 362123474Swpaul * Apply the base relocations to this image. The relocation table 363123474Swpaul * resides within the .reloc section. Relocations are specified in 364123474Swpaul * blocks which refer to a particular page. We apply the relocations 365123474Swpaul * one page block at a time. 366123474Swpaul */ 367123474Swpaul 368123474Swpaulint 369123474Swpaulpe_relocate(imgbase) 370123474Swpaul vm_offset_t imgbase; 371123474Swpaul{ 372123474Swpaul image_section_header sect; 373123474Swpaul image_base_reloc *relhdr; 374123474Swpaul uint16_t rel, *sloc; 375141963Swpaul vm_offset_t base; 376141963Swpaul vm_size_t delta; 377141963Swpaul uint32_t *lloc; 378141963Swpaul uint64_t *qloc; 379123474Swpaul int i, count; 380123474Swpaul vm_offset_t txt; 381123474Swpaul 382123474Swpaul base = pe_imagebase(imgbase); 383123474Swpaul pe_get_section(imgbase, §, ".text"); 384123474Swpaul txt = pe_translate_addr(imgbase, sect.ish_vaddr); 385123474Swpaul delta = (uint32_t)(txt) - base - sect.ish_vaddr; 386123474Swpaul 387123474Swpaul pe_get_section(imgbase, §, ".reloc"); 388123474Swpaul 389123474Swpaul relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); 390123474Swpaul 391123474Swpaul do { 392123474Swpaul count = (relhdr->ibr_blocksize - 393123474Swpaul (sizeof(uint32_t) * 2)) / sizeof(uint16_t); 394123474Swpaul for (i = 0; i < count; i++) { 395123474Swpaul rel = relhdr->ibr_rel[i]; 396123474Swpaul switch (IMR_RELTYPE(rel)) { 397123474Swpaul case IMAGE_REL_BASED_ABSOLUTE: 398123474Swpaul break; 399123474Swpaul case IMAGE_REL_BASED_HIGHLOW: 400123474Swpaul lloc = (uint32_t *)pe_translate_addr(imgbase, 401123474Swpaul relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 402123474Swpaul *lloc = pe_translate_addr(imgbase, 403123474Swpaul (*lloc - base)); 404123474Swpaul break; 405123474Swpaul case IMAGE_REL_BASED_HIGH: 406123474Swpaul sloc = (uint16_t *)pe_translate_addr(imgbase, 407123474Swpaul relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 408123474Swpaul *sloc += (delta & 0xFFFF0000) >> 16; 409123474Swpaul break; 410123474Swpaul case IMAGE_REL_BASED_LOW: 411123474Swpaul sloc = (uint16_t *)pe_translate_addr(imgbase, 412123474Swpaul relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 413123474Swpaul *sloc += (delta & 0xFFFF); 414123474Swpaul break; 415141963Swpaul case IMAGE_REL_BASED_DIR64: 416141963Swpaul qloc = (uint64_t *)pe_translate_addr(imgbase, 417141963Swpaul relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 418141963Swpaul *qloc = pe_translate_addr(imgbase, 419141963Swpaul (*qloc - base)); 420189488Sweongyo break; 421141963Swpaul 422123474Swpaul default: 423198786Srpaulo printf("[%d]reloc type: %d\n",i, 424123474Swpaul IMR_RELTYPE(rel)); 425123474Swpaul break; 426123474Swpaul } 427123474Swpaul } 428123474Swpaul relhdr = (image_base_reloc *)((vm_offset_t)relhdr + 429123474Swpaul relhdr->ibr_blocksize); 430123474Swpaul } while (relhdr->ibr_blocksize); 431123474Swpaul 432198786Srpaulo return (0); 433123474Swpaul} 434123474Swpaul 435123474Swpaul/* 436123474Swpaul * Return the import descriptor for a particular module. An image 437123474Swpaul * may be linked against several modules, typically HAL.dll, ntoskrnl.exe 438123474Swpaul * and NDIS.SYS. For each module, there is a list of imported function 439123474Swpaul * names and their addresses. 440142387Swpaul * 441142387Swpaul * Note: module names are case insensitive! 442123474Swpaul */ 443123474Swpaul 444123474Swpaulint 445123474Swpaulpe_get_import_descriptor(imgbase, desc, module) 446123474Swpaul vm_offset_t imgbase; 447123474Swpaul image_import_descriptor *desc; 448123474Swpaul char *module; 449189488Sweongyo{ 450123474Swpaul vm_offset_t offset; 451123474Swpaul image_import_descriptor *imp_desc; 452123474Swpaul char *modname; 453123474Swpaul 454123821Swpaul if (imgbase == 0 || module == NULL || desc == NULL) 455198786Srpaulo return (EINVAL); 456123474Swpaul 457123474Swpaul offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); 458123474Swpaul if (offset == 0) 459123474Swpaul return (ENOENT); 460123474Swpaul 461123474Swpaul imp_desc = (void *)offset; 462123474Swpaul 463123474Swpaul while (imp_desc->iid_nameaddr) { 464123474Swpaul modname = (char *)pe_translate_addr(imgbase, 465123474Swpaul imp_desc->iid_nameaddr); 466142387Swpaul if (!strncasecmp(module, modname, strlen(module))) { 467123474Swpaul bcopy((char *)imp_desc, (char *)desc, 468123474Swpaul sizeof(image_import_descriptor)); 469198786Srpaulo return (0); 470123474Swpaul } 471123474Swpaul imp_desc++; 472123474Swpaul } 473123474Swpaul 474123474Swpaul return (ENOENT); 475123474Swpaul} 476123474Swpaul 477124165Swpaulint 478124165Swpaulpe_get_messagetable(imgbase, md) 479124165Swpaul vm_offset_t imgbase; 480124165Swpaul message_resource_data **md; 481124165Swpaul{ 482124165Swpaul image_resource_directory *rdir, *rtype; 483124165Swpaul image_resource_directory_entry *dent, *dent2; 484124165Swpaul image_resource_data_entry *rent; 485124165Swpaul vm_offset_t offset; 486124165Swpaul int i; 487124165Swpaul 488124165Swpaul if (imgbase == 0) 489198786Srpaulo return (EINVAL); 490124165Swpaul 491124165Swpaul offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); 492124165Swpaul if (offset == 0) 493124165Swpaul return (ENOENT); 494124165Swpaul 495124165Swpaul rdir = (image_resource_directory *)offset; 496124165Swpaul 497124165Swpaul dent = (image_resource_directory_entry *)(offset + 498124165Swpaul sizeof(image_resource_directory)); 499124165Swpaul 500124165Swpaul for (i = 0; i < rdir->ird_id_entries; i++){ 501124165Swpaul if (dent->irde_name != RT_MESSAGETABLE) { 502124165Swpaul dent++; 503124165Swpaul continue; 504124165Swpaul } 505124165Swpaul dent2 = dent; 506124165Swpaul while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { 507124165Swpaul rtype = (image_resource_directory *)(offset + 508124165Swpaul (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); 509124165Swpaul dent2 = (image_resource_directory_entry *) 510124165Swpaul ((uintptr_t)rtype + 511124165Swpaul sizeof(image_resource_directory)); 512124165Swpaul } 513124165Swpaul rent = (image_resource_data_entry *)(offset + 514124165Swpaul dent2->irde_dataoff); 515124165Swpaul *md = (message_resource_data *)pe_translate_addr(imgbase, 516124165Swpaul rent->irde_offset); 517198786Srpaulo return (0); 518124165Swpaul } 519124165Swpaul 520198786Srpaulo return (ENOENT); 521124165Swpaul} 522124165Swpaul 523124165Swpaulint 524124173Swpaulpe_get_message(imgbase, id, str, len, flags) 525124165Swpaul vm_offset_t imgbase; 526124165Swpaul uint32_t id; 527124165Swpaul char **str; 528124165Swpaul int *len; 529124173Swpaul uint16_t *flags; 530124165Swpaul{ 531124165Swpaul message_resource_data *md = NULL; 532124165Swpaul message_resource_block *mb; 533124165Swpaul message_resource_entry *me; 534124173Swpaul uint32_t i; 535124165Swpaul 536124165Swpaul pe_get_messagetable(imgbase, &md); 537124165Swpaul 538124165Swpaul if (md == NULL) 539198786Srpaulo return (ENOENT); 540124165Swpaul 541124165Swpaul mb = (message_resource_block *)((uintptr_t)md + 542124165Swpaul sizeof(message_resource_data)); 543124165Swpaul 544124165Swpaul for (i = 0; i < md->mrd_numblocks; i++) { 545124165Swpaul if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { 546124165Swpaul me = (message_resource_entry *)((uintptr_t)md + 547124165Swpaul mb->mrb_entryoff); 548124165Swpaul for (i = id - mb->mrb_lowid; i > 0; i--) 549124165Swpaul me = (message_resource_entry *)((uintptr_t)me + 550124165Swpaul me->mre_len); 551124173Swpaul *str = me->mre_text; 552124165Swpaul *len = me->mre_len; 553124173Swpaul *flags = me->mre_flags; 554198786Srpaulo return (0); 555124165Swpaul } 556124165Swpaul mb++; 557124165Swpaul } 558124165Swpaul 559198786Srpaulo return (ENOENT); 560124165Swpaul} 561124165Swpaul 562123474Swpaul/* 563123474Swpaul * Find the function that matches a particular name. This doesn't 564123474Swpaul * need to be particularly speedy since it's only run when loading 565123474Swpaul * a module for the first time. 566123474Swpaul */ 567123474Swpaul 568123474Swpaulstatic vm_offset_t 569123474Swpaulpe_functbl_match(functbl, name) 570123474Swpaul image_patch_table *functbl; 571123474Swpaul char *name; 572123474Swpaul{ 573123474Swpaul image_patch_table *p; 574123474Swpaul 575123474Swpaul if (functbl == NULL || name == NULL) 576198786Srpaulo return (0); 577123474Swpaul 578123474Swpaul p = functbl; 579123474Swpaul 580123474Swpaul while (p->ipt_name != NULL) { 581123474Swpaul if (!strcmp(p->ipt_name, name)) 582198786Srpaulo return ((vm_offset_t)p->ipt_wrap); 583123474Swpaul p++; 584123474Swpaul } 585198786Srpaulo printf("no match for %s\n", name); 586141963Swpaul 587141963Swpaul /* 588141963Swpaul * Return the wrapper pointer for this routine. 589141963Swpaul * For x86, this is the same as the funcptr. 590141963Swpaul * For amd64, this points to a wrapper routine 591141963Swpaul * that does calling convention translation and 592141963Swpaul * then invokes the underlying routine. 593141963Swpaul */ 594198786Srpaulo return ((vm_offset_t)p->ipt_wrap); 595123474Swpaul} 596123474Swpaul 597123474Swpaul/* 598123474Swpaul * Patch the imported function addresses for a given module. 599123474Swpaul * The caller must specify the module name and provide a table 600123474Swpaul * of function pointers that will be patched into the jump table. 601123474Swpaul * Note that there are actually two copies of the jump table: one 602123474Swpaul * copy is left alone. In a .SYS file, the jump tables are usually 603123474Swpaul * merged into the INIT segment. 604123474Swpaul */ 605123474Swpaul 606123474Swpaulint 607123474Swpaulpe_patch_imports(imgbase, module, functbl) 608123474Swpaul vm_offset_t imgbase; 609123474Swpaul char *module; 610123474Swpaul image_patch_table *functbl; 611123474Swpaul{ 612123474Swpaul image_import_descriptor imp_desc; 613123474Swpaul char *fname; 614123474Swpaul vm_offset_t *nptr, *fptr; 615123474Swpaul vm_offset_t func; 616123474Swpaul 617123821Swpaul if (imgbase == 0 || module == NULL || functbl == NULL) 618198786Srpaulo return (EINVAL); 619123474Swpaul 620123474Swpaul if (pe_get_import_descriptor(imgbase, &imp_desc, module)) 621198786Srpaulo return (ENOEXEC); 622123474Swpaul 623123474Swpaul nptr = (vm_offset_t *)pe_translate_addr(imgbase, 624123474Swpaul imp_desc.iid_import_name_table_addr); 625123474Swpaul fptr = (vm_offset_t *)pe_translate_addr(imgbase, 626123474Swpaul imp_desc.iid_import_address_table_addr); 627123474Swpaul 628123848Swpaul while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) { 629123474Swpaul fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2); 630123474Swpaul func = pe_functbl_match(functbl, fname); 631123474Swpaul if (func) 632123474Swpaul *fptr = func; 633123474Swpaul#ifdef notdef 634123474Swpaul if (*fptr == 0) 635198786Srpaulo return (ENOENT); 636123474Swpaul#endif 637123474Swpaul nptr++; 638123474Swpaul fptr++; 639123474Swpaul } 640123474Swpaul 641198786Srpaulo return (0); 642123474Swpaul} 643