source: trunk/kLdr/kLdrModPE.c@ 2856

Last change on this file since 2856 was 2856, checked in by bird, 19 years ago

More code.

File size: 48.1 KB
Line 
1/* $Id: kLdrMod.c 2851 2006-11-02 03:21:54Z bird $ */
2/** @file
3 *
4 * kLdr - The Module Interpreter for the Portable Executable (PE) Format.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include "kLdrHlp.h"
33#include "kLdrInternal.h"
34#include "kLdrModPE.h"
35
36
37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** @def KLDRMODPE_STRICT
41 * Define KLDRMODPE_STRICT to enabled strict checks in KLDRMODPE. */
42#define KLDRMOD_STRICT 1
43
44/** @def KLDRMODPE_ASSERT
45 * Assert that an expression is true when KLDR_STRICT is defined.
46 */
47#ifdef KLDRMODPE_STRICT
48# define KLDRMODPE_ASSERT(expr) kldrHlpAssert(expr)
49#else
50# define KLDRMODPE_ASSERT(expr) do {} while (0)
51#endif
52
53/** @def KLDRMODPE_RVA2TYPE
54 * Converts a RVA to a pointer of the specified type.
55 * @param pvBits The bits (image base).
56 * @param uRVA The image relative virtual address.
57 * @param type The type to cast to.
58 */
59#define KLDRMODPE_RVA2TYPE(pvBits, uRVA, type) \
60 ( (type) ((uintptr_t)(pvBits) + (uRVA)) )
61
62
63
64/*******************************************************************************
65* Structures and Typedefs *
66*******************************************************************************/
67/**
68 * Instance data for the PE module interpreter.
69 */
70typedef struct KLDRMODPE
71{
72 /** Pointer to the module. (Follows the section table.) */
73 PKLDRMOD pMod;
74 /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */
75 const void *pvBits;
76 /** Pointer to the user mapping. */
77 const void *pvMapping;
78 /** Reserved flags. */
79 uint32_t f32Reserved;
80 /** The number of imported modules.
81 * If ~(uint32_t)0 this hasn't been determined yet. */
82 uint32_t cImportModules;
83 /** The offset of the NT headers. */
84 off_t offHdrs;
85 /** Copy of the NT headers. */
86 IMAGE_NT_HEADERS64 Hdrs;
87 /** The section header table . */
88 IMAGE_SECTION_HEADER aShdrs[1];
89} KLDRMODPE, *PKLDRMODPE;
90
91
92/*******************************************************************************
93* Internal Functions *
94*******************************************************************************/
95static int kldrModPECreateInstance(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODPE *ppMod);
96static void kldrModPEConvertLoadConfig(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg);
97static int kLdrModPEValidateOptionalHeader(PKLDRMODPE pModPE);
98static int kLdrModPEValidateSectionHeaders(PKLDRMODPE pModPE);
99static void kldrModPEConvertOptionalHeader(PIMAGE_OPTIONAL_HEADER64 pOptionalHeader);
100static int kldrModPEQueryForwarder(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
101 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind);
102static int32_t kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits);
103static int kldrModPEUnprotect(PKLDRMODPE pModPE, const void *pvMapping);
104static int kldrModPEProtect(PKLDRMODPE pModPE, const void *pvMapping);
105static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
106static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
107static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, unsigned uOp, uintptr_t uHandle);
108static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, unsigned uOp, uintptr_t uHandle);
109static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
110 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
111
112
113/**
114 * Create a loader module instance interpreting the executable image found
115 * in the specified file provider instance.
116 *
117 * @returns 0 on success and *ppMod pointing to a module instance.
118 * On failure, a non-zero OS specific error code is returned.
119 * @param pOps Pointer to the registered method table.
120 * @param pRdr The file provider instance to use.
121 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
122 * @param ppMod Where to store the module instance pointer.
123 */
124static int kldrModPECreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
125{
126 PKLDRMODPE pModPE;
127 int rc;
128
129 /*
130 * Create the instance data and do a minimal header validation.
131 */
132 rc = kldrModPECreateInstance(pRdr, offNewHdr, &pModPE);
133 if (!rc)
134 {
135 pModPE->pMod->pOps = pOps;
136 pModPE->pMod->u32Magic = KLDRMOD_MAGIC;
137 *ppMod = pModPE->pMod;
138 return 0;
139 }
140 kldrHlpFree(pModPE);
141 return rc;
142}
143
144
145/**
146 * Separate function for reading creating the PE module instance to
147 * simplify cleanup on failure.
148 */
149static int kldrModPECreateInstance(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODPE *ppModPE)
150{
151 struct
152 {
153 uint32_t Signature;
154 IMAGE_FILE_HEADER FileHdr;
155 } s;
156 PKLDRMODPE pModPE;
157 PKLDRMOD pMod;
158 size_t cb;
159 size_t cchFilename;
160 off_t off;
161 uint32_t i;
162 int rc;
163 *ppModPE = NULL;
164
165 /*
166 * Read the signature and file header.
167 */
168 rc = kLdrRdrRead(pRdr, &s, sizeof(s), offNewHdr > 0 ? offNewHdr : 0);
169 if (rc)
170 return rc;
171 if (s.Signature != IMAGE_NT_SIGNATURE)
172 return KLDR_ERR_UNKNOWN_FORMAT;
173
174 /* sanity checks. */
175 if ( s.FileHdr.NumberOfSections > 1024*1024
176 || ( s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32)
177 && s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64))
178 )
179 return KLDR_ERR_PE_BAD_FILE_HEADER;
180 if ( s.FileHdr.Machine != IMAGE_FILE_MACHINE_I386
181 && s.FileHdr.Machine != IMAGE_FILE_MACHINE_AMD64
182 )
183 return KLDR_ERR_PE_UNSUPPORTED_MACHINE;
184
185 /*
186 * Calc the instance size, allocate and initialize it.
187 */
188 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
189 cb = sizeof(KLDRMOD)
190 + s.FileHdr.NumberOfSections * sizeof(KLDRSEG)
191 + sizeof(KLDRMODPE) - sizeof(IMAGE_SECTION_HEADER)
192 + s.FileHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
193 + cchFilename + 1;
194 pModPE = (PKLDRMODPE)kldrHlpAlloc(cb);
195 if (!pModPE)
196 return KLDR_ERR_NO_MEMORY;
197
198 /* KLDRMOD */
199 pMod = (PKLDRMOD)((uint8_t *)pModPE + sizeof(KLDRMOD) + (s.FileHdr.NumberOfSections + 1) * sizeof(KLDRSEG));
200 pMod->pvData = pModPE;
201 pMod->pRdr = pRdr;
202 pMod->pOps = NULL; /* set upon success. */
203 pMod->cSegments = s.FileHdr.NumberOfSections + 1;
204 pMod->cchFilename = cchFilename;
205 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
206 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
207 pMod->pszName = kldrHlpGetFilename(pMod->pszFilename);
208 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
209 switch (s.FileHdr.Machine)
210 {
211 case IMAGE_FILE_MACHINE_I386:
212 pMod->enmCpu = KLDRCPU_I386;
213 pMod->enmArch = KLDRARCH_X86_32;
214 pMod->enmEndian = KLDRENDIAN_LITTLE;
215 break;
216
217 case IMAGE_FILE_MACHINE_AMD64:
218 pMod->enmCpu = KLDRCPU_K8;
219 pMod->enmArch = KLDRARCH_AMD64;
220 pMod->enmEndian = KLDRENDIAN_LITTLE;
221 break;
222 default:
223 kldrHlpAssert(0);
224 break;
225 }
226 pMod->enmFmt = KLDRFMT_PE;
227 pMod->u32Magic = 0; /* set upon success. */
228
229 /* KLDRMODPE */
230 pModPE->pMod = pMod;
231 pModPE->pvBits = NULL;
232 pModPE->f32Reserved = 0;
233 pModPE->cImportModules = ~(uint32_t)0;
234 pModPE->offHdrs = offNewHdr >= 0 ? offNewHdr : 0;
235 pModPE->Hdrs.Signature = s.Signature;
236 pModPE->Hdrs.FileHeader = s.FileHdr;
237 *ppModPE = pModPE;
238
239 /*
240 * Read the optional header and the section table.
241 */
242 off = pModPE->offHdrs + sizeof(pModPE->Hdrs.Signature) + sizeof(pModPE->Hdrs.FileHeader);
243 rc = kLdrRdrRead(pRdr, &pModPE->Hdrs.OptionalHeader, pModPE->Hdrs.FileHeader.SizeOfOptionalHeader, off);
244 if (rc)
245 return rc;
246 if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader != sizeof(pModPE->Hdrs.OptionalHeader))
247 kldrModPEConvertOptionalHeader(&pModPE->Hdrs.OptionalHeader);
248 off += pModPE->Hdrs.FileHeader.SizeOfOptionalHeader;
249 rc = kLdrRdrRead(pRdr, &pModPE->aShdrs[0], sizeof(IMAGE_SECTION_HEADER) * pModPE->Hdrs.FileHeader.NumberOfSections, off);
250 if (rc)
251 return rc;
252
253 /*
254 * Validate the two.
255 */
256 rc = kLdrModPEValidateOptionalHeader(pModPE);
257 if (rc)
258 return rc;
259 for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
260 {
261 rc = kLdrModPEValidateSectionHeaders(pModPE);
262 if (rc)
263 return rc;
264 }
265
266 /*
267 * Setup the KLDRMOD segment array.
268 */
269 /* The implied headers section. */
270 pMod->aSegments[0].pvUser = NULL;
271 pMod->aSegments[0].pchName = "TheHeaders";
272 pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1;
273 pMod->aSegments[0].cb = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
274 pMod->aSegments[0].LinkAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
275 pMod->aSegments[0].MapAddress = NIL_KLDRADDR;
276 pMod->aSegments[0].enmProt = KLDRPROT_READONLY;
277
278 /* The section headers. */
279 for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
280 {
281 char *pch;
282 pMod->aSegments[i + 1].pvUser = NULL;
283 pMod->aSegments[i + 1].pchName = pch = &pModPE->aShdrs[i].Name[0];
284 cb = IMAGE_SIZEOF_SHORT_NAME;
285 while ( cb > 0
286 && (pch[cb - 1] == ' ' || pch[cb - 1] == '\0'))
287 cb--;
288 pMod->aSegments[i + 1].cchName = cb;
289 if (!(pModPE->aShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
290 {
291 pMod->aSegments[i + 1].cb = pModPE->aShdrs[i].Misc.VirtualSize;
292 pMod->aSegments[i + 1].LinkAddress = pModPE->aShdrs[i].VirtualAddress;
293 }
294 else
295 {
296 pMod->aSegments[i + 1].cb = 0;
297 pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR;
298 }
299 pMod->aSegments[i + 1].MapAddress = NIL_KLDRADDR;
300 switch ( pModPE->aShdrs[i].Characteristics
301 & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
302 {
303 case 0:
304 case IMAGE_SCN_MEM_SHARED:
305 pMod->aSegments[i + 1].enmProt = KLDRPROT_NOACCESS;
306 break;
307 case IMAGE_SCN_MEM_READ:
308 case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
309 pMod->aSegments[i + 1].enmProt = KLDRPROT_READONLY;
310 break;
311 case IMAGE_SCN_MEM_WRITE:
312 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
313 pMod->aSegments[i + 1].enmProt = KLDRPROT_WRITECOPY;
314 break;
315 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
316 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
317 pMod->aSegments[i + 1].enmProt = KLDRPROT_READWRITE;
318 break;
319 case IMAGE_SCN_MEM_EXECUTE:
320 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED:
321 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE;
322 break;
323 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ:
324 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
325 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_READ;
326 break;
327 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE:
328 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
329 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
330 break;
331 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
332 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
333 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_READWRITE;
334 break;
335 }
336 switch (pModPE->aShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
337 {
338 default: kldrHlpAssert(0);
339 case 0: pMod->aSegments[i + 1].Alignment = 0; break;
340 case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break;
341 case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break;
342 case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break;
343 case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break;
344 case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break;
345 case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break;
346 case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break;
347 case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break;
348 case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break;
349 case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break;
350 case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break;
351 case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break;
352 case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break;
353 case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break;
354 }
355 }
356
357 /*
358 * We're done.
359 */
360 *ppModPE = pModPE;
361 return 0;
362}
363
364
365/**
366 * Internal worker which validates the section headers.
367 */
368static int kLdrModPEValidateOptionalHeader(PKLDRMODPE pModPE)
369{
370 const unsigned fIs32Bit = pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32);
371
372 /* the magic */
373 if ( pModPE->Hdrs.OptionalHeader.Magic
374 != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
375 return KLDR_ERR_PE_BAD_OPTIONAL_HEADER;
376
377 /** @todo validate more */
378 return 0;
379}
380
381
382/**
383 * Internal worker which validates the section headers.
384 */
385static int kLdrModPEValidateSectionHeaders(PKLDRMODPE pModPE)
386{
387 /** @todo validate shdrs */
388 return 0;
389}
390
391
392/**
393 * Converts a 32-bit optional header to a 64-bit one
394 *
395 * @param pOptHdr The optional header to convert.
396 */
397static void kldrModPEConvertOptionalHeader(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
398{
399 /* volatile everywhere! */
400 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
401 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
402 uint32_t volatile *pu32Dst;
403 uint32_t volatile *pu32Src;
404 uint32_t volatile *pu32SrcLast;
405 uint32_t u32;
406
407 /* From LoaderFlags and out the difference is 4 * 32-bits. */
408 pu32Dst = (uint32_t *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
409 pu32Src = (uint32_t *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
410 pu32SrcLast = (uint32_t *)&pOptHdr32->LoaderFlags;
411 while (pu32Src >= pu32SrcLast)
412 *pu32Dst-- = *pu32Src--;
413
414 /* The previous 4 fields are 32/64 and needs special attention. */
415 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
416 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
417 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
418 u32 = pOptHdr32->SizeOfStackReserve;
419 pOptHdr64->SizeOfStackReserve = u32;
420
421 /*
422 * The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version.
423 * Thus, ImageBase needs some special treatement. It will probably work fine assigning one to the
424 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
425 */
426 u32 = pOptHdr32->ImageBase;
427 pOptHdr64->ImageBase = u32;
428}
429
430
431/**
432 * Converts a 32-bit load config directory to a 64 bit one.
433 *
434 * @param pOptHdr The load config to convert.
435 */
436static void kldrModPEConvertLoadConfig(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
437{
438 /* volatile everywhere! */
439 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
440 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
441 uint32_t u32;
442
443 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
444 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
445 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
446 pLoadCfg64->EditList = pLoadCfg32->EditList;
447 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
448 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
449 /* (ProcessHeapFlags switched place with ProcessAffinityMask, but we're
450 * more than 16 byte off by now so it doesn't matter.) */
451 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags;
452 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
453 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
454 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
455 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
456 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
457 u32 = pLoadCfg32->DeCommitFreeBlockThreshold;
458 pLoadCfg64->DeCommitFreeBlockThreshold = u32;
459 /* the remainder matches. */
460}
461
462
463/** @copydoc KLDRMODOPS::pfnDestroy */
464static int kldrModPEDestroy(PKLDRMOD pMod)
465{
466 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
467 int rc = 0;
468 KLDRMODPE_ASSERT(pModPE->fMapped);
469
470 if (pMod->pRdr)
471 {
472 rc = kLdrRdrClose(pMod->pRdr);
473 pMod->pRdr = NULL;
474 }
475 pMod->u32Magic = 0;
476 pMod->pOps = NULL;
477 kldrHlpFree(pModPE);
478 return rc;
479}
480
481
482/**
483 * Performs the mapping of the image.
484 *
485 * This can be used to do the internal mapping as well as the
486 * user requested mapping. fForReal indicates which is desired.
487 *
488 * @returns 0 on success, non-zero OS or kLdr status code on failure.
489 * @param pModPE The interpreter module instance
490 * @param fForReal If set, do the user mapping. if clear, do the internal mapping.
491 */
492static int kldrModPEDoMap(PKLDRMODPE pModPE, unsigned fForReal)
493{
494 return -1;
495}
496
497
498/**
499 * Unmaps a image mapping.
500 *
501 * This can be used to do the internal mapping as well as the
502 * user requested mapping. fForReal indicates which is desired.
503 *
504 * @returns 0 on success, non-zero OS or kLdr status code on failure.
505 * @param pModPE The interpreter module instance
506 * @param fForReal If set, unmap the user mapping. if clear, unmap the internal mapping.
507 */
508static int kldrModPEDoUnmap(PKLDRMODPE pModPE, unsigned fForReal)
509{
510 return -1;
511}
512
513
514/**
515 * Gets usable bits and the right base address.
516 *
517 * @returns 0 on success.
518 * @returns A non-zero status code if the BaseAddress isn't right or some problem is encountered
519 * featch in a temp mapping the bits.
520 * @param pModPE The interpreter module instance
521 * @param ppvBits The bits address, IN & OUT.
522 * @param pBaseAddress The base address, IN & OUT. Optional.
523 */
524static int kldrModPEBitsAndBaseAddress(PKLDRMODPE pModPE, const void **ppvBits, PKLDRADDR pBaseAddress)
525{
526 int rc = 0;
527
528 /*
529 * Correct the base address.
530 *
531 * We don't use the base address for interpreting the bits in this
532 * interpreter, which makes things relativly simple.
533 */
534 if (pBaseAddress)
535 {
536 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
537 *pBaseAddress = pModPE->pMod->aSegments[0].MapAddress;
538 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
539 *pBaseAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
540 }
541
542 /*
543 * Get bits.
544 */
545 if (!*ppvBits)
546 {
547 if (pModPE->pvMapping)
548 *ppvBits = pModPE->pvMapping;
549 else if (pModPE->pvBits)
550 *ppvBits = pModPE->pvBits;
551 else
552 {
553 /** @todo do an internal mapping. */
554 rc = -1;
555 }
556 }
557
558 return 0;
559}
560
561
562/** @copydoc kLdrModQuerySymbol */
563static int kldrModPEQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t uSymbol,
564 const char *pszSymbol, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser,
565 PKLDRADDR puValue, uint32_t *pfKind)
566{
567 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
568 const uint32_t *paExportRVAs;
569 const IMAGE_EXPORT_DIRECTORY *pExpDir;
570 uint32_t iExpOrd;
571 uint32_t uRVA;
572 int rc;
573
574 /*
575 * Make sure we've got mapped bits and resolve any base address aliases.
576 */
577 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
578 if (rc)
579 return rc;
580 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
581 < sizeof(IMAGE_EXPORT_DIRECTORY))
582 return KLDR_ERR_SYMBOL_NOT_FOUND;
583
584 pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
585 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
586 PIMAGE_EXPORT_DIRECTORY);
587 if (!pszSymbol)
588 {
589 /*
590 * Simple, calculate the unbased ordinal and bounds check it.
591 */
592 iExpOrd = uSymbol - pExpDir->Base;
593 if (iExpOrd >= KLDR_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions))
594 return KLDR_ERR_SYMBOL_NOT_FOUND;
595 }
596 else
597 {
598 /*
599 * Do a binary search for the name.
600 * (The name table is sorted in ascending ordered by the linker.)
601 */
602 const uint32_t *paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const uint32_t *);
603 const uint16_t *paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const uint16_t *);
604 int32_t iStart = 1; /* one based binary searching is simpler. */
605 int32_t iEnd = pExpDir->NumberOfNames;
606
607 for (;;)
608 {
609 int32_t i;
610 int diff;
611 const char *pszName;
612
613 /* done? */
614 if (iStart > iEnd)
615 {
616#ifdef KLDRMODPE_STRICT /* Make sure the linker and we both did our job right. */
617 for (i = 0; i < pExpDir->NumberOfNames; i++)
618
619 {
620 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i], const char *);
621 KLDRMODPE_ASSERT(kLdrHlpStrComp(pszName, pszSymbol));
622 KLDRMODPE_ASSERT(i == 0 || kLdrHlpStrComp(pszName, KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)));
623 }
624#endif
625 return KLDR_ERR_SYMBOL_NOT_FOUND;
626 }
627
628 i = (iEnd - iStart) / 2 + iStart;
629 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
630 diff = kLdrHlpStrComp(pszName, pszSymbol);
631 if (diff < 0)
632 iStart = i + 1; /* The symbol must be after the current name. */
633 else if (diff)
634 iEnd = i - 1; /* The symbol must be before the current name. */
635 else
636 {
637 iExpOrd = paOrdinals[i - 1]; /* match! */
638 break;
639 }
640 }
641 }
642
643 /*
644 * Lookup the address in the 'symbol' table.
645 */
646 paExportRVAs = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const uint32_t *);
647 uRVA = paExportRVAs[iExpOrd];
648 if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
649 < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
650 return kldrModPEQueryForwarder(pModPE, pvBits, KLDRMODPE_RVA2TYPE(pvBits, uRVA, const char *),
651 pfnGetForwarder, pvUser, puValue, pfKind);
652
653 /*
654 * Set the return value.
655 */
656 if (puValue)
657 *puValue = BaseAddress + uRVA;
658 if (pfKind)
659 *pfKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
660 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
661 | KLDRSYMKIND_NO_TYPE;
662 return 0;
663}
664
665
666/**
667 * Deal with a forwarder entry.
668 *
669 * We do this seprately from kldrModPEQuerySymbol because the code is clumsy (as is all PE code
670 * thanks to the descriptive field names), and because it uses quite a bit more stack and we're
671 * trying to avoid allocating stack unless we have to.
672 *
673 * @returns See kLdrModQuerySymbol.
674 * @param pModPE The PE module interpreter instance.
675 * @param pvBits Where to read the image from.
676 * @param pszForwarder The forwarder entry name.
677 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
678 * @param pvUser The user argument for the callback.
679 * @param puValue Where to put the value. (optional)
680 * @param pfKind Where to put the symbol kind. (optional)
681 */
682static int kldrModPEQueryForwarder(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
683 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
684{
685 const IMAGE_IMPORT_DESCRIPTOR *paImpDir;
686 uint32_t iImpModule;
687 uint32_t cchImpModule;
688 const char *pszSymbol;
689 uint32_t uSymbol;
690 int rc;
691
692 if (!pfnGetForwarder)
693 return KLDR_ERR_FORWARDER_SYMBOL;
694
695 /*
696 * Separate the name into a module name and a symbol name or ordinal.
697 *
698 * The module name ends at the first dot ('.').
699 * After the dot follows either a symbol name or a hash ('#') + ordinal.
700 */
701 pszSymbol = pszForwarder;
702 while (*pszSymbol != '.')
703 pszSymbol++;
704 if (!*pszSymbol)
705 return KLDR_ERR_PE_BAD_FORWARDER;
706 cchImpModule = pszSymbol - pszForwarder;
707
708 pszSymbol++; /* skip the dot */
709 if (!*pszSymbol)
710 return KLDR_ERR_PE_BAD_FORWARDER;
711 if (*pszSymbol == '#')
712 {
713 unsigned uBase;
714 pszSymbol++; /* skip the hash */
715
716 /* base detection */
717 uBase = 10;
718 if (pszSymbol[0] == '0' && (pszSymbol[1] == 'x' || pszSymbol[1] == 'X'))
719 {
720 uBase = 16;
721 pszSymbol += 2;
722 }
723
724 /* ascii to integer */
725 uSymbol = 0;
726 for (;;)
727 {
728 /* convert char to digit. */
729 unsigned uDigit = *pszSymbol++;
730 if (uDigit >= '0' && uDigit <= '9')
731 uDigit -= '0';
732 else if (uDigit >= 'a' && uDigit <= 'z')
733 uDigit -= 'a' + 10;
734 else if (uDigit >= 'A' && uDigit <= 'Z')
735 uDigit -= 'A' + 10;
736 else if (!uDigit)
737 break;
738 else
739 return KLDR_ERR_PE_BAD_FORWARDER;
740 if (uDigit >= uBase)
741 return KLDR_ERR_PE_BAD_FORWARDER;
742
743 /* insert the digit */
744 uSymbol *= uBase;
745 uSymbol += uDigit;
746 }
747
748 pszSymbol = NULL; /* no symbol name. */
749 }
750 else
751 uSymbol = NIL_KLDRMOD_SYM_ORDINAL; /* no ordinal number. */
752
753
754 /*
755 * Find the import module name.
756 *
757 * We ASSUME the linker will make sure there is an import
758 * entry for the module... not sure if this is right though.
759 */
760 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
761 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
762 return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
763 paImpDir = KLDRMODPE_RVA2TYPE(pvBits,
764 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
765 const IMAGE_IMPORT_DESCRIPTOR *);
766
767 kldrModPENumberOfImports(pModPE->pMod, pvBits);
768 for (iImpModule = 0; iImpModule < pModPE->cImportModules; iImpModule++)
769 {
770 const char *pszName = KLDRMODPE_RVA2TYPE(pvBits, paImpDir[iImpModule].Name, const char *);
771 size_t cchName = kLdrHlpStrLen(pszName);
772 if ( ( cchName == cchImpModule
773 || ( cchName > cchImpModule
774 && pszName[cchImpModule] == '.'
775 && (pszName[cchImpModule + 1] == 'd' || pszName[cchImpModule + 1] == 'D')
776 && (pszName[cchImpModule + 2] == 'l' || pszName[cchImpModule + 2] == 'L')
777 && (pszName[cchImpModule + 3] == 'l' || pszName[cchImpModule + 3] == 'L'))
778 )
779 && kLdrHlpMemIComp(pszName, pszForwarder, cchImpModule)
780 )
781 {
782 /*
783 * Now the rest is up to the callback (almost).
784 */
785 rc = pfnGetForwarder(pModPE->pMod, iImpModule, uSymbol, pszSymbol, puValue, pfKind, pvUser);
786 if (!rc && pfKind)
787 *pfKind |= KLDRSYMKIND_FORWARDER;
788 return rc;
789 }
790 }
791 return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
792}
793
794
795/** @copydoc kLdrModEnumSymbols */
796static int kldrModPEEnumSymbols(PKLDRMOD pMod, uint32_t fFlags, const void *pvBits, KLDRADDR BaseAddress,
797 PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
798{
799 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
800 const uint32_t *paFunctions;
801 const IMAGE_EXPORT_DIRECTORY *pExpDir;
802 const uint32_t *paRVANames;
803 const uint16_t *paOrdinals;
804 uint32_t iFunction;
805 uint32_t cFunctions;
806 uint32_t cNames;
807 int rc;
808
809 /*
810 * Make sure we've got mapped bits and resolve any base address aliases.
811 */
812 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
813 if (rc)
814 return rc;
815
816 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
817 < sizeof(IMAGE_EXPORT_DIRECTORY))
818 return KLDR_ERR_SYMBOL_NOT_FOUND;
819 pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
820 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
821 PIMAGE_EXPORT_DIRECTORY);
822
823 /*
824 * Enumerate the ordinal exports.
825 */
826 paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const uint32_t *);
827 paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const uint16_t *);
828 paFunctions = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const uint32_t *);
829 cFunctions = pExpDir->NumberOfFunctions;
830 cNames = pExpDir->NumberOfNames;
831 for (iFunction = 0; iFunction < cFunctions; iFunction++)
832 {
833 unsigned fFoundName;
834 uint32_t iName;
835 const uint32_t uRVA = paFunctions[iFunction];
836 const KLDRADDR uValue = BaseAddress + uRVA;
837 uint32_t fKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
838 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
839 | KLDRSYMKIND_NO_TYPE;
840 if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
841 < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
842 fKind |= KLDRSYMKIND_FORWARDER;
843
844 /*
845 * Any symbol names?
846 */
847 fFoundName = 0;
848 for (iName = 0; iName < cNames; iName++)
849 {
850 if (!paOrdinals[iName] != iFunction)
851 continue;
852 fFoundName = 1;
853 rc = pfnCallback(pMod, iName + pExpDir->Base, KLDRMODPE_RVA2TYPE(pvBits, paRVANames[iName], const char *),
854 uValue, fKind, pvUser);
855 if (rc)
856 return rc;
857 }
858
859 /*
860 * If no names, call once with the ordinal only.
861 */
862 if (!fFoundName)
863 {
864 rc = pfnCallback(pMod, iName + pExpDir->Base, NULL, uValue, fKind, pvUser);
865 if (rc)
866 return rc;
867 }
868 }
869
870 return 0;
871}
872
873
874/** @copydoc kLdrModGetImport */
875static int kldrModPEGetImport(PKLDRMOD pMod, void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
876{
877 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
878 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
879 const char *pszImportName;
880 size_t cchImportName;
881 int rc;
882
883 /*
884 * Make sure we've got mapped bits and resolve any base address aliases.
885 */
886 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
887 if (rc)
888 return rc;
889
890 /*
891 * Simple bounds check.
892 */
893 if (iImport >= (uint32_t)kldrModPENumberOfImports(pMod, pvBits))
894 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
895
896 /*
897 * Get the name.
898 */
899 pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
900 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
901 + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport,
902 const IMAGE_IMPORT_DESCRIPTOR *);
903 pszImportName = KLDRMODPE_RVA2TYPE(pvBits, pImpDesc->Name, const char *);
904 cchImportName = strlen(pszImportName);
905 if (cchImportName < cchName)
906 {
907 kLdrHlpMemCopy(pszName, pszImportName, cchImportName + 1);
908 rc = 0;
909 }
910 else
911 {
912 kLdrHlpMemCopy(pszName, pszImportName, cchName);
913 if (cchName)
914 pszName[cchName - 1] = '\0';
915 rc = KLDR_ERR_BUFFER_OVERFLOW;
916 }
917
918 return rc;
919}
920
921
922/** @copydoc kLdrModNumberOfImports */
923static int32_t kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits)
924{
925 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
926 if (pModPE->cImportModules == ~(uint32_t)0)
927 {
928 /*
929 * We'll have to walk the import descriptors to figure out their number.
930 * First, make sure we've got mapped bits.
931 */
932 if (kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL))
933 return -1;
934 pModPE->cImportModules = 0;
935 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
936 && pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
937 {
938 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
939
940 pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
941 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
942 const IMAGE_IMPORT_DESCRIPTOR *);
943 while (pImpDesc->Name && pImpDesc->FirstThunk)
944 {
945 pModPE->cImportModules = 0;
946 pImpDesc++;
947 }
948 }
949 }
950 return pModPE->cImportModules;
951}
952
953
954/** @copydoc kLdrModGetStackInfo */
955static int kldrModPEGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
956{
957 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
958
959 pStackInfo->Address = NIL_KLDRADDR;
960 pStackInfo->LinkAddress = NIL_KLDRADDR;
961 pStackInfo->cbStack = pStackInfo->cbStackThread = pModPE->Hdrs.OptionalHeader.SizeOfStackReserve;
962
963 return 0;
964}
965
966
967/** @copydoc kLdrModQueryMainEntrypoint */
968static int kldrModPEQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
969{
970 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
971 int rc;
972
973 /*
974 * Resolve base address alias if any.
975 */
976 rc = kldrModPEBitsAndBaseAddress(pModPE, NULL, &BaseAddress);
977 if (rc)
978 return rc;
979
980 /*
981 * Convert the address from the header.
982 */
983 *pMainEPAddress = pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
984 ? BaseAddress + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
985 : NIL_KLDRADDR;
986 return 0;
987}
988
989
990/** @copydoc kLdrModEnumDbgInfo */
991static int kldrModPEEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
992{
993 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
994 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
995 uint32_t iDbgInfo;
996 uint32_t cb;
997 int rc;
998
999 /*
1000 * Check that there is a debug directory first.
1001 */
1002 cb = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
1003 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1004 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1005 return 0;
1006
1007 /*
1008 * Make sure we've got mapped bits.
1009 */
1010 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
1011 if (rc)
1012 return rc;
1013
1014 /*
1015 * Enumerate the debug directory.
1016 */
1017 pDbgDir = KLDRMODPE_RVA2TYPE(pvBits,
1018 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
1019 const IMAGE_DEBUG_DIRECTORY *);
1020 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
1021 {
1022 KLDRDBGINFOTYPE enmDbgInfoType;
1023
1024 /* convert the type. */
1025 switch (pDbgDir->Type)
1026 {
1027 case IMAGE_DEBUG_TYPE_UNKNOWN:
1028 case IMAGE_DEBUG_TYPE_FPO:
1029 case IMAGE_DEBUG_TYPE_COFF: //stabs dialect??
1030 case IMAGE_DEBUG_TYPE_MISC:
1031 case IMAGE_DEBUG_TYPE_EXCEPTION:
1032 case IMAGE_DEBUG_TYPE_FIXUP:
1033 case IMAGE_DEBUG_TYPE_BORLAND:
1034 default:
1035 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
1036 break;
1037 case IMAGE_DEBUG_TYPE_CODEVIEW:
1038 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
1039 break;
1040 }
1041
1042 rc = pfnCallback(pMod, iDbgInfo,
1043 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
1044 pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
1045 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
1046 pDbgDir->SizeOfData,
1047 NULL,
1048 pvUser);
1049 if (rc)
1050 break;
1051
1052 /* next */
1053 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
1054 break;
1055 }
1056
1057 return rc;
1058}
1059
1060
1061/** @copydoc kLdrModHasDbgInfo */
1062static int kldrModPEHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1063{
1064 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1065
1066 /*
1067 * Base this entirely on the presence of a debug directory.
1068 */
1069 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
1070 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1071 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1072 return KLDR_ERR_NO_DEBUG_INFO;
1073 return 0;
1074}
1075
1076
1077/** @copydoc kLdrModMap */
1078static int kldrModPEMap(PKLDRMOD pMod)
1079{
1080 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1081 int rc;
1082
1083 /*
1084 * Already mapped?
1085 */
1086 if (pModPE->pvMapping)
1087 return KLDR_ERR_ALREADY_MAPPED;
1088
1089 /*
1090 * We've got a common worker which does this.
1091 */
1092 rc = kldrModPEDoMap(pModPE, 1 /* the real thing */);
1093 if (rc)
1094 return rc;
1095 KLDRMODPE_ASSERT(pModPE->pvMapping);
1096 return 0;
1097}
1098
1099
1100/** @copydoc kLdrModUnmap */
1101static int kldrModPEUnmap(PKLDRMOD pMod)
1102{
1103 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1104 int rc;
1105
1106 /*
1107 * Mapped?
1108 */
1109 if (!pModPE->pvMapping)
1110 return KLDR_ERR_NOT_MAPPED;
1111
1112 /*
1113 * We've got a common worker which does this.
1114 */
1115 rc = kldrModPEDoMap(pModPE, 1 /* the real thing */);
1116 if (rc)
1117 return rc;
1118 KLDRMODPE_ASSERT(pModPE->pvMapping);
1119 return 0;
1120
1121}
1122
1123
1124/** @copydoc kLdrModAllocTLS */
1125static int kldrModPEAllocTLS(PKLDRMOD pMod)
1126{
1127 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1128
1129 /*
1130 * Mapped?
1131 */
1132 if (!pModPE->pvMapping)
1133 return KLDR_ERR_NOT_MAPPED;
1134
1135 /*
1136 * If no TLS directory then there is nothing to do.
1137 */
1138 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
1139 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
1140 return 0;
1141 /** @todo implement TLS. */
1142 return -1;
1143}
1144
1145
1146/** @copydoc kLdrModFreeTLS */
1147static void kldrModPEFreeTLS(PKLDRMOD pMod)
1148{
1149 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1150
1151 /*
1152 * Mapped?
1153 */
1154 if (!pModPE->pvMapping)
1155 return;
1156
1157 /*
1158 * If no TLS directory then there is nothing to do.
1159 */
1160 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
1161 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
1162 return;
1163 /** @todo implement TLS. */
1164 return;
1165}
1166
1167
1168/** @copydoc kLdrModReload */
1169static int kldrModPEReload(PKLDRMOD pMod)
1170{
1171 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1172 uint32_t i;
1173 int rc;
1174 const size_t cbPage = kLdrRdrPageSize(pMod->pRdr);
1175
1176 /*
1177 * Mapped?
1178 */
1179 if (!pModPE->pvMapping)
1180 return KLDR_ERR_NOT_MAPPED;
1181
1182 /*
1183 * Iterate the objects and ask the file provider to undo all the changes.
1184 */
1185 for (i = rc = 0; !rc && i < pMod->cSegments; i++)
1186 rc = kLdrRdrRefreshMap(pMod->pRdr,
1187 (void *)pMod->aSegments[i].MapAddress,
1188 (size_t)pMod->aSegments[i].cb,
1189 pMod->aSegments[i].enmProt,
1190 pMod->aSegments[i].offFile,
1191 pMod->aSegments[i].cbFile);
1192
1193 return rc;
1194}
1195
1196
1197/** @copydoc kLdrModFixupMapping */
1198static int kldrModPEFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1199{
1200 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1201 int rc, rc2;
1202
1203 /*
1204 * Mapped?
1205 */
1206 if (!pModPE->pvMapping)
1207 return KLDR_ERR_NOT_MAPPED;
1208
1209 /*
1210 * Before doing anything we'll have to make all pages writable.
1211 */
1212 rc = kldrModPEUnprotect(pModPE, pModPE->pvMapping);
1213 if (rc)
1214 return rc;
1215
1216 /*
1217 * Do we need to apply base relocations?
1218 */
1219 if (pModPE->Hdrs.OptionalHeader.ImageBase != (uintptr_t)pModPE->pvMapping)
1220 rc = kldrModPEDoFixups(pModPE, (void *)pModPE->pvMapping, (uintptr_t)pModPE->pvMapping,
1221 pModPE->Hdrs.OptionalHeader.ImageBase);
1222
1223 /*
1224 * Resolve imports.
1225 */
1226 if (!rc)
1227 rc = kldrModPEDoImports(pModPE, (void *)pModPE->pvMapping, pfnGetImport, pvUser);
1228
1229 /*
1230 * Restore protection.
1231 */
1232 rc2 = kldrModPEProtect(pModPE, pModPE->pvMapping);
1233 if (!rc && rc2)
1234 rc = rc2;
1235 return rc;
1236}
1237
1238
1239/** @copydoc kLdrModCallInit */
1240static int kldrModPECallInit(PKLDRMOD pMod, uintptr_t uHandle)
1241{
1242 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1243 int rc;
1244
1245 /*
1246 * Mapped?
1247 */
1248 if (!pModPE->pvMapping)
1249 return KLDR_ERR_NOT_MAPPED;
1250
1251 /*
1252 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1253 */
1254 rc = kldrModPEDoCallTLS(pModPE, DLL_PROCESS_ATTACH, uHandle);
1255 if ( !rc
1256 && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL))
1257 {
1258 rc = kldrModPEDoCallDLL(pModPE, DLL_PROCESS_ATTACH, uHandle);
1259 if (rc)
1260 kldrModPEDoCallTLS(pModPE, DLL_PROCESS_DETACH, uHandle);
1261 }
1262
1263 return rc;
1264}
1265
1266
1267/** @copydoc kLdrModCallTerm */
1268static int kldrModPECallTerm(PKLDRMOD pMod, uintptr_t uHandle)
1269{
1270 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1271
1272 /*
1273 * Mapped?
1274 */
1275 if (!pModPE->pvMapping)
1276 return KLDR_ERR_NOT_MAPPED;
1277
1278 /*
1279 * Do TLS callbacks first.
1280 */
1281 kldrModPEDoCallTLS(pModPE, DLL_PROCESS_DETACH, uHandle);
1282 if (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL)
1283 kldrModPEDoCallDLL(pModPE, DLL_PROCESS_DETACH, uHandle);
1284
1285 return 0;
1286}
1287
1288
1289/** @copydoc kLdrModCallThread */
1290static int kldrModPECallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
1291{
1292 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1293 unsigned uOp = fAttachingOrDetaching ? DLL_THREAD_ATTACH : DLL_THREAD_DETACH;
1294 int rc;
1295
1296 /*
1297 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1298 */
1299 rc = kldrModPEDoCallTLS(pModPE, uOp, uHandle);
1300 if (!fAttachingOrDetaching)
1301 rc = 0;
1302 if ( !rc
1303 && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL))
1304 {
1305 rc = kldrModPEDoCallDLL(pModPE, uOp, uHandle);
1306 if (!fAttachingOrDetaching)
1307 rc = 0;
1308 if (rc)
1309 kldrModPEDoCallTLS(pModPE, uOp, uHandle);
1310 }
1311
1312 return rc;
1313}
1314
1315
1316/** @copydoc kLdrModSize */
1317static KLDRADDR kldrModPESize(PKLDRMOD pMod)
1318{
1319 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1320 return pModPE->Hdrs.OptionalHeader.SizeOfImage;
1321}
1322
1323
1324/** @copydoc kLdrModGetBits */
1325static int kldrModPEGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1326{
1327 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1328 uint32_t i;
1329 int rc;
1330
1331 /*
1332 * Iterate the segments and read the data within them.
1333 */
1334 for (i = 0; i < pMod->cSegments; i++)
1335 {
1336 /// @todo
1337 rc = 0;
1338 }
1339
1340 /*
1341 * Perform relocations.
1342 */
1343 return kldrModPERelocateBits(pMod, pvBits, BaseAddress, pModPE->Hdrs.OptionalHeader.ImageBase, pfnGetImport, pvUser);
1344
1345}
1346
1347
1348/** @copydoc kLdrModRelocateBits */
1349static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
1350 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1351{
1352 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1353 int rc;
1354
1355 /*
1356 * Call workers to do the jobs.
1357 */
1358 rc = kldrModPEDoFixups(pModPE, pvBits, NewBaseAddress, OldBaseAddress);
1359 if (!rc)
1360 rc = kldrModPEDoImports(pModPE, pvBits, pfnGetImport, pvUser);
1361
1362 return rc;
1363}
1364
Note: See TracBrowser for help on using the repository browser.