source: trunk/kLdr/kLdrModLX.c@ 2886

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

Bugfixing.

  • Property svn:keywords set to Id
File size: 63.5 KB
Line 
1/* $Id: kLdrModLX.c 2886 2006-11-18 15:01:05Z 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 off_t 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, off_t 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 *pszSymbol, uint32_t *piSymbol);
121static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable,
122 char *pchSymbol, size_t cchSymbol);
123static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
124static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
125static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
126static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb);
127static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
128static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle);
129static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
130 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind);
131static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX);
132static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
133
134
135/**
136 * Create a loader module instance interpreting the executable image found
137 * in the specified file provider instance.
138 *
139 * @returns 0 on success and *ppMod pointing to a module instance.
140 * On failure, a non-zero OS specific error code is returned.
141 * @param pOps Pointer to the registered method table.
142 * @param pRdr The file provider instance to use.
143 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
144 * @param ppMod Where to store the module instance pointer.
145 */
146static int kldrModLXCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
147{
148 PKLDRMODLX pModLX;
149 int rc;
150
151 /*
152 * Create the instance data and do a minimal header validation.
153 */
154 rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX);
155 if (!rc)
156 {
157 pModLX->pMod->pOps = pOps;
158 pModLX->pMod->u32Magic = KLDRMOD_MAGIC;
159 *ppMod = pModLX->pMod;
160 return 0;
161 }
162 kldrHlpFree(pModLX);
163 return rc;
164}
165
166
167/**
168 * Separate function for reading creating the LX module instance to
169 * simplify cleanup on failure.
170 */
171static int kldrModLXDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODLX *ppModLX)
172{
173 struct e32_exe Hdr;
174 PKLDRMODLX pModLX;
175 PKLDRMOD pMod;
176 size_t cb;
177 size_t cchFilename;
178 uint32_t off, offEnd;
179 uint32_t i;
180 int rc;
181 *ppModLX = NULL;
182
183 /*
184 * Read the signature and file header.
185 */
186 rc = kLdrRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
187 if (rc)
188 return rc;
189 if ( Hdr.e32_magic[0] != E32MAGIC1
190 || Hdr.e32_magic[1] != E32MAGIC2)
191 return KLDR_ERR_UNKNOWN_FORMAT;
192
193 /* We're not interested in anything but x86 images. */
194 if ( Hdr.e32_level != E32LEVEL
195 || Hdr.e32_border != E32LEBO
196 || Hdr.e32_worder != E32LEWO
197 || Hdr.e32_cpu < E32CPU286
198 || Hdr.e32_cpu > E32CPU486
199 || Hdr.e32_pagesize != OBJPAGELEN
200 )
201 return KLDR_ERR_LX_BAD_HEADER;
202
203 /* Some rough sanity checks. */
204 offEnd = kLdrRdrSize(pRdr) >= (off_t)~(uint32_t)16 ? ~(uint32_t)16 : (uint32_t)kLdrRdrSize(pRdr);
205 if ( Hdr.e32_itermap > offEnd
206 || Hdr.e32_datapage > offEnd
207 || Hdr.e32_nrestab > offEnd
208 || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
209 || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
210 || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
211 || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
212 return KLDR_ERR_LX_BAD_HEADER;
213
214 /* Verify the loader section. */
215 offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
216 if (Hdr.e32_objtab < sizeof(Hdr))
217 return KLDR_ERR_LX_BAD_LOADER_SECTION;
218 off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
219 if (off > offEnd)
220 return KLDR_ERR_LX_BAD_LOADER_SECTION;
221 if ( Hdr.e32_objmap
222 && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
223 return KLDR_ERR_LX_BAD_LOADER_SECTION;
224 if ( Hdr.e32_rsrccnt
225 && ( Hdr.e32_rsrctab < off
226 || Hdr.e32_rsrctab > offEnd
227 || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
228 return KLDR_ERR_LX_BAD_LOADER_SECTION;
229 if ( Hdr.e32_restab
230 && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
231 return KLDR_ERR_LX_BAD_LOADER_SECTION;
232 if ( Hdr.e32_enttab
233 && (Hdr.e32_enttab < off || Hdr.e32_enttab > offEnd - 2))
234 return KLDR_ERR_LX_BAD_LOADER_SECTION;
235 if ( Hdr.e32_dircnt
236 && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd))
237 return KLDR_ERR_LX_BAD_LOADER_SECTION;
238
239 /* Verify the fixup section. */
240 off = offEnd;
241 offEnd = off + Hdr.e32_fixupsize;
242 if ( Hdr.e32_fpagetab
243 && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
244 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
245 if ( Hdr.e32_frectab
246 && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
247 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
248 if ( Hdr.e32_impmod
249 && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
250 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
251 if ( Hdr.e32_impproc
252 && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
253 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
254
255 /*
256 * Calc the instance size, allocate and initialize it.
257 */
258 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
259 cb = KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8)
260 + KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8)
261 + KLDR_ALIGN_Z(cchFilename + 1, 8)
262 + Hdr.e32_ldrsize;
263 pModLX = (PKLDRMODLX)kldrHlpAlloc(cb);
264 if (!pModLX)
265 return KLDR_ERR_NO_MEMORY;
266 *ppModLX = pModLX;
267
268 /* KLDRMOD */
269 pMod = (PKLDRMOD)((uint8_t *)pModLX + KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8));
270 pMod->pvData = pModLX;
271 pMod->pRdr = pRdr;
272 pMod->pOps = NULL; /* set upon success. */
273 pMod->cSegments = Hdr.e32_objcnt;
274 pMod->cchFilename = cchFilename;
275 pMod->pszFilename = (char *)KLDR_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8);
276 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
277 pMod->pszName = NULL; /* finalized further down */
278 pMod->cchName = 0;
279 switch (Hdr.e32_cpu)
280 {
281 case E32CPU286:
282 pMod->enmCpu = KLDRCPU_I80286;
283 pMod->enmArch = KLDRARCH_X86_16;
284 break;
285 case E32CPU386:
286 pMod->enmCpu = KLDRCPU_I386;
287 pMod->enmArch = KLDRARCH_X86_32;
288 break;
289 case E32CPU486:
290 pMod->enmCpu = KLDRCPU_I486;
291 pMod->enmArch = KLDRARCH_X86_32;
292 break;
293 }
294 pMod->enmEndian = KLDRENDIAN_LITTLE;
295 pMod->enmFmt = KLDRFMT_LX;
296 switch (Hdr.e32_mflags & E32MODMASK)
297 {
298 case E32MODEXE:
299 pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX)
300 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
301 : KLDRTYPE_EXECUTABLE_FIXED;
302 break;
303
304 case E32MODDLL:
305 case E32PROTDLL:
306 case E32MODPROTDLL:
307 pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL)
308 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
309 : KLDRTYPE_SHARED_LIBRARY_FIXED;
310 break;
311
312 case E32MODPDEV:
313 case E32MODVDEV:
314 pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
315 break;
316 }
317 pMod->u32Magic = 0; /* set upon success. */
318
319 /* KLDRMODLX */
320 pModLX->pMod = pMod;
321 pModLX->pvMapping = 0;
322 pModLX->cbMapped = Hdr.e32_mpages * Hdr.e32_pagesize;
323 pModLX->f32Reserved = 0;
324
325 pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
326 pModLX->Hdr = Hdr;
327
328 pModLX->pbLoaderSection = KLDR_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16);
329 pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize;
330 pModLX->paObjs = NULL;
331 pModLX->paPageMappings = NULL;
332 pModLX->paRsrcs = NULL;
333 pModLX->pbResNameTab = NULL;
334 pModLX->pbEntryTab = NULL;
335
336 pModLX->pbNonResNameTab = NULL;
337 pModLX->pbNonResNameTabLast = NULL;
338
339 pModLX->pbFixupSection = NULL;
340 pModLX->pbFixupSectionLast = NULL;
341 pModLX->paoffPageFixups = NULL;
342 pModLX->pbFixupRecs = NULL;
343 pModLX->pbImportMods = NULL;
344 pModLX->pbImportProcs = NULL;
345
346 /*
347 * Read the loader data.
348 */
349 rc = kLdrRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
350 if (rc)
351 return rc;
352 if (pModLX->Hdr.e32_objcnt)
353 pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
354 if (pModLX->Hdr.e32_objmap)
355 pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
356 if (pModLX->Hdr.e32_rsrccnt)
357 pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
358 if (pModLX->Hdr.e32_restab)
359 pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
360 if (pModLX->Hdr.e32_enttab)
361 pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
362
363 /*
364 * Get the soname from the resident name table.
365 * Very convenient that it's the 0 ordinal, because then we get a
366 * free string terminator.
367 * (The table entry consists of a pascal string followed by a 16-bit ordinal.)
368 */
369 pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab,
370 pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
371 0);
372 if (!pMod->pszName)
373 return KLDR_ERR_LX_NO_SONAME;
374 pMod->cchName = *(const uint8_t *)pMod->pszName++;
375 if (pMod->cchName != kLdrHlpStrLen(pMod->pszName))
376 return KLDR_ERR_LX_BAD_SONAME;
377
378 /*
379 * Quick validation of the object table.
380 */
381 cb = 0;
382 for (i = 0; i < pMod->cSegments; i++)
383 {
384 if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
385 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
386 if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
387 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
388 if (pModLX->paObjs[i].o32_mapsize > pModLX->paObjs[i].o32_size / OBJPAGELEN)
389 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
390 if ( pModLX->paObjs[i].o32_mapsize
391 && ( (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
392 || (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
393 > pModLX->pbLoaderSectionLast))
394 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
395 if (i > 0)
396 {
397 if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
398 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
399 if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
400 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
401 }
402 }
403 pModLX->cbMapped = pMod->cSegments
404 ? pModLX->paObjs[pMod->cSegments - 1].o32_base + pModLX->paObjs[pMod->cSegments - 1].o32_size
405 - pModLX->paObjs[pMod->cSegments - 1].o32_size
406 : 0;
407
408 /*
409 * Setup the KLDRMOD segment array.
410 */
411 for (i = 0; i < pMod->cSegments; i++)
412 {
413 /* unused */
414 pMod->aSegments[i].pvUser = NULL;
415 pMod->aSegments[i].MapAddress = 0;
416 pMod->aSegments[i].pchName = NULL;
417 pMod->aSegments[i].cchName = 0;
418 pMod->aSegments[i].offFile = -1;
419 pMod->aSegments[i].cbFile = 0;
420
421 /* size and addresses */
422 pMod->aSegments[i].Alignment = OBJPAGELEN;
423 pMod->aSegments[i].cb = pModLX->paObjs[i].o32_size;
424 pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
425 pMod->aSegments[i].RVA = pModLX->paObjs[i].o32_base - pModLX->paObjs[0].o32_base;
426 pMod->aSegments[i].cbMapped = KLDR_ALIGN_Z(pModLX->paObjs[i].o32_size, 16);
427 if (i + 1 < pMod->cSegments)
428 pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
429
430 /* protection */
431 switch ( pModLX->paObjs[i].o32_flags
432 & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
433 {
434 case 0:
435 case OBJSHARED:
436 pMod->aSegments[i].enmProt = KLDRPROT_NOACCESS;
437 break;
438 case OBJREAD:
439 case OBJREAD | OBJSHARED:
440 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
441 break;
442 case OBJWRITE:
443 case OBJWRITE | OBJREAD:
444 pMod->aSegments[i].enmProt = KLDRPROT_WRITECOPY;
445 break;
446 case OBJWRITE | OBJSHARED:
447 case OBJWRITE | OBJSHARED | OBJREAD:
448 pMod->aSegments[i].enmProt = KLDRPROT_READWRITE;
449 break;
450 case OBJEXEC:
451 case OBJEXEC | OBJSHARED:
452 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE;
453 break;
454 case OBJEXEC | OBJREAD:
455 case OBJEXEC | OBJREAD | OBJSHARED:
456 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READ;
457 break;
458 case OBJEXEC | OBJWRITE:
459 case OBJEXEC | OBJWRITE | OBJREAD:
460 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
461 break;
462 case OBJEXEC | OBJWRITE | OBJSHARED:
463 case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
464 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READWRITE;
465 break;
466 }
467 if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
468 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
469 /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
470 pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
471 pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */
472 }
473
474 /*
475 * We're done.
476 */
477 *ppModLX = pModLX;
478 return 0;
479}
480
481
482/** @copydoc KLDRMODOPS::pfnDestroy */
483static int kldrModLXDestroy(PKLDRMOD pMod)
484{
485 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
486 int rc = 0;
487 KLDRMODLX_ASSERT(pModLX->pvMapping);
488
489 if (pMod->pRdr)
490 {
491 rc = kLdrRdrClose(pMod->pRdr);
492 pMod->pRdr = NULL;
493 }
494 if (pModLX->pbNonResNameTab)
495 {
496 kldrHlpFree(pModLX->pbNonResNameTab);
497 pModLX->pbNonResNameTab = NULL;
498 }
499 if (pModLX->pbFixupSection)
500 {
501 kldrHlpFree(pModLX->pbFixupSection);
502 pModLX->pbFixupSection = NULL;
503 }
504 pMod->u32Magic = 0;
505 pMod->pOps = NULL;
506 kldrHlpFree(pModLX);
507 return rc;
508}
509
510
511/**
512 * Resolved base address aliases.
513 *
514 * @param pModLX The interpreter module instance
515 * @param pBaseAddress The base address, IN & OUT.
516 */
517static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress)
518{
519 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
520 *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress;
521 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
522 *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress;
523}
524
525
526/** @copydoc kLdrModQuerySymbol */
527static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
528 const char *pszSymbol, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser,
529 PKLDRADDR puValue, uint32_t *pfKind)
530{
531 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
532 uint32_t iOrdinal;
533 int rc;
534 const struct b32_bundle *pBundle;
535
536
537 /*
538 * Give up at once if there is no entry table.
539 */
540 if (!pModLX->Hdr.e32_enttab)
541 return KLDR_ERR_SYMBOL_NOT_FOUND;
542
543 /*
544 * Translate the symbol name into an ordinal.
545 */
546 if (pszSymbol)
547 {
548 rc = kldrModLXDoNameLookup(pModLX, pszSymbol, &iSymbol);
549 if (rc)
550 return rc;
551 }
552
553 /*
554 * Iterate the entry table.
555 * (The entry table is made up of bundles of similar exports.)
556 */
557 iOrdinal = 0;
558 pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
559 while (!pBundle->b32_cnt && iOrdinal <= iSymbol)
560 {
561 static const size_t s_cbEntry[] = { 0, 3, 5, 5, 7 };
562
563 /*
564 * Check for a hit first.
565 */
566 iOrdinal += pBundle->b32_cnt;
567 if (iSymbol < iOrdinal)
568 {
569 uint32_t offObject;
570 const struct e32_entry *pEntry = (const struct e32_entry *)((uintptr_t)(pBundle + 1)
571 + iSymbol - (iOrdinal - pBundle->b32_cnt));
572
573 /*
574 * Calculate the return address.
575 */
576 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
577 switch (pBundle->b32_type)
578 {
579 /* empty bundles are place holders unused ordinal ranges. */
580 case EMPTY:
581 return KLDR_ERR_SYMBOL_NOT_FOUND;
582
583 /* e32_flags + a 16-bit offset. */
584 case ENTRY16:
585 offObject = pEntry->e32_variant.e32_offset.offset16;
586 if (pfKind)
587 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE;
588 break;
589
590 /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
591 case GATE16:
592 offObject = pEntry->e32_variant.e32_callgate.offset;
593 if (pfKind)
594 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE;
595 break;
596
597 /* e32_flags + a 32-bit offset. */
598 case ENTRY32:
599 offObject = pEntry->e32_variant.e32_offset.offset32;
600 if (pfKind)
601 *pfKind = KLDRSYMKIND_32BIT;
602 break;
603
604 /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
605 case ENTRYFWD:
606 return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind);
607
608 default:
609 /* anyone actually using TYPEINFO will end up here. */
610 KLDRMODLX_ASSERT(!"Bad bundle type");
611 break;
612 }
613
614 /*
615 * Validate the object number and calc the return address.
616 */
617 if ( pBundle->b32_obj <= 0
618 || pBundle->b32_obj > pMod->cSegments)
619 return KLDR_ERR_LX_BAD_BUNDLE;
620 if (puValue)
621 *puValue = BaseAddress
622 + offObject
623 + pMod->aSegments[pBundle->b32_obj - 1].RVA;
624 return 0;
625 }
626
627 /*
628 * Skip the bundle.
629 */
630 if (pBundle->b32_type > ENTRYFWD)
631 {
632 KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
633 return KLDR_ERR_LX_BAD_BUNDLE;
634 }
635 if (pBundle->b32_type == 0)
636 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + 2);
637 else
638 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
639 }
640
641 return KLDR_ERR_SYMBOL_NOT_FOUND;
642}
643
644
645/**
646 * Do name lookup.
647 *
648 * @returns See kLdrModQuerySymbol.
649 * @param pModLX The module to lookup the symbol in.
650 * @param pszSymbol The symbol to lookup.
651 * @param piSymbol Where to store the symbol ordinal.
652 */
653static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pszSymbol, uint32_t *piSymbol)
654{
655
656 /*
657 * First do a hash table lookup.
658 */
659
660
661
662 /*
663
664 */
665
666 return -1;
667}
668
669
670/**
671 * Hash a symbol using the algorithm from sdbm.
672 *
673 * The following was is the documenation of the orignal sdbm functions:
674 *
675 * This algorithm was created for sdbm (a public-domain reimplementation of
676 * ndbm) database library. it was found to do well in scrambling bits,
677 * causing better distribution of the keys and fewer splits. it also happens
678 * to be a good general hashing function with good distribution. the actual
679 * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
680 * is the faster version used in gawk. [there is even a faster, duff-device
681 * version] the magic constant 65599 was picked out of thin air while
682 * experimenting with different constants, and turns out to be a prime.
683 * this is one of the algorithms used in berkeley db (see sleepycat) and
684 * elsewhere.
685 */
686static uint32_t kldrModLXDoHash(const char *pchSymbol, uint8_t cchSymbol)
687{
688 uint32_t hash = 0;
689 int ch;
690
691 while ( cchSymbol-- > 0
692 && (ch = *(unsigned const char *)pchSymbol++))
693 hash = ch + (hash << 6) + (hash << 16) - hash;
694
695 return hash;
696}
697
698
699/**
700 * Lookup a name table entry by name.
701 *
702 * @returns Pointer to the name table entry if found.
703 * @returns NULL if not found.
704 * @param pbNameTable Pointer to the name table that should be searched.
705 * @param cbNameTable The size of the name table.
706 * @param pchSymbol The name of the symbol we're looking for.
707 * @param cchSymbol The length of the symbol name.
708 */
709static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable,
710 char *pchSymbol, size_t cchSymbol)
711{
712 /*
713 * Determin the namelength up front so we can skip anything which doesn't matches the length.
714 */
715 uint8_t cbSymbol8Bit = (uint8_t)cchSymbol;
716 if (cbSymbol8Bit != cchSymbol)
717 return NULL; /* too long. */
718
719 /*
720 * Walk the name table.
721 */
722 while (*pbNameTable != 0 && cbNameTable > 0)
723 {
724 const uint8_t cbName = *pbNameTable;
725
726 cbNameTable -= cbName + 1 + 2;
727 if (cbNameTable < 0)
728 break;
729
730 if ( cbName == cbSymbol8Bit
731 && !kLdrHlpMemComp(pbNameTable + 1, pchSymbol, cbName))
732 return pbNameTable;
733
734 /* next entry */
735 pbNameTable += cbName + 1 + 2;
736 }
737
738 return NULL;
739}
740
741
742/**
743 * Deal with a forwarder entry.
744 *
745 * @returns See kLdrModQuerySymbol.
746 * @param pModLX The PE module interpreter instance.
747 * @param pEntry The forwarder entry.
748 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
749 * @param pvUser The user argument for the callback.
750 * @param puValue Where to put the value. (optional)
751 * @param pfKind Where to put the symbol kind. (optional)
752 */
753static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
754 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
755{
756 int rc;
757 uint32_t iSymbol;
758 const char *pszSymbol;
759
760 if (!pfnGetForwarder)
761 return KLDR_ERR_FORWARDER_SYMBOL;
762
763 /*
764 * Validate the entry import module ordinal.
765 */
766 if ( !pEntry->e32_variant.e32_fwd.modord
767 || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt)
768 return KLDR_ERR_LX_BAD_FORWARDER;
769
770 /*
771 * Figure out the parameters.
772 */
773 if (pEntry->e32_flags & FWD_ORDINAL)
774 {
775 iSymbol = pEntry->e32_variant.e32_fwd.value;
776 pszSymbol = NULL; /* no symbol name. */
777 }
778 else
779 {
780 const uint8_t *pbName;
781
782 /* load the fixup section if necessary. */
783 if (!pModLX->pbImportProcs)
784 {
785 rc = kldrModLXDoLoadFixupSection(pModLX);
786 if (rc)
787 return rc;
788 }
789
790 /* Make name pointer. */
791 pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value;
792 if ( pbName >= pModLX->pbFixupSectionLast
793 || pbName < pModLX->pbFixupSectionLast
794 || !*pbName)
795 return KLDR_ERR_LX_BAD_FORWARDER;
796
797
798 /* check for '#' name. */
799 if (pbName[1] == '#')
800 {
801 uint8_t cbLeft = *pbName;
802 const uint8_t *pb = pbName + 1;
803 unsigned uBase;
804
805 /* base detection */
806 uBase = 10;
807 if ( cbLeft > 1
808 && pb[1] == '0'
809 && (pb[2] == 'x' || pb[2] == 'X'))
810 {
811 uBase = 16;
812 pb += 2;
813 cbLeft -= 2;
814 }
815
816 /* ascii to integer */
817 iSymbol = 0;
818 while (cbLeft-- > 0)
819 {
820 /* convert char to digit. */
821 unsigned uDigit = *pb++;
822 if (uDigit >= '0' && uDigit <= '9')
823 uDigit -= '0';
824 else if (uDigit >= 'a' && uDigit <= 'z')
825 uDigit -= 'a' + 10;
826 else if (uDigit >= 'A' && uDigit <= 'Z')
827 uDigit -= 'A' + 10;
828 else if (!uDigit)
829 break;
830 else
831 return KLDR_ERR_LX_BAD_FORWARDER;
832 if (uDigit >= uBase)
833 return KLDR_ERR_LX_BAD_FORWARDER;
834
835 /* insert the digit */
836 iSymbol *= uBase;
837 iSymbol += uDigit;
838 }
839 if (!iSymbol)
840 return KLDR_ERR_LX_BAD_FORWARDER;
841
842 pszSymbol = NULL; /* no symbol name. */
843 }
844 else
845 {
846 /* Make a stack copy of the name that's zero terminated. */
847 char *pszCopy = kLdrHlpAllocA(*pbName + 1);
848 kLdrHlpMemCopy(pszCopy, pbName + 1, *pbName);
849 pszCopy[*pbName] = '\0';
850
851 pszSymbol = pszCopy;
852 iSymbol = NIL_KLDRMOD_SYM_ORDINAL;
853 }
854 }
855
856 /*
857 * Resolve the forwarder.
858 */
859 rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pszSymbol, puValue, pfKind, pvUser);
860 if (!rc && pfKind)
861 *pfKind |= KLDRSYMKIND_FORWARDER;
862 return rc;
863}
864
865
866/**
867 * Loads the fixup section from the executable image.
868 *
869 * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone().
870 *
871 * @returns 0 on success, non-zero kLdr or native status code on failure.
872 * @param pModLX The PE module interpreter instance.
873 */
874static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX)
875{
876 return -1;
877}
878
879
880/** @copydoc kLdrModEnumSymbols */
881static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
882 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
883{
884 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
885/* int rc; */
886
887 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
888
889 return -1;
890}
891
892
893/**
894 * Lookup a name table entry by ordinal.
895 *
896 * @returns Pointer to the name table entry if found.
897 * @returns NULL if not found.
898 * @param pbNameTable Pointer to the name table that should be searched.
899 * @param cbNameTable The size of the name table.
900 * @param iOrdinal The ordinal to search for.
901 */
902static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal)
903{
904 while (*pbNameTable != 0 && cbNameTable > 0)
905 {
906 const uint8_t cbName = *pbNameTable;
907 uint32_t iName;
908
909 cbNameTable -= cbName + 1 + 2;
910 if (cbNameTable < 0)
911 break;
912
913 iName = *(pbNameTable + cbName)
914 | ((unsigned)*(pbNameTable + cbName + 1) << 8);
915 if (iName == iOrdinal)
916 return pbNameTable;
917
918 /* next entry */
919 pbNameTable += cbName + 1 + 2;
920 }
921
922 return NULL;
923}
924
925
926/** @copydoc kLdrModGetImport */
927static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
928{
929 /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/
930 const uint8_t * pb = NULL;
931 int rc;
932
933 /** @todo */
934
935 if (*pb < cchName)
936 {
937 kLdrHlpMemCopy(pszName, pb + 1, *pb);
938 pszName[*pb] = '\0';
939 rc = 0;
940 }
941 else
942 {
943 kLdrHlpMemCopy(pszName, pb + 1, cchName);
944 if (cchName)
945 pszName[cchName - 1] = '\0';
946 rc = KLDR_ERR_BUFFER_OVERFLOW;
947 }
948
949 return rc;
950}
951
952
953/** @copydoc kLdrModNumberOfImports */
954static int32_t kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits)
955{
956 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
957 return pModLX->Hdr.e32_impmodcnt;
958}
959
960
961/** @copydoc kLdrModGetStackInfo */
962static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
963{
964 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
965 const uint32_t i = pModLX->Hdr.e32_stackobj;
966
967 if ( i
968 && i <= pMod->cSegments
969 && pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb
970 && pModLX->Hdr.e32_stacksize
971 && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress)
972 {
973
974 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
975 pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
976 pStackInfo->Address = BaseAddress
977 + pMod->aSegments[i - 1].RVA
978 + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress;
979 }
980 else
981 {
982 pStackInfo->Address = NIL_KLDRADDR;
983 pStackInfo->LinkAddress = NIL_KLDRADDR;
984 }
985 pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
986 pStackInfo->cbStackThread = 0;
987
988 return 0;
989}
990
991
992/** @copydoc kLdrModQueryMainEntrypoint */
993static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
994{
995 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
996
997 /*
998 * Convert the address from the header.
999 */
1000 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1001 *pMainEPAddress = pModLX->Hdr.e32_startobj
1002 && pModLX->Hdr.e32_startobj <= pMod->cSegments
1003 && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb
1004 ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
1005 : NIL_KLDRADDR;
1006 return 0;
1007}
1008
1009
1010/** @copydoc kLdrModEnumDbgInfo */
1011static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1012{
1013 /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/
1014
1015 /*
1016 * Quit immediately if no debug info.
1017 */
1018 if (kldrModLXHasDbgInfo(pMod, pvBits))
1019 return 0;
1020#if 0
1021 /*
1022 * Read the debug info and look for familiar magics and structures.
1023 */
1024 /** @todo */
1025#endif
1026
1027 return 0;
1028}
1029
1030
1031/** @copydoc kLdrModHasDbgInfo */
1032static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1033{
1034 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1035
1036 /*
1037 * Don't curretnly bother with linkers which doesn't advertise it in the header.
1038 */
1039 if ( !pModLX->Hdr.e32_debuginfo
1040 || !pModLX->Hdr.e32_debuglen)
1041 return KLDR_ERR_NO_DEBUG_INFO;
1042 return 0;
1043}
1044
1045
1046/** @copydoc kLdrModMap */
1047static int kldrModLXMap(PKLDRMOD pMod)
1048{
1049 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1050 unsigned fFixed;
1051 void *pvBase;
1052 int rc;
1053
1054 /*
1055 * Already mapped?
1056 */
1057 if (pModLX->pvMapping)
1058 return KLDR_ERR_ALREADY_MAPPED;
1059
1060 /*
1061 * Allocate memory for it.
1062 */
1063 /* fixed image? */
1064 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
1065 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1066 if (!fFixed)
1067 pvBase = NULL;
1068 else
1069 {
1070 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
1071 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
1072 return KLDR_ERR_ADDRESS_OVERFLOW;
1073 }
1074 rc = kldrHlpPageAlloc(&pvBase, pModLX->cbMapped, KLDRPROT_EXECUTE_READWRITE, fFixed);
1075 if (rc)
1076 return rc;
1077
1078 /*
1079 * Load the bits, apply page protection, and update the segment table.
1080 */
1081 rc = kldrModLXDoLoadBits(pModLX, pvBase);
1082 if (!rc)
1083 rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
1084 if (!rc)
1085 {
1086 uint32_t i;
1087 for (i = 0; i < pMod->cSegments; i++)
1088 {
1089 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
1090 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
1091 }
1092 pModLX->pvMapping = pvBase;
1093 }
1094 else
1095 kldrHlpPageFree(pvBase, pModLX->cbMapped);
1096 return rc;
1097}
1098
1099
1100/**
1101 * Loads the LX pages into the specified memory mapping.
1102 *
1103 * @returns 0 on success.
1104 * @returns non-zero kLdr or OS status code on failure.
1105 *
1106 * @param pModLX The LX module interpreter instance.
1107 * @param pvBits Where to load the bits.
1108 */
1109static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
1110{
1111 const PKLDRRDR pRdr = pModLX->pMod->pRdr;
1112 uint8_t *pbTmpPage = NULL;
1113 int rc = 0;
1114 uint32_t i;
1115
1116 /*
1117 * Iterate the segments.
1118 */
1119 for (i = 0; i < pModLX->Hdr.e32_objcnt; i++)
1120 {
1121 const struct o32_obj * const pObj = &pModLX->paObjs[i];
1122 const uint32_t cPages = pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN;
1123 uint32_t iPage;
1124 uint8_t *pbPage = (uint8_t *)pvBits + (uintptr_t)pModLX->pMod->aSegments[i].RVA;
1125
1126 /*
1127 * Iterate the page map pages.
1128 */
1129 for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN)
1130 {
1131 const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1];
1132 switch (pMap->o32_pageflags)
1133 {
1134 case VALID:
1135 if (pMap->o32_pagesize == OBJPAGELEN)
1136 rc = kLdrRdrRead(pRdr, pbPage, OBJPAGELEN, pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift);
1137 else if (pMap->o32_pagesize < OBJPAGELEN)
1138 {
1139 rc = kLdrRdrRead(pRdr, pbPage, pMap->o32_pagesize, pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift);
1140 kLdrHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize);
1141 }
1142 else
1143 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1144 break;
1145
1146 case ITERDATA:
1147 case ITERDATA2:
1148 /* make sure we've got a temp page .*/
1149 if (!pbTmpPage)
1150 {
1151 pbTmpPage = kldrHlpAlloc(OBJPAGELEN + 256);
1152 if (!pbTmpPage)
1153 break;
1154 }
1155 /* validate the size. */
1156 if (pMap->o32_pagesize > OBJPAGELEN + 252)
1157 {
1158 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1159 break;
1160 }
1161
1162 /* read it and ensure 4 extra zero bytes. */
1163 rc = kLdrRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize, pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift);
1164 if (rc)
1165 break;
1166 kLdrHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4);
1167
1168 /* unpack it into the image page. */
1169 if (pMap->o32_pageflags == ITERDATA2)
1170 rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1171 else
1172 rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1173 break;
1174
1175 case INVALID: /* we're probably not dealing correctly with INVALID pages... */
1176 case ZEROED:
1177 kLdrHlpMemSet(pbPage, 0, OBJPAGELEN);
1178 break;
1179
1180 case RANGE:
1181 KLDRMODLX_ASSERT(!"RANGE");
1182 default:
1183 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1184 break;
1185 }
1186 }
1187 if (rc)
1188 break;
1189
1190 /*
1191 * Zero the remaining pages.
1192 */
1193 if (iPage < cPages)
1194 kLdrHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN);
1195 }
1196
1197 if (pbTmpPage)
1198 kldrHlpFree(pbTmpPage);
1199 return rc;
1200}
1201
1202
1203/**
1204 * Unpacks iterdata (aka EXEPACK).
1205 *
1206 * @returns 0 on success, non-zero kLdr status code on failure.
1207 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1208 * @param pbSrc The compressed source data.
1209 * @param cbSrc The file size of the compressed data. The source buffer
1210 * contains 4 additional zero bytes.
1211 */
1212static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1213{
1214 const struct LX_Iter *pIter = (const struct LX_Iter *)pbSrc;
1215 int cbDst = OBJPAGELEN;
1216
1217 /* Validate size of data. */
1218 if (cbSrc >= OBJPAGELEN - 2)
1219 return KLDR_ERR_LX_BAD_ITERDATA;
1220
1221 /*
1222 * Expand the page.
1223 */
1224 while (cbSrc > 0 && pIter->LX_nIter)
1225 {
1226 if (pIter->LX_nBytes == 1)
1227 {
1228 /*
1229 * Special case - one databyte.
1230 */
1231 cbDst -= pIter->LX_nIter;
1232 if (cbDst < 0)
1233 return KLDR_ERR_LX_BAD_ITERDATA;
1234
1235 cbSrc -= 4 + 1;
1236 if (cbSrc < -4)
1237 return KLDR_ERR_LX_BAD_ITERDATA;
1238
1239 kLdrHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter);
1240 pbDst += pIter->LX_nIter;
1241 pIter++;
1242 }
1243 else
1244 {
1245 /*
1246 * General.
1247 */
1248 int i;
1249
1250 cbDst -= pIter->LX_nIter * pIter->LX_nBytes;
1251 if (cbDst < 0)
1252 return KLDR_ERR_LX_BAD_ITERDATA;
1253
1254 cbSrc -= 4 + pIter->LX_nBytes;
1255 if (cbSrc < -4)
1256 return KLDR_ERR_LX_BAD_ITERDATA;
1257
1258 for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes)
1259 kLdrHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes);
1260 pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
1261 }
1262 }
1263
1264 /*
1265 * Zero remainder of the page.
1266 */
1267 if (cbDst > 0)
1268 kLdrHlpMemSet(pbDst, 0, cbDst);
1269
1270 return 0;
1271}
1272
1273
1274/**
1275 * Unpacks iterdata (aka EXEPACK).
1276 *
1277 * @returns 0 on success, non-zero kLdr status code on failure.
1278 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1279 * @param pbSrc The compressed source data.
1280 * @param cbSrc The file size of the compressed data. The source buffer
1281 * contains 4 additional zero bytes.
1282 */
1283static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1284{
1285 int cbDst = OBJPAGELEN;
1286
1287 while (cbSrc > 0)
1288 {
1289 /*
1290 * Bit 0 and 1 is the encoding type.
1291 */
1292 switch (*pbSrc & 0x03)
1293 {
1294 /*
1295 *
1296 * 0 1 2 3 4 5 6 7
1297 * type | |
1298 * ----------------
1299 * cb <cb bytes of data>
1300 *
1301 * Bits 2-7 is, if not zero, the length of an uncompressed run
1302 * starting at the following byte.
1303 *
1304 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1305 * type | | | | | |
1306 * ---------------- ---------------------- -----------------------
1307 * zero cb char to multiply
1308 *
1309 * If the bits are zero, the following two bytes describes a 1 byte interation
1310 * run. First byte is count, second is the byte to copy. A count of zero is
1311 * means end of data, and we simply stops. In that case the rest of the data
1312 * should be zero.
1313 */
1314 case 0:
1315 {
1316 if (*pbSrc)
1317 {
1318 const int cb = *pbSrc >> 2;
1319 cbDst -= cb;
1320 if (cbDst < 0)
1321 return KLDR_ERR_LX_BAD_ITERDATA2;
1322 cbSrc -= cb;
1323 if (cbSrc < 0)
1324 return KLDR_ERR_LX_BAD_ITERDATA2;
1325 kLdrHlpMemCopy(pbDst, ++pbSrc, cb);
1326 pbDst += cb;
1327 pbSrc += cb;
1328 }
1329 else if (cbSrc < 2)
1330 return KLDR_ERR_LX_BAD_ITERDATA2;
1331 else
1332 {
1333 const int cb = pbSrc[1];
1334 if (!cb)
1335 goto l_endloop;
1336 cbDst -= cb;
1337 if (cbDst < 0)
1338 return KLDR_ERR_LX_BAD_ITERDATA2;
1339 cbSrc -= 3;
1340 if (cbSrc < 0)
1341 return KLDR_ERR_LX_BAD_ITERDATA2;
1342 kLdrHlpMemSet(pbDst, pbSrc[2], cb);
1343 pbDst += cb;
1344 pbSrc += 3;
1345 }
1346 break;
1347 }
1348
1349
1350 /*
1351 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1352 * type | | | | | |
1353 * ---- ------- -------------------------
1354 * cb1 cb2 - 3 offset <cb1 bytes of data>
1355 *
1356 * Two bytes layed out as described above, followed by cb1 bytes of data to be copied.
1357 * The cb2(+3) and offset describes an amount of data to be copied from the expanded
1358 * data relative to the current position. The data copied as you would expect it to be.
1359 */
1360 case 1:
1361 {
1362 cbSrc -= 2;
1363 if (cbSrc < 0)
1364 return KLDR_ERR_LX_BAD_ITERDATA2;
1365 else
1366 {
1367 const unsigned off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7);
1368 const int cb1 = (*pbSrc >> 2) & 3;
1369 const int cb2 = ((*pbSrc >> 4) & 7) + 3;
1370
1371 pbSrc += 2;
1372 cbSrc -= cb1;
1373 if (cbSrc < 0)
1374 return KLDR_ERR_LX_BAD_ITERDATA2;
1375 cbDst -= cb1;
1376 if (cbDst < 0)
1377 return KLDR_ERR_LX_BAD_ITERDATA2;
1378 kLdrHlpMemCopy(pbDst, pbSrc, cb1);
1379 pbDst += cb1;
1380
1381 if (off > OBJPAGELEN - cbDst)
1382 return KLDR_ERR_LX_BAD_ITERDATA2;
1383 cbDst -= cb2;
1384 if (cbDst < 0)
1385 return KLDR_ERR_LX_BAD_ITERDATA2;
1386 kLdrHlpMemMove(pbDst, pbDst - off, cb2);
1387 pbDst += cb2;
1388 }
1389 break;
1390 }
1391
1392
1393 /*
1394 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1395 * type | | | |
1396 * ---- ----------------------------------
1397 * cb-3 offset
1398 *
1399 * Two bytes layed out as described above.
1400 * The cb(+3) and offset describes an amount of data to be copied from the expanded
1401 * data relative to the current position.
1402 *
1403 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1404 */
1405 case 2:
1406 {
1407 cbSrc -= 2;
1408 if (cbSrc < 0)
1409 return KLDR_ERR_LX_BAD_ITERDATA2;
1410 else
1411 {
1412 const unsigned off = ((unsigned)pbSrc[2] << 4) | (*pbSrc >> 4);
1413 const int cb = ((*pbSrc >> 2) & 3) + 3;
1414
1415 pbSrc += 2;
1416 if (off > OBJPAGELEN - cbDst)
1417 return KLDR_ERR_LX_BAD_ITERDATA2;
1418 cbDst -= cb;
1419 if (cbDst < 0)
1420 return KLDR_ERR_LX_BAD_ITERDATA2;
1421 kLdrModLXMemCopyW(pbDst, pbDst - off, cb);
1422 pbDst += cb;
1423 }
1424 break;
1425 }
1426
1427
1428 /*
1429 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1430 * type | | | | | |
1431 * ---------- ---------------- ----------------------------------
1432 * cb1 cb2 offset <cb1 bytes of data>
1433 *
1434 * Three bytes layed out as described above, followed by cb1 bytes of data to be copied.
1435 * The cb2 and offset describes an amount of data to be copied from the expanded
1436 * data relative to the current position.
1437 *
1438 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1439 */
1440 case 3:
1441 {
1442 cbSrc -= 3;
1443 if (cbSrc < 0)
1444 return KLDR_ERR_LX_BAD_ITERDATA2;
1445 else
1446 {
1447 const int cb1 = (*pbSrc >> 2) & 0xf;
1448 const int cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6);
1449 const unsigned off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4);
1450
1451 pbSrc += 3;
1452 cbSrc -= cb1;
1453 if (cbSrc < 0)
1454 return KLDR_ERR_LX_BAD_ITERDATA2;
1455 cbDst -= cb1;
1456 if (cbDst < 0)
1457 return KLDR_ERR_LX_BAD_ITERDATA2;
1458 kLdrHlpMemCopy(pbDst, pbSrc, cb1);
1459 pbDst += cb1;
1460
1461 if (off > OBJPAGELEN - cbDst)
1462 return KLDR_ERR_LX_BAD_ITERDATA2;
1463 cbDst -= cb2;
1464 if (cbDst < 0)
1465 return KLDR_ERR_LX_BAD_ITERDATA2;
1466 kLdrModLXMemCopyW(pbDst, pbDst - off, cb2);
1467 pbDst += cb2;
1468 }
1469 break;
1470 }
1471 } /* type switch. */
1472 } /* unpack loop */
1473
1474l_endloop:
1475
1476
1477 /*
1478 * Zero remainder of the page.
1479 */
1480 if (cbDst > 0)
1481 kLdrHlpMemSet(pbDst, 0, cbDst);
1482
1483 return 0;
1484}
1485
1486
1487/**
1488 * Special memcpy employed by the iterdata2 algorithm.
1489 *
1490 * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this
1491 * has if src is very close to the destination.
1492 *
1493 * @param pbDst Destination pointer.
1494 * @param pbSrc Source pointer. Will always be <= pbDst.
1495 * @param cb Amount of data to be copied.
1496 * @remark This assumes that unaligned word and dword access is fine.
1497 */
1498static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb)
1499{
1500 switch (pbDst - pbSrc)
1501 {
1502 case 0:
1503 case 1:
1504 case 2:
1505 case 3:
1506 /* 16-bit copy (unaligned) */
1507 if (cb & 1)
1508 *pbDst++ = *pbSrc++;
1509 for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2)
1510 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
1511 break;
1512
1513 default:
1514 /* 32-bit copy (unaligned) */
1515 if (cb & 1)
1516 *pbDst++ = *pbSrc++;
1517 if (cb & 2)
1518 {
1519 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
1520 pbDst += 2;
1521 pbSrc += 2;
1522 }
1523 for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4)
1524 *(uint32_t *)pbDst = *(const uint32_t *)pbSrc;
1525 break;
1526 }
1527}
1528
1529
1530/**
1531 * Unprotects or protects the specified image mapping.
1532 *
1533 * @returns 0 on success.
1534 * @returns non-zero kLdr or OS status code on failure.
1535 *
1536 * @param pModLX The LX module interpreter instance.
1537 * @param pvBits The mapping to protect.
1538 * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise
1539 * protect according to the object table.
1540 */
1541static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect)
1542{
1543 uint32_t i;
1544 PKLDRMOD pMod = pModLX->pMod;
1545
1546 /*
1547 * Change object protection.
1548 */
1549 for (i = 0; i < pMod->cSegments; i++)
1550 {
1551 int rc;
1552 void *pv;
1553 KLDRPROT enmProt;
1554
1555 /* calc new protection. */
1556 enmProt = pMod->aSegments[i].enmProt;
1557 if (fUnprotectOrProtect)
1558 {
1559 switch (enmProt)
1560 {
1561 case KLDRPROT_NOACCESS:
1562 case KLDRPROT_READONLY:
1563 case KLDRPROT_READWRITE:
1564 case KLDRPROT_WRITECOPY:
1565 enmProt = KLDRPROT_READWRITE;
1566 break;
1567 case KLDRPROT_EXECUTE:
1568 case KLDRPROT_EXECUTE_READ:
1569 case KLDRPROT_EXECUTE_READWRITE:
1570 case KLDRPROT_EXECUTE_WRITECOPY:
1571 enmProt = KLDRPROT_EXECUTE_READWRITE;
1572 break;
1573 default:
1574 KLDRMODLX_ASSERT(!"bad enmProt");
1575 return -1;
1576 }
1577 }
1578 else
1579 {
1580 /* copy on write -> normal write. */
1581 if (enmProt == KLDRPROT_EXECUTE_WRITECOPY)
1582 enmProt = KLDRPROT_EXECUTE_READWRITE;
1583 else if (enmProt == KLDRPROT_WRITECOPY)
1584 enmProt = KLDRPROT_READWRITE;
1585 }
1586
1587
1588 /* calc the address and set page protection. */
1589 pv = (uint8_t *)pvBits + pMod->aSegments[i].RVA;
1590
1591 rc = kldrHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt);
1592 if (rc)
1593 break;
1594
1595 /** @todo the gap page should be marked NOACCESS! */
1596 }
1597
1598 return 0;
1599}
1600
1601
1602/** @copydoc kLdrModUnmap */
1603static int kldrModLXUnmap(PKLDRMOD pMod)
1604{
1605 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1606 uint32_t i;
1607 int rc;
1608
1609 /*
1610 * Mapped?
1611 */
1612 if (!pModLX->pvMapping)
1613 return KLDR_ERR_NOT_MAPPED;
1614
1615 /*
1616 * Free the mapping and update the segments.
1617 */
1618 rc = kldrHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
1619 KLDRMODLX_ASSERT(!rc);
1620 pModLX->pvMapping = NULL;
1621
1622 for (i = 0; i < pMod->cSegments; i++)
1623 pMod->aSegments[i].MapAddress = 0;
1624
1625 return rc;
1626}
1627
1628
1629/** @copydoc kLdrModAllocTLS */
1630static int kldrModLXAllocTLS(PKLDRMOD pMod)
1631{
1632 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1633
1634 /* no tls, just do the error checking. */
1635 if (!pModLX->pvMapping)
1636 return KLDR_ERR_NOT_MAPPED;
1637 return 0;
1638}
1639
1640
1641/** @copydoc kLdrModFreeTLS */
1642static void kldrModLXFreeTLS(PKLDRMOD pMod)
1643{
1644 /* no tls. */
1645}
1646
1647
1648/** @copydoc kLdrModReload */
1649static int kldrModLXReload(PKLDRMOD pMod)
1650{
1651 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1652
1653 /*
1654 * Mapped?
1655 */
1656 if (!pModLX->pvMapping)
1657 return KLDR_ERR_NOT_MAPPED;
1658
1659 /* the file provider does it all */
1660 return kLdrRdrRefresh(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments);
1661}
1662
1663
1664/** @copydoc kLdrModFixupMapping */
1665static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1666{
1667 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1668 int rc, rc2;
1669
1670 /*
1671 * Mapped?
1672 */
1673 if (!pModLX->pvMapping)
1674 return KLDR_ERR_NOT_MAPPED;
1675
1676 /*
1677 * Before doing anything we'll have to make all pages writable.
1678 */
1679 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
1680 if (rc)
1681 return rc;
1682
1683 /*
1684 * Apply fixups and resolve imports.
1685 */
1686 rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (uintptr_t)pModLX->pvMapping,
1687 pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
1688
1689 /*
1690 * Restore protection.
1691 */
1692 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
1693 if (!rc && rc2)
1694 rc = rc2;
1695 return rc;
1696}
1697
1698
1699/** @copydoc kLdrModCallInit */
1700static int kldrModLXCallInit(PKLDRMOD pMod, uintptr_t uHandle)
1701{
1702 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1703 int rc;
1704
1705 /*
1706 * Mapped?
1707 */
1708 if (!pModLX->pvMapping)
1709 return KLDR_ERR_NOT_MAPPED;
1710
1711 /*
1712 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1713 */
1714 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
1715 rc = kldrModLXDoCallDLL(pModLX, 0 /* attach */, uHandle);
1716 else
1717 rc = 0;
1718 return rc;
1719}
1720
1721
1722/**
1723 * Call the DLL entrypoint.
1724 *
1725 * @returns 0 on success.
1726 * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
1727 * @param pModLX The LX module interpreter instance.
1728 * @param uOp The operation (DLL_*).
1729 * @param uHandle The module handle to present.
1730 */
1731static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle)
1732{
1733 int rc;
1734
1735 /*
1736 * If no entrypoint there isn't anything to be done.
1737 */
1738 if ( !pModLX->Hdr.e32_startobj
1739 || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
1740 return 0;
1741
1742 /*
1743 * Invoke the entrypoint and convert the boolean result to a kLdr status code.
1744 */
1745 rc = kldrModLXDoCall((uintptr_t)pModLX->pvMapping
1746 + (uintptr_t)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
1747 + pModLX->Hdr.e32_eip,
1748 uHandle, uOp, NULL);
1749 if (rc)
1750 rc = 0;
1751 else if (uOp == 0 /* attach */)
1752 rc = KLDR_ERR_MODULE_INIT_FAILED;
1753 else /* detach: ignore failures */
1754 rc = 0;
1755 return rc;
1756}
1757
1758
1759/**
1760 * Do a 3 parameter callback.
1761 *
1762 * @returns 32-bit callback return.
1763 * @param uEntrypoint The address of the function to be called.
1764 * @param uHandle The first argument, the module handle.
1765 * @param uOp The second argumnet, the reason we're calling.
1766 * @param pvReserved The third argument, reserved argument. (figure this one out)
1767 */
1768static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved)
1769{
1770#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
1771 int32_t rc;
1772/** @todo try/except */
1773
1774 /*
1775 * Paranoia.
1776 */
1777# ifdef __GNUC__
1778 __asm__ __volatile__(
1779 "pushl %2\n\t"
1780 "pushl %1\n\t"
1781 "pushl %0\n\t"
1782 "lea 12(%%esp), %2\n\t"
1783 "call *%3\n\t"
1784 "movl %2, %%esp\n\t"
1785 : "=a" (rc)
1786 : "d" (uOp),
1787 "S" (0),
1788 "c" (uEntrypoint),
1789 "0" (uHandle));
1790# elif defined(_MSC_VER)
1791 __asm {
1792 mov eax, [uHandle]
1793 mov edx, [uOp]
1794 mov ecx, 0
1795 mov ebx, [uEntrypoint]
1796 push edi
1797 mov edi, esp
1798 push ecx
1799 push edx
1800 push eax
1801 call ebx
1802 mov esp, edi
1803 pop edi
1804 mov [rc], eax
1805 }
1806# else
1807# error "port me!"
1808# endif
1809 return rc;
1810
1811#else
1812 return KLDR_ERR_ARCH_CPU_NOT_COMPATIBLE;
1813#endif
1814}
1815
1816
1817/** @copydoc kLdrModCallTerm */
1818static int kldrModLXCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
1819{
1820 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1821
1822 /*
1823 * Mapped?
1824 */
1825 if (!pModLX->pvMapping)
1826 return KLDR_ERR_NOT_MAPPED;
1827
1828 /*
1829 * Do the call.
1830 */
1831 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
1832 kldrModLXDoCallDLL(pModLX, 1 /* detach */, uHandle);
1833
1834 return 0;
1835}
1836
1837
1838/** @copydoc kLdrModCallThread */
1839static int kldrModLXCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
1840{
1841 /* no thread attach/detach callout. */
1842 return 0;
1843}
1844
1845
1846/** @copydoc kLdrModSize */
1847static KLDRADDR kldrModLXSize(PKLDRMOD pMod)
1848{
1849 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1850 return pModLX->cbMapped;
1851}
1852
1853
1854/** @copydoc kLdrModGetBits */
1855static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1856{
1857 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1858 int rc;
1859
1860 /*
1861 * Load the image bits.
1862 */
1863 rc = kldrModLXDoLoadBits(pModLX, pvBits);
1864 if (rc)
1865 return rc;
1866
1867 /*
1868 * Perform relocations.
1869 */
1870 return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
1871
1872}
1873
1874
1875/** @copydoc kLdrModRelocateBits */
1876static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
1877 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1878{
1879 /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1880 int rc;*/
1881
1882 /** @todo Implement this. */
1883
1884 return -1;
1885}
1886
1887
1888/**
1889 * The LX module interpreter method table.
1890 */
1891KLDRMODOPS g_kLdrModLXOps =
1892{
1893 "LX",
1894 NULL,
1895 kldrModLXCreate,
1896 kldrModLXDestroy,
1897 kldrModLXQuerySymbol,
1898 kldrModLXEnumSymbols,
1899 kldrModLXGetImport,
1900 kldrModLXNumberOfImports,
1901 NULL /* can execute one is optional */,
1902 kldrModLXGetStackInfo,
1903 kldrModLXQueryMainEntrypoint,
1904 kldrModLXEnumDbgInfo,
1905 kldrModLXHasDbgInfo,
1906 kldrModLXMap,
1907 kldrModLXUnmap,
1908 kldrModLXAllocTLS,
1909 kldrModLXFreeTLS,
1910 kldrModLXReload,
1911 kldrModLXFixupMapping,
1912 kldrModLXCallInit,
1913 kldrModLXCallTerm,
1914 kldrModLXCallThread,
1915 kldrModLXSize,
1916 kldrModLXGetBits,
1917 kldrModLXRelocateBits,
1918 42 /* the end */
1919};
1920
Note: See TracBrowser for help on using the repository browser.