source: trunk/kLdr/kLdrModLX.c@ 2879

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

started coding on the LX module interpreter.

  • Property svn:keywords set to Id
File size: 33.7 KB
Line 
1/* $Id: kLdrModLX.c 2879 2006-11-12 17:21:16Z 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 int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
120static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
121static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle);
122static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
123
124
125/**
126 * Create a loader module instance interpreting the executable image found
127 * in the specified file provider instance.
128 *
129 * @returns 0 on success and *ppMod pointing to a module instance.
130 * On failure, a non-zero OS specific error code is returned.
131 * @param pOps Pointer to the registered method table.
132 * @param pRdr The file provider instance to use.
133 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
134 * @param ppMod Where to store the module instance pointer.
135 */
136static int kldrModLXCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
137{
138 PKLDRMODLX pModLX;
139 int rc;
140
141 /*
142 * Create the instance data and do a minimal header validation.
143 */
144 rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX);
145 if (!rc)
146 {
147 pModLX->pMod->pOps = pOps;
148 pModLX->pMod->u32Magic = KLDRMOD_MAGIC;
149 *ppMod = pModLX->pMod;
150 return 0;
151 }
152 kldrHlpFree(pModLX);
153 return rc;
154}
155
156
157/**
158 * Separate function for reading creating the LX module instance to
159 * simplify cleanup on failure.
160 */
161static int kldrModLXDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODLX *ppModLX)
162{
163 struct e32_exe Hdr;
164 PKLDRMODLX pModLX;
165 PKLDRMOD pMod;
166 size_t cb;
167 size_t cchFilename;
168 uint32_t off, offEnd;
169 uint32_t i;
170 int rc;
171 *ppModLX = NULL;
172
173 /*
174 * Read the signature and file header.
175 */
176 rc = kLdrRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
177 if (rc)
178 return rc;
179 if (Hdr.e32_magic[0] != E32MAGIC1 || Hdr.e32_magic[0] != E32MAGIC2)
180 return KLDR_ERR_UNKNOWN_FORMAT;
181
182 /* We're not interested in anything but x86 images. */
183 if ( Hdr.e32_level != E32LEVEL
184 || Hdr.e32_border != E32LEBO
185 || Hdr.e32_worder != E32LEWO
186 || Hdr.e32_cpu < E32CPU286
187 || Hdr.e32_cpu > E32CPU486
188 || Hdr.e32_pagesize != OBJPAGELEN
189 )
190 return KLDR_ERR_LX_BAD_HEADER;
191
192 /* Some rough sanity checks. */
193 offEnd = kLdrRdrSize(pRdr) >= (off_t)~(uint32_t)16 ? ~(uint32_t)16 : (uint32_t)kLdrRdrSize(pRdr);
194 if ( Hdr.e32_itermap > offEnd
195 || Hdr.e32_datapage > offEnd
196 || Hdr.e32_nrestab > offEnd
197 || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
198 || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
199 || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
200 || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
201 return KLDR_ERR_LX_BAD_HEADER;
202
203 /* Verify the loader section. */
204 offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
205 if (Hdr.e32_objtab < sizeof(Hdr))
206 return KLDR_ERR_LX_BAD_LOADER_SECTION;
207 off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
208 if (off > offEnd)
209 return KLDR_ERR_LX_BAD_LOADER_SECTION;
210 if ( Hdr.e32_objmap
211 && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
212 return KLDR_ERR_LX_BAD_LOADER_SECTION;
213 if ( Hdr.e32_rsrccnt
214 && ( Hdr.e32_rsrctab < off
215 || Hdr.e32_rsrctab > offEnd
216 || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
217 return KLDR_ERR_LX_BAD_LOADER_SECTION;
218 if ( Hdr.e32_restab
219 && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
220 return KLDR_ERR_LX_BAD_LOADER_SECTION;
221 if ( Hdr.e32_enttab
222 && (Hdr.e32_enttab < off || Hdr.e32_enttab > offEnd - 2))
223 return KLDR_ERR_LX_BAD_LOADER_SECTION;
224 if ( Hdr.e32_dircnt
225 && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd))
226 return KLDR_ERR_LX_BAD_LOADER_SECTION;
227
228 /* Verify the fixup section. */
229 off = offEnd;
230 offEnd = off + Hdr.e32_fixupsize;
231 if ( Hdr.e32_fpagetab
232 && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
233 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
234 if ( Hdr.e32_frectab
235 && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
236 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
237 if ( Hdr.e32_impmod
238 && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
239 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
240 if ( Hdr.e32_impproc
241 && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
242 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
243
244 /*
245 * Calc the instance size, allocate and initialize it.
246 */
247 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
248 cb = KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8)
249 + KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8)
250 + KLDR_ALIGN_Z(cchFilename + 1, 8),
251 + Hdr.e32_ldrsize;
252 pModLX = (PKLDRMODLX)kldrHlpAlloc(cb);
253 if (!pModLX)
254 return KLDR_ERR_NO_MEMORY;
255 *ppModLX = pModLX;
256
257 /* KLDRMOD */
258 pMod = (PKLDRMOD)((uint8_t *)pModLX + KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8));
259 pMod->pvData = pModLX;
260 pMod->pRdr = pRdr;
261 pMod->pOps = NULL; /* set upon success. */
262 pMod->cSegments = Hdr.e32_objcnt;
263 pMod->cchFilename = cchFilename;
264 pMod->pszFilename = (char *)KLDR_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8);
265 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
266 pMod->pszName = NULL; /* finalized further down */
267 pMod->cchName = 0;
268 switch (Hdr.e32_cpu)
269 {
270 case E32CPU286:
271 pMod->enmCpu = KLDRCPU_I80286;
272 pMod->enmArch = KLDRARCH_X86_16;
273 break;
274 case E32CPU386:
275 pMod->enmCpu = KLDRCPU_I386;
276 pMod->enmArch = KLDRARCH_X86_32;
277 break;
278 case E32CPU486:
279 pMod->enmCpu = KLDRCPU_I486;
280 pMod->enmArch = KLDRARCH_X86_32;
281 break;
282 }
283 pMod->enmEndian = KLDRENDIAN_LITTLE;
284 pMod->enmFmt = KLDRFMT_LX;
285 switch (Hdr.e32_mflags & E32MODMASK)
286 {
287 case E32MODEXE:
288 pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX)
289 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
290 : KLDRTYPE_EXECUTABLE_FIXED;
291 break;
292
293 case E32MODDLL:
294 case E32PROTDLL:
295 case E32MODPROTDLL:
296 pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL)
297 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
298 : KLDRTYPE_SHARED_LIBRARY_FIXED;
299 break;
300
301 case E32MODPDEV:
302 case E32MODVDEV:
303 pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
304 break;
305 }
306 pMod->u32Magic = 0; /* set upon success. */
307
308 /* KLDRMODLX */
309 pModLX->pMod = pMod;
310 pModLX->pvMapping = 0;
311 pModLX->cbMapped = Hdr.e32_mpages * Hdr.e32_pagesize;
312 pModLX->f32Reserved = 0;
313
314 pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
315 pModLX->Hdr = Hdr;
316
317 pModLX->pbLoaderSection = KLDR_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16);
318 pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize;
319 pModLX->paObjs = NULL;
320 pModLX->paPageMappings = NULL;
321 pModLX->paRsrcs = NULL;
322 pModLX->pbResNameTab = NULL;
323 pModLX->pbEntryTab = NULL;
324
325 pModLX->pbNonResNameTab = NULL;
326 pModLX->pbNonResNameTabLast = NULL;
327
328 pModLX->pbFixupSection = NULL;
329 pModLX->pbFixupSectionLast = NULL;
330 pModLX->paoffPageFixups = NULL;
331 pModLX->pbFixupRecs = NULL;
332 pModLX->pbImportMods = NULL;
333 pModLX->pbImportProcs = NULL;
334
335 /*
336 * Read the loader data.
337 */
338 rc = kLdrRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
339 if (rc)
340 return rc;
341 if (pModLX->Hdr.e32_objcnt)
342 pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
343 if (pModLX->Hdr.e32_objmap)
344 pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
345 if (pModLX->Hdr.e32_rsrccnt)
346 pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
347 if (pModLX->Hdr.e32_restab)
348 pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
349 if (pModLX->Hdr.e32_enttab)
350 pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
351
352 /*
353 * Get the soname from the resident name table.
354 */
355 /** @todo */
356
357 /*
358 * Quick validation of the object table.
359 */
360 cb = 0;
361 for (i = 0; i < pMod->cSegments; i++)
362 {
363 if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
364 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
365 if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
366 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
367 if (pModLX->paObjs[i].o32_mapsize > pModLX->paObjs[i].o32_size / OBJPAGELEN)
368 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
369 if ( pModLX->paObjs[i].o32_mapsize
370 && ( (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
371 || (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
372 > pModLX->pbLoaderSectionLast))
373 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
374 if (i > 0)
375 {
376 if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
377 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
378 if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
379 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
380 }
381 }
382 pModLX->cbMapped = pMod->cSegments
383 ? pModLX->paObjs[pMod->cSegments - 1].o32_base + pModLX->paObjs[pMod->cSegments - 1].o32_size
384 - pModLX->paObjs[pMod->cSegments - 1].o32_size
385 : 0;
386
387 /*
388 * Setup the KLDRMOD segment array.
389 */
390 for (i = 0; i < pMod->cSegments; i++)
391 {
392 /* unused */
393 pMod->aSegments[i].pvUser = NULL;
394 pMod->aSegments[i].MapAddress = 0;
395 pMod->aSegments[i].pchName = NULL;
396 pMod->aSegments[i].cchName = 0;
397 pMod->aSegments[i].offFile = -1;
398 pMod->aSegments[i].cbFile = 0;
399
400 /* size and addresses */
401 pMod->aSegments[i].Alignment = OBJPAGELEN;
402 pMod->aSegments[i].cb = pModLX->paObjs[i].o32_size;
403 pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
404 pMod->aSegments[i].RVA = pModLX->paObjs[i].o32_base - pModLX->paObjs[0].o32_base;
405 pMod->aSegments[i].cbMapped = KLDR_ALIGN_Z(pModLX->paObjs[i].o32_size, 16);
406 if (i + 1 < pMod->cSegments)
407 pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
408
409 /* protection */
410 switch ( pModLX->paObjs[i].o32_flags
411 & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
412 {
413 case 0:
414 case OBJSHARED:
415 pMod->aSegments[i].enmProt = KLDRPROT_NOACCESS;
416 break;
417 case OBJREAD:
418 case OBJREAD | OBJSHARED:
419 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
420 break;
421 case OBJWRITE:
422 case OBJWRITE | OBJREAD:
423 pMod->aSegments[i].enmProt = KLDRPROT_WRITECOPY;
424 break;
425 case OBJWRITE | OBJSHARED:
426 case OBJWRITE | OBJSHARED | OBJREAD:
427 pMod->aSegments[i].enmProt = KLDRPROT_READWRITE;
428 break;
429 case OBJEXEC:
430 case OBJEXEC | OBJSHARED:
431 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE;
432 break;
433 case OBJEXEC | OBJREAD:
434 case OBJEXEC | OBJREAD | OBJSHARED:
435 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READ;
436 break;
437 case OBJEXEC | OBJWRITE:
438 case OBJEXEC | OBJWRITE | OBJREAD:
439 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
440 break;
441 case OBJEXEC | OBJWRITE | OBJSHARED:
442 case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
443 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READWRITE;
444 break;
445 }
446 if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
447 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
448 //pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
449 //pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
450 //pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM)
451 }
452
453 /*
454 * We're done.
455 */
456 *ppModLX = pModLX;
457 return 0;
458}
459
460
461/** @copydoc KLDRMODOPS::pfnDestroy */
462static int kldrModLXDestroy(PKLDRMOD pMod)
463{
464 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
465 int rc = 0;
466 KLDRMODLX_ASSERT(pModLX->pvMapping);
467
468 if (pMod->pRdr)
469 {
470 rc = kLdrRdrClose(pMod->pRdr);
471 pMod->pRdr = NULL;
472 }
473 if (pModLX->pbNonResNameTab)
474 {
475 kldrHlpFree(pModLX->pbNonResNameTab);
476 pModLX->pbNonResNameTab = NULL;
477 }
478 if (pModLX->pbFixupSection)
479 {
480 kldrHlpFree(pModLX->pbFixupSection);
481 pModLX->pbFixupSection = NULL;
482 }
483 if (pMod->pszName)
484 {
485 kldrHlpFree((void *)pMod->pszName);
486 pMod->pszName = NULL;
487 }
488 pMod->u32Magic = 0;
489 pMod->pOps = NULL;
490 kldrHlpFree(pModLX);
491 return rc;
492}
493
494
495/**
496 * Resolved base address aliases.
497 *
498 * @param pModLX The interpreter module instance
499 * @param pBaseAddress The base address, IN & OUT.
500 */
501static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress)
502{
503 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
504 *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress;
505 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
506 *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress;
507}
508
509
510/** @copydoc kLdrModQuerySymbol */
511static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
512 const char *pszSymbol, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser,
513 PKLDRADDR puValue, uint32_t *pfKind)
514{
515 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
516 //int rc;
517
518 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
519
520 return -1;
521}
522
523
524/** @copydoc kLdrModEnumSymbols */
525static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
526 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
527{
528 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
529// int rc;
530
531 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
532
533 return -1;
534}
535
536
537/** @copydoc kLdrModGetImport */
538static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
539{
540 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
541 const uint8_t * pb = NULL;
542 int rc;
543
544 /** @todo */
545
546 if (*pb < cchName)
547 {
548 kLdrHlpMemCopy(pszName, pb + 1, *pb);
549 pszName[*pb] = '\0';
550 rc = 0;
551 }
552 else
553 {
554 kLdrHlpMemCopy(pszName, pb + 1, cchName);
555 if (cchName)
556 pszName[cchName - 1] = '\0';
557 rc = KLDR_ERR_BUFFER_OVERFLOW;
558 }
559
560 return rc;
561}
562
563
564/** @copydoc kLdrModNumberOfImports */
565static int32_t kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits)
566{
567 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
568 return pModLX->Hdr.e32_impmodcnt;
569}
570
571
572/** @copydoc kLdrModGetStackInfo */
573static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
574{
575 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
576 const uint32_t i = pModLX->Hdr.e32_stackobj;
577
578 if ( i
579 && i <= pMod->cSegments
580 && pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb
581 && pModLX->Hdr.e32_stacksize
582 && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress)
583 {
584
585 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
586 pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
587 pStackInfo->Address = BaseAddress
588 + pMod->aSegments[i - 1].RVA
589 + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress;
590 }
591 else
592 {
593 pStackInfo->Address = NIL_KLDRADDR;
594 pStackInfo->LinkAddress = NIL_KLDRADDR;
595 }
596 pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
597 pStackInfo->cbStackThread = 0;
598
599 return 0;
600}
601
602
603/** @copydoc kLdrModQueryMainEntrypoint */
604static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
605{
606 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
607
608 /*
609 * Convert the address from the header.
610 */
611 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
612 *pMainEPAddress = pModLX->Hdr.e32_startobj
613 && pModLX->Hdr.e32_startobj <= pMod->cSegments
614 && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb
615 ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
616 : NIL_KLDRADDR;
617 return 0;
618}
619
620
621/** @copydoc kLdrModEnumDbgInfo */
622static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
623{
624 //PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
625
626 /*
627 * Quit immediately if no debug info.
628 */
629 if (kldrModLXHasDbgInfo(pMod, pvBits))
630 return 0;
631#if 0
632 /*
633 * Read the debug info and look for familiar magics and structures.
634 */
635 /** @todo */
636#endif
637
638 return 0;
639}
640
641
642/** @copydoc kLdrModHasDbgInfo */
643static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
644{
645 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
646
647 /*
648 * Don't curretnly bother with linkers which doesn't advertise it in the header.
649 */
650 if ( !pModLX->Hdr.e32_debuginfo
651 || !pModLX->Hdr.e32_debuglen)
652 return KLDR_ERR_NO_DEBUG_INFO;
653 return 0;
654}
655
656
657/** @copydoc kLdrModMap */
658static int kldrModLXMap(PKLDRMOD pMod)
659{
660 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
661 unsigned fFixed;
662 void *pvBase;
663 int rc;
664
665 /*
666 * Already mapped?
667 */
668 if (pModLX->pvMapping)
669 return KLDR_ERR_ALREADY_MAPPED;
670
671 /*
672 * Allocate memory for it.
673 */
674 /* fixed image? */
675 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
676 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
677 if (!fFixed)
678 pvBase = NULL;
679 else
680 {
681 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
682 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
683 return KLDR_ERR_ADDRESS_OVERFLOW;
684 }
685 rc = kldrHlpPageAlloc(&pvBase, pModLX->cbMapped, KLDRPROT_EXECUTE_READWRITE, fFixed);
686 if (rc)
687 return rc;
688
689 /*
690 * Load the bits, apply page protection, and update the segment table.
691 */
692 rc = kldrModLXDoLoadBits(pModLX, pvBase);
693 if (!rc)
694 rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
695 if (!rc)
696 {
697 uint32_t i;
698 for (i = 0; i < pMod->cSegments; i++)
699 {
700 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
701 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
702 }
703 pModLX->pvMapping = pvBase;
704 }
705 else
706 kldrHlpPageFree(pvBase, pModLX->cbMapped);
707 return rc;
708}
709
710
711/**
712 * Loads the LX pages into the specified memory mapping.
713 *
714 * @returns 0 on success.
715 * @returns non-zero kLdr or OS status code on failure.
716 *
717 * @param pModLX The LX module interpreter instance.
718 * @param pvBits Where to load the bits.
719 */
720static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
721{
722 //E32NOLOAD
723
724 return -1;
725}
726
727
728/**
729 * Unprotects or protects the specified image mapping.
730 *
731 * @returns 0 on success.
732 * @returns non-zero kLdr or OS status code on failure.
733 *
734 * @param pModLX The LX module interpreter instance.
735 * @param pvBits The mapping to protect.
736 * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise
737 * protect according to the object table.
738 */
739static int kldrModLXDoProtect(PKLDRMODLX pMod, void *pvBits, unsigned fUnprotectOrProtect)
740{
741 return -1;
742}
743
744
745/** @copydoc kLdrModUnmap */
746static int kldrModLXUnmap(PKLDRMOD pMod)
747{
748 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
749 uint32_t i;
750 int rc;
751
752 /*
753 * Mapped?
754 */
755 if (!pModLX->pvMapping)
756 return KLDR_ERR_NOT_MAPPED;
757
758 /*
759 * Free the mapping and update the segments.
760 */
761 rc = kldrHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
762 KLDRMODLX_ASSERT(!rc);
763 pModLX->pvMapping = NULL;
764
765 for (i = 0; i < pMod->cSegments; i++)
766 pMod->aSegments[i].MapAddress = 0;
767
768 return rc;
769}
770
771
772/** @copydoc kLdrModAllocTLS */
773static int kldrModLXAllocTLS(PKLDRMOD pMod)
774{
775 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
776
777 /* just do the error checking. */
778 if (!pModLX->pvMapping)
779 return KLDR_ERR_NOT_MAPPED;
780 return 0;
781}
782
783
784/** @copydoc kLdrModFreeTLS */
785static void kldrModLXFreeTLS(PKLDRMOD pMod)
786{
787}
788
789
790/** @copydoc kLdrModReload */
791static int kldrModLXReload(PKLDRMOD pMod)
792{
793 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
794
795 /*
796 * Mapped?
797 */
798 if (!pModLX->pvMapping)
799 return KLDR_ERR_NOT_MAPPED;
800
801 /* the file provider does it all */
802 return kLdrRdrRefresh(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments);
803}
804
805
806/** @copydoc kLdrModFixupMapping */
807static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
808{
809 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
810 int rc, rc2;
811
812 /*
813 * Mapped?
814 */
815 if (!pModLX->pvMapping)
816 return KLDR_ERR_NOT_MAPPED;
817
818 /*
819 * Before doing anything we'll have to make all pages writable.
820 */
821 rc = kLdrRdrProtect(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
822 if (rc)
823 return rc;
824
825 /*
826 * Apply fixups and resolve imports.
827 */
828 rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (uintptr_t)pModLX->pvMapping,
829 pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
830
831 /*
832 * Restore protection.
833 */
834 rc2 = kLdrRdrProtect(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
835 if (!rc && rc2)
836 rc = rc2;
837 return rc;
838}
839
840
841/** @copydoc kLdrModCallInit */
842static int kldrModLXCallInit(PKLDRMOD pMod, uintptr_t uHandle)
843{
844 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
845 int rc;
846
847 /*
848 * Mapped?
849 */
850 if (!pModLX->pvMapping)
851 return KLDR_ERR_NOT_MAPPED;
852
853 /*
854 * Do TLS callbacks first and then call the init/term function if it's a DLL.
855 */
856 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
857 rc = kldrModLXDoCallDLL(pModLX, 0 /* attach */, uHandle);
858 else
859 rc = 0;
860 return rc;
861}
862
863
864/**
865 * Call the DLL entrypoint.
866 *
867 * @returns 0 on success.
868 * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
869 * @param pModLX The LX module interpreter instance.
870 * @param uOp The operation (DLL_*).
871 * @param uHandle The module handle to present.
872 */
873static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle)
874{
875 int rc;
876
877 /*
878 * If no entrypoint there isn't anything to be done.
879 */
880 if ( !pModLX->Hdr.e32_startobj
881 || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
882 return 0;
883
884 /*
885 * Invoke the entrypoint and convert the boolean result to a kLdr status code.
886 */
887 rc = kldrModLXDoCall((uintptr_t)pModLX->pvMapping
888 + (uintptr_t)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
889 + pModLX->Hdr.e32_eip,
890 uHandle, uOp, NULL);
891 if (rc)
892 rc = 0;
893 else if (uOp == 0 /* attach */)
894 rc = KLDR_ERR_MODULE_INIT_FAILED;
895 else /* detach: ignore failures */
896 rc = 0;
897 return rc;
898}
899
900
901/**
902 * Do a 3 parameter callback.
903 *
904 * @returns 32-bit callback return.
905 * @param uEntrypoint The address of the function to be called.
906 * @param uHandle The first argument, the module handle.
907 * @param uOp The second argumnet, the reason we're calling.
908 * @param pvReserved The third argument, reserved argument. (figure this one out)
909 */
910static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved)
911{
912#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
913 int32_t rc;
914/** @todo try/except */
915
916 /*
917 * Paranoia.
918 */
919# ifdef __GNUC__
920 __asm__ __volatile__(
921 "pushl %2\n\t"
922 "pushl %1\n\t"
923 "pushl %0\n\t"
924 "lea 12(%%esp), %2\n\t"
925 "call *%3\n\t"
926 "movl %2, %%esp\n\t"
927 : "=a" (rc)
928 : "d" (uOp),
929 "S" (0),
930 "c" (uEntrypoint),
931 "0" (uHandle));
932# elif defined(_MSC_VER)
933 __asm {
934 mov eax, [uHandle]
935 mov edx, [uOp]
936 mov ecx, 0
937 mov ebx, [uEntrypoint]
938 push edi
939 mov edi, esp
940 push ecx
941 push edx
942 push eax
943 call ebx
944 mov esp, edi
945 pop edi
946 mov [rc], eax
947 }
948# else
949# error "port me!"
950# endif
951 return rc;
952
953#else
954 return KLDR_ERR_ARCH_CPU_NOT_COMPATIBLE;
955#endif
956}
957
958
959/** @copydoc kLdrModCallTerm */
960static int kldrModLXCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
961{
962 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
963
964 /*
965 * Mapped?
966 */
967 if (!pModLX->pvMapping)
968 return KLDR_ERR_NOT_MAPPED;
969
970 /*
971 * Do the call.
972 */
973 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
974 kldrModLXDoCallDLL(pModLX, 1 /* detach */, uHandle);
975
976 return 0;
977}
978
979
980/** @copydoc kLdrModCallThread */
981static int kldrModLXCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
982{
983 return 0;
984}
985
986
987/** @copydoc kLdrModSize */
988static KLDRADDR kldrModLXSize(PKLDRMOD pMod)
989{
990 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
991 return pModLX->cbMapped;
992}
993
994
995/** @copydoc kLdrModGetBits */
996static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
997{
998 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
999 int rc;
1000
1001 /*
1002 * Load the image bits.
1003 */
1004 rc = kldrModLXDoLoadBits(pModLX, pvBits);
1005 if (rc)
1006 return rc;
1007
1008 /*
1009 * Perform relocations.
1010 */
1011 return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
1012
1013}
1014
1015
1016/** @copydoc kLdrModRelocateBits */
1017static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
1018 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1019{
1020 //PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1021 //int rc;
1022
1023 /** @todo Implement this. */
1024
1025 return -1;
1026}
1027
1028
1029/**
1030 * The LX module interpreter method table.
1031 */
1032KLDRMODOPS g_kLdrModLXOps =
1033{
1034 "LX",
1035 NULL,
1036 kldrModLXCreate,
1037 kldrModLXDestroy,
1038 kldrModLXQuerySymbol,
1039 kldrModLXEnumSymbols,
1040 kldrModLXGetImport,
1041 kldrModLXNumberOfImports,
1042 NULL /* can execute one is optional */,
1043 kldrModLXGetStackInfo,
1044 kldrModLXQueryMainEntrypoint,
1045 kldrModLXEnumDbgInfo,
1046 kldrModLXHasDbgInfo,
1047 kldrModLXMap,
1048 kldrModLXUnmap,
1049 kldrModLXAllocTLS,
1050 kldrModLXFreeTLS,
1051 kldrModLXReload,
1052 kldrModLXFixupMapping,
1053 kldrModLXCallInit,
1054 kldrModLXCallTerm,
1055 kldrModLXCallThread,
1056 kldrModLXSize,
1057 kldrModLXGetBits,
1058 kldrModLXRelocateBits,
1059 42 /* the end */
1060};
1061
Note: See TracBrowser for help on using the repository browser.