source: trunk/kLdr/kLdrModLX.c@ 2883

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

cleanup.

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