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

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 43.2 KB
Line 
1/* $Id: winimagepe2lx.cpp,v 1.22 2004-01-15 10:39:12 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 "windllbase.h"
38#include "winexebase.h"
39#include "winimagepe2lx.h"
40#include "winimagepeldr.h"
41#include "windllpeldr.h"
42#include "winimagelx.h"
43#include "windlllx.h"
44#include "Win32k.h"
45
46#define DBG_LOCALLOG DBG_winimagepe2lx
47#include "dbglocal.h"
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52#ifndef QS_MTE
53 /* From OS/2 Toolkit v4.5 (BSEDOS.H) */
54
55 /* Global Record structure
56 * Holds all global system information. Placed first in user buffer
57 */
58 typedef struct qsGrec_s { /* qsGrec */
59 ULONG cThrds;
60 ULONG c32SSem;
61 ULONG cMFTNodes;
62 }qsGrec_t;
63
64 /*
65 * System wide MTE information
66 * ________________________________
67 * | pNextRec |----|
68 * |-------------------------------| |
69 * | hmte | |
70 * |-------------------------------| |
71 * | ctImpMod | |
72 * |-------------------------------| |
73 * | ctObj | |
74 * |-------------------------------| |
75 * | pObjInfo |----|----------|
76 * |-------------------------------| | |
77 * | pName |----|----| |
78 * |-------------------------------| | | |
79 * | imported module handles | | | |
80 * | . | | | |
81 * | . | | | |
82 * | . | | | |
83 * |-------------------------------| <--|----| |
84 * | "pathname" | | |
85 * |-------------------------------| <--|----------|
86 * | Object records | |
87 * | (if requested) | |
88 * |_______________________________| |
89 * <-----
90 * NOTE that if the level bit is set to QS_MTE, the base Lib record will be followed
91 * by a series of object records (qsLObj_t); one for each object of the
92 * module.
93 */
94
95 typedef struct qsLObjrec_s { /* qsLOrec */
96 ULONG oaddr; /* object address */
97 ULONG osize; /* object size */
98 ULONG oflags; /* object flags */
99 } qsLObjrec_t;
100
101 typedef struct qsLrec_s { /* qsLrec */
102 void FAR *pNextRec; /* pointer to next record in buffer */
103 USHORT hmte; /* handle for this mte */
104 USHORT fFlat; /* true if 32 bit module */
105 ULONG ctImpMod; /* # of imported modules in table */
106 ULONG ctObj; /* # of objects in module (mte_objcnt)*/
107 qsLObjrec_t FAR *pObjInfo; /* pointer to per object info if any */
108 UCHAR FAR *pName; /* -> name string following struc */
109 } qsLrec_t;
110
111
112
113 /* Pointer Record Structure
114 * This structure is the first in the user buffer.
115 * It contains pointers to heads of record types that are loaded
116 * into the buffer.
117 */
118
119 typedef struct qsPtrRec_s { /* qsPRec */
120 qsGrec_t *pGlobalRec;
121 void *pProcRec; /* ptr to head of process records */
122 void *p16SemRec; /* ptr to head of 16 bit sem recds */
123 void *p32SemRec; /* ptr to head of 32 bit sem recds */
124 void *pMemRec; /* ptr to head of shared mem recs */
125 qsLrec_t *pLibRec; /* ptr to head of mte records */
126 void *pShrMemRec; /* ptr to head of shared mem records */
127 void *pFSRec; /* ptr to head of file sys records */
128 } qsPtrRec_t;
129
130#else
131 #if defined(QS_MODVER) && defined(QS_DCE_AUTORESET) && defined(LIBPATHSTRICT) /* hope these didn't exists in the other toolkits */
132 /*
133 * Workaround for the 4.5.1+ toolkits.
134 */
135 #define qsPtrRec_t QSPTRREC
136 #define qsLrec_t QSLREC
137 #define qsLObjrec_t QSLOBJREC
138 #define qsGrec_t QSGREC
139 #endif
140#endif
141
142
143/*******************************************************************************
144* External Functions *
145*******************************************************************************/
146#ifndef QS_MTE
147 /* from OS/2 Toolkit v4.5 */
148
149 APIRET APIENTRY DosQuerySysState(ULONG EntityList, ULONG EntityLevel, PID pid,
150 TID tid, PVOID pDataBuf, ULONG cbBuf);
151 #define QS_MTE 0x0004
152#endif
153
154
155
156/**
157 * Constructor - creates an pe2lx image object from a module handle to a pe2lx module.
158 * @param hinstance OS/2 module handle.
159 * @param fWin32k TRUE: Win32k module.
160 * FALSE: Pe2Lx module.
161 * @status partially implemented.
162 * @author knut st. osmundsen, Sander van Leeuwen
163 */
164Win32Pe2LxImage::Win32Pe2LxImage(HINSTANCE hinstance, BOOL fWin32k)
165 : Win32ImageBase(hinstance),
166 paSections(NULL), cSections(0), pNtHdrs(NULL), fWin32k(fWin32k),
167 hmod(hinstance)
168{
169 setFullPath(szFileName);
170}
171
172
173/**
174 * Free memory associated with this object.
175 * @status completely implemented.
176 * @author knut st. osmundsen, Sander van Leeuwen
177 */
178Win32Pe2LxImage::~Win32Pe2LxImage()
179{
180 cleanup();
181}
182
183
184/**
185 * Initiates the object.
186 * Must be called immediately after the object construction.
187 * @returns Error value, LDRERROR_SUCCESS == success; failure otherwise.
188 * @sketch Get section placement and sizes for this module. (paSections, cSections)
189 * Verify that there is at least one section - the header section.
190 * Locate the NT headers.
191 * Set pNtHdrs pointer.
192 * Validate the NT headers.
193 * Read the PE section table the set the RVAs in paSections.
194 * Set instance handle to address of header.
195 * Locate and set the entrypoint.
196 * Locate the resource directory (if any). (pResRootDir, ulRVAResourceSection)
197 * TLS - FIXME!
198 * @status completely implemented.
199 * @author knut st. osmundsen
200 * @remark Object must be destroyed if failure!
201 */
202DWORD Win32Pe2LxImage::init()
203{
204 APIRET rc;
205
206 /* Get section placement and sizes for this module. (paSections, cSections) */
207 rc = getSections();
208 if (rc != NO_ERROR)
209 {
210 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: error - getSection failed with rc=%d\n",
211 rc));
212 return LDRERROR_INVALID_HEADER;
213 }
214
215 /* Verify that there is at least one section - the header section. */
216 if (cSections < 1)
217 {
218 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: no header section, cSections is 0\n"));
219 return LDRERROR_INVALID_HEADER;
220 }
221
222 /* Locate the NT headers. */
223 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)paSections[0].ulAddress;
224 if ((pDosHdr->e_magic != IMAGE_DOS_SIGNATURE
225 || pDosHdr->e_lfanew < sizeof(IMAGE_DOS_HEADER) /* Larger than 64 bytes */
226 || pDosHdr->e_lfanew > 0x04000000UL /* or less that 64MB. */
227 )
228 && !*(PDWORD)paSections[0].ulAddress == IMAGE_NT_SIGNATURE
229 )
230 {
231 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
232 return LDRERROR_INVALID_HEADER;
233 }
234
235 /* Set pNtHdrs pointer. */
236 if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
237 pNtHdrs = (PIMAGE_NT_HEADERS)(paSections[0].ulAddress + pDosHdr->e_lfanew);
238 else
239 pNtHdrs = (PIMAGE_NT_HEADERS)paSections[0].ulAddress;
240
241 /* Validate the NT headers. */
242 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE
243 || pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC
244 || pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386
245 || (cSections != 1 /* all in one object */
246 && pNtHdrs->FileHeader.NumberOfSections
247 > cSections - 1 - (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ? 0 : 1) /* hdr section and stack */
248 )
249 /* TODO: add more tests? */
250 )
251 {
252 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
253 return LDRERROR_INVALID_HEADER;
254 }
255
256 /* set RVAs */
257 rc = setSectionRVAs();
258 if (rc != NO_ERROR)
259 {
260 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: setSectionRVAs failed with rc=%d\n", rc));
261 return LDRERROR_INVALID_HEADER;
262 }
263
264 /* Set instance handle to address of header. */
265 hinstance = (HINSTANCE)paSections[0].ulAddress;
266
267 /* Set poh & pExportDir (base class stuff) */
268 poh = &pNtHdrs->OptionalHeader;
269 pExportDir = (PIMAGE_EXPORT_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
270
271 /* Locate and set the entrypoint. */
272 setEntryPoint((ULONG)getPointerFromRVA(pNtHdrs->OptionalHeader.AddressOfEntryPoint));
273 if (entryPoint == 0UL &&
274 (pNtHdrs->OptionalHeader.AddressOfEntryPoint != NULL /* getPointerFromRVA failed... */
275 || !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)) /* EXEs must have and entry point! */
276 )
277 {
278 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: entrypoint is incorrect, AddrOfEP=0x%08x, entryPoint=0x%08x\n",
279 pNtHdrs->OptionalHeader.AddressOfEntryPoint, entryPoint));
280 return LDRERROR_NO_ENTRYPOINT;
281 }
282
283 /* Locate the resource directory (if any) */
284 rc = doResources();
285 if (rc)
286 return rc;
287
288 /*
289 * TLS - Thread Local Storage
290 */
291 rc = doTLS();
292 if (rc)
293 return rc;
294
295
296 /*
297 * Process imports.
298 */
299 rc = doImports();
300 if (rc)
301 return rc;
302
303 return LDRERROR_SUCCESS;
304}
305
306
307/**
308 * Gets the object layout for this module. Creates the paSections array.
309 * @returns OS2 errorcode. (NO_ERROR == success)
310 * @sketch Allocate output buffer.
311 * Call DosQuerySysState.
312 * IF buffer overflow THEN retry calling it with larger buffers, until buffer size is 1MB.
313 * IF success THEN
314 * BEGIN
315 * Find record for this module.
316 * IF record found THEN allocate memory for object table and copy it. (paSections, cSections)
317 * END
318 * @status Completely implemented.
319 * @author knut st. osmundsen
320 */
321ULONG Win32Pe2LxImage::getSections()
322{
323 APIRET rc = NO_ERROR;
324
325 /*
326 * If Win32k.sys is installed we'll use it.
327 */
328 if (libWin32kInstalled())
329 {
330 ULONG cbQte = sizeof(QOTEBUFFER) + sizeof(QOTE)*20;
331 PQOTEBUFFER pQOte = (PQOTEBUFFER)malloc(sizeof(QOTEBUFFER) + sizeof(QOTE)*20);
332 if (pQOte != NULL)
333 {
334 /*
335 * Get the query OTEs for this module.
336 * If there is a buffer overflow we'll allocate more storage and retry.
337 */
338 rc = W32kQueryOTEs(hmod, pQOte, cbQte);
339 while (rc == ERROR_BUFFER_OVERFLOW && cbQte < 32000);
340 {
341 PVOID pvOld = pQOte;
342 cbQte += sizeof(QOTE) * 20;
343 pQOte = (PQOTEBUFFER)realloc(pQOte, cbQte);
344 if (pQOte == NULL)
345 {
346 free(pvOld);
347 return ERROR_NOT_ENOUGH_MEMORY;
348 }
349
350 rc = W32kQueryOTEs(hmod, pQOte, cbQte);
351 }
352
353 /*
354 * If successfully got the OTEs then allocate and set paSections structs.
355 */
356 if (rc == NO_ERROR)
357 {
358 /* Allocate memory for paSections */
359 paSections = (PSECTION)malloc(pQOte->cOTEs * sizeof(SECTION));
360 if (paSections != NULL)
361 {
362 /* objects -> section array */
363 for (int i = 0; i < pQOte->cOTEs; i++)
364 {
365 paSections[i].ulRVA = ~0UL;
366 paSections[i].cbVirtual = pQOte->aOTE[i].ote_size;
367 paSections[i].ulAddress = pQOte->aOTE[i].ote_base;
368 }
369 cSections = pQOte->cOTEs;
370 }
371 else
372 rc = ERROR_NOT_ENOUGH_MEMORY;
373 }
374 else
375 {
376 dprintf(("Win32Pe2LxImage::getSections: libW32kQueryOTEs failed with rc=%d."
377 " Falls back on the DosQuerySysState method.\n", rc));
378 }
379 }
380 else
381 { /* server error, no use in trying the fallback method. */
382 dprintf(("Win32Pe2LxImage::getSections: malloc failed\n"));
383 return ERROR_NOT_ENOUGH_MEMORY;
384 }
385
386 if (rc == NO_ERROR)
387 return rc;
388 }
389
390
391 /*
392 * Fallback method, using DosQuerySysState.
393 */
394 qsPtrRec_t * pPtrRec;
395 ULONG cbBuf = 65536;
396
397 pPtrRec = (qsPtrRec_t *)malloc(cbBuf);
398 if (pPtrRec != NULL)
399 {
400 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
401 while (cbBuf < 1024*1024 && rc == ERROR_BUFFER_OVERFLOW)
402 {
403 PVOID pv = pPtrRec;
404 cbBuf += 65536;
405 pPtrRec = (qsPtrRec_t *)realloc(pv, cbBuf);
406 if (pPtrRec != NULL)
407 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
408 else
409 {
410 rc = ERROR_NOT_ENOUGH_MEMORY;
411 free(pv);
412 }
413 }
414
415 if (rc == NO_ERROR)
416 {
417 qsLrec_t * pLrec = pPtrRec->pLibRec;
418 while (pLrec != NULL)
419 {
420 /*
421 * Bug detected in OS/2 FP13. Probably a problem which occurs
422 * in _LDRSysMteInfo when qsCheckCache is calle before writing
423 * object info. The result is that the cache flushed and the
424 * attempt of updating the qsLrec_t next and object pointer is
425 * not done. This used to work earlier and on Aurora AFAIK.
426 *
427 * The fix for this problem is to check if the pObjInfo is NULL
428 * while the number of objects isn't 0 and correct this. pNextRec
429 * will also be NULL at this time. This will be have to corrected
430 * before we exit the loop or moves to the next record.
431 * There is also a nasty alignment of the object info... Hope
432 * I got it right. (This aligment seems new to FP13.)
433 */
434 if (pLrec->pObjInfo == NULL /*&& pLrec->pNextRec == NULL*/ && pLrec->ctObj > 0)
435 {
436 pLrec->pObjInfo = (qsLObjrec_t*)(
437 (char*)pLrec
438 + ((sizeof(qsLrec_t) /* size of the lib record */
439 + pLrec->ctImpMod * sizeof(short) /* size of the array of imported modules */
440 + strlen((char*)pLrec->pName) + 1 /* size of the filename */
441 + 3) & ~3)); /* the size is align on 4 bytes boundrary */
442#ifdef __INNOTEK_LIBC__
443 pLrec->pNextRec = (void **)(qsLrec_t*)((char*)pLrec->pObjInfo
444 + sizeof(qsLObjrec_t) * pLrec->ctObj);
445#else
446 pLrec->pNextRec = (qsLrec_t*)((char*)pLrec->pObjInfo
447 + sizeof(qsLObjrec_t) * pLrec->ctObj);
448#endif
449 }
450 if (pLrec->hmte == hmod)
451 break;
452
453 /*
454 * Next record
455 */
456 pLrec = (qsLrec_t*)pLrec->pNextRec;
457 }
458
459
460 if (pLrec)
461 {
462 if (pLrec->pObjInfo != NULL)
463 {
464 /* Allocate memory for paSections */
465 paSections = (PSECTION)malloc(pLrec->ctObj*sizeof(SECTION));
466 if (paSections != NULL)
467 {
468 /* objects -> section array */
469 for (int i = 0; i < pLrec->ctObj; i++)
470 {
471 paSections[i].ulRVA = ~0UL;
472 paSections[i].cbVirtual = pLrec->pObjInfo[i].osize;
473 paSections[i].ulAddress = pLrec->pObjInfo[i].oaddr;
474 }
475 cSections = pLrec->ctObj;
476 }
477 else
478 rc = ERROR_NOT_ENOUGH_MEMORY;
479 }
480 else
481 {
482 rc = ERROR_BAD_EXE_FORMAT;
483 dprintf(("Win32Pe2LxImage::getSections: Error - no object table!\n"));
484 }
485 }
486 else
487 rc = ERROR_MOD_NOT_FOUND;
488 }
489 else
490 dprintf(("DosQuerySysState - failed with rc=%d (cbBuf=%d)\n", rc, cbBuf));
491
492 if (pPtrRec != NULL)
493 free(pPtrRec);
494 }
495 else
496 rc = ERROR_NOT_ENOUGH_MEMORY;
497
498 return rc;
499}
500
501
502/**
503 * Sets the ulRVA according to the original PE section table.
504 * @returns OS/2 errorcode. (NO_ERROR == success)
505 * @sketch DEBUG: Validate pNtHdrs
506 * Make pointer to start of PE section table.
507 * Set RVA for the header section.
508 * IF not all in one object exe? THEN
509 * Loop thru the sections in the PE section table.
510 * Note: due to the header section: PE section no. + 1 == LX object no.
511 * ELSE
512 * BEGIN
513 * (try) Reallocate paSections to NumberOfSections + 3.
514 * Loop thru the PE sections and make paSections from them.
515 * Add final Stack or TIBFix+Stack section if necessary.
516 * Resize header section.
517 * END
518 * @status completely implemented.
519 * @author knut st. osmundsen
520 * @remark Must not be called before pNtHdrs is set.
521 */
522ULONG Win32Pe2LxImage::setSectionRVAs()
523{
524 #if DEBUG
525 if (pNtHdrs == NULL)
526 {
527 DebugInt3();
528 return ERROR_INVALID_PARAMETER;
529 }
530 #endif
531
532 PIMAGE_SECTION_HEADER paPESections = (PIMAGE_SECTION_HEADER)
533 ((unsigned)pNtHdrs + sizeof(*pNtHdrs) +
534 (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY)
535 );
536
537 /* set RVA for the header section to 0UL. */
538 paSections[0].ulRVA = 0UL;
539
540 /* All in one object exe? */
541 if (pNtHdrs->FileHeader.NumberOfSections < cSections)
542 {
543 /* loop thru the other sections */
544 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
545 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
546 }
547 else
548 { /* all in one object */
549 /* (try) Reallocate paSections to NumberOfSections + 3. */
550 PVOID pv = realloc(paSections, sizeof(paSections[0]) * (pNtHdrs->FileHeader.NumberOfSections + 3));
551 if (pv != NULL)
552 {
553 paSections = (PSECTION)pv;
554
555 /* loop thru the PE sections */
556 int i;
557 for (i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
558 {
559 if (paSections[0].cbVirtual < paPESections[i].VirtualAddress)
560 {
561 dprintf(("Win32Pe2LxImage::setSectionRVAs: mismatch between section table and all-in-one-object"
562 "paSections[0].cbVirtual %#x paPESections[i].VirtualAddress %#x\n",
563 paSections[0].cbVirtual, paPESections[i].VirtualAddress
564 ));
565 return ERROR_BAD_EXE_FORMAT;
566 }
567 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
568 paSections[i+1].cbVirtual = max(paPESections[i].Misc.VirtualSize, paPESections[i].SizeOfRawData);
569 paSections[i+1].ulAddress = paSections[0].ulAddress + paPESections[i].VirtualAddress;
570 }
571 cSections = pNtHdrs->FileHeader.NumberOfSections + 1;
572
573 /* add final Stack or TIBFix+Stack section if necessary */
574 if (paSections[0].cbVirtual > paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000))
575 {
576 paSections[i+1].ulRVA = ~0UL;
577 paSections[i+1].cbVirtual = paSections[0].cbVirtual - paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000);
578 paSections[i+1].ulAddress = paSections[i].ulAddress + ALIGN(paSections[i].cbVirtual, 0x1000);
579 i++;
580 cSections++;
581 }
582
583 /* resize header section */
584 paSections[0].cbVirtual = paSections[1].ulRVA; /*....*/
585 }
586 else
587 return ERROR_NOT_ENOUGH_MEMORY;
588 }
589
590 return NO_ERROR;
591}
592
593
594/**
595 * Process resource section.
596 */
597ULONG Win32Pe2LxImage::doResources()
598{
599 ULONG rc;
600
601 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
602 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
603 {
604 ulRVAResourceSection = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
605 pResRootDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(ulRVAResourceSection);
606 /* _temporary_ fix:
607 * We'll have to make the resource section writable.
608 * And we'll have to make the pages before it readable.
609 */
610 LONG iSection = getSectionIndexFromRVA(ulRVAResourceSection);
611 if (iSection >= 0)
612 {
613 rc = DosSetMem((PVOID)paSections[iSection].ulAddress, paSections[iSection].cbVirtual, PAG_WRITE | PAG_READ);
614
615 ULONG ulAddr = paSections[iSection].ulAddress - 0x10000; //64KB
616 while (ulAddr < paSections[iSection].ulAddress)
617 {
618 ULONG fl = ~0UL;
619 ULONG cb = ~0UL;
620 rc = DosQueryMem((PVOID)ulAddr, &cb, &fl);
621 if (rc == NO_ERROR)
622 {
623 if (fl & PAG_GUARD)
624 rc = -1;
625 else if (fl & PAG_COMMIT)
626 fl &= ~(PAG_COMMIT);
627 else
628 fl |= PAG_COMMIT;
629 cb = (cb + 0xfffUL) & ~0xfffUL;
630 }
631 else
632 {
633 fl = PAG_COMMIT;
634 cb = 0x1000;
635 }
636 fl &= PAG_READ | PAG_COMMIT | PAG_WRITE | PAG_GUARD;
637 fl |= PAG_READ;
638 if (cb > paSections[iSection].ulAddress - ulAddr)
639 cb = paSections[iSection].ulAddress - ulAddr;
640 if (rc == NO_ERROR)
641 rc = DosSetMem((PVOID)ulAddr, cb, fl);
642
643 ulAddr += cb;
644 }
645 }
646 }
647
648 return 0;
649}
650
651
652/**
653 * Do TLS related matters.
654 */
655ULONG Win32Pe2LxImage::doTLS()
656{
657 if (pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0UL
658 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0UL)
659 {
660 PIMAGE_TLS_DIRECTORY pTLSDir;
661 LONG iSection;
662 iSection = getSectionIndexFromRVA(pNtHdrs->OptionalHeader.
663 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
664 VirtualAddress);
665 pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
666 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
667 VirtualAddress);
668
669 if (pTLSDir != NULL && iSection != -1)
670 {
671 PVOID pv;
672
673 /*
674 * According to the docs StartAddressOfRawData and EndAddressOfRawData is
675 * real pointers with a baserelocs.
676 *
677 * The docs says nothing about the two AddressOf pointers. So, we'll assume that
678 * these also are real pointers. But, we'll try compensate if they should not have
679 * base realocations.
680 */
681 if (validateRealPointer((PVOID)pTLSDir->StartAddressOfRawData)
682 &&
683 validateRealPointer((PVOID)pTLSDir->EndAddressOfRawData)
684 )
685 {
686 setTLSAddress((PVOID)pTLSDir->StartAddressOfRawData);
687 setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
688 setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
689
690 if (pTLSDir->AddressOfIndex)
691 {
692 if (validateRealPointer(pTLSDir->AddressOfIndex))
693 /* assume baserelocations for thepointer; use it without any change. */
694 setTLSIndexAddr((LPDWORD)(void*)pTLSDir->AddressOfIndex);
695 else
696 { /* assume no baserelocs for these pointers? Complain and debugint3 */
697 eprintf(("Win32Pe2LxImage::init: TLS - AddressOfIndex(%#8x) is not a pointer with basereloc.\n",
698 pTLSDir->AddressOfIndex));
699 pv = getPointerFromPointer(pTLSDir->AddressOfIndex);
700 if (pv == NULL)
701 {
702 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOfIndex - %#8x.\n",
703 pTLSDir->AddressOfIndex));
704 return LDRERROR_INVALID_HEADER;
705 }
706 setTLSIndexAddr((LPDWORD)pv);
707 }
708 }
709
710 if (pTLSDir->AddressOfCallBacks)
711 {
712 if (validateRealPointer(pTLSDir->AddressOfCallBacks))
713 /* assume baserelocations for thepointer; use it without any change. */
714 setTLSCallBackAddr(pTLSDir->AddressOfCallBacks);
715 else
716 { /* assume no baserelocs for these pointers? Complain and debugint3 */
717 eprintf(("Win32Pe2LxImage::init: Warning: TLS - AddressOfCallBacks(%#8x) is not a pointer with basereloc.\n",
718 pTLSDir->AddressOfCallBacks));
719 pv = getPointerFromPointer(pTLSDir->AddressOfCallBacks);
720 if (pv == NULL)
721 {
722 eprintf(("Win32Pe2LxImage::init: invalid pointer to TLS AddressOfCallBacks - %#8x.\n",
723 pTLSDir->AddressOfIndex));
724 return LDRERROR_INVALID_HEADER;
725 }
726 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
727 }
728 }
729 }
730 }
731 else
732 {
733 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
734 pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
735 return LDRERROR_INVALID_HEADER;
736 }
737 }
738
739 return 0;
740}
741
742/**
743 * Processes the import directory of the image.
744 * @returns LDRERROR_*
745 * @remark This could be in base class and shared with the peldr.
746 */
747ULONG Win32Pe2LxImage::doImports()
748{
749 ULONG rc;
750 PIMAGE_IMPORT_DESCRIPTOR pImps;
751
752 /*
753 * Check if there is actually anything to work on.
754 */
755 if ( !pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].VirtualAddress
756 || !pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size)
757 {
758 dprintf(("Win32Pe2LxImage::initImports: there are no imports\n"));
759 return 0;
760 }
761
762 /*
763 * Walk the IMAGE_IMPORT_DESCRIPTOR table.
764 */
765 for (rc = 0, pImps = (PIMAGE_IMPORT_DESCRIPTOR)getPointerFromRVA(pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].VirtualAddress);
766 !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
767 pImps++)
768 {
769 const char * pszName = (const char*)getPointerFromRVA(pImps->Name);
770 Win32ImageBase *pModule;
771 dprintf(("Win32Pe2LxImage::initImports: DLL %s\n", pszName));
772
773 /*
774 * Try find the table.
775 */
776 pModule = importsGetModule(pszName);
777 if (pModule)
778 {
779 PIMAGE_THUNK_DATA pFirstThunk; /* update this. */
780 PIMAGE_THUNK_DATA pThunk; /* read from this. */
781
782 /*
783 * Walk the thunks table(s).
784 */
785 pFirstThunk = (PIMAGE_THUNK_DATA)getPointerFromRVA((ULONG)pImps->FirstThunk);
786 pThunk = pImps->u.OriginalFirstThunk == 0 ? pFirstThunk
787 : (PIMAGE_THUNK_DATA)getPointerFromRVA((ULONG)pImps->FirstThunk);
788 while (!rc && pThunk->u1.Ordinal != 0)
789 {
790 if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
791 rc = importsByOrdinal(pModule, IMAGE_ORDINAL(pThunk->u1.Ordinal), (void**)&pFirstThunk->u1.Function);
792 else if ( pThunk->u1.Ordinal > 0
793 && pThunk->u1.Ordinal < pNtHdrs->OptionalHeader.SizeOfImage)
794 rc = importsByName(pModule, (const char*)getPointerFromRVA((ULONG)pThunk->u1.AddressOfData + 2), (void**)&pFirstThunk->u1.Function);
795 else
796 {
797 dprintf(("Win32Pe2LxImage::initImports: bad import data thunk!\n"));
798 DebugInt3();
799 rc = LDRERROR_IMPORTS;
800 }
801
802 pThunk++;
803 pFirstThunk++;
804 }
805 }
806 else
807 {
808 dprintf(("Win32Pe2LxImage::initImports: cannot find module '%s'!!!\n", pszName));
809 DebugInt3();
810 rc = LDRERROR_IMPORTS;
811 }
812 }
813
814 return rc;
815}
816
817
818/**
819 * Find a module.
820 *
821 * @returns Pointer to module
822 * @returns NULL on failure.
823 * @param pszModName Pointer to module name.
824 * @remark This should be in base class and shared with the peldr.
825 */
826Win32ImageBase * Win32Pe2LxImage::importsGetModule(const char *pszModName)
827{
828 Win32ImageBase *pMod;
829 Win32DllBase *pDll;
830
831 /*
832 * Look if it's already loaded.
833 */
834 pDll = Win32DllBase::findModule((char*)pszModName);
835 if (pDll)
836 {
837 dprintf(("Win32Pe2LxImage::importGetModule(%s) already loaded\n", pszModName));
838 pDll->AddRef();
839 }
840 else if (WinExe != NULL && WinExe->matchModName(pszModName))
841 {
842 dprintf(("Win32Pe2LxImage::importGetModule(%s) already loaded (exe)\n", pszModName));
843 pMod = (Win32ImageBase *)WinExe;
844 pDll = NULL;
845 }
846 else
847 {
848 /*
849 * Load it (simplified).
850 */
851 pDll = importsLoadModule(pszModName);
852 if (!pDll)
853 return NULL;
854 dprintf(("Win32Pe2LxImage::importGetModule(%s) Loaded module\n", pszModName));
855 }
856
857 /*
858 * Update dependendcies.
859 */
860 if (pDll)
861 {
862 /*
863 * Add the dll we just loaded to dependency list for this image.
864 */
865 addDependency(pDll);
866
867 /*
868 * Make sure the dependency list is correct (already done in the ctor
869 * of Win32DllBase, but for LX dlls the parent is then set to NULL)
870 * so, change it here again
871 */
872 pDll->setUnloadOrder(this);
873 pMod = pDll;
874 }
875
876 return pMod;
877}
878
879/**
880 * Loads a module this module is depending on.
881 * @returns Pointer to loaded module.
882 * @returns NULL on failure.
883 * @param pszModName Name of the module to be loaded.
884 * @remark This should be in base class and shared with the peldr.
885 */
886Win32DllBase *Win32Pe2LxImage::importsLoadModule(const char *pszModName)
887{
888 Win32DllBase *pDll;
889 char szRenamed[CCHMAXPATH];
890
891 /*
892 * Copy and rename the module name. (i.e. OLE32 -> OLE32OS2)
893 */
894 Win32DllBase::renameDll(strcpy(szRenamed, pszModName));
895
896 /*
897 * Find the filename (using the standard search stuff).
898 */
899 char szFullname[CCHMAXPATH];
900 if (!Win32ImageBase::findDll(szRenamed, szFullname, sizeof(szFullname)))
901 {
902 dprintf(("Module %s not found!", szRenamed));
903 errorState = ERROR_FILE_NOT_FOUND;
904 return NULL;
905 }
906
907 /*
908 * Check which type of executable module this is.
909 */
910 if (isPEImage(szFullname, NULL, NULL) != ERROR_SUCCESS_W)
911 {
912 /*
913 * LX image: let OS/2 do all the work for us
914 */
915 char szModuleFailure[CCHMAXPATH];
916 HMODULE hmodLXDll;
917 APIRET rc;
918
919 rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), szFullname, (HMODULE *)&hmodLXDll);
920 if (rc)
921 {
922 dprintf(("DosLoadModule returned %X for %s", rc, szModuleFailure));
923 errorState = rc;
924 return NULL;
925 }
926
927 pDll = Win32DllBase::findModuleByOS2Handle((HINSTANCE)hmodLXDll);
928 if (pDll == NULL)
929 {
930 dprintf(("Just loaded the dll, but can't find it anywhere?!!?"));
931 DebugInt3();
932 errorState = ERROR_INTERNAL;
933 return NULL;
934 }
935
936 /*
937 * For none Pe2Lx'ed LX modules we'll have to do a little work here.
938 */
939 if (pDll->isLxDll())
940 {
941 Win32LxDll *pLXDll = (Win32LxDll *)pDll;
942 pLXDll->setDllHandleOS2(hmodLXDll);
943 if (pLXDll->AddRef() == -1) //-1 -> load failed (attachProcess)
944 {
945 dprintf(("Dll %s refused to be loaded; aborting", szFullname));
946 delete pLXDll;
947 errorState = ERROR_INTERNAL;
948 return NULL;
949 }
950 }
951 }
952 else
953 {
954 /*
955 * PE image: use the peldr.
956 */
957 Win32PeLdrDll *pPEDll;
958
959 pPEDll = new Win32PeLdrDll(szFullname, this);
960 if (!pPEDll)
961 {
962 dprintf(("pedll: Error allocating memory" ));
963 errorState = ERROR_INTERNAL;
964 return NULL;
965 }
966 dprintf(("**********************************************************************"));
967 dprintf(("********************** Loading Module *********************"));
968 dprintf(("**********************************************************************"));
969 if (pPEDll->init(0) != LDRERROR_SUCCESS)
970 {
971 dprintf(("Internal WinDll error ", pPEDll->getError()));
972 delete pPEDll;
973 return NULL;
974 }
975
976#ifdef DEBUG
977 pPEDll->AddRef(getModuleName());
978#else
979 pPEDll->AddRef();
980#endif
981 if (pPEDll->attachProcess() == FALSE)
982 {
983 dprintf(("attachProcess failed!"));
984 delete pPEDll;
985 errorState = ERROR_INTERNAL;
986 return NULL;
987 }
988 pDll = (Win32DllBase*)pPEDll;
989 }
990
991 dprintf(("**********************************************************************"));
992 dprintf(("********************** Finished Loading Module %s ", szFullname));
993 dprintf(("**********************************************************************"));
994 return pDll;
995}
996
997
998/**
999 * Resolve an import by symbol name.
1000 *
1001 * @returns 0 on success, error code on failure.
1002 * @param pModule Pointer to module.
1003 * @param uOrdinal Ordinal of the symbol to import.
1004 * @param ppvAddr Where to store the symbol address.
1005 * @remark This should be in base class and shared with the peldr.
1006 */
1007ULONG Win32Pe2LxImage::importsByOrdinal(Win32ImageBase *pModule, unsigned uOrdinal, void **ppvAddr)
1008{
1009 void *pfn;
1010 pfn = (void*)pModule->getApi(uOrdinal);
1011 if (pfn)
1012 {
1013 dprintf(("Win32Pe2LxImage::importsByOrdinal: *%p=%p %s!%d\n", ppvAddr, pfn, pModule->getModuleName(), uOrdinal));
1014 *ppvAddr = pfn;
1015 return 0;
1016 }
1017
1018 dprintf(("Win32Pe2LxImage::importsByOrdinal: %s!%u\n", pModule->getModuleName(), uOrdinal));
1019 DebugInt3();
1020 /** @todo: missing api */
1021 *ppvAddr = NULL;
1022 return LDRERROR_IMPORTS;
1023}
1024
1025
1026/**
1027 * Resolve an import by symbol name.
1028 *
1029 * @returns 0 on success, error code on failure.
1030 * @param pModule Pointer to module.
1031 * @param pszSymName Name of symbol to import.
1032 * @param ppvAddr Where to store the symbol address.
1033 * @remark This should be in base class and shared with the peldr.
1034 */
1035ULONG Win32Pe2LxImage::importsByName(Win32ImageBase *pModule, const char *pszSymName, void **ppvAddr)
1036{
1037 void *pfn;
1038 pfn = (void*)pModule->getApi((char*)pszSymName);
1039 if (pfn)
1040 {
1041 dprintf(("Win32Pe2LxImage::importsByName: *%p=%p %s!%s\n", ppvAddr, pfn, pModule->getModuleName(), pszSymName));
1042 *ppvAddr = pfn;
1043 return 0;
1044 }
1045
1046 dprintf(("Win32Pe2LxImage::importsByName: %s!%s\n", pModule->getModuleName(), pszSymName));
1047 DebugInt3();
1048 /** @todo: missing api */
1049 *ppvAddr = NULL;
1050 return LDRERROR_IMPORTS;
1051}
1052
1053
1054/**
1055 * Frees memory used by this object.
1056 * When an exception is to be thrown, this function is called first to clean up
1057 * the object. Base class(es) are automatically clean up by theire destructor(s).
1058 * @status completely implemented.
1059 * @author knut st. osmundsen
1060 */
1061VOID Win32Pe2LxImage::cleanup()
1062{
1063 if (paSections != NULL)
1064 {
1065 free(paSections);
1066 paSections = NULL;
1067 cSections = 0;
1068 }
1069
1070 if (fDll)
1071 DosFreeModule(hmod);
1072}
1073
1074
1075/**
1076 * Converts a RVA into a pointer.
1077 * @returns Pointer matching the given RVA, NULL on error.
1078 * @param ulRVA An address relative to the imagebase of the original PE image.
1079 * If this is 0UL NULL is returned.
1080 * @param fOverride If set the ulRVA doesn't have to be inside the image.
1081 * @sketch DEBUG: validate state, paSections != NULL
1082 * IF ulRVA is 0 THEN return NULL
1083 * LOOP while more section left and ulRVA is not within section
1084 * next section
1085 * IF section matching ulRVA is not found THEN fail.
1086 * return pointer matching RVA.
1087 * @status completely implemented.
1088 * @author knut st. osmundsen
1089 * @remark Should not be called until getSections has returned successfully.
1090 * RVA == 0 is ignored.
1091 */
1092void * Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA, BOOL fOverride)
1093{
1094 #ifdef DEBUG
1095 if (paSections == NULL)
1096 {
1097 eprintf(("Win32Pe2LxImage::getPointerFromRVA: paSections is NULL!\n"));
1098 return NULL;
1099 }
1100 #endif
1101
1102 if (ulRVA == 0UL)
1103 return NULL;
1104
1105 int i = 0;
1106 while (i < cSections &&
1107 (paSections[i].ulRVA > ulRVA || paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
1108 i++;
1109 if (i >= cSections)
1110 {
1111 /* This isn't good, but it's required to support api overrides. */
1112 if (fOverride)
1113 return (char*)hinstance + ulRVA;
1114 return NULL;
1115 }
1116
1117 return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
1118}
1119
1120
1121/** Converts a pointer to an RVA for the loaded image.
1122 * @remark Because of export overriding addresses outside the image must be supported.
1123 */
1124ULONG Win32Pe2LxImage::getRVAFromPointer(void *pv, BOOL fOverride/* = FALSE*/)
1125{
1126 #ifdef DEBUG
1127 if (paSections == NULL)
1128 {
1129 eprintf(("Win32Pe2LxImage::getPointerFromRVA: paSections is NULL!\n"));
1130 return NULL;
1131 }
1132 #endif
1133
1134 if (pv == 0UL)
1135 return NULL;
1136
1137 int i = 0;
1138 while (i < cSections &&
1139 (paSections[i].ulAddress > (ULONG)pv || paSections[i].ulAddress + paSections[i].cbVirtual <= (ULONG)pv)) /* ALIGN on page too? */
1140 i++;
1141 if (i >= cSections)
1142 {
1143 /* This isn't good, but it's required to support api overrides. */
1144 if (fOverride)
1145 return (ULONG)pv - (ULONG)hinstance;
1146 return NULL;
1147 }
1148
1149 return (ULONG)pv - paSections[i].ulAddress + paSections[i].ulRVA;
1150}
1151
1152
1153/**
1154 * Converts a pointer with not basereloc to a pointer.
1155 * @returns Pointer with baserelocation applied.
1156 * @param pv Pointer without baserelocation.
1157 * @status completely implemented.
1158 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1159 */
1160PVOID Win32Pe2LxImage::getPointerFromPointer(PVOID pv)
1161{
1162 if (pv == NULL)
1163 return NULL;
1164
1165 return getPointerFromRVA((ULONG)pv - pNtHdrs->OptionalHeader.ImageBase);
1166}
1167
1168
1169/**
1170 * Converts a RVA into a paSections index.
1171 * @returns Index into paSections for the section containing the RVA.
1172 * -1 on error.
1173 * @param ulRVA An address relative to the imagebase of the original PE image.
1174 * If this is 0UL -1 is returned.
1175 * @sketch DEBUG: validate state, paSections != NULL
1176 * IF ulRVA is 0 THEN return -1
1177 * LOOP while more section left and ulRVA is not within section
1178 * next section
1179 * IF section matching ulRVA is found THEN return index ELSE fail.
1180 * @status completely implemented.
1181 * @author knut st. osmundsen
1182 * @remark Should not be called until getSections has returned successfully.
1183 * RVA == 0 is ignored.
1184 */
1185LONG Win32Pe2LxImage::getSectionIndexFromRVA(ULONG ulRVA)
1186{
1187 LONG i;
1188
1189 #ifdef DEBUG
1190 if (paSections == NULL)
1191 {
1192 eprintf(("Win32Pe2LxImage::getSectionIndexFromRVA: paSections is NULL!\n"));
1193 return NULL;
1194 }
1195 #endif
1196
1197 if (ulRVA == 0UL)
1198 return -1;
1199
1200 i = 0;
1201 while (i < cSections &&
1202 (paSections[i].ulRVA > ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
1203 i++;
1204
1205 return i < cSections ? i : -1;
1206}
1207
1208
1209/**
1210 * Validates that a given pointer is pointing to valid memory within
1211 * the loaded executable image.
1212 * @returns TRUE if the pointer is valid.
1213 * FALSE if the pointer is invalid.
1214 * @param pv Pointer to validate.
1215 * @sketch
1216 * @status completely implemented.
1217 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1218 */
1219BOOL Win32Pe2LxImage::validateRealPointer(PVOID pv)
1220{
1221 int i;
1222
1223 #ifdef DEBUG
1224 if (paSections == NULL)
1225 {
1226 eprintf(("Win32Pe2LxImage::validateRealPointer: paSections is NULL!\n"));
1227 return NULL;
1228 }
1229 #endif
1230
1231 if (pv == NULL)
1232 return FALSE;
1233
1234 i = 0;
1235 while (i < cSections &&
1236 (paSections[i].ulAddress < (ULONG)pv ||
1237 paSections[i].ulAddress + paSections[i].cbVirtual <= (ULONG)pv) /* Align on page too? */
1238 )
1239 i++;
1240
1241 return i < cSections;
1242}
1243
1244
Note: See TracBrowser for help on using the repository browser.