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

Last change on this file since 9537 was 9537, checked in by sandervl, 23 years ago

Don't display message boxes for module load errors. Pass errors back to the PE loader.

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