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

Last change on this file since 10397 was 10397, checked in by sandervl, 22 years ago

Loader updates

File size: 43.0 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 pLrec->pNextRec = (qsLrec_t*)((char*)pLrec->pObjInfo
443 + sizeof(qsLObjrec_t) * pLrec->ctObj);
444 }
445 if (pLrec->hmte == hmod)
446 break;
447
448 /*
449 * Next record
450 */
451 pLrec = (qsLrec_t*)pLrec->pNextRec;
452 }
453
454
455 if (pLrec)
456 {
457 if (pLrec->pObjInfo != NULL)
458 {
459 /* Allocate memory for paSections */
460 paSections = (PSECTION)malloc(pLrec->ctObj*sizeof(SECTION));
461 if (paSections != NULL)
462 {
463 /* objects -> section array */
464 for (int i = 0; i < pLrec->ctObj; i++)
465 {
466 paSections[i].ulRVA = ~0UL;
467 paSections[i].cbVirtual = pLrec->pObjInfo[i].osize;
468 paSections[i].ulAddress = pLrec->pObjInfo[i].oaddr;
469 }
470 cSections = pLrec->ctObj;
471 }
472 else
473 rc = ERROR_NOT_ENOUGH_MEMORY;
474 }
475 else
476 {
477 rc = ERROR_BAD_EXE_FORMAT;
478 dprintf(("Win32Pe2LxImage::getSections: Error - no object table!\n"));
479 }
480 }
481 else
482 rc = ERROR_MOD_NOT_FOUND;
483 }
484 else
485 dprintf(("DosQuerySysState - failed with rc=%d (cbBuf=%d)\n", rc, cbBuf));
486
487 if (pPtrRec != NULL)
488 free(pPtrRec);
489 }
490 else
491 rc = ERROR_NOT_ENOUGH_MEMORY;
492
493 return rc;
494}
495
496
497/**
498 * Sets the ulRVA according to the original PE section table.
499 * @returns OS/2 errorcode. (NO_ERROR == success)
500 * @sketch DEBUG: Validate pNtHdrs
501 * Make pointer to start of PE section table.
502 * Set RVA for the header section.
503 * IF not all in one object exe? THEN
504 * Loop thru the sections in the PE section table.
505 * Note: due to the header section: PE section no. + 1 == LX object no.
506 * ELSE
507 * BEGIN
508 * (try) Reallocate paSections to NumberOfSections + 3.
509 * Loop thru the PE sections and make paSections from them.
510 * Add final Stack or TIBFix+Stack section if necessary.
511 * Resize header section.
512 * END
513 * @status completely implemented.
514 * @author knut st. osmundsen
515 * @remark Must not be called before pNtHdrs is set.
516 */
517ULONG Win32Pe2LxImage::setSectionRVAs()
518{
519 #if DEBUG
520 if (pNtHdrs == NULL)
521 {
522 DebugInt3();
523 return ERROR_INVALID_PARAMETER;
524 }
525 #endif
526
527 PIMAGE_SECTION_HEADER paPESections = (PIMAGE_SECTION_HEADER)
528 ((unsigned)pNtHdrs + sizeof(*pNtHdrs) +
529 (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY)
530 );
531
532 /* set RVA for the header section to 0UL. */
533 paSections[0].ulRVA = 0UL;
534
535 /* All in one object exe? */
536 if (pNtHdrs->FileHeader.NumberOfSections < cSections)
537 {
538 /* loop thru the other sections */
539 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
540 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
541 }
542 else
543 { /* all in one object */
544 /* (try) Reallocate paSections to NumberOfSections + 3. */
545 PVOID pv = realloc(paSections, sizeof(paSections[0]) * (pNtHdrs->FileHeader.NumberOfSections + 3));
546 if (pv != NULL)
547 {
548 paSections = (PSECTION)pv;
549
550 /* loop thru the PE sections */
551 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
552 {
553 if (paSections[0].cbVirtual < paPESections[i].VirtualAddress)
554 {
555 dprintf(("Win32Pe2LxImage::setSectionRVAs: mismatch between section table and all-in-one-object"
556 "paSections[0].cbVirtual %#x paPESections[i].VirtualAddress %#x\n",
557 paSections[0].cbVirtual, paPESections[i].VirtualAddress
558 ));
559 return ERROR_BAD_EXE_FORMAT;
560 }
561 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
562 paSections[i+1].cbVirtual = max(paPESections[i].Misc.VirtualSize, paPESections[i].SizeOfRawData);
563 paSections[i+1].ulAddress = paSections[0].ulAddress + paPESections[i].VirtualAddress;
564 }
565 cSections = pNtHdrs->FileHeader.NumberOfSections + 1;
566
567 /* add final Stack or TIBFix+Stack section if necessary */
568 if (paSections[0].cbVirtual > paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000))
569 {
570 paSections[i+1].ulRVA = ~0UL;
571 paSections[i+1].cbVirtual = paSections[0].cbVirtual - paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000);
572 paSections[i+1].ulAddress = paSections[i].ulAddress + ALIGN(paSections[i].cbVirtual, 0x1000);
573 i++;
574 cSections++;
575 }
576
577 /* resize header section */
578 paSections[0].cbVirtual = paSections[1].ulRVA; /*....*/
579 }
580 else
581 return ERROR_NOT_ENOUGH_MEMORY;
582 }
583
584 return NO_ERROR;
585}
586
587
588/**
589 * Process resource section.
590 */
591ULONG Win32Pe2LxImage::doResources()
592{
593 ULONG rc;
594
595 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
596 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
597 {
598 ulRVAResourceSection = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
599 pResRootDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(ulRVAResourceSection);
600 /* _temporary_ fix:
601 * We'll have to make the resource section writable.
602 * And we'll have to make the pages before it readable.
603 */
604 LONG iSection = getSectionIndexFromRVA(ulRVAResourceSection);
605 if (iSection >= 0)
606 {
607 rc = DosSetMem((PVOID)paSections[iSection].ulAddress, paSections[iSection].cbVirtual, PAG_WRITE | PAG_READ);
608
609 ULONG ulAddr = paSections[iSection].ulAddress - 0x10000; //64KB
610 while (ulAddr < paSections[iSection].ulAddress)
611 {
612 ULONG fl = ~0UL;
613 ULONG cb = ~0UL;
614 rc = DosQueryMem((PVOID)ulAddr, &cb, &fl);
615 if (rc == NO_ERROR)
616 {
617 if (fl & PAG_GUARD)
618 rc = -1;
619 else if (fl & PAG_COMMIT)
620 fl &= ~(PAG_COMMIT);
621 else
622 fl |= PAG_COMMIT;
623 cb = (cb + 0xfffUL) & ~0xfffUL;
624 }
625 else
626 {
627 fl = PAG_COMMIT;
628 cb = 0x1000;
629 }
630 fl &= PAG_READ | PAG_COMMIT | PAG_WRITE | PAG_GUARD;
631 fl |= PAG_READ;
632 if (cb > paSections[iSection].ulAddress - ulAddr)
633 cb = paSections[iSection].ulAddress - ulAddr;
634 if (rc == NO_ERROR)
635 rc = DosSetMem((PVOID)ulAddr, cb, fl);
636
637 ulAddr += cb;
638 }
639 }
640 }
641
642 return 0;
643}
644
645
646/**
647 * Do TLS related matters.
648 */
649ULONG Win32Pe2LxImage::doTLS()
650{
651 if (pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0UL
652 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0UL)
653 {
654 PIMAGE_TLS_DIRECTORY pTLSDir;
655 LONG iSection;
656 iSection = getSectionIndexFromRVA(pNtHdrs->OptionalHeader.
657 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
658 VirtualAddress);
659 pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
660 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
661 VirtualAddress);
662
663 if (pTLSDir != NULL && iSection != -1)
664 {
665 PVOID pv;
666
667 /*
668 * According to the docs StartAddressOfRawData and EndAddressOfRawData is
669 * real pointers with a baserelocs.
670 *
671 * The docs says nothing about the two AddressOf pointers. So, we'll assume that
672 * these also are real pointers. But, we'll try compensate if they should not have
673 * base realocations.
674 */
675 if (validateRealPointer((PVOID)pTLSDir->StartAddressOfRawData)
676 &&
677 validateRealPointer((PVOID)pTLSDir->EndAddressOfRawData)
678 )
679 {
680 setTLSAddress((PVOID)pTLSDir->StartAddressOfRawData);
681 setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
682 setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
683
684 if (pTLSDir->AddressOfIndex)
685 {
686 if (validateRealPointer(pTLSDir->AddressOfIndex))
687 /* assume baserelocations for thepointer; use it without any change. */
688 setTLSIndexAddr((LPDWORD)(void*)pTLSDir->AddressOfIndex);
689 else
690 { /* assume no baserelocs for these pointers? Complain and debugint3 */
691 eprintf(("Win32Pe2LxImage::init: TLS - AddressOfIndex(%#8x) is not a pointer with basereloc.\n",
692 pTLSDir->AddressOfIndex));
693 pv = getPointerFromPointer(pTLSDir->AddressOfIndex);
694 if (pv == NULL)
695 {
696 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOfIndex - %#8x.\n",
697 pTLSDir->AddressOfIndex));
698 return LDRERROR_INVALID_HEADER;
699 }
700 setTLSIndexAddr((LPDWORD)pv);
701 }
702 }
703
704 if (pTLSDir->AddressOfCallBacks)
705 {
706 if (validateRealPointer(pTLSDir->AddressOfCallBacks))
707 /* assume baserelocations for thepointer; use it without any change. */
708 setTLSCallBackAddr(pTLSDir->AddressOfCallBacks);
709 else
710 { /* assume no baserelocs for these pointers? Complain and debugint3 */
711 eprintf(("Win32Pe2LxImage::init: Warning: TLS - AddressOfCallBacks(%#8x) is not a pointer with basereloc.\n",
712 pTLSDir->AddressOfCallBacks));
713 pv = getPointerFromPointer(pTLSDir->AddressOfCallBacks);
714 if (pv == NULL)
715 {
716 eprintf(("Win32Pe2LxImage::init: invalid pointer to TLS AddressOfCallBacks - %#8x.\n",
717 pTLSDir->AddressOfIndex));
718 return LDRERROR_INVALID_HEADER;
719 }
720 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
721 }
722 }
723 }
724 }
725 else
726 {
727 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
728 pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
729 return LDRERROR_INVALID_HEADER;
730 }
731 }
732
733 return 0;
734}
735
736/**
737 * Processes the import directory of the image.
738 * @returns LDRERROR_*
739 * @remark This could be in base class and shared with the peldr.
740 */
741ULONG Win32Pe2LxImage::doImports()
742{
743 ULONG rc;
744 PIMAGE_IMPORT_DESCRIPTOR pImps;
745
746 /*
747 * Check if there is actually anything to work on.
748 */
749 if ( !pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].VirtualAddress
750 || !pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size)
751 {
752 dprintf(("Win32Pe2LxImage::initImports: there are no imports\n"));
753 return 0;
754 }
755
756 /*
757 * Walk the IMAGE_IMPORT_DESCRIPTOR table.
758 */
759 for (rc = 0, pImps = (PIMAGE_IMPORT_DESCRIPTOR)getPointerFromRVA(pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].VirtualAddress);
760 !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
761 pImps++)
762 {
763 const char * pszName = (const char*)getPointerFromRVA(pImps->Name);
764 Win32ImageBase *pModule;
765 dprintf(("Win32Pe2LxImage::initImports: DLL %s\n", pszName));
766
767 /*
768 * Try find the table.
769 */
770 pModule = importsGetModule(pszName);
771 if (pModule)
772 {
773 PIMAGE_THUNK_DATA pFirstThunk; /* update this. */
774 PIMAGE_THUNK_DATA pThunk; /* read from this. */
775
776 /*
777 * Walk the thunks table(s).
778 */
779 pFirstThunk = (PIMAGE_THUNK_DATA)getPointerFromRVA((ULONG)pImps->FirstThunk);
780 pThunk = pImps->u.OriginalFirstThunk == 0 ? pFirstThunk
781 : (PIMAGE_THUNK_DATA)getPointerFromRVA((ULONG)pImps->FirstThunk);
782 while (!rc && pThunk->u1.Ordinal != 0)
783 {
784 if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
785 rc = importsByOrdinal(pModule, IMAGE_ORDINAL(pThunk->u1.Ordinal), (void**)&pFirstThunk->u1.Function);
786 else if ( pThunk->u1.Ordinal > 0
787 && pThunk->u1.Ordinal < pNtHdrs->OptionalHeader.SizeOfImage)
788 rc = importsByName(pModule, (const char*)getPointerFromRVA((ULONG)pThunk->u1.AddressOfData + 2), (void**)&pFirstThunk->u1.Function);
789 else
790 {
791 dprintf(("Win32Pe2LxImage::initImports: bad import data thunk!\n"));
792 DebugInt3();
793 rc = LDRERROR_IMPORTS;
794 }
795
796 pThunk++;
797 pFirstThunk++;
798 }
799 }
800 else
801 {
802 dprintf(("Win32Pe2LxImage::initImports: cannot find module '%s'!!!\n", pszName));
803 DebugInt3();
804 rc = LDRERROR_IMPORTS;
805 }
806 }
807
808 return rc;
809}
810
811
812/**
813 * Find a module.
814 *
815 * @returns Pointer to module
816 * @returns NULL on failure.
817 * @param pszModName Pointer to module name.
818 * @remark This should be in base class and shared with the peldr.
819 */
820Win32ImageBase * Win32Pe2LxImage::importsGetModule(const char *pszModName)
821{
822 Win32ImageBase *pMod;
823 Win32DllBase *pDll;
824
825 /*
826 * Look if it's already loaded.
827 */
828 pDll = Win32DllBase::findModule((char*)pszModName);
829 if (pDll)
830 {
831 dprintf(("Win32Pe2LxImage::importGetModule(%s) already loaded\n", pszModName));
832 pDll->AddRef();
833 }
834 else if (WinExe != NULL && WinExe->matchModName(pszModName))
835 {
836 dprintf(("Win32Pe2LxImage::importGetModule(%s) already loaded (exe)\n", pszModName));
837 pMod = (Win32ImageBase *)WinExe;
838 pDll = NULL;
839 }
840 else
841 {
842 /*
843 * Load it (simplified).
844 */
845 pDll = importsLoadModule(pszModName);
846 if (!pDll)
847 return NULL;
848 dprintf(("Win32Pe2LxImage::importGetModule(%s) Loaded module\n", pszModName));
849 }
850
851 /*
852 * Update dependendcies.
853 */
854 if (pDll)
855 {
856 /*
857 * Add the dll we just loaded to dependency list for this image.
858 */
859 addDependency(pDll);
860
861 /*
862 * Make sure the dependency list is correct (already done in the ctor
863 * of Win32DllBase, but for LX dlls the parent is then set to NULL)
864 * so, change it here again
865 */
866 pDll->setUnloadOrder(this);
867 pMod = pDll;
868 }
869
870 return pMod;
871}
872
873/**
874 * Loads a module this module is depending on.
875 * @returns Pointer to loaded module.
876 * @returns NULL on failure.
877 * @param pszModName Name of the module to be loaded.
878 * @remark This should be in base class and shared with the peldr.
879 */
880Win32DllBase *Win32Pe2LxImage::importsLoadModule(const char *pszModName)
881{
882 Win32DllBase *pDll;
883 char szRenamed[CCHMAXPATH];
884
885 /*
886 * Copy and rename the module name. (i.e. OLE32 -> OLE32OS2)
887 */
888 Win32DllBase::renameDll(strcpy(szRenamed, pszModName));
889
890 /*
891 * Find the filename (using the standard search stuff).
892 */
893 char szFullname[CCHMAXPATH];
894 if (!Win32ImageBase::findDll(szRenamed, szFullname, sizeof(szFullname)))
895 {
896 dprintf(("Module %s not found!", szRenamed));
897 errorState = ERROR_FILE_NOT_FOUND;
898 return NULL;
899 }
900
901 /*
902 * Check which type of executable module this is.
903 */
904 if (isPEImage(szFullname, NULL, NULL) != ERROR_SUCCESS_W)
905 {
906 /*
907 * LX image: let OS/2 do all the work for us
908 */
909 char szModuleFailure[CCHMAXPATH];
910 HMODULE hmodLXDll;
911 APIRET rc;
912
913 rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), szFullname, (HMODULE *)&hmodLXDll);
914 if (rc)
915 {
916 dprintf(("DosLoadModule returned %X for %s", rc, szModuleFailure));
917 errorState = rc;
918 return NULL;
919 }
920
921 pDll = Win32DllBase::findModuleByOS2Handle((HINSTANCE)hmodLXDll);
922 if (pDll == NULL)
923 {
924 dprintf(("Just loaded the dll, but can't find it anywhere?!!?"));
925 DebugInt3();
926 errorState = ERROR_INTERNAL;
927 return NULL;
928 }
929
930 /*
931 * For none Pe2Lx'ed LX modules we'll have to do a little work here.
932 */
933 if (pDll->isLxDll())
934 {
935 Win32LxDll *pLXDll = (Win32LxDll *)pDll;
936 pLXDll->setDllHandleOS2(hmodLXDll);
937 if (pLXDll->AddRef() == -1) //-1 -> load failed (attachProcess)
938 {
939 dprintf(("Dll %s refused to be loaded; aborting", szFullname));
940 delete pLXDll;
941 errorState = ERROR_INTERNAL;
942 return NULL;
943 }
944 }
945 }
946 else
947 {
948 /*
949 * PE image: use the peldr.
950 */
951 Win32PeLdrDll *pPEDll;
952
953 pPEDll = new Win32PeLdrDll(szFullname, this);
954 if (!pPEDll)
955 {
956 dprintf(("pedll: Error allocating memory" ));
957 errorState = ERROR_INTERNAL;
958 return NULL;
959 }
960 dprintf(("**********************************************************************"));
961 dprintf(("********************** Loading Module *********************"));
962 dprintf(("**********************************************************************"));
963 if (pPEDll->init(0) != LDRERROR_SUCCESS)
964 {
965 dprintf(("Internal WinDll error ", pPEDll->getError()));
966 delete pPEDll;
967 return NULL;
968 }
969
970#ifdef DEBUG
971 pPEDll->AddRef(getModuleName());
972#else
973 pPEDll->AddRef();
974#endif
975 if (pPEDll->attachProcess() == FALSE)
976 {
977 dprintf(("attachProcess failed!"));
978 delete pPEDll;
979 errorState = ERROR_INTERNAL;
980 return NULL;
981 }
982 pDll = (Win32DllBase*)pPEDll;
983 }
984
985 dprintf(("**********************************************************************"));
986 dprintf(("********************** Finished Loading Module %s ", szFullname));
987 dprintf(("**********************************************************************"));
988 return pDll;
989}
990
991
992/**
993 * Resolve an import by symbol name.
994 *
995 * @returns 0 on success, error code on failure.
996 * @param pModule Pointer to module.
997 * @param uOrdinal Ordinal of the symbol to import.
998 * @param ppvAddr Where to store the symbol address.
999 * @remark This should be in base class and shared with the peldr.
1000 */
1001ULONG Win32Pe2LxImage::importsByOrdinal(Win32ImageBase *pModule, unsigned uOrdinal, void **ppvAddr)
1002{
1003 void *pfn;
1004 pfn = (void*)pModule->getApi(uOrdinal);
1005 if (pfn)
1006 {
1007 dprintf(("Win32Pe2LxImage::importsByOrdinal: *%p=%p %s!%d\n", ppvAddr, pfn, pModule->getModuleName(), uOrdinal));
1008 *ppvAddr = pfn;
1009 return 0;
1010 }
1011
1012 dprintf(("Win32Pe2LxImage::importsByOrdinal: %s!%u\n", pModule->getModuleName(), uOrdinal));
1013 DebugInt3();
1014 /** @todo: missing api */
1015 *ppvAddr = NULL;
1016 return LDRERROR_IMPORTS;
1017}
1018
1019
1020/**
1021 * Resolve an import by symbol name.
1022 *
1023 * @returns 0 on success, error code on failure.
1024 * @param pModule Pointer to module.
1025 * @param pszSymName Name of symbol to import.
1026 * @param ppvAddr Where to store the symbol address.
1027 * @remark This should be in base class and shared with the peldr.
1028 */
1029ULONG Win32Pe2LxImage::importsByName(Win32ImageBase *pModule, const char *pszSymName, void **ppvAddr)
1030{
1031 void *pfn;
1032 pfn = (void*)pModule->getApi((char*)pszSymName);
1033 if (pfn)
1034 {
1035 dprintf(("Win32Pe2LxImage::importsByName: *%p=%p %s!%s\n", ppvAddr, pfn, pModule->getModuleName(), pszSymName));
1036 *ppvAddr = pfn;
1037 return 0;
1038 }
1039
1040 dprintf(("Win32Pe2LxImage::importsByName: %s!%s\n", pModule->getModuleName(), pszSymName));
1041 DebugInt3();
1042 /** @todo: missing api */
1043 *ppvAddr = NULL;
1044 return LDRERROR_IMPORTS;
1045}
1046
1047
1048/**
1049 * Frees memory used by this object.
1050 * When an exception is to be thrown, this function is called first to clean up
1051 * the object. Base class(es) are automatically clean up by theire destructor(s).
1052 * @status completely implemented.
1053 * @author knut st. osmundsen
1054 */
1055VOID Win32Pe2LxImage::cleanup()
1056{
1057 if (paSections != NULL)
1058 {
1059 free(paSections);
1060 paSections = NULL;
1061 cSections = 0;
1062 }
1063
1064 if (fDll)
1065 DosFreeModule(hmod);
1066}
1067
1068
1069/**
1070 * Converts a RVA into a pointer.
1071 * @returns Pointer matching the given RVA, NULL on error.
1072 * @param ulRVA An address relative to the imagebase of the original PE image.
1073 * If this is 0UL NULL is returned.
1074 * @param fOverride If set the ulRVA doesn't have to be inside the image.
1075 * @sketch DEBUG: validate state, paSections != NULL
1076 * IF ulRVA is 0 THEN return NULL
1077 * LOOP while more section left and ulRVA is not within section
1078 * next section
1079 * IF section matching ulRVA is not found THEN fail.
1080 * return pointer matching RVA.
1081 * @status completely implemented.
1082 * @author knut st. osmundsen
1083 * @remark Should not be called until getSections has returned successfully.
1084 * RVA == 0 is ignored.
1085 */
1086void * Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA, BOOL fOverride)
1087{
1088 #ifdef DEBUG
1089 if (paSections == NULL)
1090 {
1091 eprintf(("Win32Pe2LxImage::getPointerFromRVA: paSections is NULL!\n"));
1092 return NULL;
1093 }
1094 #endif
1095
1096 if (ulRVA == 0UL)
1097 return NULL;
1098
1099 int i = 0;
1100 while (i < cSections &&
1101 (paSections[i].ulRVA > ulRVA || paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
1102 i++;
1103 if (i >= cSections)
1104 {
1105 /* This isn't good, but it's required to support api overrides. */
1106 if (fOverride)
1107 return (char*)hinstance + ulRVA;
1108 return NULL;
1109 }
1110
1111 return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
1112}
1113
1114
1115/** Converts a pointer to an RVA for the loaded image.
1116 * @remark Because of export overriding addresses outside the image must be supported.
1117 */
1118ULONG Win32Pe2LxImage::getRVAFromPointer(void *pv, BOOL fOverride/* = FALSE*/)
1119{
1120 #ifdef DEBUG
1121 if (paSections == NULL)
1122 {
1123 eprintf(("Win32Pe2LxImage::getPointerFromRVA: paSections is NULL!\n"));
1124 return NULL;
1125 }
1126 #endif
1127
1128 if (pv == 0UL)
1129 return NULL;
1130
1131 int i = 0;
1132 while (i < cSections &&
1133 (paSections[i].ulAddress > (ULONG)pv || paSections[i].ulAddress + paSections[i].cbVirtual <= (ULONG)pv)) /* ALIGN on page too? */
1134 i++;
1135 if (i >= cSections)
1136 {
1137 /* This isn't good, but it's required to support api overrides. */
1138 if (fOverride)
1139 return (ULONG)pv - (ULONG)hinstance;
1140 return NULL;
1141 }
1142
1143 return (ULONG)pv - paSections[i].ulAddress + paSections[i].ulRVA;
1144}
1145
1146
1147/**
1148 * Converts a pointer with not basereloc to a pointer.
1149 * @returns Pointer with baserelocation applied.
1150 * @param pv Pointer without baserelocation.
1151 * @status completely implemented.
1152 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1153 */
1154PVOID Win32Pe2LxImage::getPointerFromPointer(PVOID pv)
1155{
1156 if (pv == NULL)
1157 return NULL;
1158
1159 return getPointerFromRVA((ULONG)pv - pNtHdrs->OptionalHeader.ImageBase);
1160}
1161
1162
1163/**
1164 * Converts a RVA into a paSections index.
1165 * @returns Index into paSections for the section containing the RVA.
1166 * -1 on error.
1167 * @param ulRVA An address relative to the imagebase of the original PE image.
1168 * If this is 0UL -1 is returned.
1169 * @sketch DEBUG: validate state, paSections != NULL
1170 * IF ulRVA is 0 THEN return -1
1171 * LOOP while more section left and ulRVA is not within section
1172 * next section
1173 * IF section matching ulRVA is found THEN return index ELSE fail.
1174 * @status completely implemented.
1175 * @author knut st. osmundsen
1176 * @remark Should not be called until getSections has returned successfully.
1177 * RVA == 0 is ignored.
1178 */
1179LONG Win32Pe2LxImage::getSectionIndexFromRVA(ULONG ulRVA)
1180{
1181 LONG i;
1182
1183 #ifdef DEBUG
1184 if (paSections == NULL)
1185 {
1186 eprintf(("Win32Pe2LxImage::getSectionIndexFromRVA: paSections is NULL!\n"));
1187 return NULL;
1188 }
1189 #endif
1190
1191 if (ulRVA == 0UL)
1192 return -1;
1193
1194 i = 0;
1195 while (i < cSections &&
1196 (paSections[i].ulRVA > ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
1197 i++;
1198
1199 return i < cSections ? i : -1;
1200}
1201
1202
1203/**
1204 * Validates that a given pointer is pointing to valid memory within
1205 * the loaded executable image.
1206 * @returns TRUE if the pointer is valid.
1207 * FALSE if the pointer is invalid.
1208 * @param pv Pointer to validate.
1209 * @sketch
1210 * @status completely implemented.
1211 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1212 */
1213BOOL Win32Pe2LxImage::validateRealPointer(PVOID pv)
1214{
1215 int i;
1216
1217 #ifdef DEBUG
1218 if (paSections == NULL)
1219 {
1220 eprintf(("Win32Pe2LxImage::validateRealPointer: paSections is NULL!\n"));
1221 return NULL;
1222 }
1223 #endif
1224
1225 if (pv == NULL)
1226 return FALSE;
1227
1228 i = 0;
1229 while (i < cSections &&
1230 (paSections[i].ulAddress < (ULONG)pv ||
1231 paSections[i].ulAddress + paSections[i].cbVirtual <= (ULONG)pv) /* Align on page too? */
1232 )
1233 i++;
1234
1235 return i < cSections;
1236}
1237
1238
Note: See TracBrowser for help on using the repository browser.