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

Last change on this file since 1274 was 1274, checked in by bird, 26 years ago

New Pe2Lx implementation.

File size: 17.2 KB
Line 
1/* $Id: winimagepe2lx.cpp,v 1.2 1999-10-14 01:37:56 bird Exp $ */
2
3/*
4 * Win32 PE2LX Image base class
5 *
6 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998-1999 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13/*******************************************************************************
14* Defined Constants And Macros *
15*******************************************************************************/
16#define INCL_DOSERRORS /* DOS Error values */
17#define INCL_DOSPROFILE /* DosQuerySysState (Toolkit 4.5) */
18
19#define ALIGN(a, alignment) (((a) + (alignment - 1UL)) & ~(alignment - 1UL))
20
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#include <os2wrap.h> //Odin32 OS/2 api wrappers
26
27#include <malloc.h>
28#include <process.h>
29#include <stdlib.h>
30
31#include <win32type.h>
32#include <misc.h>
33#include <winimagebase.h>
34#include <winimagepe2lx.h>
35
36
37/*******************************************************************************
38* Structures and Typedefs *
39*******************************************************************************/
40#ifndef QS_MTE
41 /* From OS/2 Toolkit v4.5 (BSEDOS.H) */
42
43 /* Global Record structure
44 * Holds all global system information. Placed first in user buffer
45 */
46 typedef struct qsGrec_s { /* qsGrec */
47 ULONG cThrds;
48 ULONG c32SSem;
49 ULONG cMFTNodes;
50 }qsGrec_t;
51
52 /*
53 * System wide MTE information
54 * ________________________________
55 * | pNextRec |----|
56 * |-------------------------------| |
57 * | hmte | |
58 * |-------------------------------| |
59 * | ctImpMod | |
60 * |-------------------------------| |
61 * | ctObj | |
62 * |-------------------------------| |
63 * | pObjInfo |----|----------|
64 * |-------------------------------| | |
65 * | pName |----|----| |
66 * |-------------------------------| | | |
67 * | imported module handles | | | |
68 * | . | | | |
69 * | . | | | |
70 * | . | | | |
71 * |-------------------------------| <--|----| |
72 * | "pathname" | | |
73 * |-------------------------------| <--|----------|
74 * | Object records | |
75 * | (if requested) | |
76 * |_______________________________| |
77 * <-----
78 * NOTE that if the level bit is set to QS_MTE, the base Lib record will be followed
79 * by a series of object records (qsLObj_t); one for each object of the
80 * module.
81 */
82
83 typedef struct qsLObjrec_s { /* qsLOrec */
84 ULONG oaddr; /* object address */
85 ULONG osize; /* object size */
86 ULONG oflags; /* object flags */
87 } qsLObjrec_t;
88
89 typedef struct qsLrec_s { /* qsLrec */
90 void FAR *pNextRec; /* pointer to next record in buffer */
91 USHORT hmte; /* handle for this mte */
92 USHORT fFlat; /* true if 32 bit module */
93 ULONG ctImpMod; /* # of imported modules in table */
94 ULONG ctObj; /* # of objects in module (mte_objcnt)*/
95 qsLObjrec_t FAR *pObjInfo; /* pointer to per object info if any */
96 UCHAR FAR *pName; /* -> name string following struc */
97 } qsLrec_t;
98
99#endif
100
101
102/*******************************************************************************
103* External Functions *
104*******************************************************************************/
105#ifndef QS_MTE
106 /* from OS/2 Toolkit v4.5 */
107
108 APIRET APIENTRY DosQuerySysState(ULONG EntityList, ULONG EntityLevel, PID pid,
109 TID tid, PVOID pDataBuf, ULONG cbBuf);
110 #define QS_MTE 0x0004
111#endif
112
113
114
115/**
116 * Constructor - creates an pe2lx image object from a module handle to a pe2lx module.
117 * @param hinstance OS/2 module handle.
118 * @param fWin32k TRUE: Win32k module.
119 * FALSE: Pe2Lx module.
120 * @sketch Get section placement and sizes for this module. (paSections, cSections)
121 * Verify that there is at least one section - the header section.
122 * Locate the NT headers.
123 * Set pNtHdrs pointer.
124 * Validate the NT headers.
125 * Read the PE section table the set the RVAs in paSections.
126 * Locate and set the entrypoint.
127 * Locate the resource directory (if any). (pResDir, pResourceSectionStart)
128 * TLS - FIXME!
129 * @status partially implmented.
130 * @author knut st. osmundsen, Sander van Leeuwen
131 */
132Win32Pe2LxImage::Win32Pe2LxImage(HINSTANCE hinstance, BOOL fWin32k) throw(ULONG)
133 : Win32ImageBase(hinstance),
134 paSections(NULL), cSections(0), pNtHdrs(NULL), fWin32k(fWin32k)
135{
136 APIRET rc;
137
138 /* Get section placement and sizes for this module. (paSections, cSections) */
139 rc = getSections();
140 if (rc != NO_ERROR)
141 {
142 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: error - getSection failed with rc=%d\n",
143 rc));
144 Win32Pe2LxImage::~Win32Pe2LxImage();
145 throw((ULONG)rc);
146 }
147
148 /* Verify that there is at least one section - the header section. */
149 if (cSections < 1)
150 {
151 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: no header section, cSections is 0\n"));
152 Win32Pe2LxImage::~Win32Pe2LxImage();
153 throw((ULONG)ERROR_BAD_EXE_FORMAT);
154 }
155
156 /* Locate the NT headers. */
157 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)paSections[0].ulAddress;
158 if ((pDosHdr->e_magic != IMAGE_DOS_SIGNATURE
159 || pDosHdr->e_lfanew < sizeof(IMAGE_DOS_HEADER) /* Larger than 64 bytes */
160 || pDosHdr->e_lfanew > 0x04000000UL /* or less that 64MB. */
161 )
162 && !*(PDWORD)paSections[0].ulAddress == IMAGE_NT_SIGNATURE
163 )
164 {
165 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
166 Win32Pe2LxImage::~Win32Pe2LxImage();
167 throw((ULONG)ERROR_BAD_EXE_FORMAT);
168 }
169
170 /* Set pNtHdrs pointer. */
171 if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
172 pNtHdrs = (PIMAGE_NT_HEADERS)(paSections[0].ulAddress + pDosHdr->e_lfanew);
173 else
174 pNtHdrs = (PIMAGE_NT_HEADERS)paSections[0].ulAddress;
175
176 /* Validate the NT headers. */
177 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE
178 || pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC
179 || pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386
180 || (cSections != 1 /* all in one object */
181 && pNtHdrs->FileHeader.NumberOfSections
182 > cSections - 1 - (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ? 0 : 1) /* hdr section and stack */
183 )
184 /* TODO: add more tests? */
185 )
186 {
187 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
188 Win32Pe2LxImage::~Win32Pe2LxImage();
189 throw((ULONG)ERROR_BAD_EXE_FORMAT);
190 }
191
192 /* set RVAs */
193 rc = setSectionRVAs();
194 if (rc != NO_ERROR)
195 {
196 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: setSectionRVAs failed with rc=%d\n", rc));
197 Win32Pe2LxImage::~Win32Pe2LxImage();
198 throw((ULONG)rc);
199 }
200
201 /* Locate and set the entrypoint. */
202 setEntryPoint((ULONG)getPointerFromRVA(pNtHdrs->OptionalHeader.AddressOfEntryPoint));
203 if (entryPoint == 0UL &&
204 (pNtHdrs->OptionalHeader.AddressOfEntryPoint != NULL /* getPointerFromRVA failed... */
205 || !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)) /* EXEs must have and entry point! */
206 )
207 {
208 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: entrypoint is incorrect, AddrOfEP=0x%08x, entryPoint=0x%08x\n",
209 pNtHdrs->OptionalHeader.AddressOfEntryPoint, entryPoint));
210 Win32Pe2LxImage::~Win32Pe2LxImage();
211 throw((ULONG)ERROR_INVALID_STARTING_CODESEG);
212 }
213
214 /* Locate the resource directory (if any) */
215 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
216 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
217 {
218 pResourceSectionStart = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
219 pResDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(pResourceSectionStart);
220 }
221
222 /* TLS - FIXME! */
223}
224
225
226/**
227 * Free memory associated with this object.
228 * @status completely implemented.
229 * @author knut st. osmundsen, Sander van Leeuwen
230 */
231Win32Pe2LxImage::~Win32Pe2LxImage()
232{
233 cleanup();
234}
235
236
237/**
238 * Gets the object layout for this module. Creates the paSections array.
239 * @returns OS2 errorcode. (NO_ERROR == success)
240 * @sketch Allocate output buffer.
241 * Call DosQuerySysState.
242 * IF buffer overflow THEN retry calling it with larger buffers, until buffer size is 1MB.
243 * IF success THEN
244 * BEGIN
245 * Find record for this module.
246 * IF record found THEN allocate memory for object table and copy it. (paSections, cSections)
247 * END
248 * @status Completely implemented.
249 * @author knut st. osmundsen
250 */
251ULONG Win32Pe2LxImage::getSections()
252{
253 APIRET rc = NO_ERROR;
254 qsGrec_t ** pBuf;
255 ULONG cbBuf = 65536;
256
257 pBuf = (qsGrec_t **)malloc(cbBuf);
258 if (pBuf != NULL)
259 {
260 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pBuf, cbBuf);
261 while (cbBuf < 1024*1024 && rc == ERROR_BUFFER_OVERFLOW)
262 {
263 PVOID pv = pBuf;
264 cbBuf += 65536;
265 pBuf = (qsGrec_t **)realloc(pv, cbBuf);
266 if (pBuf != NULL)
267 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pBuf, cbBuf);
268 else
269 {
270 rc = ERROR_NOT_ENOUGH_MEMORY;
271 free(pv);
272 }
273 }
274
275 if (rc == NO_ERROR)
276 {
277 qsGrec_t * pGrec = *pBuf;
278 qsLrec_t * pLrec = (qsLrec_t * )((ULONG)pGrec + sizeof(qsGrec_t));
279 while (pLrec != NULL && pLrec->hmte != hinstance)
280 pLrec = (qsLrec_t*)pLrec->pNextRec;
281
282 if (pLrec)
283 {
284 if (pLrec->pObjInfo != NULL)
285 {
286 /* Allocate memory for paSections */
287 paSections = (PSECTION)malloc(pLrec->ctObj*sizeof(SECTION));
288 if (paSections != NULL)
289 {
290 /* objects -> section array */
291 for (int i = 0; i < pLrec->ctObj; i++)
292 {
293 paSections[i].ulRVA = ~0UL;
294 paSections[i].cbVirtual = pLrec->pObjInfo[i].osize;
295 paSections[i].ulAddress = pLrec->pObjInfo[i].oaddr;
296 }
297 cSections = pLrec->ctObj;
298 }
299 else
300 rc = ERROR_NOT_ENOUGH_MEMORY;
301 }
302 else
303 {
304 rc = ERROR_BAD_EXE_FORMAT;
305 dprintf(("Win32Pe2LxImage::getSections: Error - no object table!\n"));
306 }
307 }
308 else
309 rc = ERROR_MOD_NOT_FOUND;
310 }
311 else
312 dprintf(("DosQuerySysState - failed with rc=%d (cbBuf=%d)\n", rc, cbBuf));
313
314 if (pBuf != NULL)
315 free(pBuf);
316 }
317 else
318 rc = ERROR_NOT_ENOUGH_MEMORY;
319
320 return rc;
321}
322
323
324/**
325 * Sets the ulRVA according to the original PE section table.
326 * @returns OS/2 errorcode. (NO_ERROR == success)
327 * @sketch DEBUG: Validate pNtHdrs
328 * Make pointer to start of PE section table.
329 * Set RVA for the header section.
330 * IF not all in one object exe? THEN
331 * Loop thru the sections in the PE section table.
332 * Note: due to the header section: PE section no. + 1 == LX object no.
333 * ELSE
334 * BEGIN
335 * (try) Reallocate paSections to NumberOfSections + 3.
336 * Loop thru the PE sections and make paSections from them.
337 * Add final Stack or TIBFix+Stack section if necessary.
338 * Resize header section.
339 * END
340 * @status completely implemented.
341 * @author knut st. osmundsen
342 * @remark Must not be called before pNtHdrs is set.
343 */
344ULONG Win32Pe2LxImage::setSectionRVAs()
345{
346 #if DEBUG
347 if (pNtHdrs == NULL)
348 {
349 DebugInt3();
350 return ERROR_INVALID_PARAMETER;
351 }
352 #endif
353
354 PIMAGE_SECTION_HEADER paPESections = (PIMAGE_SECTION_HEADER)
355 ((unsigned)pNtHdrs + sizeof(*pNtHdrs) +
356 (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY)
357 );
358
359 /* set RVA for the header section to 0UL. */
360 paSections[0].ulRVA = 0UL;
361
362 /* All in one object exe? */
363 if (pNtHdrs->FileHeader.NumberOfSections < cSections)
364 {
365 /* loop thru the other sections */
366 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
367 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
368 }
369 else
370 { /* all in one object */
371 /* (try) Reallocate paSections to NumberOfSections + 3. */
372 PVOID pv = realloc(paSections, sizeof(paSections[0]) * (pNtHdrs->FileHeader.NumberOfSections + 3));
373 if (pv != NULL)
374 {
375 paSections = (PSECTION)pv;
376
377 /* loop thru the PE sections */
378 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
379 {
380 if (paSections[0].cbVirtual < paPESections[i].VirtualAddress)
381 {
382 dprintf(("Win32Pe2LxImage::setSectionRVAs: mismatch between section table and all-in-one-object"
383 "paSections[0].cbVirtual %#x paPESections[i].VirtualAddress %#x\n",
384 paSections[0].cbVirtual, paPESections[i].VirtualAddress
385 ));
386 return ERROR_BAD_EXE_FORMAT;
387 }
388 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
389 paSections[i+1].cbVirtual = max(paPESections[i].Misc.VirtualSize, paPESections[i].SizeOfRawData);
390 paSections[i+1].ulAddress = paSections[0].ulAddress + paPESections[i].VirtualAddress;
391 }
392 cSections = pNtHdrs->FileHeader.NumberOfSections + 1;
393
394 /* add final Stack or TIBFix+Stack section if necessary */
395 if (paSections[0].cbVirtual > paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000))
396 {
397 paSections[i+1].ulRVA = ~0UL;
398 paSections[i+1].cbVirtual = paSections[0].cbVirtual - paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000);
399 paSections[i+1].ulAddress = paSections[i].ulAddress + ALIGN(paSections[i].cbVirtual, 0x1000);
400 i++;
401 cSections++;
402 }
403
404 /* resize header section */
405 paSections[0].cbVirtual = paSections[1].ulRVA; /*....*/
406 }
407 else
408 return ERROR_NOT_ENOUGH_MEMORY;
409 }
410
411 return NO_ERROR;
412}
413
414
415/**
416 * Frees memory used by this object.
417 * When an exception is to be thrown, this function is called first to clean up
418 * the object. Base class(es) are automatically clean up by theire destructor(s).
419 * @status completely implemented.
420 * @author knut st. osmundsen
421 */
422VOID Win32Pe2LxImage::cleanup()
423{
424 if (paSections != NULL)
425 {
426 free(paSections);
427 paSections = NULL;
428 cSections = 0;
429 }
430}
431
432
433/**
434 * Converts a RVA to an pointer.
435 * @returns Pointer matching the given RVA, NULL on error.
436 * @param ulRVA An address relative to the imagebase of the original PE image.
437 * @sketch DEBUG: validate state, paSections != NULL
438 * LOOP while more section left and ulRVA is not within section
439 * next section
440 * IF section matching ulRVA is not found THEN fail.
441 * return pointer matching RVA.
442 * @status completely implemented.
443 * @author knut st. osmundsen
444 * @remark Should not be called until getSections has returned successfully.
445 */
446PVOID Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA)
447{
448 int i;
449 #ifdef DEBUG
450 if (paSections == NULL)
451 return NULL;
452 #endif
453
454 i = 0;
455 while (i < cSections &&
456 !(paSections[i].ulRVA <= ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual > ulRVA)) /* ALIGN on page too? */
457 i++;
458
459 if (i >= cSections)
460 return NULL;
461
462 return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
463}
464
Note: See TracBrowser for help on using the repository browser.