source: trunk/kLdr/kLdrMod.c@ 2879

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

started coding on the LX module interpreter.

  • Property svn:keywords set to Id
File size: 22.3 KB
Line 
1/* $Id: kLdrMod.c 2879 2006-11-12 17:21:16Z bird $ */
2/** @file
3 *
4 * kLdr - The Module Interpreter.
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 "kLdrModMZ.h"
35#if 1 /* testing headers */
36# include "kLdrModPE.h"
37# include "kLdrModLX.h"
38# include "kLdrModELF32.h"
39# include "kLdrModELF64.h"
40#endif
41
42
43/*******************************************************************************
44* Defined Constants And Macros *
45*******************************************************************************/
46/** @def KLDRMOD_STRICT
47 * Define KLDRMOD_STRICT to enabled strict checks in KLDRMOD. */
48#define KLDRMOD_STRICT 1
49
50/** @def KLDRMOD_ASSERT
51 * Assert that an expression is true when KLDR_STRICT is defined.
52 */
53#ifdef KLDRMOD_STRICT
54# define KLDRMOD_ASSERT(expr) kldrHlpAssert(expr)
55#else
56# define KLDRMOD_ASSERT(expr) do {} while (0)
57#endif
58
59/** Return / crash validation of a module argument. */
60#define KLDRMOD_VALIDATE_EX(pMod, rc) \
61 do { \
62 if ( (pMod)->u32Magic != KLDRMOD_MAGIC \
63 || (pMod)->pOps == NULL \
64 )\
65 { \
66 return (rc); \
67 } \
68 } while (0)
69
70/** Return / crash validation of a module argument. */
71#define KLDRMOD_VALIDATE(pMod) \
72 KLDRMOD_VALIDATE_EX(pMod, KLDR_ERR_INVALID_PARAMETER)
73
74/** Return / crash validation of a module argument. */
75#define KLDRMOD_VALIDATE_VOID(pMod) \
76 do { \
77 if ( (pMod)->u32Magic != KLDRMOD_MAGIC \
78 || (pMod)->pOps == NULL \
79 )\
80 { \
81 return; \
82 } \
83 } while (0)
84
85
86/*******************************************************************************
87* Global Variables *
88*******************************************************************************/
89/** The list of module interpreters. */
90static PCKLDRMODOPS g_pModInterpreterHead = NULL;
91
92
93
94/*******************************************************************************
95* Internal Functions *
96*******************************************************************************/
97
98
99
100/**
101 * Open a executable image by file name.
102 *
103 * @returns 0 on success and *ppMod pointing to a module instance.
104 * On failure, a non-zero OS specific error code is returned.
105 * @param pszFilename The filename to open.
106 * @param ppMod Where to store the module handle.
107 */
108int kLdrModOpen(const char *pszFilename, PPKLDRMOD ppMod)
109{
110 /*
111 * Open the file using a bit provider.
112 */
113 PKLDRRDR pRdr;
114 int rc = kLdrRdrOpen(&pRdr, pszFilename);
115 if (!rc)
116 {
117 rc = kLdrModOpenFromRdr(pRdr, ppMod);
118 if (!rc)
119 return 0;
120 kLdrRdrClose(pRdr);
121 }
122 return rc;
123}
124
125
126/**
127 * Open a executable image from a file provider instance.
128 *
129 * @returns 0 on success and *ppMod pointing to a module instance.
130 * On failure, a non-zero OS specific error code is returned.
131 * @param pRdr The file provider instance to use.
132 * On success, the ownership of the instance is taken by the
133 * module and the caller must not ever touch it again.
134 * (The instance is not closed on failure, the call has to do that.)
135 * @param ppMod Where to store the module handle.
136 */
137int kLdrModOpenFromRdr(PKLDRRDR pRdr, PPKLDRMOD ppMod)
138{
139 union
140 {
141 uint32_t u32;
142 uint16_t u16;
143 uint16_t au16[2];
144 uint8_t au8[4];
145 } u;
146 off_t offHdr = 0;
147 int rc;
148
149 /*
150 * Try figure out what kind of image this is.
151 * Always read the 'new header' if we encounter MZ.
152 */
153 rc = kLdrRdrRead(pRdr, &u, sizeof(u), 0);
154 if (rc)
155 return rc;
156 if ( u.u16 == IMAGE_DOS_SIGNATURE
157 && kLdrRdrSize(pRdr) > sizeof(IMAGE_DOS_HEADER))
158 {
159 rc = kLdrRdrRead(pRdr, &u, sizeof(u.u32), KLDR_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew));
160 if (rc)
161 return rc;
162 if ((off_t)u.u32 < kLdrRdrSize(pRdr))
163 {
164 offHdr = u.u32;
165 rc = kLdrRdrRead(pRdr, &u, sizeof(u.u32), offHdr);
166 if (rc)
167 return rc;
168 }
169 else
170 u.u16 = IMAGE_DOS_SIGNATURE;
171 }
172
173 /*
174 * Use the magic to select the appropriate image interpreter head on.
175 */
176 if (u.u16 == IMAGE_DOS_SIGNATURE)
177 rc = KLDR_ERR_MZ_NOT_SUPPORTED;
178 else if (u.u16 == IMAGE_NE_SIGNATURE)
179 rc = KLDR_ERR_NE_NOT_SUPPORTED;
180 else if (u.u16 == IMAGE_LX_SIGNATURE)
181 rc = g_kLdrModLXOps.pfnCreate(&g_kLdrModLXOps, pRdr, offHdr, ppMod);
182 else if (u.u16 == IMAGE_LE_SIGNATURE)
183 rc = KLDR_ERR_LE_NOT_SUPPORTED;
184 else if (u.u32 == IMAGE_NT_SIGNATURE)
185 rc = g_kLdrModPEOps.pfnCreate(&g_kLdrModPEOps, pRdr, offHdr, ppMod);
186 else if (u.u32 == IMAGE_ELF_SIGNATURE)
187 rc = KLDR_ERR_ELF_NOT_SUPPORTED;
188 else
189 rc = KLDR_ERR_UNKNOWN_FORMAT;
190
191 /*
192 * If no head on hit, let each interpreter have a go.
193 */
194 if (rc)
195 {
196 PCKLDRMODOPS pOps;
197 for (pOps = g_pModInterpreterHead; pOps; pOps = pOps->pNext)
198 {
199 int rc2 = pOps->pfnCreate(pOps, pRdr, offHdr, ppMod);
200 if (!rc2)
201 return rc;
202 }
203 *ppMod = NULL;
204 }
205 return rc;
206}
207
208
209/**
210 * Closes an open module.
211 *
212 * The caller is responsible for calling kLdrModUnmap() and kLdrFreeTLS()
213 * before closing the module.
214 *
215 * @returns 0 on success, non-zero on failure. The module instance state
216 * is unknown on failure, it's best not to touch it.
217 * @param pMod The module.
218 */
219int kLdrModClose(PKLDRMOD pMod)
220{
221 KLDRMOD_VALIDATE(pMod);
222 return pMod->pOps->pfnDestroy(pMod);
223}
224
225
226/**
227 * Queries a symbol by name or ordinal number.
228 *
229 * @returns 0 and *puValue and *pfKind on success.
230 * KLDR_ERR_SYMBOL_NOT_FOUND is returned if the symbol wasn't found.
231 * Other failures could stem from bad executable format failures,
232 * read failure in case pvBits isn't specified and no mapping should be used.
233 * @param pMod The module.
234 * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
235 * This can be used by some module interpreters to reduce memory consumption.
236 * @param BaseAddress The module base address to use when calculating the symbol value.
237 * There are two special values that can be used:
238 * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
239 * @param iSymbol The symbol ordinal. (optional)
240 * @param pszSymbol The symbol name. (optional)
241 * @param pfnGetForwarder The callback to use when resolving a forwarder symbol. This is optional
242 * and if not specified KLDR_ERR_FORWARDER is returned instead.
243 * @param pvUser The user argument for the pfnGetForwarder callback.
244 * @param puValue Where to store the symbol value. (optional)
245 * @param pfKind Where to store the symbol kind. (optional)
246 */
247int kLdrModQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
248 const char *pszSymbol, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser,
249 PKLDRADDR puValue, uint32_t *pfKind)
250{
251 KLDRMOD_VALIDATE(pMod);
252 if (!puValue && !pfKind)
253 return KLDR_ERR_INVALID_PARAMETER;
254 if (puValue)
255 *puValue = 0;
256 if (pfKind)
257 *pfKind = 0;
258 return pMod->pOps->pfnQuerySymbol(pMod, pvBits, BaseAddress, iSymbol, pszSymbol, pfnGetForwarder, pvUser, puValue, pfKind);
259}
260
261
262/**
263 * Enumerate the symbols in the module.
264 *
265 * @returns 0 on success and non-zero a status code on failure.
266 * @param pMod The module which symbols should be enumerated.
267 * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
268 * This can be used by some module interpreters to reduce memory consumption.
269 * @param BaseAddress The module base address to use when calculating the symbol values.
270 * There are two special values that could be can:
271 * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
272 * @param fFlags The enumeration flags. A combination of the KLDRMOD_ENUM_SYMS_FLAGS_* \#defines.
273 * @param pfnCallback The enumeration callback function.
274 * @param pvUser The user argument to the callback function.
275 */
276int kLdrModEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t fFlags,
277 PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
278{
279 KLDRMOD_VALIDATE(pMod);
280 KLDRHLP_VALIDATE_FLAGS(fFlags, KLDRMOD_ENUM_SYMS_FLAGS_ALL);
281 return pMod->pOps->pfnEnumSymbols(pMod, pvBits, BaseAddress, fFlags, pfnCallback, pvUser);
282}
283
284
285/**
286 * Get the name of an import module by ordinal number.
287 *
288 * @returns 0 and name in pszName on success.
289 * On buffer overruns KLDR_ERR_BUFFER_OVERFLOW will be returned.
290 * On other failures and appropriate error code is returned.
291 * @param pMod The module.
292 * @param pvBits Optional pointer to bits returned by kLdrModGetBits().
293 * This can be used by some module interpreters to reduce memory consumption.
294 * @param iImport The import module ordinal number.
295 * @param pszName Where to store the name.
296 * @param cchName The size of the name buffer.
297 */
298int kLdrModGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
299{
300 KLDRMOD_VALIDATE(pMod);
301 return pMod->pOps->pfnGetImport(pMod, pvBits, iImport, pszName, cchName);
302}
303
304
305/**
306 * Get the number of import modules.
307 *
308 * @returns The number of import modules. -1 if something really bad happens.
309 * @param pMod The module.
310 * @param pvBits Optional pointer to bits returned by kLdrModGetBits().
311 * This can be used by some module interpreters to reduce memory consumption.
312 */
313int32_t kLdrModNumberOfImports(PKLDRMOD pMod, const void *pvBits)
314{
315 KLDRMOD_VALIDATE(pMod);
316 return pMod->pOps->pfnNumberOfImports(pMod, pvBits);
317}
318
319
320/**
321 * Checks if this module can be executed by the specified arch+cpu.
322 *
323 * @returns 0 if it can, KLDR_ERR_ARCH_CPU_NOT_COMPATIBLE if it can't.
324 * Other failures may occur and cause other return values.
325 * @param pMod The module.
326 * @param pvBits Optional pointer to bits returned by kLdrModGetBits().
327 * This can be used by some module interpreters to reduce memory consumption.
328 */
329int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KLDRARCH enmArch, KLDRCPU enmCpu)
330{
331 KLDRMOD_VALIDATE(pMod);
332 if (pMod->pOps->pfnCanExecuteOn)
333 return pMod->pOps->pfnCanExecuteOn(pMod, pvBits, enmArch, enmCpu);
334 return kLdrCompareCpus(pMod->enmArch, pMod->enmCpu, enmArch, enmCpu);
335}
336
337
338/**
339 * Gets the image stack info.
340 *
341 * @returns 0 on success, non-zero on failure.
342 * @param pMod
343 * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
344 * This can be used by some module interpreters to reduce memory consumption.
345 * @param BaseAddress The module base address to use when calculating the stack address.
346 * There are two special values that can be used:
347 * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
348 * @param pStackInfo The stack information.
349 */
350int kLdrModGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
351{
352 KLDRMOD_VALIDATE(pMod);
353 return pMod->pOps->pfnGetStackInfo(pMod, pvBits, BaseAddress, pStackInfo);
354}
355
356
357/**
358 * Queries the main entrypoint of the module.
359 *
360 * Only executable are supposed to have an main entrypoint, though some object and DLL
361 * formats will also allow this.
362 *
363 * @returns 0 and *pMainEPAddress on success. Non-zero status code on failure.
364 * @param pMod The module.
365 * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
366 * This can be used by some module interpreters to reduce memory consumption.
367 * @param BaseAddress The module base address to use when calculating the entrypoint address.
368 * There are two special values that can be used:
369 * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
370 * @param pMainEPAddress Where to store the entry point address.
371 */
372int kLdrModQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
373{
374 KLDRMOD_VALIDATE(pMod);
375 *pMainEPAddress = 0;
376 return pMod->pOps->pfnQueryMainEntrypoint(pMod, pvBits, BaseAddress, pMainEPAddress);
377}
378
379
380/**
381 * Enumerate the debug info formats contained in the executable image.
382 *
383 * @returns 0 on success, non-zero OS or kLdr status code on failure, or non-zero callback status.
384 * @param pMod The module.
385 * @param pvBits Optional pointer to bits returned by kLdrModGetBits().
386 * This can be used by some module interpreters to reduce memory consumption.
387 * @param pfnCallback The callback function.
388 * @param pvUser The user argument.
389 * @see pg_kDbg for the debug info reader.
390 */
391int kLdrModEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
392{
393 KLDRMOD_VALIDATE(pMod);
394 return pMod->pOps->pfnEnumDbgInfo(pMod, pvBits, pfnCallback, pvUser);
395}
396
397
398/**
399 * Checks if the module has debug info embedded or otherwise associated with it.
400 *
401 * @returns 0 if it has debug info, KLDR_ERR_NO_DEBUG_INFO if no debug info,
402 * and non-zero OS or kLdr status code on failure.
403 * @param pMod The module.
404 * @param pvBits Optional pointer to bits returned by kLdrModGetBits().
405 * This can be used by some module interpreters to reduce memory consumption.
406 */
407int kLdrModHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
408{
409 KLDRMOD_VALIDATE(pMod);
410 return pMod->pOps->pfnHasDbgInfo(pMod, pvBits);
411}
412
413
414/**
415 * Maps the module into the memory of the caller.
416 *
417 * On success the actual addresses for the segments can be found in MapAddress
418 * member of each segment in the segment array.
419 *
420 * @returns 0 on success, non-zero OS or kLdr status code on failure.
421 * @param pMod The module to be mapped.
422 * @remark kLdr only supports one mapping at a time of a module.
423 */
424int kLdrModMap(PKLDRMOD pMod)
425{
426 KLDRMOD_VALIDATE(pMod);
427 return pMod->pOps->pfnMap(pMod);
428}
429
430
431/**
432 * Unmaps a module previously mapped by kLdrModMap().
433 *
434 * @returns 0 on success, non-zero OS or kLdr status code on failure.
435 * @param pMod The module to unmap.
436 */
437int kLdrModUnmap(PKLDRMOD pMod)
438{
439 KLDRMOD_VALIDATE(pMod);
440 return pMod->pOps->pfnUnmap(pMod);
441}
442
443
444/**
445 * Allocates Thread Local Storage for module mapped by kLdrModMap().
446 *
447 * Calling kLdrModAllocTLS() more than once without calling kLdrModFreeTLS()
448 * between each invocation is not supported.
449 *
450 * @returns 0 on success, non-zero OS or kLdr status code on failure.
451 * @param pMod The module.
452 */
453int kLdrModAllocTLS(PKLDRMOD pMod)
454{
455 KLDRMOD_VALIDATE(pMod);
456 return pMod->pOps->pfnAllocTLS(pMod);
457}
458
459
460/**
461 * Frees Thread Local Storage previously allocated by kLdrModAllocTLS().
462 *
463 * The caller is responsible for only calling kLdrModFreeTLS() once
464 * after calling kLdrModAllocTLS().
465 *
466 * @returns 0 on success, non-zero OS or kLdr status code on failure.
467 * @param pMod The module.
468 */
469void kLdrModFreeTLS(PKLDRMOD pMod)
470{
471 KLDRMOD_VALIDATE_VOID(pMod);
472 pMod->pOps->pfnFreeTLS(pMod);
473}
474
475
476/**
477 * Reloads all dirty pages in a module previously mapped by kLdrModMap().
478 *
479 * The module interpreter may omit code pages if it can safely apply code
480 * fixups again in a subsequent kLdrModFixupMapping() call.
481 *
482 * The caller is responsible for freeing TLS before calling this function.
483 *
484 * @returns 0 on success, non-zero OS or kLdr status code on failure.
485 * @param pMod The module.
486 */
487int kLdrModReload(PKLDRMOD pMod)
488{
489 KLDRMOD_VALIDATE(pMod);
490 return pMod->pOps->pfnReload(pMod);
491}
492
493
494/**
495 * Fixup the mapping made by kLdrModMap().
496 *
497 * The caller is only responsible for not calling this function more than
498 * once without doing kLDrModReload() inbetween.
499 *
500 * @returns 0 on success, non-zero OS or kLdr status code on failure.
501 * @param pMod The module.
502 * @param pfnGetImport The callback for resolving external (imported) symbols.
503 * @param pvUser The callback user argument.
504 */
505int kLdrModFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
506{
507 KLDRMOD_VALIDATE(pMod);
508 return pMod->pOps->pfnFixupMapping(pMod, pfnGetImport, pvUser);
509}
510
511
512/**
513 * Call the module initializiation function of a mapped module (if any).
514 *
515 * @returns 0 on success or no init function, non-zero on init function failure or invalid pMod.
516 * @param pMod The module.
517 * @param uHandle The module handle to use if any of the init functions requires the module handle.
518 */
519int kLdrModCallInit(PKLDRMOD pMod, uintptr_t uHandle)
520{
521 KLDRMOD_VALIDATE(pMod);
522 return pMod->pOps->pfnCallInit(pMod, uHandle);
523}
524
525
526/**
527 * Call the module termination function of a mapped module (if any).
528 *
529 * @returns 0 on success or no term function, non-zero on invalid pMod.
530 * @param pMod The module.
531 * @param uHandle The module handle to use if any of the term functions requires the module handle.
532 *
533 * @remark Termination function failure will be ignored by the module interpreter.
534 */
535int kLdrModCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
536{
537 KLDRMOD_VALIDATE(pMod);
538 return pMod->pOps->pfnCallTerm(pMod, uHandle);
539}
540
541
542/**
543 * Call the thread attach or detach function of a mapped module (if any).
544 *
545 * Any per-thread TLS initialization/termination will have to be done at this time too.
546 *
547 * @returns 0 on success or no attach/detach function, non-zero on attach failure or invalid pMod.
548 * @param pMod The module.
549 * @param uHandle The module handle to use if any of the thread attach/detach functions
550 * requires the module handle.
551 *
552 * @remark Detach function failure will be ignored by the module interpreter.
553 */
554int kLdrModCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
555{
556 KLDRMOD_VALIDATE(pMod);
557 KLDRHLP_VALIDATE_FLAGS(fAttachingOrDetaching, 1);
558 return pMod->pOps->pfnCallThread(pMod, uHandle, fAttachingOrDetaching);
559}
560
561
562/**
563 * Get the size of the mapped module.
564 *
565 * @returns The size of the mapped module (in bytes).
566 * @param pMod The module.
567 */
568KLDRADDR kLdrModSize(PKLDRMOD pMod)
569{
570 KLDRMOD_VALIDATE_EX(pMod, 0);
571 return pMod->pOps->pfnSize(pMod);
572}
573
574
575/**
576 * Gets the module bits.
577 *
578 * The module interpreter will fill a mapping allocated by the caller with the
579 * module bits reallocated to the specified address.
580 *
581 * @returns 0 on succes, non-zero OS or kLdr status code on failure.
582 * @param pMod The module.
583 * @param pvBits Where to put the bits.
584 * @param BaseAddress The base address that should correspond to the first byte in pvBits
585 * upon return.
586 * @param pfnGetImport The callback ufor resolving external (imported) symbols.
587 * @param pvUser The callback user argument.
588 */
589int kLdrModGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
590{
591 KLDRMOD_VALIDATE(pMod);
592 return pMod->pOps->pfnGetBits(pMod, pvBits, BaseAddress, pfnGetImport, pvUser);
593}
594
595
596/**
597 * Relocates the module bits previously obtained by kLdrModGetBits().
598 *
599 * @returns 0 on succes, non-zero OS or kLdr status code on failure.
600 * @param pMod The module.
601 * @param pvBits Where to put the bits.
602 * @param NewBaseAddress The new base address.
603 * @param OldBaseAddress The old base address (i.e. the one specified to kLdrModGetBits() or as
604 * NewBaseAddressto the previous kLdrModRelocateBits() call).
605 * @param pfnGetImport The callback ufor resolving external (imported) symbols.
606 * @param pvUser The callback user argument.
607 */
608int kLdrModRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
609 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
610{
611 KLDRMOD_VALIDATE(pMod);
612 return pMod->pOps->pfnRelocateBits(pMod, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
613}
614
Note: See TracBrowser for help on using the repository browser.