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

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

Optimizations for Win32k.sys.

File size: 29.1 KB
Line 
1/* $Id: winimagepe2lx.cpp,v 1.14 2000-09-02 21:14:50 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{
151 setFullPath(szFileName);
152}
153
154
155/**
156 * Free memory associated with this object.
157 * @status completely implemented.
158 * @author knut st. osmundsen, Sander van Leeuwen
159 */
160Win32Pe2LxImage::~Win32Pe2LxImage()
161{
162 cleanup();
163}
164
165
166/**
167 * Initiates the object.
168 * Must be called immediately after the object construction.
169 * @returns Success indicator, TRUE == success; FALSE = failure.
170 * @sketch Get section placement and sizes for this module. (paSections, cSections)
171 * Verify that there is at least one section - the header section.
172 * Locate the NT headers.
173 * Set pNtHdrs pointer.
174 * Validate the NT headers.
175 * Read the PE section table the set the RVAs in paSections.
176 * Locate and set the entrypoint.
177 * Locate the resource directory (if any). (pResRootDir, ulRVAResourceSection)
178 * TLS - FIXME!
179 * @status completely implemented.
180 * @author knut st. osmundsen
181 * @remark Object must be destroyed if failure!
182 */
183BOOL Win32Pe2LxImage::init()
184{
185 APIRET rc;
186
187 /* Get section placement and sizes for this module. (paSections, cSections) */
188 rc = getSections();
189 if (rc != NO_ERROR)
190 {
191 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: error - getSection failed with rc=%d\n",
192 rc));
193 return FALSE;
194 }
195
196 /* Verify that there is at least one section - the header section. */
197 if (cSections < 1)
198 {
199 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: no header section, cSections is 0\n"));
200 return FALSE;
201 }
202
203 /* Locate the NT headers. */
204 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)paSections[0].ulAddress;
205 if ((pDosHdr->e_magic != IMAGE_DOS_SIGNATURE
206 || pDosHdr->e_lfanew < sizeof(IMAGE_DOS_HEADER) /* Larger than 64 bytes */
207 || pDosHdr->e_lfanew > 0x04000000UL /* or less that 64MB. */
208 )
209 && !*(PDWORD)paSections[0].ulAddress == IMAGE_NT_SIGNATURE
210 )
211 {
212 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
213 return FALSE;
214 }
215
216 /* Set pNtHdrs pointer. */
217 if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
218 pNtHdrs = (PIMAGE_NT_HEADERS)(paSections[0].ulAddress + pDosHdr->e_lfanew);
219 else
220 pNtHdrs = (PIMAGE_NT_HEADERS)paSections[0].ulAddress;
221
222 /* Validate the NT headers. */
223 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE
224 || pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC
225 || pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386
226 || (cSections != 1 /* all in one object */
227 && pNtHdrs->FileHeader.NumberOfSections
228 > cSections - 1 - (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ? 0 : 1) /* hdr section and stack */
229 )
230 /* TODO: add more tests? */
231 )
232 {
233 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
234 return FALSE;
235 }
236
237 /* set RVAs */
238 rc = setSectionRVAs();
239 if (rc != NO_ERROR)
240 {
241 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: setSectionRVAs failed with rc=%d\n", rc));
242 return FALSE;
243 }
244
245 /* Locate and set the entrypoint. */
246 setEntryPoint((ULONG)getPointerFromRVA(pNtHdrs->OptionalHeader.AddressOfEntryPoint));
247 if (entryPoint == 0UL &&
248 (pNtHdrs->OptionalHeader.AddressOfEntryPoint != NULL /* getPointerFromRVA failed... */
249 || !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)) /* EXEs must have and entry point! */
250 )
251 {
252 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: entrypoint is incorrect, AddrOfEP=0x%08x, entryPoint=0x%08x\n",
253 pNtHdrs->OptionalHeader.AddressOfEntryPoint, entryPoint));
254 return FALSE;
255 }
256
257 /* Locate the resource directory (if any) */
258 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
259 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
260 {
261 ulRVAResourceSection = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
262 pResRootDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(ulRVAResourceSection);
263 /* _temporary_ fix:
264 * We'll have to make the resource section writable.
265 * And we'll have to make the pages before it readable.
266 */
267 ULONG iSection = getSectionIndexFromRVA(ulRVAResourceSection);
268 if (iSection >= 0)
269 {
270 rc = DosSetMem((PVOID)paSections[iSection].ulAddress, paSections[iSection].cbVirtual, PAG_WRITE | PAG_READ);
271
272 ULONG ulAddr = paSections[iSection].ulAddress - 0x10000; //64KB
273 while (ulAddr < paSections[iSection].ulAddress)
274 {
275 ULONG fl = ~0UL;
276 ULONG cb = ~0UL;
277 rc = DosQueryMem((PVOID)ulAddr, &cb, &fl);
278 if (rc == NO_ERROR)
279 {
280 if (fl & PAG_GUARD)
281 rc = -1;
282 else if (fl & PAG_COMMIT)
283 fl &= ~(PAG_COMMIT);
284 else
285 fl |= PAG_COMMIT;
286 cb = (cb + 0xfffUL) & ~0xfffUL;
287 }
288 else
289 {
290 fl = PAG_COMMIT;
291 cb = 0x1000;
292 }
293 fl &= PAG_READ | PAG_COMMIT | PAG_WRITE | PAG_GUARD;
294 fl |= PAG_READ;
295 if (cb > paSections[iSection].ulAddress - ulAddr)
296 cb = paSections[iSection].ulAddress - ulAddr;
297 if (rc == NO_ERROR)
298 rc = DosSetMem((PVOID)ulAddr, cb, fl);
299
300 ulAddr += cb;
301 }
302 }
303 }
304
305 /* TLS - Thread Local Storage */
306 if (pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0UL
307 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0UL)
308 {
309 PIMAGE_TLS_DIRECTORY pTLSDir;
310 pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
311 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
312 VirtualAddress);
313
314 if (pTLSDir != NULL)
315 {
316 PVOID pv;
317 ULONG ulBorlandRVAFix = 0UL;
318
319 pv = getPointerFromRVA(pTLSDir->StartAddressOfRawData);
320 /*
321 * Borland seems to have problems getting things right...
322 * Needs to subtract image base to make the TLSDir "RVA"s real
323 * RVAs before converting them to pointers.
324 */
325 if ((pv == NULL || pTLSDir->StartAddressOfRawData == 0UL)
326 && pTLSDir->StartAddressOfRawData > this->pNtHdrs->OptionalHeader.ImageBase)
327 {
328 ulBorlandRVAFix = this->pNtHdrs->OptionalHeader.ImageBase;
329 pv = getPointerFromRVA(pTLSDir->StartAddressOfRawData - ulBorlandRVAFix);
330 }
331 if (pv == NULL || pTLSDir->StartAddressOfRawData == 0UL)
332 {
333 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS StartAddressOfRawData - %#8x.\n",
334 pTLSDir->StartAddressOfRawData));
335 return FALSE;
336 }
337 setTLSAddress(pv);
338 setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
339 setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
340 pv = getPointerFromRVA((ULONG)pTLSDir->AddressOfIndex - ulBorlandRVAFix);
341 if (pv == NULL)
342 {
343 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOffIndex - %#8x.\n",
344 pTLSDir->AddressOfIndex));
345 return FALSE;
346 }
347 setTLSIndexAddr((LPDWORD)pv);
348 if (pTLSDir->AddressOfCallBacks != 0)
349 {
350 pv = getPointerFromRVA((ULONG)pTLSDir->AddressOfCallBacks - ulBorlandRVAFix);
351 if (pv == NULL)
352 {
353 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOffIndex - %#8x.\n",
354 pTLSDir->AddressOfIndex));
355 return FALSE;
356 }
357 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
358 }
359 }
360 else
361 {
362 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
363 pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
364 return FALSE;
365 }
366 }
367 return TRUE;
368}
369
370
371
372/**
373 * Gets the object layout for this module. Creates the paSections array.
374 * @returns OS2 errorcode. (NO_ERROR == success)
375 * @sketch Allocate output buffer.
376 * Call DosQuerySysState.
377 * IF buffer overflow THEN retry calling it with larger buffers, until buffer size is 1MB.
378 * IF success THEN
379 * BEGIN
380 * Find record for this module.
381 * IF record found THEN allocate memory for object table and copy it. (paSections, cSections)
382 * END
383 * @status Completely implemented.
384 * @author knut st. osmundsen
385 */
386ULONG Win32Pe2LxImage::getSections()
387{
388 APIRET rc = NO_ERROR;
389
390 /*
391 * If Win32k.sys is installed we'll use it.
392 */
393 if (libWin32kInstalled())
394 {
395 ULONG cbQte = sizeof(QOTEBUFFER) + sizeof(QOTE)*20;
396 PQOTEBUFFER pQOte = (PQOTEBUFFER)malloc(sizeof(QOTEBUFFER) + sizeof(QOTE)*20);
397 if (pQOte != NULL)
398 {
399 /*
400 * Get the query OTEs for this module.
401 * If there is a buffer overflow we'll allocate more storage and retry.
402 */
403 rc = W32kQueryOTEs(hinstance, pQOte, cbQte);
404 while (rc == ERROR_BUFFER_OVERFLOW && cbQte < 32000);
405 {
406 PVOID pvOld = pQOte;
407 cbQte += sizeof(QOTE) * 20;
408 pQOte = (PQOTEBUFFER)realloc(pQOte, cbQte);
409 if (pQOte == NULL)
410 {
411 free(pvOld);
412 return ERROR_NOT_ENOUGH_MEMORY;
413 }
414
415 rc = W32kQueryOTEs(hinstance, pQOte, cbQte);
416 }
417
418 /*
419 * If successfully got the OTEs then allocate and set paSections structs.
420 */
421 if (rc == NO_ERROR)
422 {
423 /* Allocate memory for paSections */
424 paSections = (PSECTION)malloc(pQOte->cOTEs * sizeof(SECTION));
425 if (paSections != NULL)
426 {
427 /* objects -> section array */
428 for (int i = 0; i < pQOte->cOTEs; i++)
429 {
430 paSections[i].ulRVA = ~0UL;
431 paSections[i].cbVirtual = pQOte->aOTE[i].ote_size;
432 paSections[i].ulAddress = pQOte->aOTE[i].ote_base;
433 }
434 cSections = pQOte->cOTEs;
435 }
436 else
437 rc = ERROR_NOT_ENOUGH_MEMORY;
438 }
439 else
440 {
441 dprintf(("Win32Pe2LxImage::getSections: libW32kQueryOTEs failed with rc=%d."
442 " Falls back on the DosQuerySysState method.\n", rc));
443 }
444 }
445 else
446 { /* server error, no use in trying the fallback method. */
447 dprintf(("Win32Pe2LxImage::getSections: malloc failed\n"));
448 return ERROR_NOT_ENOUGH_MEMORY;
449 }
450
451 if (rc == NO_ERROR)
452 return rc;
453 }
454
455
456 /*
457 * Fallback method, using DosQuerySysState.
458 */
459 qsPtrRec_t * pPtrRec;
460 ULONG cbBuf = 65536;
461
462 pPtrRec = (qsPtrRec_t *)malloc(cbBuf);
463 if (pPtrRec != NULL)
464 {
465 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
466 while (cbBuf < 1024*1024 && rc == ERROR_BUFFER_OVERFLOW)
467 {
468 PVOID pv = pPtrRec;
469 cbBuf += 65536;
470 pPtrRec = (qsPtrRec_t *)realloc(pv, cbBuf);
471 if (pPtrRec != NULL)
472 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
473 else
474 {
475 rc = ERROR_NOT_ENOUGH_MEMORY;
476 free(pv);
477 }
478 }
479
480 if (rc == NO_ERROR)
481 {
482 qsLrec_t * pLrec = pPtrRec->pLibRec;
483 while (pLrec != NULL)
484 {
485 /*
486 * Bug detected in OS/2 FP13. Probably a problem which occurs
487 * in _LDRSysMteInfo when qsCheckCache is calle before writing
488 * object info. The result is that the cache flushed and the
489 * attempt of updating the qsLrec_t next and object pointer is
490 * not done. This used to work earlier and on Aurora AFAIK.
491 *
492 * The fix for this problem is to check if the pObjInfo is NULL
493 * while the number of objects isn't 0 and correct this. pNextRec
494 * will also be NULL at this time. This will be have to corrected
495 * before we exit the loop or moves to the next record.
496 * There is also a nasty alignment of the object info... Hope
497 * I got it right. (This aligment seems new to FP13.)
498 */
499 if (pLrec->pObjInfo == NULL /*&& pLrec->pNextRec == NULL*/ && pLrec->ctObj > 0)
500 {
501 pLrec->pObjInfo = (qsLObjrec_t*)(
502 (char*)pLrec
503 + ((sizeof(qsLrec_t) /* size of the lib record */
504 + pLrec->ctImpMod * sizeof(short) /* size of the array of imported modules */
505 + strlen((char*)pLrec->pName) + 1 /* size of the filename */
506 + 3) & ~3)); /* the size is align on 4 bytes boundrary */
507 pLrec->pNextRec = (qsLrec_t*)((char*)pLrec->pObjInfo
508 + sizeof(qsLObjrec_t) * pLrec->ctObj);
509 }
510 if (pLrec->hmte == hinstance)
511 break;
512
513 /*
514 * Next record
515 */
516 pLrec = (qsLrec_t*)pLrec->pNextRec;
517 }
518
519
520 if (pLrec)
521 {
522 if (pLrec->pObjInfo != NULL)
523 {
524 /* Allocate memory for paSections */
525 paSections = (PSECTION)malloc(pLrec->ctObj*sizeof(SECTION));
526 if (paSections != NULL)
527 {
528 /* objects -> section array */
529 for (int i = 0; i < pLrec->ctObj; i++)
530 {
531 paSections[i].ulRVA = ~0UL;
532 paSections[i].cbVirtual = pLrec->pObjInfo[i].osize;
533 paSections[i].ulAddress = pLrec->pObjInfo[i].oaddr;
534 }
535 cSections = pLrec->ctObj;
536 }
537 else
538 rc = ERROR_NOT_ENOUGH_MEMORY;
539 }
540 else
541 {
542 rc = ERROR_BAD_EXE_FORMAT;
543 dprintf(("Win32Pe2LxImage::getSections: Error - no object table!\n"));
544 }
545 }
546 else
547 rc = ERROR_MOD_NOT_FOUND;
548 }
549 else
550 dprintf(("DosQuerySysState - failed with rc=%d (cbBuf=%d)\n", rc, cbBuf));
551
552 if (pPtrRec != NULL)
553 free(pPtrRec);
554 }
555 else
556 rc = ERROR_NOT_ENOUGH_MEMORY;
557
558 return rc;
559}
560
561
562/**
563 * Sets the ulRVA according to the original PE section table.
564 * @returns OS/2 errorcode. (NO_ERROR == success)
565 * @sketch DEBUG: Validate pNtHdrs
566 * Make pointer to start of PE section table.
567 * Set RVA for the header section.
568 * IF not all in one object exe? THEN
569 * Loop thru the sections in the PE section table.
570 * Note: due to the header section: PE section no. + 1 == LX object no.
571 * ELSE
572 * BEGIN
573 * (try) Reallocate paSections to NumberOfSections + 3.
574 * Loop thru the PE sections and make paSections from them.
575 * Add final Stack or TIBFix+Stack section if necessary.
576 * Resize header section.
577 * END
578 * @status completely implemented.
579 * @author knut st. osmundsen
580 * @remark Must not be called before pNtHdrs is set.
581 */
582ULONG Win32Pe2LxImage::setSectionRVAs()
583{
584 #if DEBUG
585 if (pNtHdrs == NULL)
586 {
587 DebugInt3();
588 return ERROR_INVALID_PARAMETER;
589 }
590 #endif
591
592 PIMAGE_SECTION_HEADER paPESections = (PIMAGE_SECTION_HEADER)
593 ((unsigned)pNtHdrs + sizeof(*pNtHdrs) +
594 (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY)
595 );
596
597 /* set RVA for the header section to 0UL. */
598 paSections[0].ulRVA = 0UL;
599
600 /* All in one object exe? */
601 if (pNtHdrs->FileHeader.NumberOfSections < cSections)
602 {
603 /* loop thru the other sections */
604 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
605 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
606 }
607 else
608 { /* all in one object */
609 /* (try) Reallocate paSections to NumberOfSections + 3. */
610 PVOID pv = realloc(paSections, sizeof(paSections[0]) * (pNtHdrs->FileHeader.NumberOfSections + 3));
611 if (pv != NULL)
612 {
613 paSections = (PSECTION)pv;
614
615 /* loop thru the PE sections */
616 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
617 {
618 if (paSections[0].cbVirtual < paPESections[i].VirtualAddress)
619 {
620 dprintf(("Win32Pe2LxImage::setSectionRVAs: mismatch between section table and all-in-one-object"
621 "paSections[0].cbVirtual %#x paPESections[i].VirtualAddress %#x\n",
622 paSections[0].cbVirtual, paPESections[i].VirtualAddress
623 ));
624 return ERROR_BAD_EXE_FORMAT;
625 }
626 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
627 paSections[i+1].cbVirtual = max(paPESections[i].Misc.VirtualSize, paPESections[i].SizeOfRawData);
628 paSections[i+1].ulAddress = paSections[0].ulAddress + paPESections[i].VirtualAddress;
629 }
630 cSections = pNtHdrs->FileHeader.NumberOfSections + 1;
631
632 /* add final Stack or TIBFix+Stack section if necessary */
633 if (paSections[0].cbVirtual > paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000))
634 {
635 paSections[i+1].ulRVA = ~0UL;
636 paSections[i+1].cbVirtual = paSections[0].cbVirtual - paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000);
637 paSections[i+1].ulAddress = paSections[i].ulAddress + ALIGN(paSections[i].cbVirtual, 0x1000);
638 i++;
639 cSections++;
640 }
641
642 /* resize header section */
643 paSections[0].cbVirtual = paSections[1].ulRVA; /*....*/
644 }
645 else
646 return ERROR_NOT_ENOUGH_MEMORY;
647 }
648
649 return NO_ERROR;
650}
651
652
653/**
654 * Frees memory used by this object.
655 * When an exception is to be thrown, this function is called first to clean up
656 * the object. Base class(es) are automatically clean up by theire destructor(s).
657 * @status completely implemented.
658 * @author knut st. osmundsen
659 */
660VOID Win32Pe2LxImage::cleanup()
661{
662 if (paSections != NULL)
663 {
664 free(paSections);
665 paSections = NULL;
666 cSections = 0;
667 }
668}
669
670
671/**
672 * Converts a RVA into a pointer.
673 * @returns Pointer matching the given RVA, NULL on error.
674 * @param ulRVA An address relative to the imagebase of the original PE image.
675 * If this is 0UL NULL is returned.
676 * @sketch DEBUG: validate state, paSections != NULL
677 * IF ulRVA is 0 THEN return NULL
678 * LOOP while more section left and ulRVA is not within section
679 * next section
680 * IF section matching ulRVA is not found THEN fail.
681 * return pointer matching RVA.
682 * @status completely implemented.
683 * @author knut st. osmundsen
684 * @remark Should not be called until getSections has returned successfully.
685 * RVA == 0 is ignored.
686 */
687PVOID Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA)
688{
689 int i;
690 #ifdef DEBUG
691 if (paSections == NULL)
692 return NULL;
693 #endif
694
695 if (ulRVA == 0UL)
696 return NULL;
697
698 i = 0;
699 while (i < cSections &&
700 !(paSections[i].ulRVA <= ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual > ulRVA)) /* ALIGN on page too? */
701 i++;
702
703 if (i >= cSections)
704 return NULL;
705
706 return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
707}
708
709
710/**
711 * Converts a RVA into a paSections index.
712 * @returns Index into paSections for the section containing the RVA.
713 * -1 on error.
714 * @param ulRVA An address relative to the imagebase of the original PE image.
715 * If this is 0UL -1 is returned.
716 * @sketch DEBUG: validate state, paSections != NULL
717 * IF ulRVA is 0 THEN return -1
718 * LOOP while more section left and ulRVA is not within section
719 * next section
720 * IF section matching ulRVA is found THEN return index ELSE fail.
721 * @status completely implemented.
722 * @author knut st. osmundsen
723 * @remark Should not be called until getSections has returned successfully.
724 * RVA == 0 is ignored.
725 */
726ULONG Win32Pe2LxImage::getSectionIndexFromRVA(ULONG ulRVA)
727{
728 int i;
729 #ifdef DEBUG
730 if (paSections == NULL)
731 return -1;
732 #endif
733
734 if (ulRVA == 0UL)
735 return -1;
736
737 i = 0;
738 while (i < cSections &&
739 !(paSections[i].ulRVA <= ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual > ulRVA)) /* ALIGN on page too? */
740 i++;
741
742 return i < cSections ? i : -1;
743}
744
745
746/**
747 * Gets pointer to an exported procedure by procedure name.
748 * @returns Address of exported procedure. 0UL if not found.
749 * @param name Exported procedure name.
750 * @status completely implemented.
751 * @author Sander van Leeuwen
752 * @remark
753 */
754ULONG Win32Pe2LxImage::getApi(char *name)
755{
756 APIRET rc;
757 ULONG ulApiAddr;
758
759 rc = DosQueryProcAddr(hinstance, 0, name, (PFN *)&ulApiAddr);
760 return rc == NO_ERROR ? ulApiAddr : 0;
761}
762
763
764/**
765 * Gets pointer to an exported procedure by ordinal.
766 * @returns Pointer to an exported procedure. 0UL if not found.
767 * @param ordinal Export ordinal number.
768 * @status completely implemented.
769 * @author Sander van Leeuwen
770 * @remark FIXME:
771 * This function should be implemented for both Exe and Dll images!
772 * It could be done similar in both peldr image and pe2lx images by
773 * accessing PE structures.
774 */
775ULONG Win32Pe2LxImage::getApi(int ordinal)
776{
777 APIRET rc;
778 ULONG ulApiAddr;
779
780 rc = DosQueryProcAddr(hinstance, ordinal, NULL, (PFN *)&ulApiAddr);
781
782 return rc == NO_ERROR ? ulApiAddr : 0;
783}
Note: See TracBrowser for help on using the repository browser.