source: trunk/src/kernel32/winimagepe2lx.cpp@ 7029

Last change on this file since 7029 was 6303, checked in by bird, 24 years ago

Call DosFreeModule in destructor if DLL.

File size: 32.0 KB
Line 
1/* $Id: winimagepe2lx.cpp,v 1.18 2001-07-10 20:19:25 bird Exp $ */
2
3/*
4 * Win32 PE2LX Image base class
5 *
6 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998-1999 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13/*******************************************************************************
14* Defined Constants And Macros *
15*******************************************************************************/
16#define INCL_DOSERRORS /* DOS Error values */
17#define INCL_DOSPROFILE /* DosQuerySysState (Toolkit 4.5) */
18#define INCL_DOSMODULEMGR /* DOS Module management */
19
20#define ALIGN(a, alignment) (((a) + (alignment - 1UL)) & ~(alignment - 1UL))
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <os2wrap.h> //Odin32 OS/2 api wrappers
27
28#include <malloc.h>
29#include <process.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include <win32type.h>
34#include <misc.h>
35#include "winimagebase.h"
36#include "winimagepe2lx.h"
37#include "Win32k.h"
38
39#define DBG_LOCALLOG DBG_winimagepe2lx
40#include "dbglocal.h"
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45#ifndef QS_MTE
46 /* From OS/2 Toolkit v4.5 (BSEDOS.H) */
47
48 /* Global Record structure
49 * Holds all global system information. Placed first in user buffer
50 */
51 typedef struct qsGrec_s { /* qsGrec */
52 ULONG cThrds;
53 ULONG c32SSem;
54 ULONG cMFTNodes;
55 }qsGrec_t;
56
57 /*
58 * System wide MTE information
59 * ________________________________
60 * | pNextRec |----|
61 * |-------------------------------| |
62 * | hmte | |
63 * |-------------------------------| |
64 * | ctImpMod | |
65 * |-------------------------------| |
66 * | ctObj | |
67 * |-------------------------------| |
68 * | pObjInfo |----|----------|
69 * |-------------------------------| | |
70 * | pName |----|----| |
71 * |-------------------------------| | | |
72 * | imported module handles | | | |
73 * | . | | | |
74 * | . | | | |
75 * | . | | | |
76 * |-------------------------------| <--|----| |
77 * | "pathname" | | |
78 * |-------------------------------| <--|----------|
79 * | Object records | |
80 * | (if requested) | |
81 * |_______________________________| |
82 * <-----
83 * NOTE that if the level bit is set to QS_MTE, the base Lib record will be followed
84 * by a series of object records (qsLObj_t); one for each object of the
85 * module.
86 */
87
88 typedef struct qsLObjrec_s { /* qsLOrec */
89 ULONG oaddr; /* object address */
90 ULONG osize; /* object size */
91 ULONG oflags; /* object flags */
92 } qsLObjrec_t;
93
94 typedef struct qsLrec_s { /* qsLrec */
95 void FAR *pNextRec; /* pointer to next record in buffer */
96 USHORT hmte; /* handle for this mte */
97 USHORT fFlat; /* true if 32 bit module */
98 ULONG ctImpMod; /* # of imported modules in table */
99 ULONG ctObj; /* # of objects in module (mte_objcnt)*/
100 qsLObjrec_t FAR *pObjInfo; /* pointer to per object info if any */
101 UCHAR FAR *pName; /* -> name string following struc */
102 } qsLrec_t;
103
104
105
106 /* Pointer Record Structure
107 * This structure is the first in the user buffer.
108 * It contains pointers to heads of record types that are loaded
109 * into the buffer.
110 */
111
112 typedef struct qsPtrRec_s { /* qsPRec */
113 qsGrec_t *pGlobalRec;
114 void *pProcRec; /* ptr to head of process records */
115 void *p16SemRec; /* ptr to head of 16 bit sem recds */
116 void *p32SemRec; /* ptr to head of 32 bit sem recds */
117 void *pMemRec; /* ptr to head of shared mem recs */
118 qsLrec_t *pLibRec; /* ptr to head of mte records */
119 void *pShrMemRec; /* ptr to head of shared mem records */
120 void *pFSRec; /* ptr to head of file sys records */
121 } qsPtrRec_t;
122
123#endif
124
125
126/*******************************************************************************
127* External Functions *
128*******************************************************************************/
129#ifndef QS_MTE
130 /* from OS/2 Toolkit v4.5 */
131
132 APIRET APIENTRY DosQuerySysState(ULONG EntityList, ULONG EntityLevel, PID pid,
133 TID tid, PVOID pDataBuf, ULONG cbBuf);
134 #define QS_MTE 0x0004
135#endif
136
137
138
139/**
140 * Constructor - creates an pe2lx image object from a module handle to a pe2lx module.
141 * @param hinstance OS/2 module handle.
142 * @param fWin32k TRUE: Win32k module.
143 * FALSE: Pe2Lx module.
144 * @status partially implemented.
145 * @author knut st. osmundsen, Sander van Leeuwen
146 */
147Win32Pe2LxImage::Win32Pe2LxImage(HINSTANCE hinstance, BOOL fWin32k)
148 : Win32ImageBase(hinstance),
149 paSections(NULL), cSections(0), pNtHdrs(NULL), fWin32k(fWin32k),
150 hmod(hinstance)
151{
152 setFullPath(szFileName);
153}
154
155
156/**
157 * Free memory associated with this object.
158 * @status completely implemented.
159 * @author knut st. osmundsen, Sander van Leeuwen
160 */
161Win32Pe2LxImage::~Win32Pe2LxImage()
162{
163 cleanup();
164}
165
166
167/**
168 * Initiates the object.
169 * Must be called immediately after the object construction.
170 * @returns Success indicator, TRUE == success; FALSE = failure.
171 * @sketch Get section placement and sizes for this module. (paSections, cSections)
172 * Verify that there is at least one section - the header section.
173 * Locate the NT headers.
174 * Set pNtHdrs pointer.
175 * Validate the NT headers.
176 * Read the PE section table the set the RVAs in paSections.
177 * Set instance handle to address of header.
178 * Locate and set the entrypoint.
179 * Locate the resource directory (if any). (pResRootDir, ulRVAResourceSection)
180 * TLS - FIXME!
181 * @status completely implemented.
182 * @author knut st. osmundsen
183 * @remark Object must be destroyed if failure!
184 */
185BOOL Win32Pe2LxImage::init()
186{
187 APIRET rc;
188
189 /* Get section placement and sizes for this module. (paSections, cSections) */
190 rc = getSections();
191 if (rc != NO_ERROR)
192 {
193 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: error - getSection failed with rc=%d\n",
194 rc));
195 return FALSE;
196 }
197
198 /* Verify that there is at least one section - the header section. */
199 if (cSections < 1)
200 {
201 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: no header section, cSections is 0\n"));
202 return FALSE;
203 }
204
205 /* Locate the NT headers. */
206 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)paSections[0].ulAddress;
207 if ((pDosHdr->e_magic != IMAGE_DOS_SIGNATURE
208 || pDosHdr->e_lfanew < sizeof(IMAGE_DOS_HEADER) /* Larger than 64 bytes */
209 || pDosHdr->e_lfanew > 0x04000000UL /* or less that 64MB. */
210 )
211 && !*(PDWORD)paSections[0].ulAddress == IMAGE_NT_SIGNATURE
212 )
213 {
214 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
215 return FALSE;
216 }
217
218 /* Set pNtHdrs pointer. */
219 if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
220 pNtHdrs = (PIMAGE_NT_HEADERS)(paSections[0].ulAddress + pDosHdr->e_lfanew);
221 else
222 pNtHdrs = (PIMAGE_NT_HEADERS)paSections[0].ulAddress;
223
224 /* Validate the NT headers. */
225 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE
226 || pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC
227 || pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386
228 || (cSections != 1 /* all in one object */
229 && pNtHdrs->FileHeader.NumberOfSections
230 > cSections - 1 - (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ? 0 : 1) /* hdr section and stack */
231 )
232 /* TODO: add more tests? */
233 )
234 {
235 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
236 return FALSE;
237 }
238
239 /* set RVAs */
240 rc = setSectionRVAs();
241 if (rc != NO_ERROR)
242 {
243 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: setSectionRVAs failed with rc=%d\n", rc));
244 return FALSE;
245 }
246
247 /* Set instance handle to address of header. */
248 hinstance = (HINSTANCE)paSections[0].ulAddress;
249
250 /* Locate and set the entrypoint. */
251 setEntryPoint((ULONG)getPointerFromRVA(pNtHdrs->OptionalHeader.AddressOfEntryPoint));
252 if (entryPoint == 0UL &&
253 (pNtHdrs->OptionalHeader.AddressOfEntryPoint != NULL /* getPointerFromRVA failed... */
254 || !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)) /* EXEs must have and entry point! */
255 )
256 {
257 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: entrypoint is incorrect, AddrOfEP=0x%08x, entryPoint=0x%08x\n",
258 pNtHdrs->OptionalHeader.AddressOfEntryPoint, entryPoint));
259 return FALSE;
260 }
261
262 /* Locate the resource directory (if any) */
263 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
264 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
265 {
266 ulRVAResourceSection = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
267 pResRootDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(ulRVAResourceSection);
268 /* _temporary_ fix:
269 * We'll have to make the resource section writable.
270 * And we'll have to make the pages before it readable.
271 */
272 LONG iSection = getSectionIndexFromRVA(ulRVAResourceSection);
273 if (iSection >= 0)
274 {
275 rc = DosSetMem((PVOID)paSections[iSection].ulAddress, paSections[iSection].cbVirtual, PAG_WRITE | PAG_READ);
276
277 ULONG ulAddr = paSections[iSection].ulAddress - 0x10000; //64KB
278 while (ulAddr < paSections[iSection].ulAddress)
279 {
280 ULONG fl = ~0UL;
281 ULONG cb = ~0UL;
282 rc = DosQueryMem((PVOID)ulAddr, &cb, &fl);
283 if (rc == NO_ERROR)
284 {
285 if (fl & PAG_GUARD)
286 rc = -1;
287 else if (fl & PAG_COMMIT)
288 fl &= ~(PAG_COMMIT);
289 else
290 fl |= PAG_COMMIT;
291 cb = (cb + 0xfffUL) & ~0xfffUL;
292 }
293 else
294 {
295 fl = PAG_COMMIT;
296 cb = 0x1000;
297 }
298 fl &= PAG_READ | PAG_COMMIT | PAG_WRITE | PAG_GUARD;
299 fl |= PAG_READ;
300 if (cb > paSections[iSection].ulAddress - ulAddr)
301 cb = paSections[iSection].ulAddress - ulAddr;
302 if (rc == NO_ERROR)
303 rc = DosSetMem((PVOID)ulAddr, cb, fl);
304
305 ulAddr += cb;
306 }
307 }
308 }
309
310 /* TLS - Thread Local Storage */
311 if (pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0UL
312 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0UL)
313 {
314 PIMAGE_TLS_DIRECTORY pTLSDir;
315 LONG iSection;
316 iSection = getSectionIndexFromRVA(pNtHdrs->OptionalHeader.
317 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
318 VirtualAddress);
319 pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
320 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
321 VirtualAddress);
322
323 if (pTLSDir != NULL && iSection != -1)
324 {
325 PVOID pv;
326
327 /*
328 * According to the docs StartAddressOfRawData and EndAddressOfRawData is
329 * real pointers with a baserelocs.
330 *
331 * The docs says nothing about the two AddressOf pointers. So, we'll assume that
332 * these also are real pointers. But, we'll try compensate if they should not have
333 * base realocations.
334 */
335 if (validateRealPointer((PVOID)pTLSDir->StartAddressOfRawData)
336 &&
337 validateRealPointer((PVOID)pTLSDir->EndAddressOfRawData)
338 )
339 {
340 setTLSAddress((PVOID)pTLSDir->StartAddressOfRawData);
341 setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
342 setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
343
344 if (pTLSDir->AddressOfIndex)
345 {
346 if (validateRealPointer(pTLSDir->AddressOfIndex))
347 /* assume baserelocations for thepointer; use it without any change. */
348 setTLSIndexAddr((LPDWORD)(void*)pTLSDir->AddressOfIndex);
349 else
350 { /* assume no baserelocs for these pointers? Complain and debugint3 */
351 eprintf(("Win32Pe2LxImage::init: TLS - AddressOfIndex(%#8x) is not a pointer with basereloc.\n",
352 pTLSDir->AddressOfIndex));
353 pv = getPointerFromPointer(pTLSDir->AddressOfIndex);
354 if (pv == NULL)
355 {
356 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOfIndex - %#8x.\n",
357 pTLSDir->AddressOfIndex));
358 return FALSE;
359 }
360 setTLSIndexAddr((LPDWORD)pv);
361 }
362 }
363
364 if (pTLSDir->AddressOfCallBacks)
365 {
366 if (validateRealPointer(pTLSDir->AddressOfCallBacks))
367 /* assume baserelocations for thepointer; use it without any change. */
368 setTLSCallBackAddr(pTLSDir->AddressOfCallBacks);
369 else
370 { /* assume no baserelocs for these pointers? Complain and debugint3 */
371 eprintf(("Win32Pe2LxImage::init: Warning: TLS - AddressOfCallBacks(%#8x) is not a pointer with basereloc.\n",
372 pTLSDir->AddressOfCallBacks));
373 pv = getPointerFromPointer(pTLSDir->AddressOfCallBacks);
374 if (pv == NULL)
375 {
376 eprintf(("Win32Pe2LxImage::init: invalid pointer to TLS AddressOfCallBacks - %#8x.\n",
377 pTLSDir->AddressOfIndex));
378 return FALSE;
379 }
380 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
381 }
382 }
383 }
384 }
385 else
386 {
387 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
388 pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
389 return FALSE;
390 }
391 }
392 return TRUE;
393}
394
395
396
397/**
398 * Gets the object layout for this module. Creates the paSections array.
399 * @returns OS2 errorcode. (NO_ERROR == success)
400 * @sketch Allocate output buffer.
401 * Call DosQuerySysState.
402 * IF buffer overflow THEN retry calling it with larger buffers, until buffer size is 1MB.
403 * IF success THEN
404 * BEGIN
405 * Find record for this module.
406 * IF record found THEN allocate memory for object table and copy it. (paSections, cSections)
407 * END
408 * @status Completely implemented.
409 * @author knut st. osmundsen
410 */
411ULONG Win32Pe2LxImage::getSections()
412{
413 APIRET rc = NO_ERROR;
414
415 /*
416 * If Win32k.sys is installed we'll use it.
417 */
418 if (libWin32kInstalled())
419 {
420 ULONG cbQte = sizeof(QOTEBUFFER) + sizeof(QOTE)*20;
421 PQOTEBUFFER pQOte = (PQOTEBUFFER)malloc(sizeof(QOTEBUFFER) + sizeof(QOTE)*20);
422 if (pQOte != NULL)
423 {
424 /*
425 * Get the query OTEs for this module.
426 * If there is a buffer overflow we'll allocate more storage and retry.
427 */
428 rc = W32kQueryOTEs(hmod, pQOte, cbQte);
429 while (rc == ERROR_BUFFER_OVERFLOW && cbQte < 32000);
430 {
431 PVOID pvOld = pQOte;
432 cbQte += sizeof(QOTE) * 20;
433 pQOte = (PQOTEBUFFER)realloc(pQOte, cbQte);
434 if (pQOte == NULL)
435 {
436 free(pvOld);
437 return ERROR_NOT_ENOUGH_MEMORY;
438 }
439
440 rc = W32kQueryOTEs(hmod, pQOte, cbQte);
441 }
442
443 /*
444 * If successfully got the OTEs then allocate and set paSections structs.
445 */
446 if (rc == NO_ERROR)
447 {
448 /* Allocate memory for paSections */
449 paSections = (PSECTION)malloc(pQOte->cOTEs * sizeof(SECTION));
450 if (paSections != NULL)
451 {
452 /* objects -> section array */
453 for (int i = 0; i < pQOte->cOTEs; i++)
454 {
455 paSections[i].ulRVA = ~0UL;
456 paSections[i].cbVirtual = pQOte->aOTE[i].ote_size;
457 paSections[i].ulAddress = pQOte->aOTE[i].ote_base;
458 }
459 cSections = pQOte->cOTEs;
460 }
461 else
462 rc = ERROR_NOT_ENOUGH_MEMORY;
463 }
464 else
465 {
466 dprintf(("Win32Pe2LxImage::getSections: libW32kQueryOTEs failed with rc=%d."
467 " Falls back on the DosQuerySysState method.\n", rc));
468 }
469 }
470 else
471 { /* server error, no use in trying the fallback method. */
472 dprintf(("Win32Pe2LxImage::getSections: malloc failed\n"));
473 return ERROR_NOT_ENOUGH_MEMORY;
474 }
475
476 if (rc == NO_ERROR)
477 return rc;
478 }
479
480
481 /*
482 * Fallback method, using DosQuerySysState.
483 */
484 qsPtrRec_t * pPtrRec;
485 ULONG cbBuf = 65536;
486
487 pPtrRec = (qsPtrRec_t *)malloc(cbBuf);
488 if (pPtrRec != NULL)
489 {
490 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
491 while (cbBuf < 1024*1024 && rc == ERROR_BUFFER_OVERFLOW)
492 {
493 PVOID pv = pPtrRec;
494 cbBuf += 65536;
495 pPtrRec = (qsPtrRec_t *)realloc(pv, cbBuf);
496 if (pPtrRec != NULL)
497 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
498 else
499 {
500 rc = ERROR_NOT_ENOUGH_MEMORY;
501 free(pv);
502 }
503 }
504
505 if (rc == NO_ERROR)
506 {
507 qsLrec_t * pLrec = pPtrRec->pLibRec;
508 while (pLrec != NULL)
509 {
510 /*
511 * Bug detected in OS/2 FP13. Probably a problem which occurs
512 * in _LDRSysMteInfo when qsCheckCache is calle before writing
513 * object info. The result is that the cache flushed and the
514 * attempt of updating the qsLrec_t next and object pointer is
515 * not done. This used to work earlier and on Aurora AFAIK.
516 *
517 * The fix for this problem is to check if the pObjInfo is NULL
518 * while the number of objects isn't 0 and correct this. pNextRec
519 * will also be NULL at this time. This will be have to corrected
520 * before we exit the loop or moves to the next record.
521 * There is also a nasty alignment of the object info... Hope
522 * I got it right. (This aligment seems new to FP13.)
523 */
524 if (pLrec->pObjInfo == NULL /*&& pLrec->pNextRec == NULL*/ && pLrec->ctObj > 0)
525 {
526 pLrec->pObjInfo = (qsLObjrec_t*)(
527 (char*)pLrec
528 + ((sizeof(qsLrec_t) /* size of the lib record */
529 + pLrec->ctImpMod * sizeof(short) /* size of the array of imported modules */
530 + strlen((char*)pLrec->pName) + 1 /* size of the filename */
531 + 3) & ~3)); /* the size is align on 4 bytes boundrary */
532 pLrec->pNextRec = (qsLrec_t*)((char*)pLrec->pObjInfo
533 + sizeof(qsLObjrec_t) * pLrec->ctObj);
534 }
535 if (pLrec->hmte == hmod)
536 break;
537
538 /*
539 * Next record
540 */
541 pLrec = (qsLrec_t*)pLrec->pNextRec;
542 }
543
544
545 if (pLrec)
546 {
547 if (pLrec->pObjInfo != NULL)
548 {
549 /* Allocate memory for paSections */
550 paSections = (PSECTION)malloc(pLrec->ctObj*sizeof(SECTION));
551 if (paSections != NULL)
552 {
553 /* objects -> section array */
554 for (int i = 0; i < pLrec->ctObj; i++)
555 {
556 paSections[i].ulRVA = ~0UL;
557 paSections[i].cbVirtual = pLrec->pObjInfo[i].osize;
558 paSections[i].ulAddress = pLrec->pObjInfo[i].oaddr;
559 }
560 cSections = pLrec->ctObj;
561 }
562 else
563 rc = ERROR_NOT_ENOUGH_MEMORY;
564 }
565 else
566 {
567 rc = ERROR_BAD_EXE_FORMAT;
568 dprintf(("Win32Pe2LxImage::getSections: Error - no object table!\n"));
569 }
570 }
571 else
572 rc = ERROR_MOD_NOT_FOUND;
573 }
574 else
575 dprintf(("DosQuerySysState - failed with rc=%d (cbBuf=%d)\n", rc, cbBuf));
576
577 if (pPtrRec != NULL)
578 free(pPtrRec);
579 }
580 else
581 rc = ERROR_NOT_ENOUGH_MEMORY;
582
583 return rc;
584}
585
586
587/**
588 * Sets the ulRVA according to the original PE section table.
589 * @returns OS/2 errorcode. (NO_ERROR == success)
590 * @sketch DEBUG: Validate pNtHdrs
591 * Make pointer to start of PE section table.
592 * Set RVA for the header section.
593 * IF not all in one object exe? THEN
594 * Loop thru the sections in the PE section table.
595 * Note: due to the header section: PE section no. + 1 == LX object no.
596 * ELSE
597 * BEGIN
598 * (try) Reallocate paSections to NumberOfSections + 3.
599 * Loop thru the PE sections and make paSections from them.
600 * Add final Stack or TIBFix+Stack section if necessary.
601 * Resize header section.
602 * END
603 * @status completely implemented.
604 * @author knut st. osmundsen
605 * @remark Must not be called before pNtHdrs is set.
606 */
607ULONG Win32Pe2LxImage::setSectionRVAs()
608{
609 #if DEBUG
610 if (pNtHdrs == NULL)
611 {
612 DebugInt3();
613 return ERROR_INVALID_PARAMETER;
614 }
615 #endif
616
617 PIMAGE_SECTION_HEADER paPESections = (PIMAGE_SECTION_HEADER)
618 ((unsigned)pNtHdrs + sizeof(*pNtHdrs) +
619 (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY)
620 );
621
622 /* set RVA for the header section to 0UL. */
623 paSections[0].ulRVA = 0UL;
624
625 /* All in one object exe? */
626 if (pNtHdrs->FileHeader.NumberOfSections < cSections)
627 {
628 /* loop thru the other sections */
629 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
630 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
631 }
632 else
633 { /* all in one object */
634 /* (try) Reallocate paSections to NumberOfSections + 3. */
635 PVOID pv = realloc(paSections, sizeof(paSections[0]) * (pNtHdrs->FileHeader.NumberOfSections + 3));
636 if (pv != NULL)
637 {
638 paSections = (PSECTION)pv;
639
640 /* loop thru the PE sections */
641 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
642 {
643 if (paSections[0].cbVirtual < paPESections[i].VirtualAddress)
644 {
645 dprintf(("Win32Pe2LxImage::setSectionRVAs: mismatch between section table and all-in-one-object"
646 "paSections[0].cbVirtual %#x paPESections[i].VirtualAddress %#x\n",
647 paSections[0].cbVirtual, paPESections[i].VirtualAddress
648 ));
649 return ERROR_BAD_EXE_FORMAT;
650 }
651 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
652 paSections[i+1].cbVirtual = max(paPESections[i].Misc.VirtualSize, paPESections[i].SizeOfRawData);
653 paSections[i+1].ulAddress = paSections[0].ulAddress + paPESections[i].VirtualAddress;
654 }
655 cSections = pNtHdrs->FileHeader.NumberOfSections + 1;
656
657 /* add final Stack or TIBFix+Stack section if necessary */
658 if (paSections[0].cbVirtual > paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000))
659 {
660 paSections[i+1].ulRVA = ~0UL;
661 paSections[i+1].cbVirtual = paSections[0].cbVirtual - paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000);
662 paSections[i+1].ulAddress = paSections[i].ulAddress + ALIGN(paSections[i].cbVirtual, 0x1000);
663 i++;
664 cSections++;
665 }
666
667 /* resize header section */
668 paSections[0].cbVirtual = paSections[1].ulRVA; /*....*/
669 }
670 else
671 return ERROR_NOT_ENOUGH_MEMORY;
672 }
673
674 return NO_ERROR;
675}
676
677
678/**
679 * Frees memory used by this object.
680 * When an exception is to be thrown, this function is called first to clean up
681 * the object. Base class(es) are automatically clean up by theire destructor(s).
682 * @status completely implemented.
683 * @author knut st. osmundsen
684 */
685VOID Win32Pe2LxImage::cleanup()
686{
687 if (paSections != NULL)
688 {
689 free(paSections);
690 paSections = NULL;
691 cSections = 0;
692 }
693
694 if (fDll)
695 DosFreeModule(hmod);
696}
697
698
699/**
700 * Converts a RVA into a pointer.
701 * @returns Pointer matching the given RVA, NULL on error.
702 * @param ulRVA An address relative to the imagebase of the original PE image.
703 * If this is 0UL NULL is returned.
704 * @sketch DEBUG: validate state, paSections != NULL
705 * IF ulRVA is 0 THEN return NULL
706 * LOOP while more section left and ulRVA is not within section
707 * next section
708 * IF section matching ulRVA is not found THEN fail.
709 * return pointer matching RVA.
710 * @status completely implemented.
711 * @author knut st. osmundsen
712 * @remark Should not be called until getSections has returned successfully.
713 * RVA == 0 is ignored.
714 */
715PVOID Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA)
716{
717 int i;
718
719 #ifdef DEBUG
720 if (paSections == NULL)
721 {
722 eprintf(("Win32Pe2LxImage::getPointerFromRVA: paSections is NULL!\n"));
723 return NULL;
724 }
725 #endif
726
727 if (ulRVA == 0UL)
728 return NULL;
729
730 i = 0;
731 while (i < cSections &&
732 (paSections[i].ulRVA > ulRVA || paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
733 i++;
734
735 if (i >= cSections)
736 return NULL;
737
738 return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
739}
740
741
742/**
743 * Converts a pointer with not basereloc to a pointer.
744 * @returns Pointer with baserelocation applied.
745 * @param pv Pointer without baserelocation.
746 * @status completely implemented.
747 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
748 */
749PVOID Win32Pe2LxImage::getPointerFromPointer(PVOID pv)
750{
751 if (pv == NULL)
752 return NULL;
753
754 return getPointerFromRVA((ULONG)pv - pNtHdrs->OptionalHeader.ImageBase);
755}
756
757
758/**
759 * Converts a RVA into a paSections index.
760 * @returns Index into paSections for the section containing the RVA.
761 * -1 on error.
762 * @param ulRVA An address relative to the imagebase of the original PE image.
763 * If this is 0UL -1 is returned.
764 * @sketch DEBUG: validate state, paSections != NULL
765 * IF ulRVA is 0 THEN return -1
766 * LOOP while more section left and ulRVA is not within section
767 * next section
768 * IF section matching ulRVA is found THEN return index ELSE fail.
769 * @status completely implemented.
770 * @author knut st. osmundsen
771 * @remark Should not be called until getSections has returned successfully.
772 * RVA == 0 is ignored.
773 */
774LONG Win32Pe2LxImage::getSectionIndexFromRVA(ULONG ulRVA)
775{
776 LONG i;
777
778 #ifdef DEBUG
779 if (paSections == NULL)
780 {
781 eprintf(("Win32Pe2LxImage::getSectionIndexFromRVA: paSections is NULL!\n"));
782 return NULL;
783 }
784 #endif
785
786 if (ulRVA == 0UL)
787 return -1;
788
789 i = 0;
790 while (i < cSections &&
791 (paSections[i].ulRVA > ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
792 i++;
793
794 return i < cSections ? i : -1;
795}
796
797
798/**
799 * Validates that a given pointer is pointing to valid memory within
800 * the loaded executable image.
801 * @returns TRUE if the pointer is valid.
802 * FALSE if the pointer is invalid.
803 * @param pv Pointer to validate.
804 * @sketch
805 * @status completely implemented.
806 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
807 */
808BOOL Win32Pe2LxImage::validateRealPointer(PVOID pv)
809{
810 int i;
811
812 #ifdef DEBUG
813 if (paSections == NULL)
814 {
815 eprintf(("Win32Pe2LxImage::validateRealPointer: paSections is NULL!\n"));
816 return NULL;
817 }
818 #endif
819
820 if (pv == NULL)
821 return FALSE;
822
823 i = 0;
824 while (i < cSections &&
825 (paSections[i].ulAddress < (ULONG)pv ||
826 paSections[i].ulAddress + paSections[i].cbVirtual <= (ULONG)pv) /* Align on page too? */
827 )
828 i++;
829
830 return i < cSections;
831}
832
833
834/**
835 * Gets pointer to an exported procedure by procedure name.
836 * @returns Address of exported procedure. 0UL if not found.
837 * @param name Exported procedure name.
838 * @status completely implemented.
839 * @author Sander van Leeuwen
840 * @remark
841 */
842ULONG Win32Pe2LxImage::getApi(char *name)
843{
844 APIRET rc;
845 ULONG ulApiAddr;
846
847 rc = DosQueryProcAddr(hmod, 0, name, (PFN *)&ulApiAddr);
848 return rc == NO_ERROR ? ulApiAddr : 0;
849}
850
851
852/**
853 * Gets pointer to an exported procedure by ordinal.
854 * @returns Pointer to an exported procedure. 0UL if not found.
855 * @param ordinal Export ordinal number.
856 * @status completely implemented.
857 * @author Sander van Leeuwen
858 * @remark FIXME:
859 * This function should be implemented for both Exe and Dll images!
860 * It could be done similar in both peldr image and pe2lx images by
861 * accessing PE structures.
862 */
863ULONG Win32Pe2LxImage::getApi(int ordinal)
864{
865 APIRET rc;
866 ULONG ulApiAddr;
867
868 rc = DosQueryProcAddr(hmod, ordinal, NULL, (PFN *)&ulApiAddr);
869
870 return rc == NO_ERROR ? ulApiAddr : 0;
871}
Note: See TracBrowser for help on using the repository browser.