source: trunk/tools/common/kFileLX.cpp@ 8596

Last change on this file since 8596 was 8003, checked in by bird, 24 years ago

New kFile* classes; now in sync with os2tools.

File size: 56.8 KB
Line 
1/* $Id: kFileLX.cpp,v 1.7 2002-02-24 02:47:26 bird Exp $
2 *
3 *
4 *
5 * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11/******************************************************************************
12* Header Files *
13******************************************************************************/
14#include <MZexe.h>
15#include <LXexe.h>
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include "kTypes.h"
22#include "kError.h"
23#include "kFile.h"
24#include "kFileFormatBase.h"
25#include "kFileInterfaces.h"
26#include "kFileLX.h"
27
28
29/*******************************************************************************
30* Structures and Typedefs *
31*******************************************************************************/
32typedef struct _LXExportState
33{
34 struct b32_bundle * pb32; /* Pointer to current bundle. */
35 int iOrdinalBundle; /* The ordinal the bundle starts at. */
36 struct e32_entry * pe32; /* Pointer to the current bundle entry. */
37 int iOrdinal; /* The current ordinal. */
38} EXPSTATE, *PEXPSTATE;
39
40
41/**
42 * relocFind*() state info.
43 * Stored as kRelocEntry::pv1.
44 */
45typedef struct _LXRelocState
46{
47 unsigned long ulSegment; /* The current segment. (0-based) */
48 unsigned long ulPage; /* The current page. (0-based index) */
49 char * pchFixupRec; /* The current fixup record. */
50 unsigned short usSrcOffIdx; /* The current source offset index. (0-based) */
51} LXRELOCSTATE, *PLXRELOCSTATE;
52
53
54/*******************************************************************************
55* Global Variables *
56*******************************************************************************/
57#if 0
58static kFileLX tst((kFile*)NULL);
59#endif
60
61
62/*******************************************************************************
63* Internal Functions *
64*******************************************************************************/
65inline void memcpyw(char *pch1, const char *pch2, size_t cch);
66inline void memcpyb(char *pch1, const char *pch2, size_t cch);
67
68
69/**
70 * Internal worker which lookup the name corresponding to an ordinal.
71 * @returns Success indicator.
72 * @param iOrdinal ( >= 0).
73 * @param pszBuffer.
74 */
75KBOOL kFileLX::queryExportName(int iOrdinal, char *pszBuffer)
76{
77 unsigned short *pus;
78 unsigned char * puch;
79
80 /* resident name table */
81 if (pe32->e32_restab)
82 {
83 puch = (unsigned char *)pvBase + offLXHdr + pe32->e32_restab;
84 while (*puch != 0)
85 {
86 pus = (unsigned short *)(puch + 1 + *puch);
87 if (*pus == iOrdinal)
88 {
89 memcpy(pszBuffer, puch + 1, *puch);
90 pszBuffer[*puch] = '\0';
91 return TRUE;
92 }
93 puch += *puch + 1 + 2;
94 }
95 }
96
97 /* not found, check the non-resident name table too */
98 if (pe32->e32_nrestab)
99 {
100 puch = (unsigned char *)pvBase + pe32->e32_nrestab;
101 while (*puch != 0)
102 {
103 pus = (unsigned short *)(puch + 1 + *puch);
104 if (*pus == iOrdinal)
105 {
106 memcpy(pszBuffer, puch + 1, *puch);
107 pszBuffer[*puch] = '\0';
108 return TRUE;
109 }
110 puch += *puch + 1 + 2;
111 }
112 }
113
114 return FALSE;
115}
116
117/**
118 * Converts a FLAT address to an obj:offset address.
119 * @returns The offset into the object.
120 * -1 (0xffffffff) on error.
121 * @param ulAddress Address to map.
122 * @param pulObject Pointer to variable which will receive the object number (0-based).
123 */
124unsigned long kFileLX::lxAddressToObjectOffset(unsigned long ulAddress, unsigned long * pulObject) const
125{
126 int i;
127
128 /* look for a object which contains the given address */
129 for (i = 0; i < pe32->e32_objcnt; i++)
130 {
131 if ( paObject[i].o32_base <= ulAddress
132 && paObject[i].o32_base + paObject[i].o32_size > ulAddress)
133 {
134 if (pulObject)
135 *pulObject = i;
136 return ulAddress - paObject[i].o32_base;
137 }
138 }
139
140 return ~0UL; /* not found */
141}
142
143
144/**
145 * Converts an sel:off address, where sel is one of the special selectors,
146 * to a obj:off address.
147 * @returns The offset into the object.
148 * -1 (0xffffffff) on error.
149 * @param offObject Offset into the selector described by *pulObject.
150 * @param pulObject IN: Special selector.
151 * OUT: Pointer to variable which will receive the object number (0-based).
152 */
153unsigned long kFileLX::lxSpecialSelectorToObjectOffset(unsigned long offObject, unsigned long * pulObject) const
154{
155 switch (*pulObject)
156 {
157 case kRelocEntry::enmRVASelector:
158 return lxAddressToObjectOffset(offObject + paObject[0].o32_base, pulObject);
159
160 case kRelocEntry::enmVASelector:
161 return lxAddressToObjectOffset(offObject, pulObject);
162
163 default:
164 kASSERT(!"Internal error line");
165 }
166
167 return ~0UL;
168}
169
170
171/**
172 * Validates a FLAT address.
173 * @returns TRUE if valid, FALSE if invalid.
174 * @param ulAddress FLAT address to validate.
175 */
176KBOOL kFileLX::lxValidateAddress(unsigned long ulAddress) const
177{
178 int i;
179
180 /* look for a object which contains the given address */
181 for (i = 0; i < pe32->e32_objcnt; i++)
182 {
183 if ( paObject[i].o32_base <= ulAddress
184 && paObject[i].o32_base + paObject[i].o32_size > ulAddress)
185 {
186 return TRUE;
187 }
188 }
189
190 return FALSE;
191}
192
193
194/**
195 * Validates a object:offset address.
196 * @returns TRUE if valid, FALSE if invalid.
197 * @param ulObject Object number. (0-based)
198 * @param offObject Offset into that object.
199 */
200KBOOL kFileLX::lxValidateObjectOffset(unsigned long ulObject, unsigned long offObject) const
201{
202 return pe32->e32_objcnt > ulObject && offObject < paObject[ulObject].o32_size;
203}
204
205
206
207/**
208 * Gets the module name corresponding to the given ordinal.
209 * @returns Pointer to sz of the modulename. The caller is responsible for freeing it.
210 * NULL if invalid ordinal.
211 * @param ordModule Ordinal number of the module name. (1-based)
212 */
213char *kFileLX::lxGetImportModuleName(unsigned long ordModule) const
214{
215 if (pe32->e32_impmodcnt < ordModule)
216 return NULL;
217
218 char *pch = (char*)pe32 + pe32->e32_impmod;
219 while (--ordModule)
220 pch += *pch + 1;
221
222 if (!*pch)
223 return NULL;
224
225 /* Copy the module name. */
226 char *psz = new char[*pch + 1];
227 strncpy(psz, pch + 1, *pch);
228 psz[*pch] = '\0';
229 return psz;
230}
231
232
233/**
234 * Gets the proc name at the given offset.
235 * @returns Pointer to sz of the proc name. The caller is responsible for freeing it.
236 * NULL if invalid offset.
237 * @param offProc Offset of the proc name.
238 */
239char *kFileLX::lxGetImportProcName(unsigned long offProc) const
240{
241 char *pch = (char*)pe32 + pe32->e32_impproc + offProc;
242 if (!*pch)
243 return NULL;
244
245 /* Copy the proc name. */
246 char *psz = new char[*pch + 1];
247 strncpy(psz, pch + 1, *pch);
248 psz[*pch] = '\0';
249 return psz;
250}
251
252
253
254/**
255 * Create an LX file object from an LX executable image.
256 * @param pszFilename LX executable image name.
257 */
258kFileLX::kFileLX(const char *pszFilename) :
259 kFileFormatBase(NULL), pvBase(NULL)
260{
261 struct exe_hdr * pehdr;
262
263 /* create filemapping */
264 pvBase = kFile::mapFile(pszFilename);
265 pehdr = (struct exe_hdr*)pvBase;
266 if (pehdr->e_magic == EMAGIC)
267 offLXHdr = pehdr->e_lfanew;
268 else
269 offLXHdr = 0;
270
271 pe32 = (struct e32_exe*)((char*)pvBase + offLXHdr);
272 if (*(unsigned short *)pe32 != E32MAGIC)
273 {
274 kFile::mapFree(pvBase);
275 pvBase = NULL;
276 throw(kError(kError::INVALID_EXE_SIGNATURE));
277 }
278
279 paObject = pe32->e32_objtab && pe32->e32_objcnt
280 ? (struct o32_obj *)((char *)pe32 + pe32->e32_objtab) : NULL;
281 paMap = pe32->e32_objmap
282 ? (struct o32_map *)((char *)pe32 + pe32->e32_objmap) : NULL;
283 paulFixupPageTable = pe32->e32_fpagetab
284 ? (unsigned long *)((char *)pe32 + pe32->e32_fpagetab) : NULL;
285 pchFixupRecs = pe32->e32_frectab
286 ? (char *)((char *)pe32 + pe32->e32_frectab) : NULL;
287}
288
289
290/**
291 * Create an LX file object from an LX executable image.
292 * @param pFile Pointer to opened LX file.
293 */
294kFileLX::kFileLX(kFile *pFile) :
295 kFileFormatBase(pFile), pvBase(NULL)
296{
297 struct exe_hdr * pehdr;
298
299 /* create filemapping */
300 pFile->setThrowOnErrors();
301 pvBase = pFile->mapFile();
302
303 pehdr = (struct exe_hdr*)pvBase;
304 if (pehdr->e_magic == EMAGIC)
305 offLXHdr = pehdr->e_lfanew;
306 else
307 offLXHdr = 0;
308
309 pe32 = (struct e32_exe*)((char*)pvBase + offLXHdr);
310 if (*(unsigned short *)pe32 != E32MAGIC)
311 {
312 kFile::mapFree(pvBase);
313 pvBase = NULL;
314 throw(kError(kError::INVALID_EXE_SIGNATURE));
315 }
316
317 paObject = pe32->e32_objtab && pe32->e32_objcnt
318 ? (struct o32_obj *)((char *)pe32 + pe32->e32_objtab) : NULL;
319 paMap = pe32->e32_objmap
320 ? (struct o32_map *)((char *)pe32 + pe32->e32_objmap) : NULL;
321 paulFixupPageTable = pe32->e32_fpagetab
322 ? (unsigned long *)((char *)pe32 + pe32->e32_fpagetab) : NULL;
323 pchFixupRecs = pe32->e32_frectab
324 ? (char *)((char *)pe32 + pe32->e32_frectab) : NULL;
325}
326
327
328
329/**
330 * Destructor.
331 */
332kFileLX::~kFileLX()
333{
334 if (pvBase != NULL)
335 kFile::mapFree(pvBase);
336 pvBase = NULL;
337}
338
339
340
341/**
342 * Query for the module name.
343 * @returns Success indicator. TRUE / FALSE.
344 * @param pszBuffer Pointer to buffer which to put the name into.
345 * @param cchBuffer Size of the buffer (defaults to 260 chars).
346 */
347KBOOL kFileLX::moduleGetName(char *pszBuffer, int cchBuffer/*= 260*/)
348{
349 /* The module name is the 0 ordinal entry in resident name table */
350 kASSERT(cchBuffer >= 255);
351 return queryExportName(0, pszBuffer);
352}
353
354
355/**
356 * Finds the first exports.
357 * @returns Success indicator. TRUE / FALSE.
358 * @param pExport Pointer to export structure.
359 */
360KBOOL kFileLX::exportFindFirst(kExportEntry *pExport)
361{
362 struct b32_bundle * pBundle = (struct b32_bundle*)((char*)pvBase + pe32->e32_enttab + offLXHdr);
363 struct e32_entry * pEntry;
364 int iOrdinal = 1;
365
366 if (pe32->e32_enttab)
367 {
368 while (pBundle->b32_cnt != 0)
369 {
370 /* skip empty bundles */
371 while (pBundle->b32_cnt != 0 && pBundle->b32_type == EMPTY)
372 {
373 iOrdinal += pBundle->b32_cnt;
374 pBundle = (struct b32_bundle*)((char*)pBundle + 2);
375 }
376
377 /* FIXME forwarders are not implemented so we'll skip them too. */
378 while (pBundle->b32_cnt != 0 && (pBundle->b32_type & ~TYPEINFO) == ENTRYFWD)
379 {
380 iOrdinal += pBundle->b32_cnt;
381 pBundle = (struct b32_bundle*)((char*)(pBundle + 1) + pBundle->b32_cnt * 7);
382 }
383
384 /* we'll ignore any flags for the moment - TODO */
385 if (pBundle->b32_cnt != 0)
386 {
387 pExport->ulOrdinal = iOrdinal;
388 pExport->iObject = pBundle->b32_obj;
389
390 /* look for name */
391 pExport->achIntName[0] = '\0';
392 if (!queryExportName(iOrdinal, pExport->achName))
393 pExport->achName[0] = '\0';
394
395 pEntry = (struct e32_entry*)(pBundle+1);
396 switch (pBundle->b32_type & ~TYPEINFO)
397 {
398 case ENTRY16:
399 pExport->ulOffset = pEntry->e32_variant.e32_offset.offset16;
400 break;
401
402 case ENTRY32:
403 pExport->ulOffset = pEntry->e32_variant.e32_offset.offset32;
404 break;
405
406 case GATE16:
407 pExport->ulOffset = pEntry->e32_variant.e32_callgate.offset;
408 break;
409 default:
410 kASSERT(!"ARG!!!! invalid bundle type!");
411 }
412
413 /* store status - current export entry */
414 PEXPSTATE pExpState = new EXPSTATE;
415 pExport->pv = pExpState;
416 pExpState->pb32 = pBundle;
417 pExpState->iOrdinalBundle = iOrdinal;
418 pExpState->pe32 = pEntry;
419 pExpState->iOrdinal = iOrdinal;
420 pExport->ulAddress = ~0UL; /* TODO */
421 return TRUE;
422 }
423 }
424
425 }
426
427 return FALSE;
428}
429
430
431/**
432 * Finds the next export.
433 * @returns Success indicator. TRUE / FALSE.
434 * @param pExport Pointer to export structure.
435 */
436KBOOL kFileLX::exportFindNext(kExportEntry *pExport)
437{
438 static int acbEntry[] =
439 {
440 0, /* EMPTY */
441 3, /* ENTRY16 */
442 5, /* GATE16 */
443 5, /* ENTRY32 */
444 7 /* ENTRYFWD */
445 };
446
447 PEXPSTATE pExpState = (PEXPSTATE)pExport->pv;
448 pExport->ulAddress = ~0UL; /* TODO */
449
450 /*
451 * Get more ordinals from the current bundle if any left.
452 */
453 if (pExpState->pb32->b32_cnt > (pExpState->iOrdinal - pExpState->iOrdinalBundle + 1))
454 {
455 /* skip to the next entry */
456 pExpState->iOrdinal++;
457 pExpState->pe32 = (struct e32_entry*)((char*)pExpState->pe32
458 + acbEntry[pExpState->pb32->b32_type & ~TYPEINFO]);
459
460 /* fill output struct */
461 pExport->ulOrdinal = pExpState->iOrdinal;
462 pExport->iObject = pExpState->pb32->b32_obj;
463
464 /* look for name */
465 pExport->achIntName[0] = '\0';
466 if (!queryExportName(pExpState->iOrdinal, pExport->achName))
467 pExport->achName[0] = '\0';
468
469 /* ulOffset */
470 switch (pExpState->pb32->b32_type & ~TYPEINFO)
471 {
472 case ENTRY16:
473 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset16;
474 break;
475
476 case ENTRY32:
477 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset32;
478 break;
479
480 case GATE16:
481 pExport->ulOffset = pExpState->pe32->e32_variant.e32_callgate.offset;
482 break;
483 }
484
485 return TRUE;
486 }
487
488 /*
489 * next bundle.
490 */
491 pExpState->pb32 = (struct b32_bundle*)((char*)(pExpState->pb32 + 1) +
492 pExpState->pb32->b32_cnt * acbEntry[pExpState->pb32->b32_type & ~TYPEINFO]);
493 while (pExpState->pb32->b32_cnt != 0)
494 {
495 /* skip empty bundles */
496 while (pExpState->pb32->b32_cnt != 0 && pExpState->pb32->b32_type == EMPTY)
497 {
498 pExpState->iOrdinal += pExpState->pb32->b32_cnt;
499 pExpState->pb32 = (struct b32_bundle*)((char*)pExpState->pb32 + 2);
500 }
501
502 /* FIXME forwarders are not implemented so we'll skip them too. */
503 while (pExpState->pb32->b32_cnt != 0 && (pExpState->pb32->b32_type & ~TYPEINFO) == ENTRYFWD)
504 {
505 pExpState->iOrdinal += pExpState->pb32->b32_cnt;
506 pExpState->pb32 = (struct b32_bundle*)((char*)(pExpState->pb32 + 1) + pExpState->pb32->b32_cnt * 7);
507 }
508
509 /* we'll ignore any flags for the moment - TODO */
510 if (pExpState->pb32->b32_cnt != 0)
511 {
512 pExpState->iOrdinalBundle = pExpState->iOrdinal;
513
514 pExport->ulOrdinal = pExpState->iOrdinal;
515 pExport->iObject = pExpState->pb32->b32_obj;
516
517 /* look for name */
518 pExport->achIntName[0] = '\0';
519 if (!queryExportName(pExpState->iOrdinal, pExport->achName))
520 pExport->achName[0] = '\0';
521
522 pExpState->pe32 = (struct e32_entry*)(pExpState->pb32+1);
523 switch (pExpState->pb32->b32_type & ~TYPEINFO)
524 {
525 case ENTRY16:
526 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset16;
527 break;
528
529 case ENTRY32:
530 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset32;
531 break;
532
533 case GATE16:
534 pExport->ulOffset = pExpState->pe32->e32_variant.e32_callgate.offset;
535 break;
536 default:
537 kASSERT(!"ARG!!!! invalid bundle type!");
538 }
539
540 return TRUE;
541 }
542 }
543
544
545 /*
546 * No more exports - clean up
547 */
548 free(pExport->pv);
549 pExport->pv = NULL;
550 return FALSE;
551}
552
553
554/**
555 * Frees resources associated with the communicatin area.
556 * It's not necessary to call this when exportFindNext has return FALSE.
557 * @param pExport Communication area which has been successfully
558 * processed by findFirstExport.
559 */
560void kFileLX::exportFindClose(kExportEntry *pExport)
561{
562 delete pExport->pv;
563 pExport->pv = NULL;
564 return;
565}
566
567
568/**
569 * Lookup information on a spesific export given by ordinal number.
570 * @returns Success indicator.
571 * @param pExport Communication area containing export information
572 * on successful return.
573 * @remark stub
574 */
575KBOOL kFileLX::exportLookup(unsigned long ulOrdinal, kExportEntry *pExport)
576{
577 kASSERT(!"not implemented.");
578 ulOrdinal = ulOrdinal;
579 pExport = pExport;
580 return FALSE;
581}
582
583/**
584 * Lookup information on a spesific export given by name.
585 * @returns Success indicator.
586 * @param pExport Communication area containing export information
587 * on successful return.
588 * @remark stub
589 */
590KBOOL kFileLX::exportLookup(const char * pszName, kExportEntry *pExport)
591{
592 kASSERT(!"not implemented.");
593 pszName = pszName;
594 pExport = pExport;
595 return FALSE;
596}
597
598
599/**
600 * Gets a specific LX object.
601 * @returns Pointer to object. NULL on error / invalid index.
602 * @param iObject object number (0-based)
603 */
604struct o32_obj * kFileLX::getObject(int iObject)
605{
606
607 if (iObject < pe32->e32_objcnt)
608 return &paObject[iObject];
609 return NULL;
610}
611
612
613/**
614 * Gets the count of LX objects.
615 * @returns Count of LX objects.
616 */
617int kFileLX::getObjectCount()
618{
619 return (int)pe32->e32_objcnt;
620}
621
622
623/**
624 * Get a code, data or resource page from the file.
625 * @returns 0 on success. kError number on error.
626 * @param pachPage Pointer to a buffer of the size of a page which
627 * will receive the page data on the specified address.
628 * @param ulAddress Page address. This must be page aligned.
629 */
630int kFileLX::pageGet(char *pachPage, unsigned long ulAddress) const
631{
632 int iObj;
633
634 for (iObj = 0; iObj < pe32->e32_objcnt; iObj++)
635 if ( paObject[iObj].o32_base <= ulAddress
636 && paObject[iObj].o32_base + paObject[iObj].o32_size > ulAddress
637 )
638 return pageGet(pachPage, iObj, ulAddress - paObject[iObj].o32_base);
639
640 return kError::INVALID_ADDRESS;
641}
642
643/**
644 * Get a code, data or resource page from the file.
645 * @returns 0 on success. kError number on error.
646 * @param pachPage Pointer to a buffer of the size of a page which
647 * will receive the page data on the specified address.
648 * @param iSegment Segment number. (0-based)
649 * @param offObject Offset into the object. This must be page aligned.
650 * @remark Object = Section.
651 */
652int kFileLX::pageGet(char *pachPage, int iSegment, int offObject) const
653{
654 /*
655 * Validation.
656 */
657 if (offObject & (pe32->e32_pagesize - 1))
658 return kError::BAD_ALIGNMENT;
659 if (iSegment >= pe32->e32_objcnt)
660 return kError::INVALID_SEGMENT_NUMBER;
661 if (offObject >= paObject[iSegment].o32_size)
662 return kError::INVALID_OFFSET;
663
664 /*
665 * Is there a pagemap entry for the requested page?
666 */
667 if ((offObject / pe32->e32_pagesize) < paObject[iSegment].o32_mapsize)
668 { /* yes */
669 int iPage = (offObject / pe32->e32_pagesize) + paObject[iSegment].o32_pagemap - 1;
670 char * pchPageData = (char*)((paMap[iPage].o32_pagedataoffset << pe32->e32_pageshift) + pe32->e32_datapage + (char*)pvBase);
671
672 switch (paMap[iPage].o32_pageflags)
673 {
674 case VALID:
675 memcpy(pachPage, pchPageData, paMap[iPage].o32_pagesize);
676 if (paMap[iPage].o32_pagesize < pe32->e32_pagesize)
677 memset(pachPage + paMap[iPage].o32_pagesize, 0, pe32->e32_pagesize - paMap[iPage].o32_pagesize);
678 break;
679
680 case ITERDATA:
681 {
682 char achTempBuffer[0x1004];
683 memcpy(achTempBuffer, pchPageData, paMap[iPage].o32_pagesize);
684 memset(achTempBuffer + paMap[iPage].o32_pagesize, 0, 4);
685 return kFileLX::expandPage1(pachPage, pe32->e32_pagesize, achTempBuffer, paMap[iPage].o32_pagesize);
686 }
687
688 case INVALID:
689 return kError::INVALID_PAGE;
690
691 case ZEROED:
692 memset(pachPage, 0, pe32->e32_pagesize);
693 break;
694
695 case ITERDATA2:
696 {
697 char achTempBuffer[0x1004];
698 memcpy(achTempBuffer, pchPageData, paMap[iPage].o32_pagesize);
699 memset(achTempBuffer + paMap[iPage].o32_pagesize, 0, 4);
700 return kFileLX::expandPage2(pachPage, pe32->e32_pagesize, achTempBuffer, paMap[iPage].o32_pagesize);
701 }
702
703 case RANGE:
704 default:
705 return kError::BAD_EXE_FORMAT;
706 }
707
708 }
709 else
710 { /* no, so it's a zerofilled page */
711 memset(pachPage, 0, pe32->e32_pagesize);
712 }
713
714 return 0;
715}
716
717
718/**
719 * Updates or adds a code, data, or resource page to the file.
720 * @returns 0 on success. kError number on error.
721 * @param pachPage Pointer to a buffer of the size of a page which
722 * holds the page data.
723 * @param ulAddress Page address. This must be page aligned.
724 */
725int kFileLX::pagePut(const char *pachPage, unsigned long ulAddress)
726{
727 int iObj;
728
729 for (iObj = 0; iObj < pe32->e32_objcnt; iObj++)
730 if ( paObject[iObj].o32_base <= ulAddress
731 && paObject[iObj].o32_base + paObject[iObj].o32_size > ulAddress
732 )
733 return pagePut(pachPage, iObj, ulAddress - paObject[iObj].o32_base);
734
735 return kError::INVALID_ADDRESS;
736}
737
738
739/**
740 * Updates or adds a code, data, or resource page to the file.
741 * @returns 0 on success. kError number on error.
742 * @param pachPage Pointer to a buffer of the size of a page which
743 * holds the page data.
744 * @param iSegment Segment number. (0-based)
745 * @param offObject Offset into the object. This must be page aligned.
746 */
747int kFileLX::pagePut(const char *pachPage, int iSegment, int offObject)
748{
749 /*
750 * Validation.
751 */
752 if (offObject & (pe32->e32_pagesize - 1))
753 return kError::BAD_ALIGNMENT;
754 if (iSegment >= pe32->e32_objcnt)
755 return kError::INVALID_SEGMENT_NUMBER;
756 if (offObject >= paObject[iSegment].o32_size)
757 return kError::INVALID_OFFSET;
758
759 /*
760 * Is there a pagemap entry for the page?
761 */
762 if ((offObject / pe32->e32_pagesize) < paObject[iSegment].o32_mapsize)
763 { /* yes */
764 int iPage = (offObject / pe32->e32_pagesize) + paObject[iSegment].o32_pagemap - 1;
765 char * pchPageData = (char*)((paMap[iPage].o32_pagedataoffset << pe32->e32_pageshift) + pe32->e32_datapage + (char*)pvBase);
766 const char *pchPageToWrite = NULL;
767 int cchPageToWrite = 0;
768 long offPageToWrite = (paMap[iPage].o32_pagedataoffset << pe32->e32_pageshift) + pe32->e32_datapage;
769
770 switch (paMap[iPage].o32_pageflags)
771 {
772 case VALID:
773 pchPageToWrite = pachPage;
774 cchPageToWrite = 0x1000;
775 if (paMap[iPage].o32_pagesize != 0x1000)
776 {
777 /*
778 * Check that everything after pagesize is zero.
779 */
780 for (const char *pch = &pachPage[paMap[iPage].o32_pagesize]; pch < &pachPage[0x1000]; pch++)
781 if (*pch)
782 return kError::NOT_SUPPORTED;
783 cchPageToWrite = paMap[iPage].o32_pagesize;
784}
785 break;
786
787 case ITERDATA:
788 case ITERDATA2:
789 {
790 char * pchCompressedPage = (char*)alloca(pe32->e32_pagesize+4);
791
792 /* remove spaces at the end of the page. */
793 int cchPage = pe32->e32_pagesize;
794 while (pachPage[cchPage-1] == '\0')
795 cchPage--;
796
797 /* call the compression function */
798 if (paMap[iPage].o32_pageflags == ITERDATA)
799 cchPageToWrite = kFileLX::compressPage1(pchCompressedPage, pachPage, cchPage);
800 else
801 cchPageToWrite = kFileLX::compressPage2(pchCompressedPage, pachPage, cchPage);
802 //if (cchPageToWrite != paMap[iPage].o32_pagesize)
803 // printf("compressPageX returned %d (%x) previous size %d (%x)\n", cchPageToWrite, cchPageToWrite, paMap[iPage].o32_pagesize, paMap[iPage].o32_pagesize);
804 if (cchPageToWrite < 0)
805 return kError::NOT_SUPPORTED;
806 #if 0
807 int cbLeft = KMIN(2, paMap[iPage].o32_pagesize - cchPageToWrite);
808 if (cbLeft > 0)
809{
810 memset(&pchCompressedPage[cchPageToWrite], 0, cbLeft);
811 cchPageToWrite += cbLeft;
812 }
813 #else
814 kASSERT(paMap[iPage].o32_pagesize - cchPageToWrite >= 0);
815 memset(&pchCompressedPage[cchPageToWrite], 0, paMap[iPage].o32_pagesize - cchPageToWrite);
816 cchPageToWrite = paMap[iPage].o32_pagesize;
817 #endif
818 pchPageToWrite = pchCompressedPage;
819 break;
820}
821
822 case ZEROED:
823{
824 /*
825 * If the passed in page is not a zero page we'll fail.
826 */
827 for (unsigned long * pul = (unsigned long *)pachPage; (char*)pul < &pachPage[0x1000]; pul++)
828 if (*pul)
829 return kError::NOT_SUPPORTED;
830 return 0;
831 }
832
833 case INVALID:
834 return kError::INVALID_PAGE;
835
836 case RANGE:
837 default:
838 return kError::BAD_EXE_FORMAT;
839 }
840
841 /*
842 * Write stuff to file.
843 */
844 pFile->setFailOnErrors();
845 return pFile->writeAt((void*)pchPageToWrite, cchPageToWrite, offPageToWrite);
846 }
847 else
848 { /*
849 * No, it's a zerofilled page
850 * If the passed in page is not a zero page we'll fail.
851 */
852 for (unsigned long * pul = (unsigned long *)pachPage; (char*)pul < &pachPage[0x1000]; pul++)
853 if (*pul)
854 return kError::NOT_SUPPORTED;
855}
856
857 return 0;
858}
859
860
861/**
862 * Get pagesize for the file.
863 * @returns Pagesize in bytes.
864 */
865int kFileLX::pageGetPageSize() const
866{
867 return pe32->e32_pagesize;
868}
869
870
871/**
872 * Expands a page compressed with the old exepack method introduced with OS/2 2.0.
873 * (/EXEPACK or just /EXEPACK)
874 * @returns 0 on success. kError error code on error.
875 * @param pachPage Pointer to output page. size: cchPage
876 * Upon successful return this will contain the expanded page data.
877 * @param cchPage Page size.
878 * @param pachSrcPage Pointer to source data. size: cchSrcPage.
879 * This data should be compressed with EXEPACK:2!
880 * @param cchSrcPage Size of compressed data.
881 * @sketch Have no good idea right now.
882 * @status Completely implemented.
883 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
884 * @remark
885 */
886int kFileLX::expandPage1(char *pachPage, int cchPage, const char * pachSrcPage, int cchSrcPage)
887{
888 struct LX_Iter *pIter = (struct LX_Iter *)pachSrcPage;
889 char * pachDestPage = pachPage; /* Store the pointer for boundrary checking. */
890
891 /* Validate size of data. */
892 if (cchSrcPage >= cchPage - 2)
893 return kError::BAD_ITERPAGE;
894
895 /*
896 * Expand the page.
897 */
898 while (pIter->LX_nIter && cchSrcPage > 0)
899 {
900 /* Check if we're out of bound. */
901 if ( pachPage - pachDestPage + pIter->LX_nIter * pIter->LX_nBytes > cchPage
902 || cchSrcPage <= 0)
903 return kError::BAD_ITERPAGE;
904
905 //if (pIter->LX_nIter == 1)
906 // printf("get 0x%03x stored %3d bytes\n", pachPage - pachDestPage, pIter->LX_nBytes);
907 //else
908 // printf("get 0x%03x %3d iterations %3d bytes\n", pachPage - pachDestPage, pIter->LX_nIter, pIter->LX_nBytes);
909
910 if (pIter->LX_nBytes == 1)
911 { /* one databyte */
912 memset(pachPage, pIter->LX_Iterdata, pIter->LX_nIter);
913 pachPage += pIter->LX_nIter;
914 cchSrcPage -= 4 + 1;
915 pIter++;
916 }
917 else
918 {
919 for (int i = pIter->LX_nIter; i > 0; i--, pachPage += pIter->LX_nBytes)
920 memcpy(pachPage, &pIter->LX_Iterdata, pIter->LX_nBytes);
921 cchSrcPage -= 4 + pIter->LX_nBytes;
922 pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
923 }
924 }
925
926 /*
927 * Zero remaining part of the page.
928 */
929 if (pachPage - pachDestPage < cchPage)
930 memset(pachPage, 0, cchPage - (pachPage - pachDestPage));
931
932 return 0;
933 }
934
935
936/**
937 * Expands a page compressed with the exepack method introduced with OS/2 Warp 3.0.
938 * (/EXEPACK:2)
939 * @returns 0 on success. kError error code on error.
940 * @param pachPage Pointer to output page. size: PAGESIZE
941 * Upon successful return this will contain the expanded page data.
942 * @param cchPage Page size.
943 * @param pachSrcPage Pointer to source data. size: cchSrcPage.
944 * This data should be compressed with EXEPACK:2!
945 * @param cchSrcPage Size of compressed data.
946 * @sketch Have no good idea right now.
947 * @status Completely implemented and tested.
948 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
949 * @remark tested.
950 */
951int kFileLX::expandPage2(char *pachPage, int cchPage, const char * pachSrcPage, int cchSrcPage)
952{
953 char * pachDestPage = pachPage; /* Store the pointer for boundrary checking. */
954
955 while (cchSrcPage > 0)
956 {
957 /*
958 * Bit 0 and 1 is the encoding type.
959 */
960 switch (*pachSrcPage & 0x03)
961 {
962 /*
963 *
964 * 0 1 2 3 4 5 6 7
965 * type | |
966 * ----------------
967 * cch <cch bytes of data>
968 *
969 * Bits 2-7 is, if not zero, the length of an uncompressed run
970 * starting at the following byte.
971 *
972 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
973 * type | | | | | |
974 * ---------------- ---------------------- -----------------------
975 * zero cch char to multiply
976 *
977 * If the bits are zero, the following two bytes describes a
978 * 1 byte interation run. First byte is count, second is the byte to copy.
979 * A count of zero is means end of data, and we simply stops. In that case
980 * the rest of the data should be zero.
981 */
982 case 0:
983 {
984 if (*pachSrcPage)
985 {
986 int cch = *pachSrcPage >> 2;
987 if (cchPage < cch || cchSrcPage < cch + 1)
988 return kError::BAD_COMPESSED_PAGE;
989 memcpy(pachPage, pachSrcPage+1, cch);
990 pachPage += cch, cchPage -= cch;
991 pachSrcPage += cch + 1, cchSrcPage -= cch + 1;
992 break;
993 }
994 if (cchSrcPage < 2)
995 return kError::BAD_COMPESSED_PAGE;
996 int cch = pachSrcPage[1];
997 if (cch)
998 {
999 if (cchSrcPage < 3 || cchPage < cch)
1000 return kError::BAD_COMPESSED_PAGE;
1001 memset(pachPage, pachSrcPage[2], cch);
1002 pachPage += cch, cchPage -= cch;
1003 pachSrcPage += 3, cchSrcPage -= 3;
1004 break;
1005 }
1006 goto endloop;
1007 }
1008
1009
1010 /*
1011 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1012 * type | | | | | |
1013 * ---- ------- -------------------------
1014 * cch1 cch2 - 3 offset <cch1 bytes of data>
1015 *
1016 * Two bytes layed out as described above, followed by cch1 bytes of data to be copied.
1017 * The cch2(+3) and offset describes an amount of data to be copied from the expanded
1018 * data relative to the current position. The data copied as you would expect it to be.
1019 */
1020 case 1:
1021 {
1022 if (cchSrcPage < 2)
1023 return kError::BAD_COMPESSED_PAGE;
1024 int off = *(unsigned short*)pachSrcPage >> 7;
1025 int cch1 = *pachSrcPage >> 2 & 3;
1026 int cch2 = (*pachSrcPage >> 4 & 7) + 3;
1027 pachSrcPage += 2, cchSrcPage -= 2;
1028 if (cchSrcPage < cch1 || cchPage < cch1 + cch2 || pachPage + cch1 - off < pachDestPage)
1029 return kError::BAD_COMPESSED_PAGE;
1030 memcpy(pachPage, pachSrcPage, cch1);
1031 pachPage += cch1, cchPage -= cch1;
1032 pachSrcPage += cch1, cchSrcPage -= cch1;
1033 memcpyb(pachPage, pachPage - off, cch2); //memmove doesn't do a good job here for some stupid reason.
1034 pachPage += cch2, cchPage -= cch2;
1035 break;
1036 }
1037
1038
1039 /*
1040 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1041 * type | | | |
1042 * ---- ----------------------------------
1043 * cch-3 offset
1044 *
1045 * Two bytes layed out as described above.
1046 * The cch(+3) and offset describes an amount of data to be copied from the expanded
1047 * data relative to the current position.
1048 *
1049 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1050 */
1051 case 2:
1052 {
1053 if (cchSrcPage < 2)
1054 return kError::BAD_COMPESSED_PAGE;
1055 int off = *(unsigned short*)pachSrcPage >> 4;
1056 int cch = (*pachSrcPage >> 2 & 3) + 3;
1057 pachSrcPage += 2, cchSrcPage -= 2;
1058 if (cchPage < cch || pachPage - off < pachDestPage)
1059 return kError::BAD_COMPESSED_PAGE;
1060 memcpyw(pachPage, pachPage - off, cch);
1061 pachPage += cch, cchPage -= cch;
1062 break;
1063 }
1064
1065
1066 /*
1067 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1068 * type | | | | | |
1069 * ---------- ---------------- ----------------------------------
1070 * cch1 cch2 offset <cch1 bytes of data>
1071 *
1072 * Three bytes layed out as described above, followed by cch1 bytes of data to be copied.
1073 * The cch2 and offset describes an amount of data to be copied from the expanded
1074 * data relative to the current position.
1075 *
1076 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1077 */
1078 case 3:
1079 {
1080 if (cchSrcPage < 3)
1081 return kError::BAD_COMPESSED_PAGE;
1082 int cch1 = *pachSrcPage >> 2 & 0x000f;
1083 int cch2 = *(unsigned short*)pachSrcPage >> 6 & 0x003f;
1084 int off = *(unsigned short*)(pachSrcPage+1) >> 4;
1085 pachSrcPage += 3, cchSrcPage -= 3;
1086 if (cchSrcPage < cch1 || cchPage < cch1 + cch2 || pachPage - off + cch1 < pachDestPage)
1087 return kError::BAD_COMPESSED_PAGE;
1088 memcpy(pachPage, pachSrcPage, cch1);
1089 pachPage += cch1, cchPage -= cch1;
1090 pachSrcPage += cch1, cchSrcPage -= cch1;
1091 memcpyw(pachPage, pachPage - off, cch2);
1092 pachPage += cch2, cchPage -= cch2;
1093 break;
1094 }
1095 }
1096 }
1097
1098endloop:;
1099
1100
1101 /*
1102 * Zero the rest of the page.
1103 */
1104 if (cchPage > 0)
1105 memset(pachPage, 0, cchPage);
1106
1107 return 0;
1108 }
1109
1110
1111/**
1112 * This is a special memcpy for expandPage2 which performs a word based copy.
1113 * The difference between this, memmove and memcpy is that we'll allways read words.
1114 * @param pch1 Target pointer.
1115 * @param pch2 Source pointer.
1116 * @param cch size of memory block to copy from pch2 to pch1.
1117 * @author knut st. osmundsen (kosmunds@csc.com)
1118 * @remark
1119 */
1120inline void memcpyw(char *pch1, const char *pch2, size_t cch)
1121{
1122 /*
1123 * Use memcpy if possible.
1124 */
1125 if ((pch2 > pch1 ? pch2 - pch1 : pch1 - pch2) >= 4)
1126 {
1127 memcpy(pch1, pch2, cch); /* BUGBUG! ASSUMES that memcpy move NO more than 4 bytes at the time! */
1128 return;
1129 }
1130
1131 /*
1132 * Difference is less than 3 bytes.
1133 */
1134 if (cch & 1)
1135 *pch1++ = *pch2++;
1136
1137 #if 0 //haven't found anyone yet. (not a big surprize!)
1138 /* Looking for a very special case! I wanna see if my theory is right. */
1139 if ((pch2 > pch1 ? pch2 - pch1 : pch1 - pch2) <= 1)
1140 INT3();
1141#endif
1142
1143 for (cch >>= 1; cch > 0; cch--, pch1 += 2, pch2 += 2)
1144 *(unsigned short *)pch1 = *(unsigned short *)pch2;
1145}
1146
1147
1148/**
1149 * This is a special memcpy for expandPage2 which performs a memmove operation.
1150 * The difference between this and memmove is that this one works.
1151 *
1152 * @param pch1 Target pointer.
1153 * @param pch2 Source pointer.
1154 * @param cch size of memory block to copy from pch2 to pch1.
1155 * @author knut st. osmundsen (kosmunds@csc.com)
1156 */
1157inline void memcpyb(char *pch1, const char *pch2, size_t cch)
1158{
1159 /*
1160 * Use memcpy if possible.
1161 */
1162 if ((pch2 > pch1 ? pch2 - pch1 : pch1 - pch2) >= 4)
1163{
1164 memcpy(pch1, pch2, cch); /* BUGBUG! ASSUMES that memcpy move NO more than 4 bytes at the time! */
1165 return;
1166 }
1167
1168 /*
1169 * Difference is less than 3 bytes.
1170 */
1171 while(cch--)
1172 *pch1++ = *pch2++;
1173}
1174
1175
1176
1177/**
1178 * Compresses a page using the old exepack method introduced with OS/2 2.0.
1179 * (/EXEPACK:1 or just /EXEPACK)
1180 * @returns Size of the compressed page in the pachPage buffer.
1181 * PAGESIZE if failed to compress the page.
1182 * -1 on error.
1183 * @param pachPage Pointer to output buffer. size: cchSrcPage.
1184 * This will hold the compressed page data upon return.
1185 * @param pachSrcPage Pointer to page to compress. size: cchSrcPage.
1186 * @param cchSrcPage Page size.
1187 * @sketch
1188 * @status stub.
1189 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1190 * @remark Not implemented.
1191 */
1192
1193int compressPage1Search(const char *pch, const char **ppchSearch, const char *pchEnd, int *pcIterations)
1194{
1195 int cch;
1196 const char* pchStart = pch;
1197 const char* pchSearch = *ppchSearch;
1198
1199// if (pch < pchSearch)
1200// pch = pchSearch - 1;
1201 while ((cch = pchSearch - pch) > 0)
1202{
1203 int cchLeft = pchEnd - pchSearch;
1204 if (cchLeft < cch)
1205 {pch++; continue;}
1206 int cIter = 1;
1207 const char *pchMatch = pchSearch;
1208 while (pchMatch < pchEnd && !memcmp(pchMatch, pch, cch))
1209 pchMatch += cch, cIter++;
1210
1211 int cchCost = pchStart < pch ? cch + 8 : cch + 4;
1212 if (cIter == 1 || cIter * cch < cchCost)
1213 {pch++; continue;}
1214 *ppchSearch = pch;
1215 *pcIterations = cIter;
1216 return cch;
1217 }
1218
1219 return -1;
1220}
1221
1222int compressPage1SearchStored(const char *pchStart, const char *pchEnd, int *pcchRun)
1223{
1224 if (pchStart+1 == pchEnd)
1225 return FALSE;
1226
1227 const char *pch = pchStart;
1228 char ch = *pch++;
1229 while (pch < pchEnd)
1230 if (*pch++ != ch)
1231 break;
1232
1233 if (pch == pchEnd)
1234 {
1235 *pcchRun = 1;
1236 return TRUE;
1237 }
1238
1239 int cch = pchEnd - pchStart;
1240 if (cch < 4 && cch % 2 != 0)
1241 return FALSE;
1242
1243 unsigned short* pus = (unsigned short*)pchStart;
1244 unsigned short us = *pus++;
1245 while ((const char*)pus < pchEnd)
1246 if (*pus++ != us)
1247 return 0;
1248
1249 *pcchRun = 2;
1250 return TRUE;
1251}
1252
1253
1254int kFileLX::compressPage1(char *pachPage, const char * pachSrcPage, int cchSrcPage)
1255{
1256 union
1257 {
1258 char * pch;
1259 unsigned short * push;
1260 struct LX_Iter * pIter;
1261 } Dst;
1262 Dst.pch = pachPage;
1263 const char *pch = pachSrcPage;
1264 const char *pchSearch = pch;
1265 const char *pchEnd = pch + cchSrcPage;
1266 while (pchSearch < pchEnd)
1267 {
1268 int cIterations;
1269 int cchPattern = compressPage1Search(pch, &pchSearch, pchEnd, &cIterations);
1270 if (cchPattern > 0)
1271 { /* Found pattern. */
1272 /* make uncompressed chunk. */
1273 if (pch < pchSearch)
1274 {
1275 int cchRun;
1276 int cch = pchSearch - pch;
1277 if (cch < 9 && cch > 1 && compressPage1SearchStored(pch, pchSearch, &cchRun))
1278 {
1279 /* make compressed chunk. */
1280 Dst.pIter->LX_nIter = cch / cchRun;
1281 Dst.pIter->LX_nBytes = cchRun;
1282 memcpy(&Dst.pIter->LX_Iterdata, pch, cchPattern);
1283 //printf("put 0x%03x %3d iterations %3d bytes\n", pch - pachSrcPage, Dst.pIter->LX_nIter, Dst.pIter->LX_nBytes);
1284 Dst.pch += cchRun + 4;
1285 }
1286 else
1287 { /* make uncompressed chunk */
1288 Dst.pIter->LX_nIter = 1;
1289 Dst.pIter->LX_nBytes = cch;
1290 memcpy(&Dst.pIter->LX_Iterdata, pch, cch);
1291 //printf("put 0x%03x stored %3d bytes\n", pch - pachSrcPage, Dst.pIter->LX_nBytes);
1292 Dst.pch += cch + 4;
1293 }
1294 pch += cch;
1295 }
1296
1297 /* make compressed chunk. */
1298 Dst.pIter->LX_nIter = cIterations;
1299 Dst.pIter->LX_nBytes = cchPattern;
1300 memcpy(&Dst.pIter->LX_Iterdata, pch, cchPattern);
1301 //printf("put 0x%03x %3d iterations %3d bytes\n", pch - pachSrcPage, Dst.pIter->LX_nIter, Dst.pIter->LX_nBytes);
1302 Dst.pch += cchPattern + 4;
1303 pchSearch = pch += cchPattern * cIterations;
1304 }
1305 else
1306 { /* No pattern - got the next byte in the source page. */
1307 pchSearch++;
1308 }
1309 }
1310
1311 /* make final uncompressed chunk(s) */
1312 if (pch < pchSearch)
1313 {
1314 int cch = pchSearch - pch;
1315 Dst.pIter->LX_nIter = 1;
1316 Dst.pIter->LX_nBytes = cch;
1317 memcpy(&Dst.pIter->LX_Iterdata, pch, cch);
1318 //printf("put 0x%03x stored %3d bytes %d\n", pch - pachSrcPage, Dst.pIter->LX_nBytes, cch);
1319 Dst.pch += cch + 4;
1320 pch += cch;
1321 }
1322
1323
1324
1325 /* write terminating word - this is really not needed AFAIK, but it makes debugging easier. */
1326 //*Dst.push++ = 0;
1327 return Dst.pch - pachPage;
1328}
1329
1330
1331
1332/**
1333 * Compresses a page using the exepack method introduced with OS/2 Warp 3.0.
1334 * (/EXEPACK:2)
1335 * @returns Size of the compressed page in the pachPage buffer.
1336 * PAGESIZE if failed to compress the page.
1337 * -1 on error.
1338 * @param pachPage Pointer to output buffer. size: cchSrcPage.
1339 * This will hold the compressed page data upon return.
1340 * @param pachSrcPage Pointer to page to compress. size: cchSrcPage.
1341 * @param cchSrcPage Page size.
1342 * @sketch Have no idea!
1343 * @status stub.
1344 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1345 * @remark Not implemented.
1346 */
1347int kFileLX::compressPage2(char *pachPage, const char * pachSrcPage, int cchSrcPage)
1348{
1349 KNOREF(pachPage);
1350 KNOREF(pachSrcPage);
1351 KNOREF(cchSrcPage);
1352 return -1;
1353}
1354
1355
1356/**
1357 * Start a relocation enumeration.
1358 * @returns TRUE: Found relocation.
1359 * FALSE: No more relocations.
1360 * @param ulSegment Segment number. Special selector may be specified.
1361 * @param offSegment Offset into the segment described by ulSegment.
1362 * @param preloc Pointer to a relocation 'handle' structure.
1363 * This is used for communicating the relocations in
1364 * a generic format and for keeping track of the current position.
1365 * Please, DO NOT change any members of this structure.
1366 */
1367KBOOL kFileLX::relocFindFirst(unsigned long ulSegment, unsigned long offSegment, kRelocEntry *preloc)
1368{
1369 if (ulSegment >= kRelocEntry::enmFirstSelector)
1370 offSegment = lxSpecialSelectorToObjectOffset(offSegment, &ulSegment);
1371
1372 if ( lxValidateObjectOffset(ulSegment, offSegment)
1373 && pe32->e32_frectab != 0
1374 && pe32->e32_fpagetab != 0
1375 )
1376 {
1377 PLXRELOCSTATE pState = new LXRELOCSTATE;
1378 pState->ulSegment = ulSegment;
1379 pState->ulPage = paObject[ulSegment].o32_pagemap - 1;
1380 pState->pchFixupRec = pchFixupRecs + paulFixupPageTable[pState->ulPage];
1381 pState->usSrcOffIdx = 0;
1382 preloc->pv1 = (void*)pState;
1383 preloc->fFlags = 0;
1384 preloc->Info.Name.pszModule = NULL;
1385 preloc->Info.Name.pszName = NULL;
1386 return relocFindNext(preloc);
1387}
1388
1389 return FALSE;
1390}
1391
1392
1393/**
1394 * Start a relocation enumeration.
1395 * @returns TRUE: Found relocation.
1396 * FALSE: No more relocations.
1397 * @param ulAddress Address to start from.
1398 * @param preloc Pointer to a relocation 'handle' structure.
1399 * This is used for communicating the relocations in
1400 * a generic format and for keeping track of the current position.
1401 * Please, DO NOT change any members of this structure.
1402 */
1403KBOOL kFileLX::relocFindFirst(unsigned long ulAddress, kRelocEntry *preloc)
1404{
1405 return relocFindFirst(kRelocEntry::enmVASelector, ulAddress, preloc);
1406}
1407
1408
1409/**
1410 * Get the next relocation.
1411 * @returns TRUE: Found relocation.
1412 * FALSE: No more relocations.
1413 * @param preloc Pointer to a relocation 'handle' structure.
1414 * @remark preloc have to be opened by relocFindFirst before calling relocFindNext!
1415 */
1416KBOOL kFileLX::relocFindNext(kRelocEntry *preloc)
1417{
1418 PLXRELOCSTATE pState = (PLXRELOCSTATE)preloc->pv1;
1419 int iObj = pState->ulSegment;
1420 KBOOL fFound = FALSE;
1421
1422 while (iObj < pe32->e32_objcnt)
1423 {
1424 int iPage = pState->ulPage;
1425
1426 while (iPage < paObject[iObj].o32_mapsize + paObject[iObj].o32_pagemap - 1)
1427 {
1428 char * pchFixupRecEnd = pchFixupRecs + paulFixupPageTable[iPage + 1];
1429
1430 while (pState->pchFixupRec < pchFixupRecEnd)
1431 {
1432 char * pch; /* Fixup record walker. */
1433 union _rel
1434 {
1435 unsigned long ul;
1436 char * pch;
1437 struct r32_rlc *prlc;
1438 } rel; /* Fixup record */
1439
1440 /*
1441 * If we're completed here we'll simply return.
1442 */
1443 if (fFound)
1444 return TRUE;
1445
1446
1447 /*
1448 * Do some init and cleanup.
1449 */
1450 rel.pch = pState->pchFixupRec;
1451 if (preloc->isName())
1452 {
1453 delete (void*)preloc->Info.Name.pszModule;
1454 delete (void*)preloc->Info.Name.pszName;
1455 preloc->Info.Name.pszName = preloc->Info.Name.pszModule = NULL;
1456 }
1457
1458
1459 /*
1460 * We've got a problem! chained relocation records!
1461 */
1462 switch (rel.prlc->nr_stype & NRSTYP)
1463 {
1464 case NRSBYT: preloc->fFlags = kRelocEntry::enm8 | kRelocEntry::enmOffset; break;
1465 case NRSSEG: preloc->fFlags = kRelocEntry::enm16_00 | kRelocEntry::enmOffset; break;
1466 case NRSPTR: preloc->fFlags = kRelocEntry::enm16_16 | kRelocEntry::enmOffset; break;
1467 case NRSOFF: preloc->fFlags = kRelocEntry::enm16 | kRelocEntry::enmOffset; break;
1468 case NRPTR48: preloc->fFlags = kRelocEntry::enm16_32 | kRelocEntry::enmOffset; break;
1469 case NROFF32: preloc->fFlags = kRelocEntry::enm32 | kRelocEntry::enmOffset; break;
1470 case NRSOFF32: preloc->fFlags = kRelocEntry::enm32 | kRelocEntry::enmRelEnd; break;
1471 default:
1472 kASSERT(FALSE);
1473 return FALSE;
1474 }
1475
1476 /* Set endian flag. */
1477 if (pe32->e32_border == E32LEBO && pe32->e32_border == E32LEWO)
1478 preloc->fFlags |= kRelocEntry::enmLittleEndian;
1479 else if (pe32->e32_border == E32BEBO && pe32->e32_border == E32BEWO)
1480 preloc->fFlags |= kRelocEntry::enmBigEndian;
1481 else
1482 {
1483 kASSERT(FALSE);
1484 return FALSE;
1485 }
1486
1487
1488 /*
1489 * LX target type.
1490 */
1491 pch = rel.pch + 3 + (rel.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */
1492 switch (rel.prlc->nr_flags & NRRTYP)
1493 {
1494 case NRRINT:
1495 preloc->fFlags |= kRelocEntry::enmInternal;
1496 if (rel.prlc->nr_flags & NR16OBJMOD)
1497 {
1498 preloc->Info.Internal.ulSegment = *(unsigned short *)pch - 1;
1499 pch += 2;
1500 }
1501 else
1502 {
1503 preloc->Info.Internal.ulSegment = *(unsigned char *)pch - 1;
1504 pch += 1;
1505 }
1506 if (rel.prlc->nr_flags & NR32BITOFF)
1507 {
1508 preloc->Info.Internal.offSegment = *(unsigned long *)pch;
1509 pch += 4;
1510 }
1511 else
1512 {
1513 preloc->Info.Internal.offSegment = *(unsigned short *)pch;
1514 pch += 2;
1515 }
1516 break;
1517
1518 case NRRORD:
1519 preloc->fFlags |= kRelocEntry::enmOrdDLL;
1520 if (rel.prlc->nr_flags & NR16OBJMOD)
1521 {
1522 preloc->Info.Name.pszModule = lxGetImportModuleName(*(unsigned short *)pch);
1523 pch += 2;
1524 }
1525 else
1526 {
1527 preloc->Info.Name.pszModule = lxGetImportModuleName(*(unsigned char *)pch);
1528 pch += 1;
1529 }
1530 if (rel.prlc->nr_flags & NR32BITOFF)
1531 {
1532 sprintf(preloc->Info.Name.pszName = new char[16], "#%lu", *(unsigned long *)pch);
1533 preloc->Info.Name.ulOrdinal = (unsigned)*(unsigned long *)pch;
1534 pch += 4;
1535 }
1536 else if (rel.prlc->nr_flags & NR8BITORD)
1537 {
1538 sprintf(preloc->Info.Name.pszName = new char[8], "#%u", (unsigned)*(unsigned char *)pch);
1539 preloc->Info.Name.ulOrdinal = (unsigned)*(unsigned char *)pch;
1540 pch += 1;
1541 }
1542 else
1543 {
1544 sprintf(preloc->Info.Name.pszName = new char[12], "#%u", (unsigned)*(unsigned short *)pch);
1545 preloc->Info.Name.ulOrdinal = (unsigned)*(unsigned short *)pch;
1546 pch += 2;
1547 }
1548 break;
1549
1550 case NRRNAM:
1551 preloc->fFlags |= kRelocEntry::enmNameDLL;
1552 if (rel.prlc->nr_flags & NR16OBJMOD)
1553 {
1554 preloc->Info.Name.pszModule = lxGetImportModuleName(*(unsigned short *)pch);
1555 pch += 2;
1556 }
1557 else
1558 {
1559 preloc->Info.Name.pszModule = lxGetImportModuleName(*(unsigned char *)pch);
1560 pch += 1;
1561 }
1562 preloc->Info.Name.ulOrdinal = ~0UL;;
1563 if (rel.prlc->nr_flags & NR32BITOFF)
1564 {
1565 preloc->Info.Name.pszName = lxGetImportProcName(*(unsigned long *)pch);
1566 pch += 4;
1567 }
1568 else
1569 {
1570 preloc->Info.Name.pszName = lxGetImportProcName(*(unsigned short *)pch);
1571 pch += 2;
1572 }
1573 break;
1574
1575 case NRRENT:
1576 preloc->fFlags |= kRelocEntry::enmInternal;
1577 kASSERT(!"Not Implemented");
1578 return FALSE;
1579 }
1580
1581 /* addiative fixup? */
1582 if (rel.prlc->nr_flags & NRADD)
1583 {
1584 preloc->fFlags |= kRelocEntry::enmAdditive;
1585 if (rel.prlc->nr_flags & NR32BITADD)
1586 {
1587 preloc->ulAdd = *(unsigned long *)pch;
1588 pch += 4;
1589 }
1590 else
1591 {
1592 preloc->ulAdd = *(unsigned short *)pch;
1593 pch += 2;
1594 }
1595 }
1596
1597 /*
1598 * obj:offset of the fixup
1599 * If the offset is negative we'll skip it (ie. not set the found flag).
1600 */
1601 preloc->ulSegment = iObj;
1602 preloc->offSegment = (iPage - paObject[iObj].o32_pagemap + 1) * pe32->e32_pagesize;
1603 if (rel.prlc->nr_stype & NRCHAIN)
1604 {
1605 while (pState->usSrcOffIdx < (unsigned char)rel.prlc->r32_soff)
1606 {
1607 if (!(((unsigned short *)pch)[pState->usSrcOffIdx] & 0x8000))
1608 {
1609 preloc->offSegment += ((unsigned short*)pch)[pState->usSrcOffIdx];
1610 fFound = TRUE;
1611 break;
1612 }
1613 pState->usSrcOffIdx++;
1614 }
1615 }
1616 else
1617 {
1618 preloc->offSegment += rel.prlc->r32_soff;
1619 if (!(rel.prlc->r32_soff & 0x8000))
1620 fFound = TRUE;
1621 }
1622
1623
1624 /*
1625 * Go to the next relocation.
1626 */
1627 if (rel.prlc->nr_stype & NRCHAIN)
1628 {
1629 if (++pState->usSrcOffIdx >= (unsigned char)rel.prlc->r32_soff)
1630 {
1631 pState->pchFixupRec = pState->pchFixupRec + (KSIZE)pch - rel.ul + ((unsigned char)rel.prlc->r32_soff) * 2;
1632 pState->usSrcOffIdx = 0;
1633 }
1634 }
1635 else
1636 pState->pchFixupRec = pState->pchFixupRec + (KSIZE)pch - rel.ul;
1637 }
1638
1639
1640 /* next page */
1641 pState->ulPage = ++iPage;
1642 pState->pchFixupRec = pchFixupRecEnd;
1643 pState->usSrcOffIdx = 0; /* Source Offset Index */
1644 }
1645
1646
1647 /* next object */
1648 pState->ulSegment = ++iObj;
1649 if (iObj >= pe32->e32_objcnt)
1650 break;
1651 pState->ulPage = paObject[iObj].o32_pagemap - 1;
1652 pState->pchFixupRec = pchFixupRecs + paulFixupPageTable[pState->ulPage];
1653 pState->usSrcOffIdx = 0; /* Source Offset Index */
1654 }
1655
1656 return fFound;
1657}
1658
1659
1660/**
1661 * Closes a relocatation search/enumeration.
1662 * Will free any internally allocated resources.
1663 *
1664 * @param preloc The enumeration 'handel'.
1665 * @remark This function *must* be called to close a search/enumeration.
1666 */
1667void kFileLX::relocFindClose(kRelocEntry *preloc)
1668{
1669 /* free name storage */
1670 if (preloc->isName())
1671 {
1672 delete (void*)preloc->Info.Name.pszModule;
1673 delete (void*)preloc->Info.Name.pszName;
1674 preloc->Info.Name.pszName = preloc->Info.Name.pszModule = NULL;
1675 }
1676
1677 /* free state info */
1678 memset(preloc->pv1, 0xff, sizeof(LXRELOCSTATE));
1679 delete preloc->pv1;
1680 preloc->pv1 = (void*)0xdeadbeef;
1681}
1682
1683
1684
Note: See TracBrowser for help on using the repository browser.