VirtualBox

source: kStuff/trunk/kLdr/kLdrModPE.c@ 49

Last change on this file since 49 was 41, checked in by bird, 14 years ago

Debug info enumration adjustments. Working on MH_DSYM support.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 69.1 KB
Line 
1/* $Id: kLdrModPE.c 41 2011-08-24 14:35:57Z bird $ */
2/** @file
3 * kLdr - The Module Interpreter for the Portable Executable (PE) Format.
4 */
5
6/*
7 * Copyright (c) 2006-2007 Knut St. Osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <k/kLdr.h>
35#include "kLdrInternal.h"
36#include <k/kLdrFmts/pe.h>
37
38
39/*******************************************************************************
40* Defined Constants And Macros *
41*******************************************************************************/
42/** @def KLDRMODPE_STRICT
43 * Define KLDRMODPE_STRICT to enabled strict checks in KLDRMODPE. */
44#define KLDRMODPE_STRICT 1
45
46/** @def KLDRMODPE_ASSERT
47 * Assert that an expression is true when KLDR_STRICT is defined.
48 */
49#ifdef KLDRMODPE_STRICT
50# define KLDRMODPE_ASSERT(expr) kHlpAssert(expr)
51#else
52# define KLDRMODPE_ASSERT(expr) do {} while (0)
53#endif
54
55/** @def KLDRMODPE_RVA2TYPE
56 * Converts a RVA to a pointer of the specified type.
57 * @param pvBits The bits (image base).
58 * @param uRVA The image relative virtual address.
59 * @param type The type to cast to.
60 */
61#define KLDRMODPE_RVA2TYPE(pvBits, uRVA, type) \
62 ( (type) ((KUPTR)(pvBits) + (KUPTR)(uRVA)) )
63
64/** @def KLDRMODPE_VALID_RVA
65 * Checks that the specified RVA value is non-zero and within the bounds of the image.
66 * @returns true/false.
67 * @param pModPE The PE module interpreter instance.
68 * @param uRVA The RVA to validate.
69 */
70#define KLDRMODPE_VALID_RVA(pModPE, uRVA) \
71 ( (uRVA) && (uRVA) < (pModPE)->Hdrs.OptionalHeader.SizeOfImage )
72
73
74
75/*******************************************************************************
76* Structures and Typedefs *
77*******************************************************************************/
78/**
79 * Instance data for the PE module interpreter.
80 */
81typedef struct KLDRMODPE
82{
83 /** Pointer to the module. (Follows the section table.) */
84 PKLDRMOD pMod;
85 /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */
86 const void *pvBits;
87 /** Pointer to the user mapping. */
88 const void *pvMapping;
89 /** Reserved flags. */
90 KU32 f32Reserved;
91 /** The number of imported modules.
92 * If ~(KU32)0 this hasn't been determined yet. */
93 KU32 cImportModules;
94 /** The offset of the NT headers. */
95 KLDRFOFF offHdrs;
96 /** Copy of the NT headers. */
97 IMAGE_NT_HEADERS64 Hdrs;
98 /** The section header table . */
99 IMAGE_SECTION_HEADER aShdrs[1];
100} KLDRMODPE, *PKLDRMODPE;
101
102
103/*******************************************************************************
104* Internal Functions *
105*******************************************************************************/
106static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits);
107static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
108 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
109
110static int kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppMod);
111/*static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg); */
112static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE);
113static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE);
114static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptionalHeader);
115static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
116 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser, PKLDRADDR puValue, KU32 *pfKind);
117static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
118static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
119 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
120static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
121 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
122static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
123static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, unsigned uOp, KUPTR uHandle);
124static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, unsigned uOp, KUPTR uHandle);
125static KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved);
126
127
128/**
129 * Create a loader module instance interpreting the executable image found
130 * in the specified file provider instance.
131 *
132 * @returns 0 on success and *ppMod pointing to a module instance.
133 * On failure, a non-zero OS specific error code is returned.
134 * @param pOps Pointer to the registered method table.
135 * @param pRdr The file provider instance to use.
136 * @param fFlags Flags, MBZ.
137 * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means
138 * anything goes, but with a preference for the current
139 * host architecture.
140 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
141 * @param ppMod Where to store the module instance pointer.
142 */
143static int kldrModPECreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
144{
145 PKLDRMODPE pModPE;
146 int rc;
147
148 /*
149 * Create the instance data and do a minimal header validation.
150 */
151 rc = kldrModPEDoCreate(pRdr, offNewHdr, &pModPE);
152 if (!rc)
153 {
154 /*
155 * Match up against the requested CPU architecture.
156 */
157 if ( enmCpuArch == KCPUARCH_UNKNOWN
158 || pModPE->pMod->enmArch == enmCpuArch)
159 {
160 pModPE->pMod->pOps = pOps;
161 pModPE->pMod->u32Magic = KLDRMOD_MAGIC;
162 *ppMod = pModPE->pMod;
163 return 0;
164 }
165 rc = KLDR_ERR_CPU_ARCH_MISMATCH;
166 }
167 kHlpFree(pModPE);
168 return rc;
169}
170
171
172/**
173 * Separate function for reading creating the PE module instance to
174 * simplify cleanup on failure.
175 */
176static int kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppModPE)
177{
178 struct
179 {
180 KU32 Signature;
181 IMAGE_FILE_HEADER FileHdr;
182 } s;
183 PKLDRMODPE pModPE;
184 PKLDRMOD pMod;
185 KSIZE cb;
186 KSIZE cchFilename;
187 KLDRFOFF off;
188 KU32 i;
189 int rc;
190 *ppModPE = NULL;
191
192 /*
193 * Read the signature and file header.
194 */
195 rc = kRdrRead(pRdr, &s, sizeof(s), offNewHdr > 0 ? offNewHdr : 0);
196 if (rc)
197 return rc;
198 if (s.Signature != IMAGE_NT_SIGNATURE)
199 return KLDR_ERR_UNKNOWN_FORMAT;
200
201 /* sanity checks. */
202 if ( s.FileHdr.NumberOfSections > 4096
203 || ( s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32)
204 && s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64))
205 || !(s.FileHdr.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
206 )
207 return KLDR_ERR_PE_BAD_FILE_HEADER;
208 if ( s.FileHdr.Machine != IMAGE_FILE_MACHINE_I386
209 && s.FileHdr.Machine != IMAGE_FILE_MACHINE_AMD64
210 )
211 return KLDR_ERR_PE_UNSUPPORTED_MACHINE;
212
213 /*
214 * Calc the instance size, allocate and initialize it.
215 */
216 cchFilename = kHlpStrLen(kRdrName(pRdr));
217 cb = K_ALIGN_Z(K_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16)
218 + K_OFFSETOF(KLDRMOD, aSegments[s.FileHdr.NumberOfSections + 1])
219 + cchFilename + 1;
220 pModPE = (PKLDRMODPE)kHlpAlloc(cb);
221 if (!pModPE)
222 return KERR_NO_MEMORY;
223 *ppModPE = pModPE;
224
225 /* KLDRMOD */
226 pMod = (PKLDRMOD)((KU8 *)pModPE + K_ALIGN_Z(K_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16));
227 pMod->pvData = pModPE;
228 pMod->pRdr = pRdr;
229 pMod->pOps = NULL; /* set upon success. */
230 pMod->cSegments = s.FileHdr.NumberOfSections + 1;
231 pMod->cchFilename = cchFilename;
232 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
233 kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1);
234 pMod->pszName = kHlpGetFilename(pMod->pszFilename);
235 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
236 switch (s.FileHdr.Machine)
237 {
238 case IMAGE_FILE_MACHINE_I386:
239 pMod->enmCpu = KCPU_I386;
240 pMod->enmArch = KCPUARCH_X86_32;
241 pMod->enmEndian = KLDRENDIAN_LITTLE;
242 break;
243
244 case IMAGE_FILE_MACHINE_AMD64:
245 pMod->enmCpu = KCPU_K8;
246 pMod->enmArch = KCPUARCH_AMD64;
247 pMod->enmEndian = KLDRENDIAN_LITTLE;
248 break;
249 default:
250 kHlpAssert(0);
251 break;
252 }
253 pMod->enmFmt = KLDRFMT_PE;
254 if (s.FileHdr.Characteristics & IMAGE_FILE_DLL)
255 pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
256 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
257 : KLDRTYPE_SHARED_LIBRARY_FIXED;
258 else
259 pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
260 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
261 : KLDRTYPE_EXECUTABLE_FIXED;
262 pMod->u32Magic = 0; /* set upon success. */
263
264 /* KLDRMODPE */
265 pModPE->pMod = pMod;
266 pModPE->pvBits = NULL;
267 pModPE->pvMapping = NULL;
268 pModPE->f32Reserved = 0;
269 pModPE->cImportModules = ~(KU32)0;
270 pModPE->offHdrs = offNewHdr >= 0 ? offNewHdr : 0;
271 pModPE->Hdrs.Signature = s.Signature;
272 pModPE->Hdrs.FileHeader = s.FileHdr;
273
274 /*
275 * Read the optional header and the section table.
276 */
277 off = pModPE->offHdrs + sizeof(pModPE->Hdrs.Signature) + sizeof(pModPE->Hdrs.FileHeader);
278 rc = kRdrRead(pRdr, &pModPE->Hdrs.OptionalHeader, pModPE->Hdrs.FileHeader.SizeOfOptionalHeader, off);
279 if (rc)
280 return rc;
281 if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader != sizeof(pModPE->Hdrs.OptionalHeader))
282 kldrModPEDoOptionalHeaderConversion(&pModPE->Hdrs.OptionalHeader);
283 off += pModPE->Hdrs.FileHeader.SizeOfOptionalHeader;
284 rc = kRdrRead(pRdr, &pModPE->aShdrs[0], sizeof(IMAGE_SECTION_HEADER) * pModPE->Hdrs.FileHeader.NumberOfSections, off);
285 if (rc)
286 return rc;
287
288 /*
289 * Validate the two.
290 */
291 rc = kLdrModPEDoOptionalHeaderValidation(pModPE);
292 if (rc)
293 return rc;
294 for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
295 {
296 rc = kLdrModPEDoSectionHeadersValidation(pModPE);
297 if (rc)
298 return rc;
299 }
300
301 /*
302 * Setup the KLDRMOD segment array.
303 */
304 /* The implied headers section. */
305 pMod->aSegments[0].pvUser = NULL;
306 pMod->aSegments[0].pchName = "TheHeaders";
307 pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1;
308 pMod->aSegments[0].enmProt = KPROT_READONLY;
309 pMod->aSegments[0].cb = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
310 pMod->aSegments[0].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment;
311 pMod->aSegments[0].LinkAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
312 pMod->aSegments[0].offFile = 0;
313 pMod->aSegments[0].cbFile = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
314 pMod->aSegments[0].RVA = 0;
315 if (pMod->cSegments > 1)
316 pMod->aSegments[0].cbMapped = pModPE->aShdrs[0].VirtualAddress;
317 else
318 pMod->aSegments[0].cbMapped = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
319 pMod->aSegments[0].MapAddress = 0;
320
321 /* The section headers. */
322 for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
323 {
324 const char *pch;
325
326 /* unused */
327 pMod->aSegments[i + 1].pvUser = NULL;
328 pMod->aSegments[i + 1].MapAddress = 0;
329 pMod->aSegments[i + 1].SelFlat = 0;
330 pMod->aSegments[i + 1].Sel16bit = 0;
331 pMod->aSegments[i + 1].fFlags = 0;
332
333 /* name */
334 pMod->aSegments[i + 1].pchName = pch = (const char *)&pModPE->aShdrs[i].Name[0];
335 cb = IMAGE_SIZEOF_SHORT_NAME;
336 while ( cb > 0
337 && (pch[cb - 1] == ' ' || pch[cb - 1] == '\0'))
338 cb--;
339 pMod->aSegments[i + 1].cchName = cb;
340
341 /* size and addresses */
342 if (!(pModPE->aShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
343 {
344 pMod->aSegments[i + 1].cb = pModPE->aShdrs[i].Misc.VirtualSize;
345 pMod->aSegments[i + 1].LinkAddress = pModPE->aShdrs[i].VirtualAddress
346 + pModPE->Hdrs.OptionalHeader.ImageBase;
347 pMod->aSegments[i + 1].RVA = pModPE->aShdrs[i].VirtualAddress;
348 pMod->aSegments[i + 1].cbMapped = pModPE->aShdrs[i].Misc.VirtualSize;
349 if (i + 2 < pMod->cSegments)
350 pMod->aSegments[i + 1].cbMapped= pModPE->aShdrs[i + 1].VirtualAddress
351 - pModPE->aShdrs[i].VirtualAddress;
352 }
353 else
354 {
355 pMod->aSegments[i + 1].cb = 0;
356 pMod->aSegments[i + 1].cbMapped = 0;
357 pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR;
358 pMod->aSegments[i + 1].RVA = 0;
359 }
360
361 /* file location */
362 pMod->aSegments[i + 1].offFile = pModPE->aShdrs[i].PointerToRawData;
363 pMod->aSegments[i + 1].cbFile = pModPE->aShdrs[i].SizeOfRawData;
364 if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */
365 && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped)
366 pMod->aSegments[i + 1].cbFile = pMod->aSegments[i + 1].cbMapped;
367
368 /* protection */
369 switch ( pModPE->aShdrs[i].Characteristics
370 & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
371 {
372 case 0:
373 case IMAGE_SCN_MEM_SHARED:
374 pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS;
375 break;
376 case IMAGE_SCN_MEM_READ:
377 case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
378 pMod->aSegments[i + 1].enmProt = KPROT_READONLY;
379 break;
380 case IMAGE_SCN_MEM_WRITE:
381 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
382 pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY;
383 break;
384 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
385 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
386 pMod->aSegments[i + 1].enmProt = KPROT_READWRITE;
387 break;
388 case IMAGE_SCN_MEM_EXECUTE:
389 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED:
390 pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE;
391 break;
392 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ:
393 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
394 pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ;
395 break;
396 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE:
397 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
398 pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY;
399 break;
400 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
401 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
402 pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE;
403 break;
404 }
405
406 /* alignment. */
407 switch (pModPE->aShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
408 {
409 case 0: /* hope this is right... */
410 pMod->aSegments[i + 1].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment;
411 break;
412 case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break;
413 case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break;
414 case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break;
415 case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break;
416 case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break;
417 case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break;
418 case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break;
419 case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break;
420 case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break;
421 case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break;
422 case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break;
423 case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break;
424 case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break;
425 case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break;
426 default: kHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break;
427 }
428 }
429
430 /*
431 * We're done.
432 */
433 *ppModPE = pModPE;
434 return 0;
435}
436
437
438/**
439 * Converts a 32-bit optional header to a 64-bit one
440 *
441 * @param pOptHdr The optional header to convert.
442 */
443static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
444{
445 /* volatile everywhere! */
446 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
447 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
448 KU32 volatile *pu32Dst;
449 KU32 volatile *pu32Src;
450 KU32 volatile *pu32SrcLast;
451 KU32 u32;
452
453 /* From LoaderFlags and out the difference is 4 * 32-bits. */
454 pu32Dst = (KU32 *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
455 pu32Src = (KU32 *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
456 pu32SrcLast = (KU32 *)&pOptHdr32->LoaderFlags;
457 while (pu32Src >= pu32SrcLast)
458 *pu32Dst-- = *pu32Src--;
459
460 /* The previous 4 fields are 32/64 and needs special attention. */
461 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
462 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
463 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
464 u32 = pOptHdr32->SizeOfStackReserve;
465 pOptHdr64->SizeOfStackReserve = u32;
466
467 /*
468 * The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version.
469 * Thus, ImageBase needs some special treatement. It will probably work fine assigning one to the
470 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
471 */
472 u32 = pOptHdr32->ImageBase;
473 pOptHdr64->ImageBase = u32;
474}
475
476
477#if 0
478/**
479 * Converts a 32-bit load config directory to a 64 bit one.
480 *
481 * @param pOptHdr The load config to convert.
482 */
483static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
484{
485 /* volatile everywhere! */
486 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
487 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
488 KU32 u32;
489
490 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
491 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
492 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
493 pLoadCfg64->EditList = pLoadCfg32->EditList;
494 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
495 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
496 /* (ProcessHeapFlags switched place with ProcessAffinityMask, but we're
497 * more than 16 byte off by now so it doesn't matter.) */
498 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags;
499 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
500 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
501 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
502 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
503 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
504 u32 = pLoadCfg32->DeCommitFreeBlockThreshold;
505 pLoadCfg64->DeCommitFreeBlockThreshold = u32;
506 /* the remainder matches. */
507}
508#endif
509
510
511/**
512 * Internal worker which validates the section headers.
513 */
514static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE)
515{
516 const unsigned fIs32Bit = pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32);
517
518 /* the magic */
519 if ( pModPE->Hdrs.OptionalHeader.Magic
520 != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
521 return KLDR_ERR_PE_BAD_OPTIONAL_HEADER;
522
523 /** @todo validate more */
524 return 0;
525}
526
527
528/**
529 * Internal worker which validates the section headers.
530 */
531static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE)
532{
533 /** @todo validate shdrs */
534 return 0;
535}
536
537
538/** @copydoc KLDRMODOPS::pfnDestroy */
539static int kldrModPEDestroy(PKLDRMOD pMod)
540{
541 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
542 int rc = 0;
543 KLDRMODPE_ASSERT(!pModPE->pvMapping);
544
545 if (pMod->pRdr)
546 {
547 rc = kRdrClose(pMod->pRdr);
548 pMod->pRdr = NULL;
549 }
550 pMod->u32Magic = 0;
551 pMod->pOps = NULL;
552 kHlpFree(pModPE);
553 return rc;
554}
555
556
557/**
558 * Performs the mapping of the image.
559 *
560 * This can be used to do the internal mapping as well as the
561 * user requested mapping. fForReal indicates which is desired.
562 *
563 * @returns 0 on success, non-zero OS or kLdr status code on failure.
564 * @param pModPE The interpreter module instance
565 * @param fForReal If set, do the user mapping. if clear, do the internal mapping.
566 */
567static int kldrModPEDoMap(PKLDRMODPE pModPE, unsigned fForReal)
568{
569 PKLDRMOD pMod = pModPE->pMod;
570 KBOOL fFixed;
571 void *pvBase;
572 int rc;
573 KU32 i;
574
575 /*
576 * Map it.
577 */
578 /* fixed image? */
579 fFixed = fForReal
580 && ( pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
581 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED);
582 if (!fFixed)
583 pvBase = NULL;
584 else
585 {
586 pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
587 if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
588 return KLDR_ERR_ADDRESS_OVERFLOW;
589 }
590
591 /* try do the prepare */
592 rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
593 if (rc)
594 return rc;
595
596 /*
597 * Update the segments with their map addresses.
598 */
599 if (fForReal)
600 {
601 for (i = 0; i < pMod->cSegments; i++)
602 {
603 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
604 pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
605 }
606 pModPE->pvMapping = pvBase;
607 }
608 else
609 pModPE->pvBits = pvBase;
610 return 0;
611}
612
613
614/**
615 * Unmaps a image mapping.
616 *
617 * This can be used to do the internal mapping as well as the
618 * user requested mapping. fForReal indicates which is desired.
619 *
620 * @returns 0 on success, non-zero OS or kLdr status code on failure.
621 * @param pModPE The interpreter module instance
622 * @param pvMapping The mapping to unmap.
623 */
624static int kldrModPEDoUnmap(PKLDRMODPE pModPE, const void *pvMapping)
625{
626 PKLDRMOD pMod = pModPE->pMod;
627 int rc;
628 KU32 i;
629
630 /*
631 * Try unmap the image.
632 */
633 rc = kRdrUnmap(pMod->pRdr, (void *)pvMapping, pMod->cSegments, pMod->aSegments);
634 if (rc)
635 return rc;
636
637 /*
638 * Update the segments to reflect that they aren't mapped any longer.
639 */
640 if (pModPE->pvMapping == pvMapping)
641 {
642 pModPE->pvMapping = NULL;
643 for (i = 0; i < pMod->cSegments; i++)
644 pMod->aSegments[i].MapAddress = 0;
645 }
646 if (pModPE->pvBits == pvMapping)
647 pModPE->pvBits = NULL;
648
649 return 0;
650}
651
652
653/**
654 * Gets usable bits and the right base address.
655 *
656 * @returns 0 on success.
657 * @returns A non-zero status code if the BaseAddress isn't right or some problem is encountered
658 * featch in a temp mapping the bits.
659 * @param pModPE The interpreter module instance
660 * @param ppvBits The bits address, IN & OUT.
661 * @param pBaseAddress The base address, IN & OUT. Optional.
662 */
663static int kldrModPEBitsAndBaseAddress(PKLDRMODPE pModPE, const void **ppvBits, PKLDRADDR pBaseAddress)
664{
665 int rc = 0;
666
667 /*
668 * Correct the base address.
669 *
670 * We don't use the base address for interpreting the bits in this
671 * interpreter, which makes things relativly simple.
672 */
673 if (pBaseAddress)
674 {
675 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
676 *pBaseAddress = pModPE->pMod->aSegments[0].MapAddress;
677 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
678 *pBaseAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
679 }
680
681 /*
682 * Get bits.
683 */
684 if (ppvBits && !*ppvBits)
685 {
686 if (pModPE->pvMapping)
687 *ppvBits = pModPE->pvMapping;
688 else if (pModPE->pvBits)
689 *ppvBits = pModPE->pvBits;
690 else
691 {
692 /* create an internal mapping. */
693 rc = kldrModPEDoMap(pModPE, 0 /* not for real */);
694 if (rc)
695 return rc;
696 KLDRMODPE_ASSERT(pModPE->pvBits);
697 *ppvBits = pModPE->pvBits;
698 }
699 }
700
701 return 0;
702}
703
704
705/** @copydoc kLdrModQuerySymbol */
706static int kldrModPEQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
707 const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
708 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
709
710{
711 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
712 const KU32 *paExportRVAs;
713 const IMAGE_EXPORT_DIRECTORY *pExpDir;
714 KU32 iExpOrd;
715 KU32 uRVA;
716 int rc;
717
718 /*
719 * Make sure we've got mapped bits and resolve any base address aliases.
720 */
721 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
722 if (rc)
723 return rc;
724 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
725 < sizeof(IMAGE_EXPORT_DIRECTORY))
726 return KLDR_ERR_SYMBOL_NOT_FOUND;
727 if (pszVersion && *pszVersion)
728 return KLDR_ERR_SYMBOL_NOT_FOUND;
729
730 pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
731 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
732 PIMAGE_EXPORT_DIRECTORY);
733 if (!pchSymbol)
734 {
735 /*
736 * Simple, calculate the unbased ordinal and bounds check it.
737 */
738 iExpOrd = iSymbol - pExpDir->Base;
739 if (iExpOrd >= K_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions))
740 return KLDR_ERR_SYMBOL_NOT_FOUND;
741 }
742 else
743 {
744 /*
745 * Do a binary search for the name.
746 * (The name table is sorted in ascending ordered by the linker.)
747 */
748 const KU32 *paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const KU32 *);
749 const KU16 *paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const KU16 *);
750 KI32 iStart = 1; /* one based binary searching is simpler. */
751 KI32 iEnd = pExpDir->NumberOfNames;
752
753 for (;;)
754 {
755 KI32 i;
756 int diff;
757 const char *pszName;
758
759 /* done? */
760 if (iStart > iEnd)
761 {
762#ifdef KLDRMODPE_STRICT /* Make sure the linker and we both did our job right. */
763 for (i = 0; i < (KI32)pExpDir->NumberOfNames; i++)
764
765 {
766 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i], const char *);
767 KLDRMODPE_ASSERT(kHlpStrNComp(pszName, pchSymbol, cchSymbol) || pszName[cchSymbol]);
768 KLDRMODPE_ASSERT(i == 0 || kHlpStrComp(pszName, KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)));
769 }
770#endif
771 return KLDR_ERR_SYMBOL_NOT_FOUND;
772 }
773
774 i = (iEnd - iStart) / 2 + iStart;
775 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
776 diff = kHlpStrNComp(pszName, pchSymbol, cchSymbol);
777 if (!diff)
778 diff = pszName[cchSymbol] - 0;
779 if (diff < 0)
780 iStart = i + 1; /* The symbol must be after the current name. */
781 else if (diff)
782 iEnd = i - 1; /* The symbol must be before the current name. */
783 else
784 {
785 iExpOrd = paOrdinals[i - 1]; /* match! */
786 break;
787 }
788 }
789 }
790
791 /*
792 * Lookup the address in the 'symbol' table.
793 */
794 paExportRVAs = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const KU32 *);
795 uRVA = paExportRVAs[iExpOrd];
796 if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
797 < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
798 return kldrModPEDoForwarderQuery(pModPE, pvBits, KLDRMODPE_RVA2TYPE(pvBits, uRVA, const char *),
799 pfnGetForwarder, pvUser, puValue, pfKind);
800
801 /*
802 * Set the return value.
803 */
804 if (puValue)
805 *puValue = BaseAddress + uRVA;
806 if (pfKind)
807 *pfKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
808 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
809 | KLDRSYMKIND_NO_TYPE;
810 return 0;
811}
812
813
814/**
815 * Deal with a forwarder entry.
816 *
817 * We do this seprately from kldrModPEQuerySymbol because the code is clumsy (as is all PE code
818 * thanks to the descriptive field names), and because it uses quite a bit more stack and we're
819 * trying to avoid allocating stack unless we have to.
820 *
821 * @returns See kLdrModQuerySymbol.
822 * @param pModPE The PE module interpreter instance.
823 * @param pvBits Where to read the image from.
824 * @param pszForwarder The forwarder entry name.
825 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
826 * @param pvUser The user argument for the callback.
827 * @param puValue Where to put the value. (optional)
828 * @param pfKind Where to put the symbol kind. (optional)
829 */
830static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
831 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
832{
833 const IMAGE_IMPORT_DESCRIPTOR *paImpDir;
834 KU32 iImpModule;
835 KU32 cchImpModule;
836 const char *pszSymbol;
837 KU32 iSymbol;
838 int rc;
839
840 if (!pfnGetForwarder)
841 return KLDR_ERR_FORWARDER_SYMBOL;
842
843 /*
844 * Separate the name into a module name and a symbol name or ordinal.
845 *
846 * The module name ends at the first dot ('.').
847 * After the dot follows either a symbol name or a hash ('#') + ordinal.
848 */
849 pszSymbol = pszForwarder;
850 while (*pszSymbol != '.')
851 pszSymbol++;
852 if (!*pszSymbol)
853 return KLDR_ERR_PE_BAD_FORWARDER;
854 cchImpModule = pszSymbol - pszForwarder;
855
856 pszSymbol++; /* skip the dot */
857 if (!*pszSymbol)
858 return KLDR_ERR_PE_BAD_FORWARDER;
859 if (*pszSymbol == '#')
860 {
861 unsigned uBase;
862 pszSymbol++; /* skip the hash */
863
864 /* base detection */
865 uBase = 10;
866 if (pszSymbol[0] == '0' && (pszSymbol[1] == 'x' || pszSymbol[1] == 'X'))
867 {
868 uBase = 16;
869 pszSymbol += 2;
870 }
871
872 /* ascii to integer */
873 iSymbol = 0;
874 for (;;)
875 {
876 /* convert char to digit. */
877 unsigned uDigit = *pszSymbol++;
878 if (uDigit >= '0' && uDigit <= '9')
879 uDigit -= '0';
880 else if (uDigit >= 'a' && uDigit <= 'z')
881 uDigit -= 'a' + 10;
882 else if (uDigit >= 'A' && uDigit <= 'Z')
883 uDigit -= 'A' + 10;
884 else if (!uDigit)
885 break;
886 else
887 return KLDR_ERR_PE_BAD_FORWARDER;
888 if (uDigit >= uBase)
889 return KLDR_ERR_PE_BAD_FORWARDER;
890
891 /* insert the digit */
892 iSymbol *= uBase;
893 iSymbol += uDigit;
894 }
895
896 pszSymbol = NULL; /* no symbol name. */
897 }
898 else
899 iSymbol = NIL_KLDRMOD_SYM_ORDINAL; /* no ordinal number. */
900
901
902 /*
903 * Find the import module name.
904 *
905 * We ASSUME the linker will make sure there is an import
906 * entry for the module... not sure if this is right though.
907 */
908 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
909 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
910 return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
911 paImpDir = KLDRMODPE_RVA2TYPE(pvBits,
912 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
913 const IMAGE_IMPORT_DESCRIPTOR *);
914
915 kldrModPENumberOfImports(pModPE->pMod, pvBits);
916 for (iImpModule = 0; iImpModule < pModPE->cImportModules; iImpModule++)
917 {
918 const char *pszName = KLDRMODPE_RVA2TYPE(pvBits, paImpDir[iImpModule].Name, const char *);
919 KSIZE cchName = kHlpStrLen(pszName);
920 if ( ( cchName == cchImpModule
921 || ( cchName > cchImpModule
922 && pszName[cchImpModule] == '.'
923 && (pszName[cchImpModule + 1] == 'd' || pszName[cchImpModule + 1] == 'D')
924 && (pszName[cchImpModule + 2] == 'l' || pszName[cchImpModule + 2] == 'L')
925 && (pszName[cchImpModule + 3] == 'l' || pszName[cchImpModule + 3] == 'L'))
926 )
927 && kHlpMemICompAscii(pszName, pszForwarder, cchImpModule)
928 )
929 {
930 /*
931 * Now the rest is up to the callback (almost).
932 */
933 rc = pfnGetForwarder(pModPE->pMod, iImpModule, iSymbol, pszSymbol,
934 pszSymbol ? kHlpStrLen(pszSymbol) : 0, NULL, puValue, pfKind, pvUser);
935 if (!rc && pfKind)
936 *pfKind |= KLDRSYMKIND_FORWARDER;
937 return rc;
938 }
939 }
940 return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
941}
942
943
944/** @copydoc kLdrModEnumSymbols */
945static int kldrModPEEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
946 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
947{
948 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
949 const KU32 *paFunctions;
950 const IMAGE_EXPORT_DIRECTORY *pExpDir;
951 const KU32 *paRVANames;
952 const KU16 *paOrdinals;
953 KU32 iFunction;
954 KU32 cFunctions;
955 KU32 cNames;
956 int rc;
957
958 /*
959 * Make sure we've got mapped bits and resolve any base address aliases.
960 */
961 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
962 if (rc)
963 return rc;
964
965 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
966 < sizeof(IMAGE_EXPORT_DIRECTORY))
967 return 0; /* no exports to enumerate, return success. */
968
969 pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
970 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
971 PIMAGE_EXPORT_DIRECTORY);
972
973 /*
974 * Enumerate the ordinal exports.
975 */
976 paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const KU32 *);
977 paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const KU16 *);
978 paFunctions = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const KU32 *);
979 cFunctions = pExpDir->NumberOfFunctions;
980 cNames = pExpDir->NumberOfNames;
981 for (iFunction = 0; iFunction < cFunctions; iFunction++)
982 {
983 unsigned fFoundName;
984 KU32 iName;
985 const KU32 uRVA = paFunctions[iFunction];
986 const KLDRADDR uValue = BaseAddress + uRVA;
987 KU32 fKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
988 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
989 | KLDRSYMKIND_NO_TYPE;
990 if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
991 < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
992 fKind |= KLDRSYMKIND_FORWARDER;
993
994 /*
995 * Any symbol names?
996 */
997 fFoundName = 0;
998 for (iName = 0; iName < cNames; iName++)
999 {
1000 const char *pszName;
1001 if (paOrdinals[iName] != iFunction)
1002 continue;
1003 fFoundName = 1;
1004 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[iName], const char *);
1005 rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, kHlpStrLen(pszName), NULL,
1006 uValue, fKind, pvUser);
1007 if (rc)
1008 return rc;
1009 }
1010
1011 /*
1012 * If no names, call once with the ordinal only.
1013 */
1014 if (!fFoundName)
1015 {
1016 rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser);
1017 if (rc)
1018 return rc;
1019 }
1020 }
1021
1022 return 0;
1023}
1024
1025
1026/** @copydoc kLdrModGetImport */
1027static int kldrModPEGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
1028{
1029 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1030 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1031 const char *pszImportName;
1032 KSIZE cchImportName;
1033 int rc;
1034
1035 /*
1036 * Make sure we've got mapped bits and resolve any base address aliases.
1037 */
1038 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
1039 if (rc)
1040 return rc;
1041
1042 /*
1043 * Simple bounds check.
1044 */
1045 if (iImport >= (KU32)kldrModPENumberOfImports(pMod, pvBits))
1046 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1047
1048 /*
1049 * Get the name.
1050 */
1051 pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
1052 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
1053 + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport,
1054 const IMAGE_IMPORT_DESCRIPTOR *);
1055 pszImportName = KLDRMODPE_RVA2TYPE(pvBits, pImpDesc->Name, const char *);
1056 cchImportName = kHlpStrLen(pszImportName);
1057 if (cchImportName < cchName)
1058 {
1059 kHlpMemCopy(pszName, pszImportName, cchImportName + 1);
1060 rc = 0;
1061 }
1062 else
1063 {
1064 kHlpMemCopy(pszName, pszImportName, cchName);
1065 if (cchName)
1066 pszName[cchName - 1] = '\0';
1067 rc = KERR_BUFFER_OVERFLOW;
1068 }
1069
1070 return rc;
1071}
1072
1073
1074/** @copydoc kLdrModNumberOfImports */
1075static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits)
1076{
1077 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1078 if (pModPE->cImportModules == ~(KU32)0)
1079 {
1080 /*
1081 * We'll have to walk the import descriptors to figure out their number.
1082 * First, make sure we've got mapped bits.
1083 */
1084 if (kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL))
1085 return -1;
1086 pModPE->cImportModules = 0;
1087 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
1088 && pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1089 {
1090 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1091
1092 pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
1093 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
1094 const IMAGE_IMPORT_DESCRIPTOR *);
1095 while (pImpDesc->Name && pImpDesc->FirstThunk)
1096 {
1097 pModPE->cImportModules++;
1098 pImpDesc++;
1099 }
1100 }
1101 }
1102 return pModPE->cImportModules;
1103}
1104
1105
1106/** @copydoc kLdrModGetStackInfo */
1107static int kldrModPEGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1108{
1109 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1110
1111 pStackInfo->Address = NIL_KLDRADDR;
1112 pStackInfo->LinkAddress = NIL_KLDRADDR;
1113 pStackInfo->cbStack = pStackInfo->cbStackThread = pModPE->Hdrs.OptionalHeader.SizeOfStackReserve;
1114
1115 return 0;
1116}
1117
1118
1119/** @copydoc kLdrModQueryMainEntrypoint */
1120static int kldrModPEQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1121{
1122 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1123 int rc;
1124
1125 /*
1126 * Resolve base address alias if any.
1127 */
1128 rc = kldrModPEBitsAndBaseAddress(pModPE, NULL, &BaseAddress);
1129 if (rc)
1130 return rc;
1131
1132 /*
1133 * Convert the address from the header.
1134 */
1135 *pMainEPAddress = pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
1136 ? BaseAddress + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
1137 : NIL_KLDRADDR;
1138 return 0;
1139}
1140
1141
1142/** @copydoc kLdrModEnumDbgInfo */
1143static int kldrModPEEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1144{
1145 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1146 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
1147 KU32 iDbgInfo;
1148 KU32 cb;
1149 int rc;
1150
1151 /*
1152 * Check that there is a debug directory first.
1153 */
1154 cb = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
1155 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1156 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1157 return 0;
1158
1159 /*
1160 * Make sure we've got mapped bits.
1161 */
1162 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
1163 if (rc)
1164 return rc;
1165
1166 /*
1167 * Enumerate the debug directory.
1168 */
1169 pDbgDir = KLDRMODPE_RVA2TYPE(pvBits,
1170 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
1171 const IMAGE_DEBUG_DIRECTORY *);
1172 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
1173 {
1174 KLDRDBGINFOTYPE enmDbgInfoType;
1175
1176 /* convert the type. */
1177 switch (pDbgDir->Type)
1178 {
1179 case IMAGE_DEBUG_TYPE_UNKNOWN:
1180 case IMAGE_DEBUG_TYPE_FPO:
1181 case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
1182 case IMAGE_DEBUG_TYPE_MISC:
1183 case IMAGE_DEBUG_TYPE_EXCEPTION:
1184 case IMAGE_DEBUG_TYPE_FIXUP:
1185 case IMAGE_DEBUG_TYPE_BORLAND:
1186 default:
1187 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
1188 break;
1189 case IMAGE_DEBUG_TYPE_CODEVIEW:
1190 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
1191 break;
1192 }
1193
1194 rc = pfnCallback(pMod, iDbgInfo,
1195 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion, NULL,
1196 pDbgDir->PointerToRawData ? (KLDRFOFF)pDbgDir->PointerToRawData : -1,
1197 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
1198 pDbgDir->SizeOfData,
1199 NULL,
1200 pvUser);
1201 if (rc)
1202 break;
1203
1204 /* next */
1205 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
1206 break;
1207 }
1208
1209 return rc;
1210}
1211
1212
1213/** @copydoc kLdrModHasDbgInfo */
1214static int kldrModPEHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1215{
1216 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1217
1218 /*
1219 * Base this entirely on the presence of a debug directory.
1220 */
1221 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
1222 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1223 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1224 return KLDR_ERR_NO_DEBUG_INFO;
1225 return 0;
1226}
1227
1228
1229/** @copydoc kLdrModMap */
1230static int kldrModPEMap(PKLDRMOD pMod)
1231{
1232 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1233 int rc;
1234
1235 /*
1236 * Already mapped?
1237 */
1238 if (pModPE->pvMapping)
1239 return KLDR_ERR_ALREADY_MAPPED;
1240
1241 /*
1242 * We've got a common worker which does this.
1243 */
1244 rc = kldrModPEDoMap(pModPE, 1 /* the real thing */);
1245 if (rc)
1246 return rc;
1247 KLDRMODPE_ASSERT(pModPE->pvMapping);
1248 return 0;
1249}
1250
1251
1252/** @copydoc kLdrModUnmap */
1253static int kldrModPEUnmap(PKLDRMOD pMod)
1254{
1255 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1256 int rc;
1257
1258 /*
1259 * Mapped?
1260 */
1261 if (!pModPE->pvMapping)
1262 return KLDR_ERR_NOT_MAPPED;
1263
1264 /*
1265 * We've got a common worker which does this.
1266 */
1267 rc = kldrModPEDoUnmap(pModPE, pModPE->pvMapping);
1268 if (rc)
1269 return rc;
1270 KLDRMODPE_ASSERT(!pModPE->pvMapping);
1271 return 0;
1272
1273}
1274
1275
1276/** @copydoc kLdrModAllocTLS */
1277static int kldrModPEAllocTLS(PKLDRMOD pMod)
1278{
1279 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1280
1281 /*
1282 * Mapped?
1283 */
1284 if (!pModPE->pvMapping)
1285 return KLDR_ERR_NOT_MAPPED;
1286
1287 /*
1288 * If no TLS directory then there is nothing to do.
1289 */
1290 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
1291 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
1292 return 0;
1293 /** @todo implement TLS. */
1294 return -1;
1295}
1296
1297
1298/** @copydoc kLdrModFreeTLS */
1299static void kldrModPEFreeTLS(PKLDRMOD pMod)
1300{
1301 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1302
1303 /*
1304 * Mapped?
1305 */
1306 if (!pModPE->pvMapping)
1307 return;
1308
1309 /*
1310 * If no TLS directory then there is nothing to do.
1311 */
1312 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
1313 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
1314 return;
1315 /** @todo implement TLS. */
1316 return;
1317}
1318
1319
1320/** @copydoc kLdrModReload */
1321static int kldrModPEReload(PKLDRMOD pMod)
1322{
1323 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1324
1325 /*
1326 * Mapped?
1327 */
1328 if (!pModPE->pvMapping)
1329 return KLDR_ERR_NOT_MAPPED;
1330
1331 /* the file provider does it all */
1332 return kRdrRefresh(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments);
1333}
1334
1335
1336/** @copydoc kLdrModFixupMapping */
1337static int kldrModPEFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1338{
1339 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1340 int rc, rc2;
1341
1342 /*
1343 * Mapped?
1344 */
1345 if (!pModPE->pvMapping)
1346 return KLDR_ERR_NOT_MAPPED;
1347
1348 /*
1349 * Before doing anything we'll have to make all pages writable.
1350 */
1351 rc = kRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
1352 if (rc)
1353 return rc;
1354
1355 /*
1356 * Apply base relocations.
1357 */
1358 rc = kldrModPEDoFixups(pModPE, (void *)pModPE->pvMapping, (KUPTR)pModPE->pvMapping,
1359 pModPE->Hdrs.OptionalHeader.ImageBase);
1360
1361 /*
1362 * Resolve imports.
1363 */
1364 if (!rc)
1365 rc = kldrModPEDoImports(pModPE, (void *)pModPE->pvMapping, pfnGetImport, pvUser);
1366
1367 /*
1368 * Restore protection.
1369 */
1370 rc2 = kRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
1371 if (!rc && rc2)
1372 rc = rc2;
1373 return rc;
1374}
1375
1376
1377/**
1378 * Applies base relocations to a (unprotected) image mapping.
1379 *
1380 * @returns 0 on success, non-zero kLdr status code on failure.
1381 * @param pModPE The PE module interpreter instance.
1382 * @param pvMapping The mapping to fixup.
1383 * @param NewBaseAddress The address to fixup the mapping to.
1384 * @param OldBaseAddress The address the mapping is currently fixed up to.
1385 */
1386static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress)
1387{
1388 const KLDRADDR Delta = NewBaseAddress - OldBaseAddress;
1389 KU32 cbLeft = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1390 const IMAGE_BASE_RELOCATION *pBR, *pFirstBR;
1391
1392 /*
1393 * Don't don anything if the delta is 0 or there aren't any relocations.
1394 */
1395 if ( !Delta
1396 || !cbLeft
1397 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
1398 return 0;
1399
1400 /*
1401 * Process the fixups block by block.
1402 * (These blocks appears to be 4KB on all archs despite the native page size.)
1403 */
1404 pBR = pFirstBR = KLDRMODPE_RVA2TYPE(pvMapping,
1405 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
1406 const IMAGE_BASE_RELOCATION *);
1407 while ( cbLeft > sizeof(IMAGE_BASE_RELOCATION)
1408 && pBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION) /* paranoia */)
1409 {
1410 union
1411 {
1412 KU8 *pu8;
1413 KU16 *pu16;
1414 KU32 *pu32;
1415 KU64 *pu64;
1416 } uChunk,
1417 u;
1418 const KU16 *poffFixup = (const KU16 *)(pBR + 1);
1419 const KU32 cbBlock = K_MIN(cbLeft, pBR->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION); /* more caution... */
1420 KU32 cFixups = cbBlock / sizeof(poffFixup[0]);
1421 uChunk.pu8 = KLDRMODPE_RVA2TYPE(pvMapping, pBR->VirtualAddress, KU8 *);
1422
1423 /*
1424 * Loop thru the fixups in this chunk.
1425 */
1426 while (cFixups > 0)
1427 {
1428 u.pu8 = uChunk.pu8 + (*poffFixup & 0xfff);
1429 switch (*poffFixup >> 12) /* ordered by value. */
1430 {
1431 /* 0 - Alignment placeholder. */
1432 case IMAGE_REL_BASED_ABSOLUTE:
1433 break;
1434
1435 /* 1 - 16-bit, add 2nd 16-bit part of the delta. (rare) */
1436 case IMAGE_REL_BASED_HIGH:
1437 *u.pu16 += (KU16)(Delta >> 16);
1438 break;
1439
1440 /* 2 - 16-bit, add 1st 16-bit part of the delta. (rare) */
1441 case IMAGE_REL_BASED_LOW:
1442 *u.pu16 += (KU16)Delta;
1443 break;
1444
1445 /* 3 - 32-bit, add delta. (frequent in 32-bit images) */
1446 case IMAGE_REL_BASED_HIGHLOW:
1447 *u.pu32 += (KU32)Delta;
1448 break;
1449
1450 /* 4 - 16-bit, add 2nd 16-bit of the delta, sign adjust for the lower 16-bit. one arg. (rare) */
1451 case IMAGE_REL_BASED_HIGHADJ:
1452 {
1453 KI32 i32;
1454 if (cFixups <= 1)
1455 return KLDR_ERR_PE_BAD_FIXUP;
1456
1457 i32 = (KU32)*u.pu16 << 16;
1458 i32 |= *++poffFixup; cFixups--; /* the addend argument */
1459 i32 += (KU32)Delta;
1460 i32 += 0x8000;
1461 *u.pu16 = (KU16)(i32 >> 16);
1462 break;
1463 }
1464
1465 /* 5 - 32-bit MIPS JMPADDR, no implemented. */
1466 case IMAGE_REL_BASED_MIPS_JMPADDR:
1467 *u.pu32 = (*u.pu32 & 0xc0000000)
1468 | ((KU32)((*u.pu32 << 2) + (KU32)Delta) >> 2);
1469 break;
1470
1471 /* 6 - Intra section? Reserved value in later specs. Not implemented. */
1472 case IMAGE_REL_BASED_SECTION:
1473 KLDRMODPE_ASSERT(!"SECTION");
1474 return KLDR_ERR_PE_BAD_FIXUP;
1475
1476 /* 7 - Relative intra section? Reserved value in later specs. Not implemented. */
1477 case IMAGE_REL_BASED_REL32:
1478 KLDRMODPE_ASSERT(!"SECTION");
1479 return KLDR_ERR_PE_BAD_FIXUP;
1480
1481 /* 8 - reserved according to binutils... */
1482 case 8:
1483 KLDRMODPE_ASSERT(!"RESERVERED8");
1484 return KLDR_ERR_PE_BAD_FIXUP;
1485
1486 /* 9 - IA64_IMM64 (/ MIPS_JMPADDR16), no specs nor need to support the platform yet.
1487 * Bet this requires more code than all the other fixups put together in good IA64 spirit :-) */
1488 case IMAGE_REL_BASED_IA64_IMM64:
1489 KLDRMODPE_ASSERT(!"IA64_IMM64 / MIPS_JMPADDR16");
1490 return KLDR_ERR_PE_BAD_FIXUP;
1491
1492 /* 10 - 64-bit, add delta. (frequently in 64-bit images) */
1493 case IMAGE_REL_BASED_DIR64:
1494 *u.pu64 += (KU64)Delta;
1495 break;
1496
1497 /* 11 - 16-bit, add 3rd 16-bit of the delta, sign adjust for the lower 32-bit. two args. (rare) */
1498 case IMAGE_REL_BASED_HIGH3ADJ:
1499 {
1500 KI64 i64;
1501 if (cFixups <= 2)
1502 return KLDR_ERR_PE_BAD_FIXUP;
1503
1504 i64 = (KU64)*u.pu16 << 32
1505 | ((KU32)poffFixup[2] << 16)
1506 | poffFixup[1];
1507 i64 += Delta;
1508 i64 += 0x80008000UL;
1509 *u.pu16 = (KU16)(i64 >> 32);
1510 /* skip the addends arguments */
1511 poffFixup += 2;
1512 cFixups -= 2;
1513 break;
1514 }
1515
1516 /* the rest are yet to be defined.*/
1517 default:
1518 return KLDR_ERR_PE_BAD_FIXUP;
1519 }
1520
1521 /*
1522 * Next relocation.
1523 */
1524 poffFixup++;
1525 cFixups--;
1526 }
1527
1528
1529 /*
1530 * Next block.
1531 */
1532 cbLeft -= pBR->SizeOfBlock;
1533 pBR = (PIMAGE_BASE_RELOCATION)((KUPTR)pBR + pBR->SizeOfBlock);
1534 }
1535
1536 return 0;
1537}
1538
1539
1540
1541/**
1542 * Resolves imports.
1543 *
1544 * @returns 0 on success, non-zero kLdr status code on failure.
1545 * @param pModPE The PE module interpreter instance.
1546 * @param pvMapping The mapping which imports should be resolved.
1547 * @param pfnGetImport The callback for resolving an imported symbol.
1548 * @param pvUser User argument to the callback.
1549 */
1550static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1551{
1552 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1553
1554 /*
1555 * If no imports, there is nothing to do.
1556 */
1557 kldrModPENumberOfImports(pModPE->pMod, pvMapping);
1558 if (!pModPE->cImportModules)
1559 return 0;
1560
1561 pImpDesc = KLDRMODPE_RVA2TYPE(pvMapping,
1562 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
1563 const IMAGE_IMPORT_DESCRIPTOR *);
1564 if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
1565 return kldrModPEDoImports32Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser);
1566 return kldrModPEDoImports64Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser);
1567}
1568
1569
1570/**
1571 * Resolves imports, 32-bit image.
1572 *
1573 * @returns 0 on success, non-zero kLdr status code on failure.
1574 * @param pModPE The PE module interpreter instance.
1575 * @param pvMapping The mapping which imports should be resolved.
1576 * @param pImpDesc Pointer to the first import descriptor.
1577 * @param pfnGetImport The callback for resolving an imported symbol.
1578 * @param pvUser User argument to the callback.
1579 */
1580static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
1581 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1582{
1583 PKLDRMOD pMod = pModPE->pMod;
1584 KU32 iImp;
1585
1586 /*
1587 * Iterate the import descriptors.
1588 */
1589 for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++)
1590 {
1591 PIMAGE_THUNK_DATA32 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA32);
1592 const IMAGE_THUNK_DATA32 *pThunk = pImpDesc->u.OriginalFirstThunk
1593 ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA32 *)
1594 : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA32 *);
1595
1596 /* Iterate the thunks. */
1597 while (pThunk->u1.Ordinal != 0)
1598 {
1599 KLDRADDR Value;
1600 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
1601 int rc;
1602
1603 /* Ordinal or name import? */
1604 if (IMAGE_SNAP_BY_ORDINAL32(pThunk->u1.Ordinal))
1605 rc = pfnGetImport(pMod, iImp, IMAGE_ORDINAL32(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser);
1606 else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal))
1607 {
1608 const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *);
1609 rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name,
1610 kHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser);
1611 }
1612 else
1613 {
1614 KLDRMODPE_ASSERT(!"bad 32-bit import");
1615 return KLDR_ERR_PE_BAD_IMPORT;
1616 }
1617 if (rc)
1618 return rc;
1619
1620 /* Apply it. */
1621 pFirstThunk->u1.Function = (KU32)Value;
1622 if (pFirstThunk->u1.Function != Value)
1623 {
1624 KLDRMODPE_ASSERT(!"overflow");
1625 return KLDR_ERR_ADDRESS_OVERFLOW;
1626 }
1627
1628 /* next */
1629 pThunk++;
1630 pFirstThunk++;
1631 }
1632 }
1633
1634 return 0;
1635}
1636
1637
1638/**
1639 * Resolves imports, 64-bit image.
1640 *
1641 * @returns 0 on success, non-zero kLdr status code on failure.
1642 * @param pModPE The PE module interpreter instance.
1643 * @param pvMapping The mapping which imports should be resolved.
1644 * @param pImpDesc Pointer to the first import descriptor.
1645 * @param pfnGetImport The callback for resolving an imported symbol.
1646 * @param pvUser User argument to the callback.
1647 */
1648static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
1649 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1650{
1651 PKLDRMOD pMod = pModPE->pMod;
1652 KU32 iImp;
1653
1654 /*
1655 * Iterate the import descriptors.
1656 */
1657 for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++)
1658 {
1659 PIMAGE_THUNK_DATA64 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA64);
1660 const IMAGE_THUNK_DATA64 *pThunk = pImpDesc->u.OriginalFirstThunk
1661 ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA64 *)
1662 : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA64 *);
1663
1664 /* Iterate the thunks. */
1665 while (pThunk->u1.Ordinal != 0)
1666 {
1667 KLDRADDR Value;
1668 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
1669 int rc;
1670
1671 /* Ordinal or name import? */
1672 if (IMAGE_SNAP_BY_ORDINAL64(pThunk->u1.Ordinal))
1673 rc = pfnGetImport(pMod, iImp, (KU32)IMAGE_ORDINAL64(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser);
1674 else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal))
1675 {
1676 const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *);
1677 rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name,
1678 kHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser);
1679 }
1680 else
1681 {
1682 KLDRMODPE_ASSERT(!"bad 64-bit import");
1683 return KLDR_ERR_PE_BAD_IMPORT;
1684 }
1685 if (rc)
1686 return rc;
1687
1688 /* Apply it. */
1689 pFirstThunk->u1.Function = Value;
1690
1691 /* next */
1692 pThunk++;
1693 pFirstThunk++;
1694 }
1695 }
1696
1697 return 0;
1698}
1699
1700
1701
1702/** @copydoc kLdrModCallInit */
1703static int kldrModPECallInit(PKLDRMOD pMod, KUPTR uHandle)
1704{
1705 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1706 int rc;
1707
1708 /*
1709 * Mapped?
1710 */
1711 if (!pModPE->pvMapping)
1712 return KLDR_ERR_NOT_MAPPED;
1713
1714 /*
1715 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1716 */
1717 rc = kldrModPEDoCallTLS(pModPE, DLL_PROCESS_ATTACH, uHandle);
1718 if ( !rc
1719 && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL))
1720 {
1721 rc = kldrModPEDoCallDLL(pModPE, DLL_PROCESS_ATTACH, uHandle);
1722 if (rc)
1723 kldrModPEDoCallTLS(pModPE, DLL_PROCESS_DETACH, uHandle);
1724 }
1725
1726 return rc;
1727}
1728
1729
1730/**
1731 * Call the DLL entrypoint.
1732 *
1733 * @returns 0 on success.
1734 * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
1735 * @param pModPE The PE module interpreter instance.
1736 * @param uOp The operation (DLL_*).
1737 * @param uHandle The module handle to present.
1738 */
1739static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, unsigned uOp, KUPTR uHandle)
1740{
1741 int rc;
1742
1743 /*
1744 * If no entrypoint there isn't anything to be done.
1745 */
1746 if (!pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint)
1747 return 0;
1748
1749 /*
1750 * Invoke the entrypoint and convert the boolean result to a kLdr status code.
1751 */
1752 rc = kldrModPEDoCall((KUPTR)pModPE->pvMapping + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint,
1753 uHandle, uOp, NULL);
1754 if (rc)
1755 rc = 0;
1756 else if (uOp == DLL_PROCESS_ATTACH)
1757 rc = KLDR_ERR_MODULE_INIT_FAILED;
1758 else if (uOp == DLL_THREAD_ATTACH)
1759 rc = KLDR_ERR_THREAD_ATTACH_FAILED;
1760 else /* detach: ignore failures */
1761 rc = 0;
1762 return rc;
1763}
1764
1765
1766/**
1767 * Call the TLS entrypoints.
1768 *
1769 * @returns 0 on success.
1770 * @returns KLDR_ERR_THREAD_ATTACH_FAILED on failure.
1771 * @param pModPE The PE module interpreter instance.
1772 * @param uOp The operation (DLL_*).
1773 * @param uHandle The module handle to present.
1774 */
1775static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, unsigned uOp, KUPTR uHandle)
1776{
1777 /** @todo implement TLS support. */
1778 return 0;
1779}
1780
1781
1782/**
1783 * Do a 3 parameter callback.
1784 *
1785 * @returns 32-bit callback return.
1786 * @param uEntrypoint The address of the function to be called.
1787 * @param uHandle The first argument, the module handle.
1788 * @param uOp The second argumnet, the reason we're calling.
1789 * @param pvReserved The third argument, reserved argument. (figure this one out)
1790 */
1791static KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved)
1792{
1793 KI32 rc;
1794
1795/** @todo try/except */
1796#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
1797 /*
1798 * Be very careful.
1799 * Not everyone will have got the calling convention right.
1800 */
1801# ifdef __GNUC__
1802 __asm__ __volatile__(
1803 "pushl %2\n\t"
1804 "pushl %1\n\t"
1805 "pushl %0\n\t"
1806 "lea 12(%%esp), %2\n\t"
1807 "call *%3\n\t"
1808 "movl %2, %%esp\n\t"
1809 : "=a" (rc)
1810 : "d" (uOp),
1811 "S" (0),
1812 "c" (uEntrypoint),
1813 "0" (uHandle));
1814# elif defined(_MSC_VER)
1815 __asm {
1816 mov eax, [uHandle]
1817 mov edx, [uOp]
1818 mov ecx, 0
1819 mov ebx, [uEntrypoint]
1820 push edi
1821 mov edi, esp
1822 push ecx
1823 push edx
1824 push eax
1825 call ebx
1826 mov esp, edi
1827 pop edi
1828 mov [rc], eax
1829 }
1830# else
1831# error "port me!"
1832# endif
1833
1834#elif defined(__AMD64__) || defined(__x86_64__) || defined(_M_IX86)
1835 /*
1836 * For now, let's just get the work done...
1837 */
1838 /** @todo Deal with GCC / MSC differences in some sensible way. */
1839 int (*pfn)(KUPTR uHandle, KU32 uOp, void *pvReserved);
1840 pfn = (int (*)(KUPTR uHandle, KU32 uOp, void *pvReserved))uEntrypoint;
1841 rc = pfn(uHandle, uOp, NULL);
1842
1843#else
1844# error "port me"
1845#endif
1846
1847 return rc;
1848}
1849
1850
1851/** @copydoc kLdrModCallTerm */
1852static int kldrModPECallTerm(PKLDRMOD pMod, KUPTR uHandle)
1853{
1854 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1855
1856 /*
1857 * Mapped?
1858 */
1859 if (!pModPE->pvMapping)
1860 return KLDR_ERR_NOT_MAPPED;
1861
1862 /*
1863 * Do TLS callbacks first.
1864 */
1865 kldrModPEDoCallTLS(pModPE, DLL_PROCESS_DETACH, uHandle);
1866 if (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL)
1867 kldrModPEDoCallDLL(pModPE, DLL_PROCESS_DETACH, uHandle);
1868
1869 return 0;
1870}
1871
1872
1873/** @copydoc kLdrModCallThread */
1874static int kldrModPECallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
1875{
1876 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1877 unsigned uOp = fAttachingOrDetaching ? DLL_THREAD_ATTACH : DLL_THREAD_DETACH;
1878 int rc;
1879
1880 /*
1881 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1882 */
1883 rc = kldrModPEDoCallTLS(pModPE, uOp, uHandle);
1884 if (!fAttachingOrDetaching)
1885 rc = 0;
1886 if ( !rc
1887 && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL))
1888 {
1889 rc = kldrModPEDoCallDLL(pModPE, uOp, uHandle);
1890 if (!fAttachingOrDetaching)
1891 rc = 0;
1892 if (rc)
1893 kldrModPEDoCallTLS(pModPE, uOp, uHandle);
1894 }
1895
1896 return rc;
1897}
1898
1899
1900/** @copydoc kLdrModSize */
1901static KLDRADDR kldrModPESize(PKLDRMOD pMod)
1902{
1903 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1904 return pModPE->Hdrs.OptionalHeader.SizeOfImage;
1905}
1906
1907
1908/** @copydoc kLdrModGetBits */
1909static int kldrModPEGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1910{
1911 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1912 KU32 i;
1913 int rc;
1914
1915 /*
1916 * Zero the entire buffer first to simplify things.
1917 */
1918 kHlpMemSet(pvBits, 0, pModPE->Hdrs.OptionalHeader.SizeOfImage);
1919
1920 /*
1921 * Iterate the segments and read the data within them.
1922 */
1923 for (i = 0; i < pMod->cSegments; i++)
1924 {
1925 /* skip it? */
1926 if ( pMod->aSegments[i].cbFile == -1
1927 || pMod->aSegments[i].offFile == -1
1928 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
1929 || !pMod->aSegments[i].Alignment)
1930 continue;
1931 rc = kRdrRead(pMod->pRdr,
1932 (KU8 *)pvBits + (pMod->aSegments[i].LinkAddress - pModPE->Hdrs.OptionalHeader.ImageBase),
1933 pMod->aSegments[i].cbFile,
1934 pMod->aSegments[i].offFile);
1935 if (rc)
1936 return rc;
1937 }
1938
1939 /*
1940 * Perform relocations.
1941 */
1942 return kldrModPERelocateBits(pMod, pvBits, BaseAddress, pModPE->Hdrs.OptionalHeader.ImageBase, pfnGetImport, pvUser);
1943
1944}
1945
1946
1947/** @copydoc kLdrModRelocateBits */
1948static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
1949 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1950{
1951 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1952 int rc;
1953
1954 /*
1955 * Call workers to do the jobs.
1956 */
1957 rc = kldrModPEDoFixups(pModPE, pvBits, NewBaseAddress, OldBaseAddress);
1958 if (!rc)
1959 rc = kldrModPEDoImports(pModPE, pvBits, pfnGetImport, pvUser);
1960
1961 return rc;
1962}
1963
1964
1965/**
1966 * The PE module interpreter method table.
1967 */
1968KLDRMODOPS g_kLdrModPEOps =
1969{
1970 "PE",
1971 NULL,
1972 kldrModPECreate,
1973 kldrModPEDestroy,
1974 kldrModPEQuerySymbol,
1975 kldrModPEEnumSymbols,
1976 kldrModPEGetImport,
1977 kldrModPENumberOfImports,
1978 NULL /* can execute one is optional */,
1979 kldrModPEGetStackInfo,
1980 kldrModPEQueryMainEntrypoint,
1981 NULL, /** @todo resources */
1982 NULL, /** @todo resources */
1983 kldrModPEEnumDbgInfo,
1984 kldrModPEHasDbgInfo,
1985 kldrModPEMap,
1986 kldrModPEUnmap,
1987 kldrModPEAllocTLS,
1988 kldrModPEFreeTLS,
1989 kldrModPEReload,
1990 kldrModPEFixupMapping,
1991 kldrModPECallInit,
1992 kldrModPECallTerm,
1993 kldrModPECallThread,
1994 kldrModPESize,
1995 kldrModPEGetBits,
1996 kldrModPERelocateBits,
1997 NULL, /** @todo mostly done */
1998 42 /* the end */
1999};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette