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

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

Made corrections for Borland TLS. (Beyond Compare works now)

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