source: trunk/kLdr/kLdrModLX.c@ 2974

Last change on this file since 2974 was 2974, checked in by bird, 19 years ago

off_t -> KLDRFOFF.

  • Property svn:keywords set to Id
File size: 82.8 KB
Line 
1/* $Id: kLdrModLX.c 2974 2007-02-14 10:12:44Z bird $ */
2/** @file
3 *
4 * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include "kLdrHlp.h"
33#include "kLdrInternal.h"
34#include "kLdrModLX.h"
35
36
37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** @def KLDRMODLX_STRICT
41 * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */
42#define KLDRMODLX_STRICT 1
43
44/** @def KLDRMODLX_ASSERT
45 * Assert that an expression is true when KLDR_STRICT is defined.
46 */
47#ifdef KLDRMODLX_STRICT
48# define KLDRMODLX_ASSERT(expr) kldrHlpAssert(expr)
49#else
50# define KLDRMODLX_ASSERT(expr) do {} while (0)
51#endif
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57/**
58 * Instance data for the LX module interpreter.
59 */
60typedef struct KLDRMODLX
61{
62 /** Pointer to the module. (Follows the section table.) */
63 PKLDRMOD pMod;
64 /** Pointer to the user mapping. */
65 const void *pvMapping;
66 /** The size of the mapped LX image. */
67 size_t cbMapped;
68 /** Reserved flags. */
69 uint32_t f32Reserved;
70
71 /** The offset of the LX header. */
72 KLDRFOFF offHdr;
73 /** Copy of the LX header. */
74 struct e32_exe Hdr;
75
76 /** Pointer to the loader section.
77 * Allocated together with this strcture. */
78 const uint8_t *pbLoaderSection;
79 /** Pointer to the last byte in the loader section. */
80 const uint8_t *pbLoaderSectionLast;
81 /** Pointer to the object table in the loader section. */
82 const struct o32_obj *paObjs;
83 /** Pointer to the object page map table in the loader section. */
84 const struct o32_map *paPageMappings;
85 /** Pointer to the resource table in the loader section. */
86 const struct rsrc32 *paRsrcs;
87 /** Pointer to the resident name table in the loader section. */
88 const uint8_t *pbResNameTab;
89 /** Pointer to the entry table in the loader section. */
90 const uint8_t *pbEntryTab;
91
92 /** Pointer to the non-resident name table. */
93 uint8_t *pbNonResNameTab;
94 /** Pointer to the last byte in the non-resident name table. */
95 const uint8_t *pbNonResNameTabLast;
96
97 /** Pointer to the fixup section. */
98 uint8_t *pbFixupSection;
99 /** Pointer to the last byte in the fixup section. */
100 const uint8_t *pbFixupSectionLast;
101 /** Pointer to the fixup page table within pvFixupSection. */
102 const uint32_t *paoffPageFixups;
103 /** Pointer to the fixup record table within pvFixupSection. */
104 const uint8_t *pbFixupRecs;
105 /** Pointer to the import module name table within pvFixupSection. */
106 const uint8_t *pbImportMods;
107 /** Pointer to the import module name table within pvFixupSection. */
108 const uint8_t *pbImportProcs;
109} KLDRMODLX, *PKLDRMODLX;
110
111
112/*******************************************************************************
113* Internal Functions *
114*******************************************************************************/
115static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits);
116static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
117 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
118static int kldrModLXDoCreate(PKLDRRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX);
119static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal);
120static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, uint32_t cchSymbol, uint32_t *piSymbol);
121#if 0
122static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable,
123 char *pchSymbol, size_t cchSymbol);
124#endif
125static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
126static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
127static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
128static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb);
129static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
130static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle);
131static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
132 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind);
133static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX);
134static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
135static int kldrModLXDoReloc(uint8_t *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc,
136 int iSelector, KLDRADDR uValue, uint32_t fKind);
137
138
139/**
140 * Create a loader module instance interpreting the executable image found
141 * in the specified file provider instance.
142 *
143 * @returns 0 on success and *ppMod pointing to a module instance.
144 * On failure, a non-zero OS specific error code is returned.
145 * @param pOps Pointer to the registered method table.
146 * @param pRdr The file provider instance to use.
147 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
148 * @param ppMod Where to store the module instance pointer.
149 */
150static int kldrModLXCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
151{
152 PKLDRMODLX pModLX;
153 int rc;
154
155 /*
156 * Create the instance data and do a minimal header validation.
157 */
158 rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX);
159 if (!rc)
160 {
161 pModLX->pMod->pOps = pOps;
162 pModLX->pMod->u32Magic = KLDRMOD_MAGIC;
163 *ppMod = pModLX->pMod;
164 return 0;
165 }
166 kldrHlpFree(pModLX);
167 return rc;
168}
169
170
171/**
172 * Separate function for reading creating the LX module instance to
173 * simplify cleanup on failure.
174 */
175static int kldrModLXDoCreate(PKLDRRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX)
176{
177 struct e32_exe Hdr;
178 PKLDRMODLX pModLX;
179 PKLDRMOD pMod;
180 size_t cb;
181 size_t cchFilename;
182 uint32_t off, offEnd;
183 uint32_t i;
184 int rc;
185 int fCanOptimizeMapping;
186 uint32_t NextRVA;
187 *ppModLX = NULL;
188
189 /*
190 * Read the signature and file header.
191 */
192 rc = kLdrRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
193 if (rc)
194 return rc;
195 if ( Hdr.e32_magic[0] != E32MAGIC1
196 || Hdr.e32_magic[1] != E32MAGIC2)
197 return KLDR_ERR_UNKNOWN_FORMAT;
198
199 /* We're not interested in anything but x86 images. */
200 if ( Hdr.e32_level != E32LEVEL
201 || Hdr.e32_border != E32LEBO
202 || Hdr.e32_worder != E32LEWO
203 || Hdr.e32_cpu < E32CPU286
204 || Hdr.e32_cpu > E32CPU486
205 || Hdr.e32_pagesize != OBJPAGELEN
206 )
207 return KLDR_ERR_LX_BAD_HEADER;
208
209 /* Some rough sanity checks. */
210 offEnd = kLdrRdrSize(pRdr) >= (KLDRFOFF)~(uint32_t)16 ? ~(uint32_t)16 : (uint32_t)kLdrRdrSize(pRdr);
211 if ( Hdr.e32_itermap > offEnd
212 || Hdr.e32_datapage > offEnd
213 || Hdr.e32_nrestab > offEnd
214 || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
215 || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
216 || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
217 || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
218 return KLDR_ERR_LX_BAD_HEADER;
219
220 /* Verify the loader section. */
221 offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
222 if (Hdr.e32_objtab < sizeof(Hdr))
223 return KLDR_ERR_LX_BAD_LOADER_SECTION;
224 off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
225 if (off > offEnd)
226 return KLDR_ERR_LX_BAD_LOADER_SECTION;
227 if ( Hdr.e32_objmap
228 && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
229 return KLDR_ERR_LX_BAD_LOADER_SECTION;
230 if ( Hdr.e32_rsrccnt
231 && ( Hdr.e32_rsrctab < off
232 || Hdr.e32_rsrctab > offEnd
233 || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
234 return KLDR_ERR_LX_BAD_LOADER_SECTION;
235 if ( Hdr.e32_restab
236 && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
237 return KLDR_ERR_LX_BAD_LOADER_SECTION;
238 if ( Hdr.e32_enttab
239 && (Hdr.e32_enttab < off || Hdr.e32_enttab >= offEnd))
240 return KLDR_ERR_LX_BAD_LOADER_SECTION;
241 if ( Hdr.e32_dircnt
242 && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd - 2))
243 return KLDR_ERR_LX_BAD_LOADER_SECTION;
244
245 /* Verify the fixup section. */
246 off = offEnd;
247 offEnd = off + Hdr.e32_fixupsize;
248 if ( Hdr.e32_fpagetab
249 && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
250 {
251 /*
252 * wlink mixes the fixup section and the loader section.
253 */
254 off = Hdr.e32_fpagetab;
255 offEnd = off + Hdr.e32_fixupsize;
256 Hdr.e32_ldrsize = off - Hdr.e32_objtab;
257 }
258 if ( Hdr.e32_frectab
259 && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
260 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
261 if ( Hdr.e32_impmod
262 && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
263 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
264 if ( Hdr.e32_impproc
265 && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
266 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
267
268 /*
269 * Calc the instance size, allocate and initialize it.
270 */
271 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
272 cb = KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8)
273 + KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8)
274 + KLDR_ALIGN_Z(cchFilename + 1, 8)
275 + Hdr.e32_ldrsize + 2; /* +2 for two extra zeros. */
276 pModLX = (PKLDRMODLX)kldrHlpAlloc(cb);
277 if (!pModLX)
278 return KLDR_ERR_NO_MEMORY;
279 *ppModLX = pModLX;
280
281 /* KLDRMOD */
282 pMod = (PKLDRMOD)((uint8_t *)pModLX + KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8));
283 pMod->pvData = pModLX;
284 pMod->pRdr = pRdr;
285 pMod->pOps = NULL; /* set upon success. */
286 pMod->cSegments = Hdr.e32_objcnt;
287 pMod->cchFilename = cchFilename;
288 pMod->pszFilename = (char *)KLDR_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8);
289 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
290 pMod->pszName = NULL; /* finalized further down */
291 pMod->cchName = 0;
292 switch (Hdr.e32_cpu)
293 {
294 case E32CPU286:
295 pMod->enmCpu = KLDRCPU_I80286;
296 pMod->enmArch = KLDRARCH_X86_16;
297 break;
298 case E32CPU386:
299 pMod->enmCpu = KLDRCPU_I386;
300 pMod->enmArch = KLDRARCH_X86_32;
301 break;
302 case E32CPU486:
303 pMod->enmCpu = KLDRCPU_I486;
304 pMod->enmArch = KLDRARCH_X86_32;
305 break;
306 }
307 pMod->enmEndian = KLDRENDIAN_LITTLE;
308 pMod->enmFmt = KLDRFMT_LX;
309 switch (Hdr.e32_mflags & E32MODMASK)
310 {
311 case E32MODEXE:
312 pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX)
313 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
314 : KLDRTYPE_EXECUTABLE_FIXED;
315 break;
316
317 case E32MODDLL:
318 case E32PROTDLL:
319 case E32MODPROTDLL:
320 pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL)
321 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
322 : KLDRTYPE_SHARED_LIBRARY_FIXED;
323 break;
324
325 case E32MODPDEV:
326 case E32MODVDEV:
327 pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
328 break;
329 }
330 pMod->u32Magic = 0; /* set upon success. */
331
332 /* KLDRMODLX */
333 pModLX->pMod = pMod;
334 pModLX->pvMapping = 0;
335 pModLX->cbMapped = 0;
336 pModLX->f32Reserved = 0;
337
338 pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
339 pModLX->Hdr = Hdr;
340
341 pModLX->pbLoaderSection = KLDR_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16);
342 pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize - 1;
343 pModLX->paObjs = NULL;
344 pModLX->paPageMappings = NULL;
345 pModLX->paRsrcs = NULL;
346 pModLX->pbResNameTab = NULL;
347 pModLX->pbEntryTab = NULL;
348
349 pModLX->pbNonResNameTab = NULL;
350 pModLX->pbNonResNameTabLast = NULL;
351
352 pModLX->pbFixupSection = NULL;
353 pModLX->pbFixupSectionLast = NULL;
354 pModLX->paoffPageFixups = NULL;
355 pModLX->pbFixupRecs = NULL;
356 pModLX->pbImportMods = NULL;
357 pModLX->pbImportProcs = NULL;
358
359 /*
360 * Read the loader data.
361 */
362 rc = kLdrRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
363 if (rc)
364 return rc;
365 ((uint8_t *)pModLX->pbLoaderSectionLast)[1] = 0;
366 ((uint8_t *)pModLX->pbLoaderSectionLast)[2] = 0;
367 if (pModLX->Hdr.e32_objcnt)
368 pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
369 if (pModLX->Hdr.e32_objmap)
370 pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
371 if (pModLX->Hdr.e32_rsrccnt)
372 pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
373 if (pModLX->Hdr.e32_restab)
374 pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
375 if (pModLX->Hdr.e32_enttab)
376 pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
377
378 /*
379 * Get the soname from the resident name table.
380 * Very convenient that it's the 0 ordinal, because then we get a
381 * free string terminator.
382 * (The table entry consists of a pascal string followed by a 16-bit ordinal.)
383 */
384 pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab,
385 pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
386 0);
387 if (!pMod->pszName)
388 return KLDR_ERR_LX_NO_SONAME;
389 pMod->cchName = *(const uint8_t *)pMod->pszName++;
390 if (pMod->cchName != kLdrHlpStrLen(pMod->pszName))
391 return KLDR_ERR_LX_BAD_SONAME;
392
393 /*
394 * Quick validation of the object table.
395 */
396 cb = 0;
397 for (i = 0; i < pMod->cSegments; i++)
398 {
399 if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
400 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
401 if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
402 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
403 if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1)))
404 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
405 if ( pModLX->paObjs[i].o32_mapsize
406 && ( (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
407 || (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
408 > pModLX->pbLoaderSectionLast))
409 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
410 if (i > 0 && !(pModLX->paObjs[i].o32_flags & OBJRSRC))
411 {
412 if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
413 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
414 if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
415 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
416 }
417 }
418
419 /*
420 * Check if we can optimize the mapping by using a different
421 * object alignment. The linker typically uses 64KB alignment,
422 * we can easily get away with page alignment in most cases.
423 */
424 fCanOptimizeMapping = !(Hdr.e32_mflags & (E32NOINTFIX | E32SYSDLL));
425 NextRVA = 0;
426
427 /*
428 * Setup the KLDRMOD segment array.
429 */
430 for (i = 0; i < pMod->cSegments; i++)
431 {
432 /* unused */
433 pMod->aSegments[i].pvUser = NULL;
434 pMod->aSegments[i].MapAddress = 0;
435 pMod->aSegments[i].pchName = NULL;
436 pMod->aSegments[i].cchName = 0;
437 pMod->aSegments[i].offFile = -1;
438 pMod->aSegments[i].cbFile = -1;
439 pMod->aSegments[i].SelFlat = 0;
440 pMod->aSegments[i].Sel16bit = 0;
441
442 /* flags */
443 pMod->aSegments[i].fFlags = 0;
444 if (pModLX->paObjs[i].o32_flags & OBJBIGDEF)
445 pMod->aSegments[i].fFlags = KLDRSEG_FLAG_16BIT;
446 if (pModLX->paObjs[i].o32_flags & OBJALIAS16)
447 pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_ALIAS16;
448 if (pModLX->paObjs[i].o32_flags & OBJCONFORM)
449 pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_CONFORM;
450 if (pModLX->paObjs[i].o32_flags & OBJIOPL)
451 pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_IOPL;
452
453 /* size and addresses */
454 pMod->aSegments[i].Alignment = OBJPAGELEN;
455 pMod->aSegments[i].cb = pModLX->paObjs[i].o32_size;
456 pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
457 pMod->aSegments[i].RVA = NextRVA;
458 if ( fCanOptimizeMapping
459 || i + 1 >= pMod->cSegments
460 || (pModLX->paObjs[i].o32_flags & OBJRSRC)
461 || (pModLX->paObjs[i + 1].o32_flags & OBJRSRC))
462 pMod->aSegments[i].cbMapped = KLDR_ALIGN_Z(pModLX->paObjs[i].o32_size, OBJPAGELEN);
463 else
464 pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
465 NextRVA += pMod->aSegments[i].cbMapped;
466
467 /* protection */
468 switch ( pModLX->paObjs[i].o32_flags
469 & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
470 {
471 case 0:
472 case OBJSHARED:
473 pMod->aSegments[i].enmProt = KLDRPROT_NOACCESS;
474 break;
475 case OBJREAD:
476 case OBJREAD | OBJSHARED:
477 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
478 break;
479 case OBJWRITE:
480 case OBJWRITE | OBJREAD:
481 pMod->aSegments[i].enmProt = KLDRPROT_WRITECOPY;
482 break;
483 case OBJWRITE | OBJSHARED:
484 case OBJWRITE | OBJSHARED | OBJREAD:
485 pMod->aSegments[i].enmProt = KLDRPROT_READWRITE;
486 break;
487 case OBJEXEC:
488 case OBJEXEC | OBJSHARED:
489 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE;
490 break;
491 case OBJEXEC | OBJREAD:
492 case OBJEXEC | OBJREAD | OBJSHARED:
493 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READ;
494 break;
495 case OBJEXEC | OBJWRITE:
496 case OBJEXEC | OBJWRITE | OBJREAD:
497 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
498 break;
499 case OBJEXEC | OBJWRITE | OBJSHARED:
500 case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
501 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READWRITE;
502 break;
503 }
504 if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
505 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
506 /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
507 pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
508 pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */
509 }
510
511 /* set the mapping size */
512 pModLX->cbMapped = NextRVA;
513
514 /*
515 * We're done.
516 */
517 *ppModLX = pModLX;
518 return 0;
519}
520
521
522/** @copydoc KLDRMODOPS::pfnDestroy */
523static int kldrModLXDestroy(PKLDRMOD pMod)
524{
525 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
526 int rc = 0;
527 KLDRMODLX_ASSERT(!pModLX->pvMapping);
528
529 if (pMod->pRdr)
530 {
531 rc = kLdrRdrClose(pMod->pRdr);
532 pMod->pRdr = NULL;
533 }
534 if (pModLX->pbNonResNameTab)
535 {
536 kldrHlpFree(pModLX->pbNonResNameTab);
537 pModLX->pbNonResNameTab = NULL;
538 }
539 if (pModLX->pbFixupSection)
540 {
541 kldrHlpFree(pModLX->pbFixupSection);
542 pModLX->pbFixupSection = NULL;
543 }
544 pMod->u32Magic = 0;
545 pMod->pOps = NULL;
546 kldrHlpFree(pModLX);
547 return rc;
548}
549
550
551/**
552 * Resolved base address aliases.
553 *
554 * @param pModLX The interpreter module instance
555 * @param pBaseAddress The base address, IN & OUT.
556 */
557static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress)
558{
559 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
560 *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress;
561 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
562 *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress;
563}
564
565
566/** @copydoc kLdrModQuerySymbol */
567static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
568 const char *pchSymbol, size_t cchSymbol, const char *pszVersion,
569 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
570{
571 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
572 uint32_t iOrdinal;
573 int rc;
574 const struct b32_bundle *pBundle;
575
576
577 /*
578 * Give up at once if there is no entry table.
579 */
580 if (!pModLX->Hdr.e32_enttab)
581 return KLDR_ERR_SYMBOL_NOT_FOUND;
582
583 /*
584 * Translate the symbol name into an ordinal.
585 */
586 if (pchSymbol)
587 {
588 rc = kldrModLXDoNameLookup(pModLX, pchSymbol, cchSymbol, &iSymbol);
589 if (rc)
590 return rc;
591 }
592
593 /*
594 * Iterate the entry table.
595 * (The entry table is made up of bundles of similar exports.)
596 */
597 iOrdinal = 0;
598 pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
599 while (!pBundle->b32_cnt && iOrdinal <= iSymbol)
600 {
601 static const size_t s_cbEntry[] = { 0, 3, 5, 5, 7 };
602
603 /*
604 * Check for a hit first.
605 */
606 iOrdinal += pBundle->b32_cnt;
607 if (iSymbol < iOrdinal)
608 {
609 uint32_t offObject;
610 const struct e32_entry *pEntry = (const struct e32_entry *)((uintptr_t)(pBundle + 1)
611 + iSymbol - (iOrdinal - pBundle->b32_cnt));
612
613 /*
614 * Calculate the return address.
615 */
616 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
617 switch (pBundle->b32_type)
618 {
619 /* empty bundles are place holders unused ordinal ranges. */
620 case EMPTY:
621 return KLDR_ERR_SYMBOL_NOT_FOUND;
622
623 /* e32_flags + a 16-bit offset. */
624 case ENTRY16:
625 offObject = pEntry->e32_variant.e32_offset.offset16;
626 if (pfKind)
627 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE;
628 break;
629
630 /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
631 case GATE16:
632 offObject = pEntry->e32_variant.e32_callgate.offset;
633 if (pfKind)
634 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE;
635 break;
636
637 /* e32_flags + a 32-bit offset. */
638 case ENTRY32:
639 offObject = pEntry->e32_variant.e32_offset.offset32;
640 if (pfKind)
641 *pfKind = KLDRSYMKIND_32BIT;
642 break;
643
644 /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
645 case ENTRYFWD:
646 return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind);
647
648 default:
649 /* anyone actually using TYPEINFO will end up here. */
650 KLDRMODLX_ASSERT(!"Bad bundle type");
651 return KLDR_ERR_LX_BAD_BUNDLE;
652 }
653
654 /*
655 * Validate the object number and calc the return address.
656 */
657 if ( pBundle->b32_obj <= 0
658 || pBundle->b32_obj > pMod->cSegments)
659 return KLDR_ERR_LX_BAD_BUNDLE;
660 if (puValue)
661 *puValue = BaseAddress
662 + offObject
663 + pMod->aSegments[pBundle->b32_obj - 1].RVA;
664 return 0;
665 }
666
667 /*
668 * Skip the bundle.
669 */
670 if (pBundle->b32_type > ENTRYFWD)
671 {
672 KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
673 return KLDR_ERR_LX_BAD_BUNDLE;
674 }
675 if (pBundle->b32_type == 0)
676 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + 2);
677 else
678 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
679 }
680
681 return KLDR_ERR_SYMBOL_NOT_FOUND;
682}
683
684
685/**
686 * Do name lookup.
687 *
688 * @returns See kLdrModQuerySymbol.
689 * @param pModLX The module to lookup the symbol in.
690 * @param pchSymbol The symbol to lookup.
691 * @param cchSymbol The symbol name length.
692 * @param piSymbol Where to store the symbol ordinal.
693 */
694static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, uint32_t cchSymbol, uint32_t *piSymbol)
695{
696
697 /*
698 * First do a hash table lookup.
699 */
700
701
702
703 /*
704
705 */
706
707 return -1;
708}
709
710
711#if 0
712/**
713 * Hash a symbol using the algorithm from sdbm.
714 *
715 * The following was is the documenation of the orignal sdbm functions:
716 *
717 * This algorithm was created for sdbm (a public-domain reimplementation of
718 * ndbm) database library. it was found to do well in scrambling bits,
719 * causing better distribution of the keys and fewer splits. it also happens
720 * to be a good general hashing function with good distribution. the actual
721 * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
722 * is the faster version used in gawk. [there is even a faster, duff-device
723 * version] the magic constant 65599 was picked out of thin air while
724 * experimenting with different constants, and turns out to be a prime.
725 * this is one of the algorithms used in berkeley db (see sleepycat) and
726 * elsewhere.
727 */
728static uint32_t kldrModLXDoHash(const char *pchSymbol, uint8_t cchSymbol)
729{
730 uint32_t hash = 0;
731 int ch;
732
733 while ( cchSymbol-- > 0
734 && (ch = *(unsigned const char *)pchSymbol++))
735 hash = ch + (hash << 6) + (hash << 16) - hash;
736
737 return hash;
738}
739
740
741/**
742 * Lookup a name table entry by name.
743 *
744 * @returns Pointer to the name table entry if found.
745 * @returns NULL if not found.
746 * @param pbNameTable Pointer to the name table that should be searched.
747 * @param cbNameTable The size of the name table.
748 * @param pchSymbol The name of the symbol we're looking for.
749 * @param cchSymbol The length of the symbol name.
750 */
751static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable,
752 char *pchSymbol, size_t cchSymbol)
753{
754 /*
755 * Determin the namelength up front so we can skip anything which doesn't matches the length.
756 */
757 uint8_t cbSymbol8Bit = (uint8_t)cchSymbol;
758 if (cbSymbol8Bit != cchSymbol)
759 return NULL; /* too long. */
760
761 /*
762 * Walk the name table.
763 */
764 while (*pbNameTable != 0 && cbNameTable > 0)
765 {
766 const uint8_t cbName = *pbNameTable;
767
768 cbNameTable -= cbName + 1 + 2;
769 if (cbNameTable < 0)
770 break;
771
772 if ( cbName == cbSymbol8Bit
773 && !kLdrHlpMemComp(pbNameTable + 1, pchSymbol, cbName))
774 return pbNameTable;
775
776 /* next entry */
777 pbNameTable += cbName + 1 + 2;
778 }
779
780 return NULL;
781}
782#endif
783
784
785/**
786 * Deal with a forwarder entry.
787 *
788 * @returns See kLdrModQuerySymbol.
789 * @param pModLX The PE module interpreter instance.
790 * @param pEntry The forwarder entry.
791 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
792 * @param pvUser The user argument for the callback.
793 * @param puValue Where to put the value. (optional)
794 * @param pfKind Where to put the symbol kind. (optional)
795 */
796static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
797 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
798{
799 int rc;
800 uint32_t iSymbol;
801 const char *pchSymbol;
802 uint8_t cchSymbol;
803
804 if (!pfnGetForwarder)
805 return KLDR_ERR_FORWARDER_SYMBOL;
806
807 /*
808 * Validate the entry import module ordinal.
809 */
810 if ( !pEntry->e32_variant.e32_fwd.modord
811 || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt)
812 return KLDR_ERR_LX_BAD_FORWARDER;
813
814 /*
815 * Figure out the parameters.
816 */
817 if (pEntry->e32_flags & FWD_ORDINAL)
818 {
819 iSymbol = pEntry->e32_variant.e32_fwd.value;
820 pchSymbol = NULL; /* no symbol name. */
821 cchSymbol = 0;
822 }
823 else
824 {
825 const uint8_t *pbName;
826
827 /* load the fixup section if necessary. */
828 if (!pModLX->pbImportProcs)
829 {
830 rc = kldrModLXDoLoadFixupSection(pModLX);
831 if (rc)
832 return rc;
833 }
834
835 /* Make name pointer. */
836 pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value;
837 if ( pbName >= pModLX->pbFixupSectionLast
838 || pbName < pModLX->pbFixupSection
839 || !*pbName)
840 return KLDR_ERR_LX_BAD_FORWARDER;
841
842
843 /* check for '#' name. */
844 if (pbName[1] == '#')
845 {
846 uint8_t cbLeft = *pbName;
847 const uint8_t *pb = pbName + 1;
848 unsigned uBase;
849
850 /* base detection */
851 uBase = 10;
852 if ( cbLeft > 1
853 && pb[1] == '0'
854 && (pb[2] == 'x' || pb[2] == 'X'))
855 {
856 uBase = 16;
857 pb += 2;
858 cbLeft -= 2;
859 }
860
861 /* ascii to integer */
862 iSymbol = 0;
863 while (cbLeft-- > 0)
864 {
865 /* convert char to digit. */
866 unsigned uDigit = *pb++;
867 if (uDigit >= '0' && uDigit <= '9')
868 uDigit -= '0';
869 else if (uDigit >= 'a' && uDigit <= 'z')
870 uDigit -= 'a' + 10;
871 else if (uDigit >= 'A' && uDigit <= 'Z')
872 uDigit -= 'A' + 10;
873 else if (!uDigit)
874 break;
875 else
876 return KLDR_ERR_LX_BAD_FORWARDER;
877 if (uDigit >= uBase)
878 return KLDR_ERR_LX_BAD_FORWARDER;
879
880 /* insert the digit */
881 iSymbol *= uBase;
882 iSymbol += uDigit;
883 }
884 if (!iSymbol)
885 return KLDR_ERR_LX_BAD_FORWARDER;
886
887 pchSymbol = NULL; /* no symbol name. */
888 cchSymbol = 0;
889 }
890 else
891 {
892 pchSymbol = (char *)pbName + 1;
893 cchSymbol = *pbName;
894 iSymbol = NIL_KLDRMOD_SYM_ORDINAL;
895 }
896 }
897
898 /*
899 * Resolve the forwarder.
900 */
901 rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pchSymbol, cchSymbol, NULL, puValue, pfKind, pvUser);
902 if (!rc && pfKind)
903 *pfKind |= KLDRSYMKIND_FORWARDER;
904 return rc;
905}
906
907
908/**
909 * Loads the fixup section from the executable image.
910 *
911 * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone().
912 *
913 * @returns 0 on success, non-zero kLdr or native status code on failure.
914 * @param pModLX The PE module interpreter instance.
915 */
916static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX)
917{
918 int rc;
919 uint32_t off;
920 void *pv;
921
922 pv = kldrHlpAlloc(pModLX->Hdr.e32_fixupsize);
923 if (!pv)
924 return KLDR_ERR_NO_MEMORY;
925
926 off = pModLX->Hdr.e32_objtab + pModLX->Hdr.e32_ldrsize;
927 rc = kLdrRdrRead(pModLX->pMod->pRdr, pv, pModLX->Hdr.e32_fixupsize,
928 off + pModLX->offHdr);
929 if (!rc)
930 {
931 pModLX->pbFixupSection = pv;
932 pModLX->pbFixupSectionLast = pModLX->pbFixupSection + pModLX->Hdr.e32_fixupsize;
933 KLDRMODLX_ASSERT(!pModLX->paoffPageFixups);
934 if (pModLX->Hdr.e32_fpagetab)
935 pModLX->paoffPageFixups = (const uint32_t *)(pModLX->pbFixupSection + pModLX->Hdr.e32_fpagetab - off);
936 KLDRMODLX_ASSERT(!pModLX->pbFixupRecs);
937 if (pModLX->Hdr.e32_frectab)
938 pModLX->pbFixupRecs = pModLX->pbFixupSection + pModLX->Hdr.e32_frectab - off;
939 KLDRMODLX_ASSERT(!pModLX->pbImportMods);
940 if (pModLX->Hdr.e32_impmod)
941 pModLX->pbImportMods = pModLX->pbFixupSection + pModLX->Hdr.e32_impmod - off;
942 KLDRMODLX_ASSERT(!pModLX->pbImportProcs);
943 if (pModLX->Hdr.e32_impproc)
944 pModLX->pbImportProcs = pModLX->pbFixupSection + pModLX->Hdr.e32_impproc - off;
945 }
946 else
947 kldrHlpFree(pv);
948 return rc;
949}
950
951
952/** @copydoc kLdrModEnumSymbols */
953static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
954 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
955{
956 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
957/* int rc; */
958
959 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
960
961 return 0;
962}
963
964
965/**
966 * Lookup a name table entry by ordinal.
967 *
968 * @returns Pointer to the name table entry if found.
969 * @returns NULL if not found.
970 * @param pbNameTable Pointer to the name table that should be searched.
971 * @param cbNameTable The size of the name table.
972 * @param iOrdinal The ordinal to search for.
973 */
974static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal)
975{
976 while (*pbNameTable != 0 && cbNameTable > 0)
977 {
978 const uint8_t cbName = *pbNameTable;
979 uint32_t iName;
980
981 cbNameTable -= cbName + 1 + 2;
982 if (cbNameTable < 0)
983 break;
984
985 iName = *(pbNameTable + cbName + 1)
986 | ((unsigned)*(pbNameTable + cbName + 2) << 8);
987 if (iName == iOrdinal)
988 return pbNameTable;
989
990 /* next entry */
991 pbNameTable += cbName + 1 + 2;
992 }
993
994 return NULL;
995}
996
997
998/** @copydoc kLdrModGetImport */
999static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
1000{
1001 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1002 const uint8_t * pb;
1003 int rc;
1004
1005 /*
1006 * Validate
1007 */
1008 if (iImport >= pModLX->Hdr.e32_impmodcnt)
1009 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1010
1011 /*
1012 * Lazy loading the fixup section.
1013 */
1014 if (!pModLX->pbImportMods)
1015 {
1016 rc = kldrModLXDoLoadFixupSection(pModLX);
1017 if (rc)
1018 return rc;
1019 }
1020
1021 /*
1022 * Iterate the module import table until we reach the requested import ordinal.
1023 */
1024 pb = pModLX->pbImportMods;
1025 while (iImport-- > 0)
1026 pb += *pb + 1;
1027
1028 /*
1029 * Copy out the result.
1030 */
1031 if (*pb < cchName)
1032 {
1033 kLdrHlpMemCopy(pszName, pb + 1, *pb);
1034 pszName[*pb] = '\0';
1035 rc = 0;
1036 }
1037 else
1038 {
1039 kLdrHlpMemCopy(pszName, pb + 1, cchName);
1040 if (cchName)
1041 pszName[cchName - 1] = '\0';
1042 rc = KLDR_ERR_BUFFER_OVERFLOW;
1043 }
1044
1045 return rc;
1046}
1047
1048
1049/** @copydoc kLdrModNumberOfImports */
1050static int32_t kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits)
1051{
1052 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1053 return pModLX->Hdr.e32_impmodcnt;
1054}
1055
1056
1057/** @copydoc kLdrModGetStackInfo */
1058static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1059{
1060 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1061 const uint32_t i = pModLX->Hdr.e32_stackobj;
1062
1063 if ( i
1064 && i <= pMod->cSegments
1065 && pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb
1066 && pModLX->Hdr.e32_stacksize
1067 && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress)
1068 {
1069
1070 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1071 pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
1072 pStackInfo->Address = BaseAddress
1073 + pMod->aSegments[i - 1].RVA
1074 + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress;
1075 }
1076 else
1077 {
1078 pStackInfo->Address = NIL_KLDRADDR;
1079 pStackInfo->LinkAddress = NIL_KLDRADDR;
1080 }
1081 pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
1082 pStackInfo->cbStackThread = 0;
1083
1084 return 0;
1085}
1086
1087
1088/** @copydoc kLdrModQueryMainEntrypoint */
1089static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1090{
1091 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1092
1093 /*
1094 * Convert the address from the header.
1095 */
1096 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1097 *pMainEPAddress = pModLX->Hdr.e32_startobj
1098 && pModLX->Hdr.e32_startobj <= pMod->cSegments
1099 && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb
1100 ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
1101 : NIL_KLDRADDR;
1102 return 0;
1103}
1104
1105
1106/** @copydoc kLdrModEnumDbgInfo */
1107static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1108{
1109 /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/
1110
1111 /*
1112 * Quit immediately if no debug info.
1113 */
1114 if (kldrModLXHasDbgInfo(pMod, pvBits))
1115 return 0;
1116#if 0
1117 /*
1118 * Read the debug info and look for familiar magics and structures.
1119 */
1120 /** @todo */
1121#endif
1122
1123 return 0;
1124}
1125
1126
1127/** @copydoc kLdrModHasDbgInfo */
1128static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1129{
1130 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1131
1132 /*
1133 * Don't curretnly bother with linkers which doesn't advertise it in the header.
1134 */
1135 if ( !pModLX->Hdr.e32_debuginfo
1136 || !pModLX->Hdr.e32_debuglen)
1137 return KLDR_ERR_NO_DEBUG_INFO;
1138 return 0;
1139}
1140
1141
1142/** @copydoc kLdrModMap */
1143static int kldrModLXMap(PKLDRMOD pMod)
1144{
1145 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1146 unsigned fFixed;
1147 void *pvBase;
1148 int rc;
1149
1150 /*
1151 * Already mapped?
1152 */
1153 if (pModLX->pvMapping)
1154 return KLDR_ERR_ALREADY_MAPPED;
1155
1156 /*
1157 * Allocate memory for it.
1158 */
1159 /* fixed image? */
1160 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
1161 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1162 if (!fFixed)
1163 pvBase = NULL;
1164 else
1165 {
1166 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
1167 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
1168 return KLDR_ERR_ADDRESS_OVERFLOW;
1169 }
1170 rc = kldrHlpPageAlloc(&pvBase, pModLX->cbMapped, KLDRPROT_EXECUTE_READWRITE, fFixed);
1171 if (rc)
1172 return rc;
1173
1174 /*
1175 * Load the bits, apply page protection, and update the segment table.
1176 */
1177 rc = kldrModLXDoLoadBits(pModLX, pvBase);
1178 if (!rc)
1179 rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
1180 if (!rc)
1181 {
1182 uint32_t i;
1183 for (i = 0; i < pMod->cSegments; i++)
1184 {
1185 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
1186 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
1187 }
1188 pModLX->pvMapping = pvBase;
1189 }
1190 else
1191 kldrHlpPageFree(pvBase, pModLX->cbMapped);
1192 return rc;
1193}
1194
1195
1196/**
1197 * Loads the LX pages into the specified memory mapping.
1198 *
1199 * @returns 0 on success.
1200 * @returns non-zero kLdr or OS status code on failure.
1201 *
1202 * @param pModLX The LX module interpreter instance.
1203 * @param pvBits Where to load the bits.
1204 */
1205static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
1206{
1207 const PKLDRRDR pRdr = pModLX->pMod->pRdr;
1208 uint8_t *pbTmpPage = NULL;
1209 int rc = 0;
1210 uint32_t i;
1211
1212 /*
1213 * Iterate the segments.
1214 */
1215 for (i = 0; i < pModLX->Hdr.e32_objcnt; i++)
1216 {
1217 const struct o32_obj * const pObj = &pModLX->paObjs[i];
1218 const uint32_t cPages = pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN;
1219 uint32_t iPage;
1220 uint8_t *pbPage = (uint8_t *)pvBits + (uintptr_t)pModLX->pMod->aSegments[i].RVA;
1221
1222 /*
1223 * Iterate the page map pages.
1224 */
1225 for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN)
1226 {
1227 const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1];
1228 switch (pMap->o32_pageflags)
1229 {
1230 case VALID:
1231 if (pMap->o32_pagesize == OBJPAGELEN)
1232 rc = kLdrRdrRead(pRdr, pbPage, OBJPAGELEN,
1233 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1234 else if (pMap->o32_pagesize < OBJPAGELEN)
1235 {
1236 rc = kLdrRdrRead(pRdr, pbPage, pMap->o32_pagesize,
1237 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1238 kLdrHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize);
1239 }
1240 else
1241 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1242 break;
1243
1244 case ITERDATA:
1245 case ITERDATA2:
1246 /* make sure we've got a temp page .*/
1247 if (!pbTmpPage)
1248 {
1249 pbTmpPage = kldrHlpAlloc(OBJPAGELEN + 256);
1250 if (!pbTmpPage)
1251 break;
1252 }
1253 /* validate the size. */
1254 if (pMap->o32_pagesize > OBJPAGELEN + 252)
1255 {
1256 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1257 break;
1258 }
1259
1260 /* read it and ensure 4 extra zero bytes. */
1261 rc = kLdrRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize,
1262 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1263 if (rc)
1264 break;
1265 kLdrHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4);
1266
1267 /* unpack it into the image page. */
1268 if (pMap->o32_pageflags == ITERDATA2)
1269 rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1270 else
1271 rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1272 break;
1273
1274 case INVALID: /* we're probably not dealing correctly with INVALID pages... */
1275 case ZEROED:
1276 kLdrHlpMemSet(pbPage, 0, OBJPAGELEN);
1277 break;
1278
1279 case RANGE:
1280 KLDRMODLX_ASSERT(!"RANGE");
1281 default:
1282 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1283 break;
1284 }
1285 }
1286 if (rc)
1287 break;
1288
1289 /*
1290 * Zero the remaining pages.
1291 */
1292 if (iPage < cPages)
1293 kLdrHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN);
1294 }
1295
1296 if (pbTmpPage)
1297 kldrHlpFree(pbTmpPage);
1298 return rc;
1299}
1300
1301
1302/**
1303 * Unpacks iterdata (aka EXEPACK).
1304 *
1305 * @returns 0 on success, non-zero kLdr status code on failure.
1306 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1307 * @param pbSrc The compressed source data.
1308 * @param cbSrc The file size of the compressed data. The source buffer
1309 * contains 4 additional zero bytes.
1310 */
1311static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1312{
1313 const struct LX_Iter *pIter = (const struct LX_Iter *)pbSrc;
1314 int cbDst = OBJPAGELEN;
1315
1316 /* Validate size of data. */
1317 if (cbSrc >= OBJPAGELEN - 2)
1318 return KLDR_ERR_LX_BAD_ITERDATA;
1319
1320 /*
1321 * Expand the page.
1322 */
1323 while (cbSrc > 0 && pIter->LX_nIter)
1324 {
1325 if (pIter->LX_nBytes == 1)
1326 {
1327 /*
1328 * Special case - one databyte.
1329 */
1330 cbDst -= pIter->LX_nIter;
1331 if (cbDst < 0)
1332 return KLDR_ERR_LX_BAD_ITERDATA;
1333
1334 cbSrc -= 4 + 1;
1335 if (cbSrc < -4)
1336 return KLDR_ERR_LX_BAD_ITERDATA;
1337
1338 kLdrHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter);
1339 pbDst += pIter->LX_nIter;
1340 pIter++;
1341 }
1342 else
1343 {
1344 /*
1345 * General.
1346 */
1347 int i;
1348
1349 cbDst -= pIter->LX_nIter * pIter->LX_nBytes;
1350 if (cbDst < 0)
1351 return KLDR_ERR_LX_BAD_ITERDATA;
1352
1353 cbSrc -= 4 + pIter->LX_nBytes;
1354 if (cbSrc < -4)
1355 return KLDR_ERR_LX_BAD_ITERDATA;
1356
1357 for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes)
1358 kLdrHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes);
1359 pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
1360 }
1361 }
1362
1363 /*
1364 * Zero remainder of the page.
1365 */
1366 if (cbDst > 0)
1367 kLdrHlpMemSet(pbDst, 0, cbDst);
1368
1369 return 0;
1370}
1371
1372
1373/**
1374 * Unpacks iterdata (aka EXEPACK).
1375 *
1376 * @returns 0 on success, non-zero kLdr status code on failure.
1377 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1378 * @param pbSrc The compressed source data.
1379 * @param cbSrc The file size of the compressed data. The source buffer
1380 * contains 4 additional zero bytes.
1381 */
1382static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1383{
1384 int cbDst = OBJPAGELEN;
1385
1386 while (cbSrc > 0)
1387 {
1388 /*
1389 * Bit 0 and 1 is the encoding type.
1390 */
1391 switch (*pbSrc & 0x03)
1392 {
1393 /*
1394 *
1395 * 0 1 2 3 4 5 6 7
1396 * type | |
1397 * ----------------
1398 * cb <cb bytes of data>
1399 *
1400 * Bits 2-7 is, if not zero, the length of an uncompressed run
1401 * starting at the following byte.
1402 *
1403 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1404 * type | | | | | |
1405 * ---------------- ---------------------- -----------------------
1406 * zero cb char to multiply
1407 *
1408 * If the bits are zero, the following two bytes describes a 1 byte interation
1409 * run. First byte is count, second is the byte to copy. A count of zero is
1410 * means end of data, and we simply stops. In that case the rest of the data
1411 * should be zero.
1412 */
1413 case 0:
1414 {
1415 if (*pbSrc)
1416 {
1417 const int cb = *pbSrc >> 2;
1418 cbDst -= cb;
1419 if (cbDst < 0)
1420 return KLDR_ERR_LX_BAD_ITERDATA2;
1421 cbSrc -= cb + 1;
1422 if (cbSrc < 0)
1423 return KLDR_ERR_LX_BAD_ITERDATA2;
1424 kLdrHlpMemCopy(pbDst, ++pbSrc, cb);
1425 pbDst += cb;
1426 pbSrc += cb;
1427 }
1428 else if (cbSrc < 2)
1429 return KLDR_ERR_LX_BAD_ITERDATA2;
1430 else
1431 {
1432 const int cb = pbSrc[1];
1433 if (!cb)
1434 goto l_endloop;
1435 cbDst -= cb;
1436 if (cbDst < 0)
1437 return KLDR_ERR_LX_BAD_ITERDATA2;
1438 cbSrc -= 3;
1439 if (cbSrc < 0)
1440 return KLDR_ERR_LX_BAD_ITERDATA2;
1441 kLdrHlpMemSet(pbDst, pbSrc[2], cb);
1442 pbDst += cb;
1443 pbSrc += 3;
1444 }
1445 break;
1446 }
1447
1448
1449 /*
1450 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1451 * type | | | | | |
1452 * ---- ------- -------------------------
1453 * cb1 cb2 - 3 offset <cb1 bytes of data>
1454 *
1455 * Two bytes layed out as described above, followed by cb1 bytes of data to be copied.
1456 * The cb2(+3) and offset describes an amount of data to be copied from the expanded
1457 * data relative to the current position. The data copied as you would expect it to be.
1458 */
1459 case 1:
1460 {
1461 cbSrc -= 2;
1462 if (cbSrc < 0)
1463 return KLDR_ERR_LX_BAD_ITERDATA2;
1464 else
1465 {
1466 const unsigned off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7);
1467 const int cb1 = (*pbSrc >> 2) & 3;
1468 const int cb2 = ((*pbSrc >> 4) & 7) + 3;
1469
1470 pbSrc += 2;
1471 cbSrc -= cb1;
1472 if (cbSrc < 0)
1473 return KLDR_ERR_LX_BAD_ITERDATA2;
1474 cbDst -= cb1;
1475 if (cbDst < 0)
1476 return KLDR_ERR_LX_BAD_ITERDATA2;
1477 kLdrHlpMemCopy(pbDst, pbSrc, cb1);
1478 pbDst += cb1;
1479 pbSrc += cb1;
1480
1481 if (off > OBJPAGELEN - cbDst)
1482 return KLDR_ERR_LX_BAD_ITERDATA2;
1483 cbDst -= cb2;
1484 if (cbDst < 0)
1485 return KLDR_ERR_LX_BAD_ITERDATA2;
1486 kLdrHlpMemMove(pbDst, pbDst - off, cb2);
1487 pbDst += cb2;
1488 }
1489 break;
1490 }
1491
1492
1493 /*
1494 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1495 * type | | | |
1496 * ---- ----------------------------------
1497 * cb-3 offset
1498 *
1499 * Two bytes layed out as described above.
1500 * The cb(+3) and offset describes an amount of data to be copied from the expanded
1501 * data relative to the current position.
1502 *
1503 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1504 */
1505 case 2:
1506 {
1507 cbSrc -= 2;
1508 if (cbSrc < 0)
1509 return KLDR_ERR_LX_BAD_ITERDATA2;
1510 else
1511 {
1512 const unsigned off = ((unsigned)pbSrc[1] << 4) | (*pbSrc >> 4);
1513 const int cb = ((*pbSrc >> 2) & 3) + 3;
1514
1515 pbSrc += 2;
1516 if (off > OBJPAGELEN - cbDst)
1517 return KLDR_ERR_LX_BAD_ITERDATA2;
1518 cbDst -= cb;
1519 if (cbDst < 0)
1520 return KLDR_ERR_LX_BAD_ITERDATA2;
1521 kLdrModLXMemCopyW(pbDst, pbDst - off, cb);
1522 pbDst += cb;
1523 }
1524 break;
1525 }
1526
1527
1528 /*
1529 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1530 * type | | | | | |
1531 * ---------- ---------------- ----------------------------------
1532 * cb1 cb2 offset <cb1 bytes of data>
1533 *
1534 * Three bytes layed out as described above, followed by cb1 bytes of data to be copied.
1535 * The cb2 and offset describes an amount of data to be copied from the expanded
1536 * data relative to the current position.
1537 *
1538 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1539 */
1540 case 3:
1541 {
1542 cbSrc -= 3;
1543 if (cbSrc < 0)
1544 return KLDR_ERR_LX_BAD_ITERDATA2;
1545 else
1546 {
1547 const int cb1 = (*pbSrc >> 2) & 0xf;
1548 const int cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6);
1549 const unsigned off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4);
1550
1551 pbSrc += 3;
1552 cbSrc -= cb1;
1553 if (cbSrc < 0)
1554 return KLDR_ERR_LX_BAD_ITERDATA2;
1555 cbDst -= cb1;
1556 if (cbDst < 0)
1557 return KLDR_ERR_LX_BAD_ITERDATA2;
1558 kLdrHlpMemCopy(pbDst, pbSrc, cb1);
1559 pbDst += cb1;
1560 pbSrc += cb1;
1561
1562 if (off > OBJPAGELEN - cbDst)
1563 return KLDR_ERR_LX_BAD_ITERDATA2;
1564 cbDst -= cb2;
1565 if (cbDst < 0)
1566 return KLDR_ERR_LX_BAD_ITERDATA2;
1567 kLdrModLXMemCopyW(pbDst, pbDst - off, cb2);
1568 pbDst += cb2;
1569 }
1570 break;
1571 }
1572 } /* type switch. */
1573 } /* unpack loop */
1574
1575l_endloop:
1576
1577
1578 /*
1579 * Zero remainder of the page.
1580 */
1581 if (cbDst > 0)
1582 kLdrHlpMemSet(pbDst, 0, cbDst);
1583
1584 return 0;
1585}
1586
1587
1588/**
1589 * Special memcpy employed by the iterdata2 algorithm.
1590 *
1591 * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this
1592 * has if src is very close to the destination.
1593 *
1594 * @param pbDst Destination pointer.
1595 * @param pbSrc Source pointer. Will always be <= pbDst.
1596 * @param cb Amount of data to be copied.
1597 * @remark This assumes that unaligned word and dword access is fine.
1598 */
1599static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb)
1600{
1601 switch (pbDst - pbSrc)
1602 {
1603 case 0:
1604 case 1:
1605 case 2:
1606 case 3:
1607 /* 16-bit copy (unaligned) */
1608 if (cb & 1)
1609 *pbDst++ = *pbSrc++;
1610 for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2)
1611 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
1612 break;
1613
1614 default:
1615 /* 32-bit copy (unaligned) */
1616 if (cb & 1)
1617 *pbDst++ = *pbSrc++;
1618 if (cb & 2)
1619 {
1620 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
1621 pbDst += 2;
1622 pbSrc += 2;
1623 }
1624 for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4)
1625 *(uint32_t *)pbDst = *(const uint32_t *)pbSrc;
1626 break;
1627 }
1628}
1629
1630
1631/**
1632 * Unprotects or protects the specified image mapping.
1633 *
1634 * @returns 0 on success.
1635 * @returns non-zero kLdr or OS status code on failure.
1636 *
1637 * @param pModLX The LX module interpreter instance.
1638 * @param pvBits The mapping to protect.
1639 * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise
1640 * protect according to the object table.
1641 */
1642static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect)
1643{
1644 uint32_t i;
1645 PKLDRMOD pMod = pModLX->pMod;
1646
1647 /*
1648 * Change object protection.
1649 */
1650 for (i = 0; i < pMod->cSegments; i++)
1651 {
1652 int rc;
1653 void *pv;
1654 KLDRPROT enmProt;
1655
1656 /* calc new protection. */
1657 enmProt = pMod->aSegments[i].enmProt;
1658 if (fUnprotectOrProtect)
1659 {
1660 switch (enmProt)
1661 {
1662 case KLDRPROT_NOACCESS:
1663 case KLDRPROT_READONLY:
1664 case KLDRPROT_READWRITE:
1665 case KLDRPROT_WRITECOPY:
1666 enmProt = KLDRPROT_READWRITE;
1667 break;
1668 case KLDRPROT_EXECUTE:
1669 case KLDRPROT_EXECUTE_READ:
1670 case KLDRPROT_EXECUTE_READWRITE:
1671 case KLDRPROT_EXECUTE_WRITECOPY:
1672 enmProt = KLDRPROT_EXECUTE_READWRITE;
1673 break;
1674 default:
1675 KLDRMODLX_ASSERT(!"bad enmProt");
1676 return -1;
1677 }
1678 }
1679 else
1680 {
1681 /* copy on write -> normal write. */
1682 if (enmProt == KLDRPROT_EXECUTE_WRITECOPY)
1683 enmProt = KLDRPROT_EXECUTE_READWRITE;
1684 else if (enmProt == KLDRPROT_WRITECOPY)
1685 enmProt = KLDRPROT_READWRITE;
1686 }
1687
1688
1689 /* calc the address and set page protection. */
1690 pv = (uint8_t *)pvBits + pMod->aSegments[i].RVA;
1691
1692 rc = kldrHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt);
1693 if (rc)
1694 break;
1695
1696 /** @todo the gap page should be marked NOACCESS! */
1697 }
1698
1699 return 0;
1700}
1701
1702
1703/** @copydoc kLdrModUnmap */
1704static int kldrModLXUnmap(PKLDRMOD pMod)
1705{
1706 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1707 uint32_t i;
1708 int rc;
1709
1710 /*
1711 * Mapped?
1712 */
1713 if (!pModLX->pvMapping)
1714 return KLDR_ERR_NOT_MAPPED;
1715
1716 /*
1717 * Free the mapping and update the segments.
1718 */
1719 rc = kldrHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
1720 KLDRMODLX_ASSERT(!rc);
1721 pModLX->pvMapping = NULL;
1722
1723 for (i = 0; i < pMod->cSegments; i++)
1724 pMod->aSegments[i].MapAddress = 0;
1725
1726 return rc;
1727}
1728
1729
1730/** @copydoc kLdrModAllocTLS */
1731static int kldrModLXAllocTLS(PKLDRMOD pMod)
1732{
1733 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1734
1735 /* no tls, just do the error checking. */
1736 if (!pModLX->pvMapping)
1737 return KLDR_ERR_NOT_MAPPED;
1738 return 0;
1739}
1740
1741
1742/** @copydoc kLdrModFreeTLS */
1743static void kldrModLXFreeTLS(PKLDRMOD pMod)
1744{
1745 /* no tls. */
1746}
1747
1748
1749/** @copydoc kLdrModReload */
1750static int kldrModLXReload(PKLDRMOD pMod)
1751{
1752 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1753 int rc, rc2;
1754
1755 /*
1756 * Mapped?
1757 */
1758 if (!pModLX->pvMapping)
1759 return KLDR_ERR_NOT_MAPPED;
1760
1761 /*
1762 * Before doing anything we'll have to make all pages writable.
1763 */
1764 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
1765 if (rc)
1766 return rc;
1767
1768 /*
1769 * Load the bits again.
1770 */
1771 rc = kldrModLXDoLoadBits(pModLX, (void *)pModLX->pvMapping);
1772
1773 /*
1774 * Restore protection.
1775 */
1776 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
1777 if (!rc && rc2)
1778 rc = rc2;
1779 return rc;
1780}
1781
1782
1783/** @copydoc kLdrModFixupMapping */
1784static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1785{
1786 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1787 int rc, rc2;
1788
1789 /*
1790 * Mapped?
1791 */
1792 if (!pModLX->pvMapping)
1793 return KLDR_ERR_NOT_MAPPED;
1794
1795 /*
1796 * Before doing anything we'll have to make all pages writable.
1797 */
1798 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
1799 if (rc)
1800 return rc;
1801
1802 /*
1803 * Apply fixups and resolve imports.
1804 */
1805 rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (uintptr_t)pModLX->pvMapping,
1806 pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
1807
1808 /*
1809 * Restore protection.
1810 */
1811 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
1812 if (!rc && rc2)
1813 rc = rc2;
1814 return rc;
1815}
1816
1817
1818/** @copydoc kLdrModCallInit */
1819static int kldrModLXCallInit(PKLDRMOD pMod, uintptr_t uHandle)
1820{
1821 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1822 int rc;
1823
1824 /*
1825 * Mapped?
1826 */
1827 if (!pModLX->pvMapping)
1828 return KLDR_ERR_NOT_MAPPED;
1829
1830 /*
1831 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1832 */
1833 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
1834 rc = kldrModLXDoCallDLL(pModLX, 0 /* attach */, uHandle);
1835 else
1836 rc = 0;
1837 return rc;
1838}
1839
1840
1841/**
1842 * Call the DLL entrypoint.
1843 *
1844 * @returns 0 on success.
1845 * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
1846 * @param pModLX The LX module interpreter instance.
1847 * @param uOp The operation (DLL_*).
1848 * @param uHandle The module handle to present.
1849 */
1850static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle)
1851{
1852 int rc;
1853
1854 /*
1855 * If no entrypoint there isn't anything to be done.
1856 */
1857 if ( !pModLX->Hdr.e32_startobj
1858 || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
1859 return 0;
1860
1861 /*
1862 * Invoke the entrypoint and convert the boolean result to a kLdr status code.
1863 */
1864 rc = kldrModLXDoCall((uintptr_t)pModLX->pvMapping
1865 + (uintptr_t)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
1866 + pModLX->Hdr.e32_eip,
1867 uHandle, uOp, NULL);
1868 if (rc)
1869 rc = 0;
1870 else if (uOp == 0 /* attach */)
1871 rc = KLDR_ERR_MODULE_INIT_FAILED;
1872 else /* detach: ignore failures */
1873 rc = 0;
1874 return rc;
1875}
1876
1877
1878/**
1879 * Do a 3 parameter callback.
1880 *
1881 * @returns 32-bit callback return.
1882 * @param uEntrypoint The address of the function to be called.
1883 * @param uHandle The first argument, the module handle.
1884 * @param uOp The second argumnet, the reason we're calling.
1885 * @param pvReserved The third argument, reserved argument. (figure this one out)
1886 */
1887static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved)
1888{
1889#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
1890 int32_t rc;
1891/** @todo try/except */
1892
1893 /*
1894 * Paranoia.
1895 */
1896# ifdef __GNUC__
1897 __asm__ __volatile__(
1898 "pushl %2\n\t"
1899 "pushl %1\n\t"
1900 "pushl %0\n\t"
1901 "lea 12(%%esp), %2\n\t"
1902 "call *%3\n\t"
1903 "movl %2, %%esp\n\t"
1904 : "=a" (rc)
1905 : "d" (uOp),
1906 "S" (0),
1907 "c" (uEntrypoint),
1908 "0" (uHandle));
1909# elif defined(_MSC_VER)
1910 __asm {
1911 mov eax, [uHandle]
1912 mov edx, [uOp]
1913 mov ecx, 0
1914 mov ebx, [uEntrypoint]
1915 push edi
1916 mov edi, esp
1917 push ecx
1918 push edx
1919 push eax
1920 call ebx
1921 mov esp, edi
1922 pop edi
1923 mov [rc], eax
1924 }
1925# else
1926# error "port me!"
1927# endif
1928 return rc;
1929
1930#else
1931 return KLDR_ERR_ARCH_CPU_NOT_COMPATIBLE;
1932#endif
1933}
1934
1935
1936/** @copydoc kLdrModCallTerm */
1937static int kldrModLXCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
1938{
1939 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1940
1941 /*
1942 * Mapped?
1943 */
1944 if (!pModLX->pvMapping)
1945 return KLDR_ERR_NOT_MAPPED;
1946
1947 /*
1948 * Do the call.
1949 */
1950 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
1951 kldrModLXDoCallDLL(pModLX, 1 /* detach */, uHandle);
1952
1953 return 0;
1954}
1955
1956
1957/** @copydoc kLdrModCallThread */
1958static int kldrModLXCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
1959{
1960 /* no thread attach/detach callout. */
1961 return 0;
1962}
1963
1964
1965/** @copydoc kLdrModSize */
1966static KLDRADDR kldrModLXSize(PKLDRMOD pMod)
1967{
1968 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1969 return pModLX->cbMapped;
1970}
1971
1972
1973/** @copydoc kLdrModGetBits */
1974static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1975{
1976 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1977 int rc;
1978
1979 /*
1980 * Load the image bits.
1981 */
1982 rc = kldrModLXDoLoadBits(pModLX, pvBits);
1983 if (rc)
1984 return rc;
1985
1986 /*
1987 * Perform relocations.
1988 */
1989 return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
1990
1991}
1992
1993
1994/** @copydoc kLdrModRelocateBits */
1995static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
1996 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1997{
1998 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1999 uint32_t iSeg;
2000 int rc;
2001
2002 /*
2003 * Do we need to to *anything*?
2004 */
2005 if ( NewBaseAddress == OldBaseAddress
2006 && NewBaseAddress == pModLX->paObjs[0].o32_base
2007 && !pModLX->Hdr.e32_impmodcnt)
2008 return 0;
2009
2010 /*
2011 * Load the fixup section.
2012 */
2013 if (!pModLX->pbFixupSection)
2014 {
2015 rc = kldrModLXDoLoadFixupSection(pModLX);
2016 if (rc)
2017 return rc;
2018 }
2019
2020 /*
2021 * Iterate the segments.
2022 */
2023 for (iSeg = 0; iSeg < pModLX->Hdr.e32_objcnt; iSeg++)
2024 {
2025 const struct o32_obj * const pObj = &pModLX->paObjs[iSeg];
2026 KLDRADDR PageAddress = NewBaseAddress + pModLX->pMod->aSegments[iSeg].RVA;
2027 uint32_t iPage;
2028 uint8_t *pbPage = (uint8_t *)pvBits + (uintptr_t)pModLX->pMod->aSegments[iSeg].RVA;
2029
2030 /*
2031 * Iterate the page map pages.
2032 */
2033 for (iPage = 0, rc = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN, PageAddress += OBJPAGELEN)
2034 {
2035 const uint8_t * const pbFixupRecEnd = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap];
2036 const uint8_t *pb = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap - 1];
2037 KLDRADDR uValue;
2038 int iSelector;
2039 uint32_t fKind;
2040
2041 /* sanity */
2042 if (pbFixupRecEnd < pb)
2043 return KLDR_ERR_BAD_FIXUP;
2044 if (pbFixupRecEnd - 1 > pModLX->pbFixupSectionLast)
2045 return KLDR_ERR_BAD_FIXUP;
2046 if (pb < pModLX->pbFixupSection)
2047 return KLDR_ERR_BAD_FIXUP;
2048
2049 /*
2050 * Iterate the fixup record.
2051 */
2052 while (pb < pbFixupRecEnd)
2053 {
2054 union _rel
2055 {
2056 const uint8_t * pb;
2057 const struct r32_rlc *prlc;
2058 } u;
2059
2060 u.pb = pb;
2061 pb += 3 + (u.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */
2062
2063 /*
2064 * Figure out the target.
2065 */
2066 switch (u.prlc->nr_flags & NRRTYP)
2067 {
2068 /*
2069 * Internal fixup.
2070 */
2071 case NRRINT:
2072 {
2073 uint16_t iTrgObject;
2074 uint32_t offTrgObject;
2075
2076 /* the object */
2077 if (u.prlc->nr_flags & NR16OBJMOD)
2078 {
2079 iTrgObject = *(const uint16_t *)pb;
2080 pb += 2;
2081 }
2082 else
2083 iTrgObject = *pb++;
2084 iTrgObject--;
2085 if (iTrgObject >= pModLX->Hdr.e32_objcnt)
2086 return KLDR_ERR_BAD_FIXUP;
2087
2088 /* the target */
2089 if ((u.prlc->nr_stype & NRSRCMASK) != NRSSEG)
2090 {
2091 if (u.prlc->nr_flags & NR32BITOFF)
2092 {
2093 offTrgObject = *(const uint32_t *)pb;
2094 pb += 4;
2095 }
2096 else
2097 {
2098 offTrgObject = *(const uint16_t *)pb;
2099 pb += 2;
2100 }
2101
2102 /* calculate the symbol info. */
2103 uValue = offTrgObject + pMod->aSegments[iSeg].MapAddress;
2104 }
2105 else
2106 uValue = pMod->aSegments[iSeg].MapAddress;
2107 if ( (u.prlc->nr_stype & NRALIAS)
2108 || (pMod->aSegments[iSeg].fFlags & KLDRSEG_FLAG_16BIT))
2109 iSelector = pMod->aSegments[iSeg].Sel16bit;
2110 else
2111 iSelector = pMod->aSegments[iSeg].SelFlat;
2112 fKind = 0;
2113 break;
2114 }
2115
2116 /*
2117 * Import by symbol ordinal.
2118 */
2119 case NRRORD:
2120 {
2121 uint16_t iModule;
2122 uint32_t iSymbol;
2123
2124 /* the module ordinal */
2125 if (u.prlc->nr_flags & NR16OBJMOD)
2126 {
2127 iModule = *(const uint16_t *)pb;
2128 pb += 2;
2129 }
2130 else
2131 iModule = *pb++;
2132 iModule--;
2133 if (iModule >= pModLX->Hdr.e32_impmodcnt)
2134 return KLDR_ERR_BAD_FIXUP;
2135#if 1
2136 if (u.prlc->nr_flags & NRICHAIN)
2137 return KLDR_ERR_BAD_FIXUP;
2138#endif
2139
2140 /* . */
2141 if (u.prlc->nr_flags & NR32BITOFF)
2142 {
2143 iSymbol = *(const uint32_t *)pb;
2144 pb += 4;
2145 }
2146 else if (!(u.prlc->nr_flags & NR8BITORD))
2147 {
2148 iSymbol = *(const uint16_t *)pb;
2149 pb += 2;
2150 }
2151 else
2152 iSymbol = *pb++;
2153
2154 /* resolve it. */
2155 rc = pfnGetImport(pMod, iModule, iSymbol, NULL, 0, NULL, &uValue, &fKind, pvUser);
2156 if (rc)
2157 return rc;
2158 iSelector = -1;
2159 break;
2160 }
2161
2162 /*
2163 * Import by symbol name.
2164 */
2165 case NRRNAM:
2166 {
2167 uint32_t iModule;
2168 uint16_t offSymbol;
2169 const uint8_t *pbSymbol;
2170
2171 /* the module ordinal */
2172 if (u.prlc->nr_flags & NR16OBJMOD)
2173 {
2174 iModule = *(const uint16_t *)pb;
2175 pb += 2;
2176 }
2177 else
2178 iModule = *pb++;
2179 iModule--;
2180 if (iModule >= pModLX->Hdr.e32_impmodcnt)
2181 return KLDR_ERR_BAD_FIXUP;
2182#if 1
2183 if (u.prlc->nr_flags & NRICHAIN)
2184 return KLDR_ERR_BAD_FIXUP;
2185#endif
2186
2187 /* . */
2188 if (u.prlc->nr_flags & NR32BITOFF)
2189 {
2190 offSymbol = *(const uint32_t *)pb;
2191 pb += 4;
2192 }
2193 else if (!(u.prlc->nr_flags & NR8BITORD))
2194 {
2195 offSymbol = *(const uint16_t *)pb;
2196 pb += 2;
2197 }
2198 else
2199 offSymbol = *pb++;
2200 pbSymbol = pModLX->pbImportProcs + offSymbol;
2201 if ( pbSymbol < pModLX->pbImportProcs
2202 || pbSymbol > pModLX->pbFixupSectionLast)
2203 return KLDR_ERR_BAD_FIXUP;
2204
2205 /* resolve it. */
2206 rc = pfnGetImport(pMod, iModule, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pbSymbol + 1, *pbSymbol, NULL,
2207 &uValue, &fKind, pvUser);
2208 if (rc)
2209 return rc;
2210 iSelector = -1;
2211 break;
2212 }
2213
2214 case NRRENT:
2215 KLDRMODLX_ASSERT(!"NRRENT");
2216 default:
2217 break;
2218 }
2219
2220 /* addend */
2221 if (u.prlc->nr_flags & NRADD)
2222 {
2223 if (u.prlc->nr_flags & NR32BITADD)
2224 {
2225 uValue += *(const uint32_t *)pb;
2226 pb += 4;
2227 }
2228 else
2229 {
2230 uValue += *(const uint16_t *)pb;
2231 pb += 2;
2232 }
2233 }
2234
2235
2236 /*
2237 * Deal with the 'source' (i.e. the place that should be modified (very logical).
2238 */
2239 if (!(u.prlc->nr_stype & NRCHAIN))
2240 {
2241 int off = u.prlc->r32_soff;
2242
2243 /* common / simple */
2244 if ( (u.prlc->nr_stype & NRSRCMASK) == NROFF32
2245 && off >= 0
2246 && off <= OBJPAGELEN - 4)
2247 *(uint32_t *)&pbPage[off] = uValue;
2248 else if ( (u.prlc->nr_stype & NRSRCMASK) == NRSOFF32
2249 && off >= 0
2250 && off <= OBJPAGELEN - 4)
2251 *(uint32_t *)&pbPage[off] = uValue - (PageAddress + off);
2252 else
2253 {
2254 /* generic */
2255 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2256 if (rc)
2257 return rc;
2258 }
2259 }
2260 else if (!(u.prlc->nr_flags & NRICHAIN))
2261 {
2262 const int16_t *poffSrc = (const int16_t *)pb;
2263 uint8_t c = u.pb[2];
2264
2265 /* common / simple */
2266 if ((u.prlc->nr_stype & NRSRCMASK) == NROFF32)
2267 {
2268 while (c-- > 0)
2269 {
2270 int off = *poffSrc++;
2271 if (off >= 0 && off <= OBJPAGELEN - 4)
2272 *(uint32_t *)&pbPage[off] = uValue;
2273 else
2274 {
2275 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2276 if (rc)
2277 return rc;
2278 }
2279 }
2280 }
2281 else if ((u.prlc->nr_stype & NRSRCMASK) == NRSOFF32)
2282 {
2283 while (c-- > 0)
2284 {
2285 int off = *poffSrc++;
2286 if (off >= 0 && off <= OBJPAGELEN - 4)
2287 *(uint32_t *)&pbPage[off] = uValue - (PageAddress + off);
2288 else
2289 {
2290 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2291 if (rc)
2292 return rc;
2293 }
2294 }
2295 }
2296 else
2297 {
2298 while (c-- > 0)
2299 {
2300 rc = kldrModLXDoReloc(pbPage, *poffSrc++, PageAddress, u.prlc, iSelector, uValue, fKind);
2301 if (rc)
2302 return rc;
2303 }
2304 }
2305 pb = (const uint8_t *)poffSrc;
2306 }
2307 else
2308 {
2309 /* This is a pain because it will require virgin pages on a relocation. */
2310 KLDRMODLX_ASSERT(!"NRICHAIN");
2311 return KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED;
2312 }
2313 }
2314 }
2315 }
2316
2317 return 0;
2318}
2319
2320
2321/**
2322 * Applies the relocation to one 'source' in a page.
2323 *
2324 * This takes care of the more esotic case while the common cases
2325 * are dealt with seperately.
2326 *
2327 * @returns 0 on success, non-zero kLdr status code on failure.
2328 * @param pbPage The page in which to apply the fixup.
2329 * @param off Page relative offset of where to apply the offset.
2330 * @param uValue The target value.
2331 * @param fKind The target kind.
2332 */
2333static int kldrModLXDoReloc(uint8_t *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc,
2334 int iSelector, KLDRADDR uValue, uint32_t fKind)
2335{
2336 static const uint8_t s_acb[16] =
2337 {
2338 1, /* 0: NRSBYT */
2339 0,
2340 2, /* 2: NRSSEG - selector */
2341 4, /* 3: NRSPTR - 16:16 */
2342 0,
2343 2, /* 5: NRSOFF - 16-bit offset */
2344 6, /* 6: NRPTR48 - 16:32 */
2345 4, /* 7: NROFF32 - 32-bit offset */
2346 4, /* 8: NRSOFF32 - 32-bit offset self relative */
2347 0, 0, 0, 0, 0, 0, 0
2348 };
2349#pragma pack(1) /* just to be sure */
2350 union
2351 {
2352 uint8_t ab[6];
2353 uint32_t off32;
2354 uint16_t off16;
2355 uint8_t off8;
2356 struct
2357 {
2358 uint16_t off;
2359 uint16_t Sel;
2360 } Far16;
2361 struct
2362 {
2363 uint32_t off;
2364 uint16_t Sel;
2365 } Far32;
2366 } uData;
2367#pragma pack()
2368 const uint8_t *pbSrc;
2369 uint8_t *pbDst;
2370 uint8_t cb;
2371
2372 /*
2373 * Compose the fixup data.
2374 */
2375 switch (prlc->nr_stype & NRSRCMASK)
2376 {
2377 case NRSBYT:
2378 uData.off8 = (uint8_t)uValue;
2379 cb = 1;
2380 break;
2381 case NRSSEG:
2382 if (iSelector == -1)
2383 {
2384 /* fixme */
2385 }
2386 uData.off16 = iSelector;
2387 cb = 2;
2388 break;
2389 case NRSPTR:
2390 if (iSelector == -1)
2391 {
2392 /* fixme */
2393 }
2394 uData.Far16.off = (uint16_t)uValue;
2395 uData.Far16.Sel = iSelector;
2396 cb = 4;
2397 break;
2398 case NRSOFF:
2399 uData.off16 = (uint16_t)uValue;
2400 cb = 2;
2401 break;
2402 case NRPTR48:
2403 if (iSelector == -1)
2404 {
2405 /* fixme */
2406 }
2407 uData.Far32.off = (uint32_t)uValue;
2408 uData.Far32.Sel = iSelector;
2409 cb = 6;
2410 break;
2411 case NROFF32:
2412 uData.off32 = (uint32_t)uValue;
2413 cb = 4;
2414 break;
2415 case NRSOFF32:
2416 uData.off32 = (uint32_t)uValue - (PageAddress + off);
2417 cb = 4;
2418 break;
2419 default:
2420 return KLDR_ERR_LX_BAD_FIXUP_SECTION; /** @todo fix error, add more checks! */
2421 }
2422
2423 /*
2424 * Apply it. This is sloooow...
2425 */
2426 pbSrc = &uData.ab[0];
2427 pbDst = pbPage + off;
2428 while (cb-- > 0)
2429 {
2430 if (off > OBJPAGELEN)
2431 break;
2432 if (off >= 0)
2433 *pbDst = *pbSrc;
2434 pbSrc++;
2435 pbDst++;
2436 }
2437
2438 return 0;
2439}
2440
2441
2442/**
2443 * The LX module interpreter method table.
2444 */
2445KLDRMODOPS g_kLdrModLXOps =
2446{
2447 "LX",
2448 NULL,
2449 kldrModLXCreate,
2450 kldrModLXDestroy,
2451 kldrModLXQuerySymbol,
2452 kldrModLXEnumSymbols,
2453 kldrModLXGetImport,
2454 kldrModLXNumberOfImports,
2455 NULL /* can execute one is optional */,
2456 kldrModLXGetStackInfo,
2457 kldrModLXQueryMainEntrypoint,
2458 NULL /* fixme */,
2459 NULL /* fixme */,
2460 kldrModLXEnumDbgInfo,
2461 kldrModLXHasDbgInfo,
2462 kldrModLXMap,
2463 kldrModLXUnmap,
2464 kldrModLXAllocTLS,
2465 kldrModLXFreeTLS,
2466 kldrModLXReload,
2467 kldrModLXFixupMapping,
2468 kldrModLXCallInit,
2469 kldrModLXCallTerm,
2470 kldrModLXCallThread,
2471 kldrModLXSize,
2472 kldrModLXGetBits,
2473 kldrModLXRelocateBits,
2474 NULL /* fixme: pfnMostlyDone */,
2475 42 /* the end */
2476};
2477
Note: See TracBrowser for help on using the repository browser.