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

Last change on this file since 4304 was 4304, checked in by bird, 25 years ago

Changed hinstance to address of module.

File size: 29.3 KB
Line 
1/* $Id: winimagepe2lx.cpp,v 1.15 2000-09-22 04:35:09 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 ULONG 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 pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
316 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
317 VirtualAddress);
318
319 if (pTLSDir != NULL)
320 {
321 PVOID pv;
322 ULONG ulBorlandRVAFix = 0UL;
323
324 pv = getPointerFromRVA(pTLSDir->StartAddressOfRawData);
325 /*
326 * Borland seems to have problems getting things right...
327 * Needs to subtract image base to make the TLSDir "RVA"s real
328 * RVAs before converting them to pointers.
329 */
330 if ((pv == NULL || pTLSDir->StartAddressOfRawData == 0UL)
331 && pTLSDir->StartAddressOfRawData > this->pNtHdrs->OptionalHeader.ImageBase)
332 {
333 ulBorlandRVAFix = this->pNtHdrs->OptionalHeader.ImageBase;
334 pv = getPointerFromRVA(pTLSDir->StartAddressOfRawData - ulBorlandRVAFix);
335 }
336 if (pv == NULL || pTLSDir->StartAddressOfRawData == 0UL)
337 {
338 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS StartAddressOfRawData - %#8x.\n",
339 pTLSDir->StartAddressOfRawData));
340 return FALSE;
341 }
342 setTLSAddress(pv);
343 setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
344 setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
345 pv = getPointerFromRVA((ULONG)pTLSDir->AddressOfIndex - ulBorlandRVAFix);
346 if (pv == NULL)
347 {
348 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOffIndex - %#8x.\n",
349 pTLSDir->AddressOfIndex));
350 return FALSE;
351 }
352 setTLSIndexAddr((LPDWORD)pv);
353 if (pTLSDir->AddressOfCallBacks != 0)
354 {
355 pv = getPointerFromRVA((ULONG)pTLSDir->AddressOfCallBacks - ulBorlandRVAFix);
356 if (pv == NULL)
357 {
358 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOffIndex - %#8x.\n",
359 pTLSDir->AddressOfIndex));
360 return FALSE;
361 }
362 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
363 }
364 }
365 else
366 {
367 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
368 pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
369 return FALSE;
370 }
371 }
372 return TRUE;
373}
374
375
376
377/**
378 * Gets the object layout for this module. Creates the paSections array.
379 * @returns OS2 errorcode. (NO_ERROR == success)
380 * @sketch Allocate output buffer.
381 * Call DosQuerySysState.
382 * IF buffer overflow THEN retry calling it with larger buffers, until buffer size is 1MB.
383 * IF success THEN
384 * BEGIN
385 * Find record for this module.
386 * IF record found THEN allocate memory for object table and copy it. (paSections, cSections)
387 * END
388 * @status Completely implemented.
389 * @author knut st. osmundsen
390 */
391ULONG Win32Pe2LxImage::getSections()
392{
393 APIRET rc = NO_ERROR;
394
395 /*
396 * If Win32k.sys is installed we'll use it.
397 */
398 if (libWin32kInstalled())
399 {
400 ULONG cbQte = sizeof(QOTEBUFFER) + sizeof(QOTE)*20;
401 PQOTEBUFFER pQOte = (PQOTEBUFFER)malloc(sizeof(QOTEBUFFER) + sizeof(QOTE)*20);
402 if (pQOte != NULL)
403 {
404 /*
405 * Get the query OTEs for this module.
406 * If there is a buffer overflow we'll allocate more storage and retry.
407 */
408 rc = W32kQueryOTEs(hmod, pQOte, cbQte);
409 while (rc == ERROR_BUFFER_OVERFLOW && cbQte < 32000);
410 {
411 PVOID pvOld = pQOte;
412 cbQte += sizeof(QOTE) * 20;
413 pQOte = (PQOTEBUFFER)realloc(pQOte, cbQte);
414 if (pQOte == NULL)
415 {
416 free(pvOld);
417 return ERROR_NOT_ENOUGH_MEMORY;
418 }
419
420 rc = W32kQueryOTEs(hmod, pQOte, cbQte);
421 }
422
423 /*
424 * If successfully got the OTEs then allocate and set paSections structs.
425 */
426 if (rc == NO_ERROR)
427 {
428 /* Allocate memory for paSections */
429 paSections = (PSECTION)malloc(pQOte->cOTEs * sizeof(SECTION));
430 if (paSections != NULL)
431 {
432 /* objects -> section array */
433 for (int i = 0; i < pQOte->cOTEs; i++)
434 {
435 paSections[i].ulRVA = ~0UL;
436 paSections[i].cbVirtual = pQOte->aOTE[i].ote_size;
437 paSections[i].ulAddress = pQOte->aOTE[i].ote_base;
438 }
439 cSections = pQOte->cOTEs;
440 }
441 else
442 rc = ERROR_NOT_ENOUGH_MEMORY;
443 }
444 else
445 {
446 dprintf(("Win32Pe2LxImage::getSections: libW32kQueryOTEs failed with rc=%d."
447 " Falls back on the DosQuerySysState method.\n", rc));
448 }
449 }
450 else
451 { /* server error, no use in trying the fallback method. */
452 dprintf(("Win32Pe2LxImage::getSections: malloc failed\n"));
453 return ERROR_NOT_ENOUGH_MEMORY;
454 }
455
456 if (rc == NO_ERROR)
457 return rc;
458 }
459
460
461 /*
462 * Fallback method, using DosQuerySysState.
463 */
464 qsPtrRec_t * pPtrRec;
465 ULONG cbBuf = 65536;
466
467 pPtrRec = (qsPtrRec_t *)malloc(cbBuf);
468 if (pPtrRec != NULL)
469 {
470 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
471 while (cbBuf < 1024*1024 && rc == ERROR_BUFFER_OVERFLOW)
472 {
473 PVOID pv = pPtrRec;
474 cbBuf += 65536;
475 pPtrRec = (qsPtrRec_t *)realloc(pv, cbBuf);
476 if (pPtrRec != NULL)
477 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
478 else
479 {
480 rc = ERROR_NOT_ENOUGH_MEMORY;
481 free(pv);
482 }
483 }
484
485 if (rc == NO_ERROR)
486 {
487 qsLrec_t * pLrec = pPtrRec->pLibRec;
488 while (pLrec != NULL)
489 {
490 /*
491 * Bug detected in OS/2 FP13. Probably a problem which occurs
492 * in _LDRSysMteInfo when qsCheckCache is calle before writing
493 * object info. The result is that the cache flushed and the
494 * attempt of updating the qsLrec_t next and object pointer is
495 * not done. This used to work earlier and on Aurora AFAIK.
496 *
497 * The fix for this problem is to check if the pObjInfo is NULL
498 * while the number of objects isn't 0 and correct this. pNextRec
499 * will also be NULL at this time. This will be have to corrected
500 * before we exit the loop or moves to the next record.
501 * There is also a nasty alignment of the object info... Hope
502 * I got it right. (This aligment seems new to FP13.)
503 */
504 if (pLrec->pObjInfo == NULL /*&& pLrec->pNextRec == NULL*/ && pLrec->ctObj > 0)
505 {
506 pLrec->pObjInfo = (qsLObjrec_t*)(
507 (char*)pLrec
508 + ((sizeof(qsLrec_t) /* size of the lib record */
509 + pLrec->ctImpMod * sizeof(short) /* size of the array of imported modules */
510 + strlen((char*)pLrec->pName) + 1 /* size of the filename */
511 + 3) & ~3)); /* the size is align on 4 bytes boundrary */
512 pLrec->pNextRec = (qsLrec_t*)((char*)pLrec->pObjInfo
513 + sizeof(qsLObjrec_t) * pLrec->ctObj);
514 }
515 if (pLrec->hmte == hmod)
516 break;
517
518 /*
519 * Next record
520 */
521 pLrec = (qsLrec_t*)pLrec->pNextRec;
522 }
523
524
525 if (pLrec)
526 {
527 if (pLrec->pObjInfo != NULL)
528 {
529 /* Allocate memory for paSections */
530 paSections = (PSECTION)malloc(pLrec->ctObj*sizeof(SECTION));
531 if (paSections != NULL)
532 {
533 /* objects -> section array */
534 for (int i = 0; i < pLrec->ctObj; i++)
535 {
536 paSections[i].ulRVA = ~0UL;
537 paSections[i].cbVirtual = pLrec->pObjInfo[i].osize;
538 paSections[i].ulAddress = pLrec->pObjInfo[i].oaddr;
539 }
540 cSections = pLrec->ctObj;
541 }
542 else
543 rc = ERROR_NOT_ENOUGH_MEMORY;
544 }
545 else
546 {
547 rc = ERROR_BAD_EXE_FORMAT;
548 dprintf(("Win32Pe2LxImage::getSections: Error - no object table!\n"));
549 }
550 }
551 else
552 rc = ERROR_MOD_NOT_FOUND;
553 }
554 else
555 dprintf(("DosQuerySysState - failed with rc=%d (cbBuf=%d)\n", rc, cbBuf));
556
557 if (pPtrRec != NULL)
558 free(pPtrRec);
559 }
560 else
561 rc = ERROR_NOT_ENOUGH_MEMORY;
562
563 return rc;
564}
565
566
567/**
568 * Sets the ulRVA according to the original PE section table.
569 * @returns OS/2 errorcode. (NO_ERROR == success)
570 * @sketch DEBUG: Validate pNtHdrs
571 * Make pointer to start of PE section table.
572 * Set RVA for the header section.
573 * IF not all in one object exe? THEN
574 * Loop thru the sections in the PE section table.
575 * Note: due to the header section: PE section no. + 1 == LX object no.
576 * ELSE
577 * BEGIN
578 * (try) Reallocate paSections to NumberOfSections + 3.
579 * Loop thru the PE sections and make paSections from them.
580 * Add final Stack or TIBFix+Stack section if necessary.
581 * Resize header section.
582 * END
583 * @status completely implemented.
584 * @author knut st. osmundsen
585 * @remark Must not be called before pNtHdrs is set.
586 */
587ULONG Win32Pe2LxImage::setSectionRVAs()
588{
589 #if DEBUG
590 if (pNtHdrs == NULL)
591 {
592 DebugInt3();
593 return ERROR_INVALID_PARAMETER;
594 }
595 #endif
596
597 PIMAGE_SECTION_HEADER paPESections = (PIMAGE_SECTION_HEADER)
598 ((unsigned)pNtHdrs + sizeof(*pNtHdrs) +
599 (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY)
600 );
601
602 /* set RVA for the header section to 0UL. */
603 paSections[0].ulRVA = 0UL;
604
605 /* All in one object exe? */
606 if (pNtHdrs->FileHeader.NumberOfSections < cSections)
607 {
608 /* loop thru the other sections */
609 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
610 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
611 }
612 else
613 { /* all in one object */
614 /* (try) Reallocate paSections to NumberOfSections + 3. */
615 PVOID pv = realloc(paSections, sizeof(paSections[0]) * (pNtHdrs->FileHeader.NumberOfSections + 3));
616 if (pv != NULL)
617 {
618 paSections = (PSECTION)pv;
619
620 /* loop thru the PE sections */
621 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
622 {
623 if (paSections[0].cbVirtual < paPESections[i].VirtualAddress)
624 {
625 dprintf(("Win32Pe2LxImage::setSectionRVAs: mismatch between section table and all-in-one-object"
626 "paSections[0].cbVirtual %#x paPESections[i].VirtualAddress %#x\n",
627 paSections[0].cbVirtual, paPESections[i].VirtualAddress
628 ));
629 return ERROR_BAD_EXE_FORMAT;
630 }
631 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
632 paSections[i+1].cbVirtual = max(paPESections[i].Misc.VirtualSize, paPESections[i].SizeOfRawData);
633 paSections[i+1].ulAddress = paSections[0].ulAddress + paPESections[i].VirtualAddress;
634 }
635 cSections = pNtHdrs->FileHeader.NumberOfSections + 1;
636
637 /* add final Stack or TIBFix+Stack section if necessary */
638 if (paSections[0].cbVirtual > paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000))
639 {
640 paSections[i+1].ulRVA = ~0UL;
641 paSections[i+1].cbVirtual = paSections[0].cbVirtual - paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000);
642 paSections[i+1].ulAddress = paSections[i].ulAddress + ALIGN(paSections[i].cbVirtual, 0x1000);
643 i++;
644 cSections++;
645 }
646
647 /* resize header section */
648 paSections[0].cbVirtual = paSections[1].ulRVA; /*....*/
649 }
650 else
651 return ERROR_NOT_ENOUGH_MEMORY;
652 }
653
654 return NO_ERROR;
655}
656
657
658/**
659 * Frees memory used by this object.
660 * When an exception is to be thrown, this function is called first to clean up
661 * the object. Base class(es) are automatically clean up by theire destructor(s).
662 * @status completely implemented.
663 * @author knut st. osmundsen
664 */
665VOID Win32Pe2LxImage::cleanup()
666{
667 if (paSections != NULL)
668 {
669 free(paSections);
670 paSections = NULL;
671 cSections = 0;
672 }
673}
674
675
676/**
677 * Converts a RVA into a pointer.
678 * @returns Pointer matching the given RVA, NULL on error.
679 * @param ulRVA An address relative to the imagebase of the original PE image.
680 * If this is 0UL NULL is returned.
681 * @sketch DEBUG: validate state, paSections != NULL
682 * IF ulRVA is 0 THEN return NULL
683 * LOOP while more section left and ulRVA is not within section
684 * next section
685 * IF section matching ulRVA is not found THEN fail.
686 * return pointer matching RVA.
687 * @status completely implemented.
688 * @author knut st. osmundsen
689 * @remark Should not be called until getSections has returned successfully.
690 * RVA == 0 is ignored.
691 */
692PVOID Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA)
693{
694 int i;
695 #ifdef DEBUG
696 if (paSections == NULL)
697 return NULL;
698 #endif
699
700 if (ulRVA == 0UL)
701 return NULL;
702
703 i = 0;
704 while (i < cSections &&
705 !(paSections[i].ulRVA <= ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual > ulRVA)) /* ALIGN on page too? */
706 i++;
707
708 if (i >= cSections)
709 return NULL;
710
711 return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
712}
713
714
715/**
716 * Converts a RVA into a paSections index.
717 * @returns Index into paSections for the section containing the RVA.
718 * -1 on error.
719 * @param ulRVA An address relative to the imagebase of the original PE image.
720 * If this is 0UL -1 is returned.
721 * @sketch DEBUG: validate state, paSections != NULL
722 * IF ulRVA is 0 THEN return -1
723 * LOOP while more section left and ulRVA is not within section
724 * next section
725 * IF section matching ulRVA is found THEN return index ELSE fail.
726 * @status completely implemented.
727 * @author knut st. osmundsen
728 * @remark Should not be called until getSections has returned successfully.
729 * RVA == 0 is ignored.
730 */
731ULONG Win32Pe2LxImage::getSectionIndexFromRVA(ULONG ulRVA)
732{
733 int i;
734 #ifdef DEBUG
735 if (paSections == NULL)
736 return -1;
737 #endif
738
739 if (ulRVA == 0UL)
740 return -1;
741
742 i = 0;
743 while (i < cSections &&
744 !(paSections[i].ulRVA <= ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual > ulRVA)) /* ALIGN on page too? */
745 i++;
746
747 return i < cSections ? i : -1;
748}
749
750
751/**
752 * Gets pointer to an exported procedure by procedure name.
753 * @returns Address of exported procedure. 0UL if not found.
754 * @param name Exported procedure name.
755 * @status completely implemented.
756 * @author Sander van Leeuwen
757 * @remark
758 */
759ULONG Win32Pe2LxImage::getApi(char *name)
760{
761 APIRET rc;
762 ULONG ulApiAddr;
763
764 rc = DosQueryProcAddr(hmod, 0, name, (PFN *)&ulApiAddr);
765 return rc == NO_ERROR ? ulApiAddr : 0;
766}
767
768
769/**
770 * Gets pointer to an exported procedure by ordinal.
771 * @returns Pointer to an exported procedure. 0UL if not found.
772 * @param ordinal Export ordinal number.
773 * @status completely implemented.
774 * @author Sander van Leeuwen
775 * @remark FIXME:
776 * This function should be implemented for both Exe and Dll images!
777 * It could be done similar in both peldr image and pe2lx images by
778 * accessing PE structures.
779 */
780ULONG Win32Pe2LxImage::getApi(int ordinal)
781{
782 APIRET rc;
783 ULONG ulApiAddr;
784
785 rc = DosQueryProcAddr(hmod, ordinal, NULL, (PFN *)&ulApiAddr);
786
787 return rc == NO_ERROR ? ulApiAddr : 0;
788}
Note: See TracBrowser for help on using the repository browser.