VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ldr/ldrLX.cpp@ 77121

Last change on this file since 77121 was 77121, checked in by vboxsync, 6 years ago

IPRT: Two more license header cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 106.6 KB
Line 
1/* $Id: ldrLX.cpp 77121 2019-02-01 15:14:32Z vboxsync $ */
2/** @file
3 * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format.
4 */
5
6/*
7 * Copyright (C) 2007-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * --------------------------------------------------------------------
27 *
28 * This code is based on: kLdr/kLdrModLX.c from kStuff r113.
29 *
30 * Copyright (c) 2006-2007 Knut St. Osmundsen <[email protected]>
31 *
32 * Permission is hereby granted, free of charge, to any person
33 * obtaining a copy of this software and associated documentation
34 * files (the "Software"), to deal in the Software without
35 * restriction, including without limitation the rights to use,
36 * copy, modify, merge, publish, distribute, sublicense, and/or sell
37 * copies of the Software, and to permit persons to whom the
38 * Software is furnished to do so, subject to the following
39 * conditions:
40 *
41 * The above copyright notice and this permission notice shall be
42 * included in all copies or substantial portions of the Software.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
45 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
46 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
47 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
48 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
49 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
50 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
51 * OTHER DEALINGS IN THE SOFTWARE.
52 */
53
54
55/*********************************************************************************************************************************
56* Header Files *
57*********************************************************************************************************************************/
58#define LOG_GROUP RTLOGGROUP_LDR
59#include <iprt/ldr.h>
60#include "internal/iprt.h"
61
62#include <iprt/asm.h>
63#include <iprt/assert.h>
64#include <iprt/err.h>
65#include <iprt/log.h>
66#include <iprt/mem.h>
67#include <iprt/string.h>
68
69#include <iprt/formats/lx.h>
70#include <iprt/formats/pecoff.h>
71#include <iprt/formats/codeview.h>
72#include <iprt/formats/elf32.h>
73#include "internal/ldr.h"
74
75
76/*********************************************************************************************************************************
77* Defined Constants And Macros *
78*********************************************************************************************************************************/
79/** @def KLDRMODLX_STRICT
80 * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */
81#define KLDRMODLX_STRICT 1
82
83/** @def KLDRMODLX_ASSERT
84 * Assert that an expression is true when KLDR_STRICT is defined.
85 */
86#ifdef KLDRMODLX_STRICT
87# define KLDRMODLX_ASSERT(expr) Assert(expr)
88#else
89# define KLDRMODLX_ASSERT(expr) do {} while (0)
90#endif
91
92
93/*********************************************************************************************************************************
94* Structures and Typedefs *
95*********************************************************************************************************************************/
96/**
97 * Instance data for the LX module interpreter.
98 */
99typedef struct KLDRMODLX
100{
101 /** Core module structure. */
102 RTLDRMODINTERNAL Core;
103
104 /** Pointer to the user mapping. */
105 const void *pvMapping;
106 /** The size of the mapped LX image. */
107 size_t cbMapped;
108 /** Reserved flags. */
109 uint32_t f32Reserved;
110
111 /** The offset of the LX header. */
112 RTFOFF offHdr;
113 /** Copy of the LX header. */
114 struct e32_exe Hdr;
115
116 /** Pointer to the loader section.
117 * Allocated together with this strcture. */
118 const uint8_t *pbLoaderSection;
119 /** Pointer to the last byte in the loader section. */
120 const uint8_t *pbLoaderSectionLast;
121 /** Pointer to the object table in the loader section. */
122 const struct o32_obj *paObjs;
123 /** Pointer to the object page map table in the loader section. */
124 const struct o32_map *paPageMappings;
125 /** Pointer to the resource table in the loader section. */
126 const struct rsrc32 *paRsrcs;
127 /** Pointer to the resident name table in the loader section. */
128 const uint8_t *pbResNameTab;
129 /** Pointer to the entry table in the loader section. */
130 const uint8_t *pbEntryTab;
131
132 /** Pointer to the non-resident name table. */
133 uint8_t *pbNonResNameTab;
134 /** Pointer to the last byte in the non-resident name table. */
135 const uint8_t *pbNonResNameTabLast;
136
137 /** Pointer to the fixup section. */
138 uint8_t *pbFixupSection;
139 /** Pointer to the last byte in the fixup section. */
140 const uint8_t *pbFixupSectionLast;
141 /** Pointer to the fixup page table within pvFixupSection. */
142 const uint32_t *paoffPageFixups;
143 /** Pointer to the fixup record table within pvFixupSection. */
144 const uint8_t *pbFixupRecs;
145 /** Pointer to the import module name table within pvFixupSection. */
146 const uint8_t *pbImportMods;
147 /** Pointer to the import module name table within pvFixupSection. */
148 const uint8_t *pbImportProcs;
149
150 /** Pointer to the module name (in the resident name table). */
151 const char *pszName;
152 /** The name length. */
153 size_t cchName;
154
155 /** The target CPU. */
156 RTLDRCPU enmCpu;
157 /** Number of segments in aSegments. */
158 uint32_t cSegments;
159 /** Segment info. */
160 RTLDRSEG aSegments[RT_FLEXIBLE_ARRAY];
161} KLDRMODLX, *PKLDRMODLX;
162
163
164/*********************************************************************************************************************************
165* Internal Functions *
166*********************************************************************************************************************************/
167static int kldrModLXHasDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits);
168static DECLCALLBACK(int) rtldrLX_RelocateBits(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress,
169 RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser);
170static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, ssize_t cbNameTable, uint32_t iOrdinal);
171static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, size_t cchSymbol, uint32_t *piSymbol);
172static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, ssize_t cbNameTable,
173 const char *pchSymbol, size_t cchSymbol);
174static int kldrModLXGetImport(PKLDRMODLX pThis, const void *pvBits, uint32_t iImport,
175 char *pszName, size_t cchName, size_t *pcbNeeded);
176static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
177static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
178static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
179static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb);
180static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
181 PFNRTLDRIMPORT pfnGetForwarder, void *pvUser, PRTLDRADDR puValue, uint32_t *pfKind);
182#if 0
183static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
184static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, uintptr_t uHandle);
185static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
186#endif
187static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX);
188static int kldrModLXDoReloc(uint8_t *pbPage, int off, RTLDRADDR PageAddress, const struct r32_rlc *prlc,
189 int iSelector, RTLDRADDR uValue, uint32_t fKind);
190
191
192/**
193 * Separate function for reading creating the LX module instance to
194 * simplify cleanup on failure.
195 */
196static int kldrModLXDoCreate(PRTLDRREADER pRdr, RTFOFF offNewHdr, uint32_t fFlags, PKLDRMODLX *ppModLX, PRTERRINFO pErrInfo)
197{
198 struct e32_exe Hdr;
199 PKLDRMODLX pModLX;
200 uint32_t off, offEnd;
201 uint32_t i;
202 int fCanOptimizeMapping;
203 uint32_t NextRVA;
204
205 RT_NOREF(fFlags);
206 *ppModLX = NULL;
207
208 /*
209 * Read the signature and file header.
210 */
211 int rc = pRdr->pfnRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
212 if (RT_FAILURE(rc))
213 return RTErrInfoSetF(pErrInfo, rc, "Error reading LX header at %RTfoff: %Rrc", offNewHdr, rc);
214 if ( Hdr.e32_magic[0] != E32MAGIC1
215 || Hdr.e32_magic[1] != E32MAGIC2)
216 return RTErrInfoSetF(pErrInfo, VERR_INVALID_EXE_SIGNATURE, "Not LX magic: %02x %02x", Hdr.e32_magic[0], Hdr.e32_magic[1]);
217
218 /* We're not interested in anything but x86 images. */
219 if ( Hdr.e32_level != E32LEVEL
220 || Hdr.e32_border != E32LEBO
221 || Hdr.e32_worder != E32LEWO
222 || Hdr.e32_cpu < E32CPU286
223 || Hdr.e32_cpu > E32CPU486
224 || Hdr.e32_pagesize != OBJPAGELEN
225 )
226 return VERR_LDRLX_BAD_HEADER;
227
228 /* Some rough sanity checks. */
229 offEnd = pRdr->pfnSize(pRdr) >= (RTFOFF)~(uint32_t)16 ? ~(uint32_t)16 : (uint32_t)pRdr->pfnSize(pRdr);
230 if ( Hdr.e32_itermap > offEnd
231 || Hdr.e32_datapage > offEnd
232 || Hdr.e32_nrestab > offEnd
233 || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
234 || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
235 || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
236 || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
237 return VERR_LDRLX_BAD_HEADER;
238
239 /* Verify the loader section. */
240 offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
241 if (Hdr.e32_objtab < sizeof(Hdr) && Hdr.e32_objcnt)
242 return RTErrInfoSetF(pErrInfo, VERR_LDRLX_BAD_LOADER_SECTION,
243 "Object table is inside the header: %#x", Hdr.e32_objtab);
244 off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
245 if (off > offEnd)
246 return RTErrInfoSetF(pErrInfo, VERR_LDRLX_BAD_LOADER_SECTION,
247 "Object table spans beyond the executable: e32_objcnt=%u", Hdr.e32_objcnt);
248 if (Hdr.e32_objcnt >= _32K)
249 return RTErrInfoSetF(pErrInfo, VERR_LDRLX_BAD_LOADER_SECTION, "Too many segments: %#x\n", Hdr.e32_objcnt);
250 if ( Hdr.e32_objmap
251 && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
252 return RTErrInfoSetF(pErrInfo, VERR_LDRLX_BAD_LOADER_SECTION,
253 "Bad object page map table offset: %#x", Hdr.e32_objmap);
254 if ( Hdr.e32_rsrccnt
255 && ( Hdr.e32_rsrctab < off
256 || Hdr.e32_rsrctab > offEnd
257 || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
258 return RTErrInfoSetF(pErrInfo, VERR_LDRLX_BAD_LOADER_SECTION,
259 "Resource table is out of bounds: %#x entries at %#x", Hdr.e32_rsrccnt, Hdr.e32_rsrctab);
260 if ( Hdr.e32_restab
261 && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
262 return VERR_LDRLX_BAD_LOADER_SECTION;
263 if ( Hdr.e32_enttab
264 && (Hdr.e32_enttab < off || Hdr.e32_enttab >= offEnd))
265 return VERR_LDRLX_BAD_LOADER_SECTION;
266 if ( Hdr.e32_dircnt
267 && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd - 2))
268 return VERR_LDRLX_BAD_LOADER_SECTION;
269
270 /* Verify the fixup section. */
271 off = offEnd;
272 offEnd = off + Hdr.e32_fixupsize;
273 if ( Hdr.e32_fpagetab
274 && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
275 {
276 /*
277 * wlink mixes the fixup section and the loader section.
278 */
279 off = Hdr.e32_fpagetab;
280 offEnd = off + Hdr.e32_fixupsize;
281 Hdr.e32_ldrsize = off - Hdr.e32_objtab;
282 }
283 if ( Hdr.e32_frectab
284 && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
285 return VERR_LDRLX_BAD_FIXUP_SECTION;
286 if ( Hdr.e32_impmod
287 && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
288 return VERR_LDRLX_BAD_FIXUP_SECTION;
289 if ( Hdr.e32_impproc
290 && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
291 return VERR_LDRLX_BAD_FIXUP_SECTION;
292
293 /*
294 * Calc the instance size, allocate and initialize it.
295 */
296 size_t cbModLXAndSegments = RT_ALIGN_Z(RT_UOFFSETOF_DYN(KLDRMODLX, aSegments[Hdr.e32_objcnt + 1]), 8);
297 cbModLXAndSegments += sizeof("segXXXXX") * (Hdr.e32_objcnt + 1);
298
299 pModLX = (PKLDRMODLX)RTMemAlloc(cbModLXAndSegments + Hdr.e32_ldrsize + 2 /*for two extra zeros*/);
300 if (!pModLX)
301 return VERR_NO_MEMORY;
302 *ppModLX = pModLX;
303
304 /* Core & CPU. */
305 pModLX->Core.u32Magic = 0; /* set by caller. */
306 pModLX->Core.eState = LDR_STATE_OPENED;
307 pModLX->Core.pOps = NULL; /* set by caller. */
308 pModLX->Core.pReader = pRdr;
309 switch (Hdr.e32_cpu)
310 {
311 case E32CPU286:
312 pModLX->enmCpu = RTLDRCPU_I80286;
313 pModLX->Core.enmArch = RTLDRARCH_X86_16;
314 break;
315 case E32CPU386:
316 pModLX->enmCpu = RTLDRCPU_I386;
317 pModLX->Core.enmArch = RTLDRARCH_X86_32;
318 break;
319 case E32CPU486:
320 pModLX->enmCpu = RTLDRCPU_I486;
321 pModLX->Core.enmArch = RTLDRARCH_X86_32;
322 break;
323 }
324 pModLX->Core.enmEndian = RTLDRENDIAN_LITTLE;
325 pModLX->Core.enmFormat = RTLDRFMT_LX;
326 switch (Hdr.e32_mflags & E32MODMASK)
327 {
328 case E32MODEXE:
329 pModLX->Core.enmType = !(Hdr.e32_mflags & E32NOINTFIX)
330 ? RTLDRTYPE_EXECUTABLE_RELOCATABLE
331 : RTLDRTYPE_EXECUTABLE_FIXED;
332 break;
333
334 case E32MODDLL:
335 case E32PROTDLL:
336 case E32MODPROTDLL:
337 pModLX->Core.enmType = !(Hdr.e32_mflags & E32SYSDLL)
338 ? RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE
339 : RTLDRTYPE_SHARED_LIBRARY_FIXED;
340 break;
341
342 case E32MODPDEV:
343 case E32MODVDEV:
344 pModLX->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
345 break;
346 }
347
348 /* KLDRMODLX */
349 pModLX->cSegments = Hdr.e32_objcnt;
350 pModLX->pszName = NULL; /* finalized further down */
351 pModLX->cchName = 0;
352 pModLX->pvMapping = 0;
353 pModLX->cbMapped = 0;
354 pModLX->f32Reserved = 0;
355
356 pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
357 memcpy(&pModLX->Hdr, &Hdr, sizeof(Hdr));
358
359 pModLX->pbLoaderSection = (uint8_t *)pModLX + cbModLXAndSegments;
360 pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize - 1;
361 pModLX->paObjs = NULL;
362 pModLX->paPageMappings = NULL;
363 pModLX->paRsrcs = NULL;
364 pModLX->pbResNameTab = NULL;
365 pModLX->pbEntryTab = NULL;
366
367 pModLX->pbNonResNameTab = NULL;
368 pModLX->pbNonResNameTabLast = NULL;
369
370 pModLX->pbFixupSection = NULL;
371 pModLX->pbFixupSectionLast = NULL;
372 pModLX->paoffPageFixups = NULL;
373 pModLX->pbFixupRecs = NULL;
374 pModLX->pbImportMods = NULL;
375 pModLX->pbImportProcs = NULL;
376
377 /*
378 * Read the loader data.
379 */
380 rc = pRdr->pfnRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
381 if (RT_FAILURE(rc))
382 return rc;
383 ((uint8_t *)pModLX->pbLoaderSectionLast)[1] = 0;
384 ((uint8_t *)pModLX->pbLoaderSectionLast)[2] = 0;
385 if (pModLX->Hdr.e32_objcnt)
386 pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
387 if (pModLX->Hdr.e32_objmap)
388 pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
389 if (pModLX->Hdr.e32_rsrccnt)
390 pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
391 if (pModLX->Hdr.e32_restab)
392 pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
393 if (pModLX->Hdr.e32_enttab)
394 pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
395
396 /*
397 * Get the soname from the resident name table.
398 * Very convenient that it's the 0 ordinal, because then we get a
399 * free string terminator.
400 * (The table entry consists of a pascal string followed by a 16-bit ordinal.)
401 */
402 if (pModLX->pbResNameTab)
403 pModLX->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab,
404 pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
405 0);
406 if (!pModLX->pszName)
407 return VERR_LDRLX_NO_SONAME;
408 pModLX->cchName = *(const uint8_t *)pModLX->pszName++;
409 if ( pModLX->pszName[pModLX->cchName] != '\0'
410 || pModLX->cchName != strlen(pModLX->pszName))
411 return VERR_LDRLX_BAD_SONAME;
412
413 /*
414 * Quick validation of the object table.
415 */
416 for (i = 0; i < pModLX->cSegments; i++)
417 {
418 if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
419 return VERR_LDRLX_BAD_OBJECT_TABLE;
420 if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
421 return VERR_LDRLX_BAD_OBJECT_TABLE;
422 if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1)))
423 return VERR_LDRLX_BAD_OBJECT_TABLE;
424 if ( pModLX->paObjs[i].o32_mapsize
425 && ( (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
426 || (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
427 > pModLX->pbLoaderSectionLast))
428 return VERR_LDRLX_BAD_OBJECT_TABLE;
429 if (i > 0 && !(pModLX->paObjs[i].o32_flags & OBJRSRC))
430 {
431 if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
432 return VERR_LDRLX_BAD_OBJECT_TABLE;
433 if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
434 return VERR_LDRLX_BAD_OBJECT_TABLE;
435 }
436 }
437
438 /*
439 * Check if we can optimize the mapping by using a different
440 * object alignment. The linker typically uses 64KB alignment,
441 * we can easily get away with page alignment in most cases.
442 *
443 * However, this screws up DwARF debug info, let's not do this
444 * when the purpose is reading debug info.
445 */
446 /** @todo Add flag for enabling this optimization. */
447 fCanOptimizeMapping = !(Hdr.e32_mflags & (E32NOINTFIX | E32SYSDLL))
448 && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION));
449 NextRVA = 0;
450
451 /*
452 * Setup the KLDRMOD segment array.
453 */
454 char *pszSegNm = (char *)&pModLX->aSegments[pModLX->cSegments];
455 for (i = 0; i < pModLX->cSegments; i++)
456 {
457 /* dummy segment name */
458 pModLX->aSegments[i].pszName = pszSegNm;
459 size_t cchName = RTStrPrintf(pszSegNm, sizeof("segXXXXX"), "seg%u", i);
460 pszSegNm += cchName + 1;
461 pModLX->aSegments[i].cchName = (uint32_t)cchName;
462
463 /* unused */
464 pModLX->aSegments[i].offFile = -1;
465 pModLX->aSegments[i].cbFile = -1;
466 pModLX->aSegments[i].SelFlat = 0;
467 pModLX->aSegments[i].Sel16bit = 0;
468
469 /* flags */
470 pModLX->aSegments[i].fFlags = 0;
471 if (pModLX->paObjs[i].o32_flags & OBJBIGDEF)
472 pModLX->aSegments[i].fFlags = RTLDRSEG_FLAG_16BIT;
473 if (pModLX->paObjs[i].o32_flags & OBJALIAS16)
474 pModLX->aSegments[i].fFlags = RTLDRSEG_FLAG_OS2_ALIAS16;
475 if (pModLX->paObjs[i].o32_flags & OBJCONFORM)
476 pModLX->aSegments[i].fFlags = RTLDRSEG_FLAG_OS2_CONFORM;
477 if (pModLX->paObjs[i].o32_flags & OBJIOPL)
478 pModLX->aSegments[i].fFlags = RTLDRSEG_FLAG_OS2_IOPL;
479
480 /* size and addresses */
481 pModLX->aSegments[i].Alignment = OBJPAGELEN;
482 pModLX->aSegments[i].cb = pModLX->paObjs[i].o32_size;
483 pModLX->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
484 pModLX->aSegments[i].RVA = NextRVA;
485 if ( fCanOptimizeMapping
486 || i + 1 >= pModLX->cSegments
487 || (pModLX->paObjs[i].o32_flags & OBJRSRC)
488 || (pModLX->paObjs[i + 1].o32_flags & OBJRSRC))
489 pModLX->aSegments[i].cbMapped = RT_ALIGN_Z(pModLX->paObjs[i].o32_size, OBJPAGELEN);
490 else
491 pModLX->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
492 /** @todo Above probably doesn't work for os2krnl and other images
493 * non-sequential virtual address assignments. */
494 NextRVA += (uint32_t)pModLX->aSegments[i].cbMapped;
495
496 /* protection */
497 switch ( pModLX->paObjs[i].o32_flags
498 & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
499 {
500 case 0:
501 case OBJSHARED:
502 pModLX->aSegments[i].fProt = 0;
503 break;
504 case OBJREAD:
505 case OBJREAD | OBJSHARED:
506 pModLX->aSegments[i].fProt = RTMEM_PROT_READ;
507 break;
508 case OBJWRITE:
509 case OBJWRITE | OBJREAD:
510 pModLX->aSegments[i].fProt = RTMEM_PROT_READ | RTMEM_PROT_WRITECOPY;
511 break;
512 case OBJWRITE | OBJSHARED:
513 case OBJWRITE | OBJSHARED | OBJREAD:
514 pModLX->aSegments[i].fProt = RTMEM_PROT_READ | RTMEM_PROT_WRITE;
515 break;
516 case OBJEXEC:
517 case OBJEXEC | OBJSHARED:
518 pModLX->aSegments[i].fProt = RTMEM_PROT_EXEC;
519 break;
520 case OBJEXEC | OBJREAD:
521 case OBJEXEC | OBJREAD | OBJSHARED:
522 pModLX->aSegments[i].fProt = RTMEM_PROT_EXEC | RTMEM_PROT_READ;
523 break;
524 case OBJEXEC | OBJWRITE:
525 case OBJEXEC | OBJWRITE | OBJREAD:
526 pModLX->aSegments[i].fProt = RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITECOPY;
527 break;
528 case OBJEXEC | OBJWRITE | OBJSHARED:
529 case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
530 pModLX->aSegments[i].fProt = RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE;
531 break;
532 }
533 if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
534 pModLX->aSegments[i].fProt = RTMEM_PROT_READ;
535 /*pModLX->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
536 pModLX->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
537 pModLX->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */
538 }
539
540 /* set the mapping size */
541 pModLX->cbMapped = NextRVA;
542
543 /*
544 * We're done.
545 */
546 *ppModLX = pModLX;
547 return VINF_SUCCESS;
548}
549
550
551/**
552 * @interface_method_impl{RTLDROPS,pfnClose}
553 */
554static DECLCALLBACK(int) rtldrLX_Close(PRTLDRMODINTERNAL pMod)
555{
556 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
557 KLDRMODLX_ASSERT(!pModLX->pvMapping);
558
559 if (pModLX->pbNonResNameTab)
560 {
561 RTMemFree(pModLX->pbNonResNameTab);
562 pModLX->pbNonResNameTab = NULL;
563 }
564 if (pModLX->pbFixupSection)
565 {
566 RTMemFree(pModLX->pbFixupSection);
567 pModLX->pbFixupSection = NULL;
568 }
569 return VINF_SUCCESS;
570}
571
572
573/**
574 * Resolved base address aliases.
575 *
576 * @param pModLX The interpreter module instance
577 * @param pBaseAddress The base address, IN & OUT.
578 */
579static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PRTLDRADDR pBaseAddress)
580{
581 if (*pBaseAddress == RTLDR_BASEADDRESS_LINK)
582 *pBaseAddress = pModLX->aSegments[0].LinkAddress;
583}
584
585
586static int kldrModLXQuerySymbol(PRTLDRMODINTERNAL pMod, const void *pvBits, RTLDRADDR BaseAddress, uint32_t iSymbol,
587 const char *pchSymbol, size_t cchSymbol, const char *pszVersion,
588 PFNRTLDRIMPORT pfnGetForwarder, void *pvUser, PRTLDRADDR puValue, uint32_t *pfKind)
589{
590 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
591 uint32_t iOrdinal;
592 int rc;
593 const struct b32_bundle *pBundle;
594 RT_NOREF(pvBits);
595 RT_NOREF(pszVersion);
596
597 /*
598 * Give up at once if there is no entry table.
599 */
600 if (!pModLX->Hdr.e32_enttab)
601 return VERR_SYMBOL_NOT_FOUND;
602
603 /*
604 * Translate the symbol name into an ordinal.
605 */
606 if (pchSymbol)
607 {
608 rc = kldrModLXDoNameLookup(pModLX, pchSymbol, cchSymbol, &iSymbol);
609 if (RT_FAILURE(rc))
610 return rc;
611 }
612
613 /*
614 * Iterate the entry table.
615 * (The entry table is made up of bundles of similar exports.)
616 */
617 iOrdinal = 1;
618 pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
619 while (pBundle->b32_cnt && iOrdinal <= iSymbol)
620 {
621 static const size_t s_cbEntry[] = { 0, 3, 5, 5, 7 };
622
623 /*
624 * Check for a hit first.
625 */
626 iOrdinal += pBundle->b32_cnt;
627 if (iSymbol < iOrdinal)
628 {
629 uint32_t offObject;
630 const struct e32_entry *pEntry = (const struct e32_entry *)((uintptr_t)(pBundle + 1)
631 + (iSymbol - (iOrdinal - pBundle->b32_cnt))
632 * s_cbEntry[pBundle->b32_type]);
633
634 /*
635 * Calculate the return address.
636 */
637 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
638 switch (pBundle->b32_type)
639 {
640 /* empty bundles are place holders unused ordinal ranges. */
641 case EMPTY:
642 return VERR_SYMBOL_NOT_FOUND;
643
644 /* e32_flags + a 16-bit offset. */
645 case ENTRY16:
646 offObject = pEntry->e32_variant.e32_offset.offset16;
647 if (pfKind)
648 *pfKind = RTLDRSYMKIND_16BIT | RTLDRSYMKIND_NO_TYPE;
649 break;
650
651 /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
652 case GATE16:
653 offObject = pEntry->e32_variant.e32_callgate.offset;
654 if (pfKind)
655 *pfKind = RTLDRSYMKIND_16BIT | RTLDRSYMKIND_CODE;
656 break;
657
658 /* e32_flags + a 32-bit offset. */
659 case ENTRY32:
660 offObject = pEntry->e32_variant.e32_offset.offset32;
661 if (pfKind)
662 *pfKind = RTLDRSYMKIND_32BIT;
663 break;
664
665 /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
666 case ENTRYFWD:
667 return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind);
668
669 default:
670 /* anyone actually using TYPEINFO will end up here. */
671 KLDRMODLX_ASSERT(!"Bad bundle type");
672 return VERR_LDRLX_BAD_BUNDLE;
673 }
674
675 /*
676 * Validate the object number and calc the return address.
677 */
678 if ( pBundle->b32_obj <= 0
679 || pBundle->b32_obj > pModLX->cSegments)
680 return VERR_LDRLX_BAD_BUNDLE;
681 if (puValue)
682 *puValue = BaseAddress
683 + offObject
684 + pModLX->aSegments[pBundle->b32_obj - 1].RVA;
685 return VINF_SUCCESS;
686 }
687
688 /*
689 * Skip the bundle.
690 */
691 if (pBundle->b32_type > ENTRYFWD)
692 {
693 KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
694 return VERR_LDRLX_BAD_BUNDLE;
695 }
696 if (pBundle->b32_type == 0)
697 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + 2);
698 else
699 pBundle = (const struct b32_bundle *)((const uint8_t *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
700 }
701
702 return VERR_SYMBOL_NOT_FOUND;
703}
704
705
706/**
707 * @interface_method_impl{RTLDROPS,pfnGetSymbolEx}
708 */
709static DECLCALLBACK(int) rtldrLX_GetSymbolEx(PRTLDRMODINTERNAL pMod, const void *pvBits, RTUINTPTR BaseAddress,
710 uint32_t iOrdinal, const char *pszSymbol, RTUINTPTR *pValue)
711{
712 uint32_t fKind = RTLDRSYMKIND_REQ_FLAT;
713 return kldrModLXQuerySymbol(pMod, pvBits, BaseAddress, iOrdinal, pszSymbol, pszSymbol ? strlen(pszSymbol) : 0,
714 NULL, NULL, NULL, pValue, &fKind);
715}
716
717
718/**
719 * Do name lookup.
720 *
721 * @returns IPRT status code.
722 * @param pModLX The module to lookup the symbol in.
723 * @param pchSymbol The symbol to lookup.
724 * @param cchSymbol The symbol name length.
725 * @param piSymbol Where to store the symbol ordinal.
726 */
727static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, size_t cchSymbol, uint32_t *piSymbol)
728{
729
730 /*
731 * First do a hash table lookup.
732 */
733 /** @todo hash name table for speed. */
734
735 /*
736 * Search the name tables.
737 */
738 const uint8_t *pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab,
739 pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
740 pchSymbol, cchSymbol);
741 if (!pbName)
742 {
743 if (!pModLX->pbNonResNameTab)
744 {
745 /* lazy load it */
746 /** @todo non-resident name table. */
747 }
748 if (pModLX->pbNonResNameTab)
749 pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab,
750 pModLX->pbNonResNameTabLast - pModLX->pbResNameTab + 1,
751 pchSymbol, cchSymbol);
752 }
753 if (!pbName)
754 return VERR_SYMBOL_NOT_FOUND;
755
756 *piSymbol = *(const uint16_t *)(pbName + 1 + *pbName);
757 return VINF_SUCCESS;
758}
759
760
761/**
762 * Lookup a name table entry by name.
763 *
764 * @returns Pointer to the name table entry if found.
765 * @returns NULL if not found.
766 * @param pbNameTable Pointer to the name table that should be searched.
767 * @param cbNameTable The size of the name table.
768 * @param pchSymbol The name of the symbol we're looking for.
769 * @param cchSymbol The length of the symbol name.
770 */
771static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, ssize_t cbNameTable,
772 const char *pchSymbol, size_t cchSymbol)
773{
774 /*
775 * Determin the namelength up front so we can skip anything which doesn't matches the length.
776 */
777 uint8_t cbSymbol8Bit = (uint8_t)cchSymbol;
778 if (cbSymbol8Bit != cchSymbol)
779 return NULL; /* too long. */
780
781 /*
782 * Walk the name table.
783 */
784 while (*pbNameTable != 0 && cbNameTable > 0)
785 {
786 const uint8_t cbName = *pbNameTable;
787
788 cbNameTable -= cbName + 1 + 2;
789 if (cbNameTable < 0)
790 break;
791
792 if ( cbName == cbSymbol8Bit
793 && !memcmp(pbNameTable + 1, pchSymbol, cbName))
794 return pbNameTable;
795
796 /* next entry */
797 pbNameTable += cbName + 1 + 2;
798 }
799
800 return NULL;
801}
802
803
804/**
805 * Deal with a forwarder entry.
806 *
807 * @returns IPRT status code.
808 * @param pModLX The PE module interpreter instance.
809 * @param pEntry The forwarder entry.
810 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
811 * @param pvUser The user argument for the callback.
812 * @param puValue Where to put the value. (optional)
813 * @param pfKind Where to put the symbol kind. (optional)
814 */
815static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
816 PFNRTLDRIMPORT pfnGetForwarder, void *pvUser, PRTLDRADDR puValue, uint32_t *pfKind)
817{
818 if (!pfnGetForwarder)
819 return VERR_LDR_FORWARDER;
820
821 /*
822 * Validate the entry import module ordinal.
823 */
824 if ( !pEntry->e32_variant.e32_fwd.modord
825 || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt)
826 return VERR_LDRLX_BAD_FORWARDER;
827
828 char szImpModule[256];
829 int rc = kldrModLXGetImport(pModLX, NULL, pEntry->e32_variant.e32_fwd.modord - 1, szImpModule, sizeof(szImpModule), NULL);
830 if (RT_FAILURE(rc))
831 return rc;
832
833 /*
834 * Figure out the parameters.
835 */
836 uint32_t iSymbol;
837 const char *pszSymbol;
838 char szSymbol[256];
839 if (pEntry->e32_flags & FWD_ORDINAL)
840 {
841 iSymbol = pEntry->e32_variant.e32_fwd.value;
842 pszSymbol = NULL; /* no symbol name. */
843 }
844 else
845 {
846 const uint8_t *pbName;
847
848 /* load the fixup section if necessary. */
849 if (!pModLX->pbImportProcs)
850 {
851 rc = kldrModLXDoLoadFixupSection(pModLX);
852 if (RT_FAILURE(rc))
853 return rc;
854 }
855
856 /* Make name pointer. */
857 pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value;
858 if ( pbName >= pModLX->pbFixupSectionLast
859 || pbName < pModLX->pbFixupSection
860 || !*pbName)
861 return VERR_LDRLX_BAD_FORWARDER;
862
863
864 /* check for '#' name. */
865 if (pbName[1] == '#')
866 {
867 uint8_t cbLeft = *pbName;
868 const uint8_t *pb = pbName + 1;
869 unsigned uBase;
870
871 /* base detection */
872 uBase = 10;
873 if ( cbLeft > 1
874 && pb[1] == '0'
875 && (pb[2] == 'x' || pb[2] == 'X'))
876 {
877 uBase = 16;
878 pb += 2;
879 cbLeft -= 2;
880 }
881
882 /* ascii to integer */
883 iSymbol = 0;
884 while (cbLeft-- > 0)
885 {
886 /* convert char to digit. */
887 unsigned uDigit = *pb++;
888 if (uDigit >= '0' && uDigit <= '9')
889 uDigit -= '0';
890 else if (uDigit >= 'a' && uDigit <= 'z')
891 uDigit -= 'a' + 10;
892 else if (uDigit >= 'A' && uDigit <= 'Z')
893 uDigit -= 'A' + 10;
894 else if (!uDigit)
895 break;
896 else
897 return VERR_LDRLX_BAD_FORWARDER;
898 if (uDigit >= uBase)
899 return VERR_LDRLX_BAD_FORWARDER;
900
901 /* insert the digit */
902 iSymbol *= uBase;
903 iSymbol += uDigit;
904 }
905 if (!iSymbol)
906 return VERR_LDRLX_BAD_FORWARDER;
907
908 pszSymbol = NULL; /* no symbol name. */
909 }
910 else
911 {
912 memcpy(szSymbol, pbName + 1, *pbName);
913 szSymbol[*pbName] = '\0';
914 pszSymbol = szSymbol;
915 iSymbol = UINT32_MAX;
916 }
917 }
918
919 /*
920 * Resolve the forwarder.
921 */
922 rc = pfnGetForwarder(&pModLX->Core, szImpModule, pszSymbol, iSymbol, puValue, /*pfKind, */pvUser);
923 if (RT_SUCCESS(rc) && pfKind)
924 *pfKind |= RTLDRSYMKIND_FORWARDER;
925 return rc;
926}
927
928
929/**
930 * Loads the fixup section from the executable image.
931 *
932 * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone().
933 *
934 * @returns IPRT status code.
935 * @param pModLX The PE module interpreter instance.
936 */
937static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX)
938{
939 void *pv = RTMemAlloc(pModLX->Hdr.e32_fixupsize);
940 if (!pv)
941 return VERR_NO_MEMORY;
942
943 uint32_t off = pModLX->Hdr.e32_objtab + pModLX->Hdr.e32_ldrsize;
944 int rc = pModLX->Core.pReader->pfnRead(pModLX->Core.pReader, pv, pModLX->Hdr.e32_fixupsize,
945 off + pModLX->offHdr);
946 if (RT_SUCCESS(rc))
947 {
948 pModLX->pbFixupSection = (uint8_t *)pv;
949 pModLX->pbFixupSectionLast = pModLX->pbFixupSection + pModLX->Hdr.e32_fixupsize;
950 KLDRMODLX_ASSERT(!pModLX->paoffPageFixups);
951 if (pModLX->Hdr.e32_fpagetab)
952 pModLX->paoffPageFixups = (const uint32_t *)(pModLX->pbFixupSection + pModLX->Hdr.e32_fpagetab - off);
953 KLDRMODLX_ASSERT(!pModLX->pbFixupRecs);
954 if (pModLX->Hdr.e32_frectab)
955 pModLX->pbFixupRecs = pModLX->pbFixupSection + pModLX->Hdr.e32_frectab - off;
956 KLDRMODLX_ASSERT(!pModLX->pbImportMods);
957 if (pModLX->Hdr.e32_impmod)
958 pModLX->pbImportMods = pModLX->pbFixupSection + pModLX->Hdr.e32_impmod - off;
959 KLDRMODLX_ASSERT(!pModLX->pbImportProcs);
960 if (pModLX->Hdr.e32_impproc)
961 pModLX->pbImportProcs = pModLX->pbFixupSection + pModLX->Hdr.e32_impproc - off;
962 }
963 else
964 RTMemFree(pv);
965 return rc;
966}
967
968
969/**
970 * @interface_method_impl{RTLDROPS,pfnEnumSymbols}
971 */
972static DECLCALLBACK(int) rtldrLX_EnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits,
973 RTUINTPTR BaseAddress, PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
974{
975 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
976 RT_NOREF(pvBits);
977 RT_NOREF(fFlags);
978
979 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
980
981 /*
982 * Enumerate the entry table.
983 * (The entry table is made up of bundles of similar exports.)
984 */
985 int rc = VINF_SUCCESS;
986 uint32_t iOrdinal = 1;
987 const struct b32_bundle *pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
988 while (pBundle->b32_cnt && iOrdinal)
989 {
990 static const size_t s_cbEntry[] = { 0, 3, 5, 5, 7 };
991
992 /*
993 * Enum the entries in the bundle.
994 */
995 if (pBundle->b32_type != EMPTY)
996 {
997 const struct e32_entry *pEntry;
998 size_t cbEntry;
999 RTLDRADDR BundleRVA;
1000 unsigned cLeft;
1001
1002
1003 /* Validate the bundle. */
1004 switch (pBundle->b32_type)
1005 {
1006 case ENTRY16:
1007 case GATE16:
1008 case ENTRY32:
1009 if ( pBundle->b32_obj <= 0
1010 || pBundle->b32_obj > pModLX->cSegments)
1011 return VERR_LDRLX_BAD_BUNDLE;
1012 BundleRVA = pModLX->aSegments[pBundle->b32_obj - 1].RVA;
1013 break;
1014
1015 case ENTRYFWD:
1016 BundleRVA = 0;
1017 break;
1018
1019 default:
1020 /* anyone actually using TYPEINFO will end up here. */
1021 KLDRMODLX_ASSERT(!"Bad bundle type");
1022 return VERR_LDRLX_BAD_BUNDLE;
1023 }
1024
1025 /* iterate the bundle entries. */
1026 cbEntry = s_cbEntry[pBundle->b32_type];
1027 pEntry = (const struct e32_entry *)(pBundle + 1);
1028 cLeft = pBundle->b32_cnt;
1029 while (cLeft-- > 0)
1030 {
1031 RTLDRADDR uValue;
1032 uint32_t fKind;
1033 int fFoundName;
1034 const uint8_t *pbName;
1035
1036 /*
1037 * Calc the symbol value and kind.
1038 */
1039 switch (pBundle->b32_type)
1040 {
1041 /* e32_flags + a 16-bit offset. */
1042 case ENTRY16:
1043 uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset16;
1044 fKind = RTLDRSYMKIND_16BIT | RTLDRSYMKIND_NO_TYPE;
1045 break;
1046
1047 /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
1048 case GATE16:
1049 uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_callgate.offset;
1050 fKind = RTLDRSYMKIND_16BIT | RTLDRSYMKIND_CODE;
1051 break;
1052
1053 /* e32_flags + a 32-bit offset. */
1054 case ENTRY32:
1055 uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset32;
1056 fKind = RTLDRSYMKIND_32BIT;
1057 break;
1058
1059 /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
1060 case ENTRYFWD:
1061 uValue = 0; /** @todo implement enumeration of forwarders properly. */
1062 fKind = RTLDRSYMKIND_FORWARDER;
1063 break;
1064
1065 default: /* shut up gcc. */
1066 uValue = 0;
1067 fKind = RTLDRSYMKIND_NO_BIT | RTLDRSYMKIND_NO_TYPE;
1068 break;
1069 }
1070
1071 /*
1072 * Any symbol names?
1073 */
1074 fFoundName = 0;
1075 char szName[256];
1076
1077 /* resident name table. */
1078 pbName = pModLX->pbResNameTab;
1079 if (pbName)
1080 {
1081 do
1082 {
1083 pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbLoaderSectionLast - pbName + 1, iOrdinal);
1084 if (!pbName)
1085 break;
1086 fFoundName = 1;
1087 memcpy(szName, (const char *)pbName + 1, *pbName);
1088 szName[*pbName] = '\0';
1089 rc = pfnCallback(pMod, szName, iOrdinal, uValue, /*fKind,*/ pvUser);
1090 if (rc != VINF_SUCCESS)
1091 return rc;
1092
1093 /* skip to the next entry */
1094 pbName += 1 + *pbName + 2;
1095 } while (pbName < pModLX->pbLoaderSectionLast);
1096 }
1097
1098 /* resident name table. */
1099 pbName = pModLX->pbNonResNameTab;
1100 /** @todo lazy load the non-resident name table. */
1101 if (pbName)
1102 {
1103 do
1104 {
1105 pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbNonResNameTabLast - pbName + 1, iOrdinal);
1106 if (!pbName)
1107 break;
1108 fFoundName = 1;
1109 memcpy(szName, (const char *)pbName + 1, *pbName);
1110 szName[*pbName] = '\0';
1111 rc = pfnCallback(pMod, szName, iOrdinal, uValue, /*fKind,*/ pvUser);
1112 if (rc != VINF_SUCCESS)
1113 return rc;
1114
1115 /* skip to the next entry */
1116 pbName += 1 + *pbName + 2;
1117 } while (pbName < pModLX->pbLoaderSectionLast);
1118 }
1119
1120 /*
1121 * If no names, call once with the ordinal only.
1122 */
1123 if (!fFoundName)
1124 {
1125 RT_NOREF(fKind);
1126 rc = pfnCallback(pMod, NULL /*pszName*/, iOrdinal, uValue, /*fKind,*/ pvUser);
1127 if (rc != VINF_SUCCESS)
1128 return rc;
1129 }
1130
1131 /* next */
1132 iOrdinal++;
1133 pEntry = (const struct e32_entry *)((uintptr_t)pEntry + cbEntry);
1134 }
1135 }
1136
1137 /*
1138 * The next bundle.
1139 */
1140 if (pBundle->b32_type > ENTRYFWD)
1141 {
1142 KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
1143 return VERR_LDRLX_BAD_BUNDLE;
1144 }
1145 if (pBundle->b32_type == 0)
1146 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + 2);
1147 else
1148 pBundle = (const struct b32_bundle *)((const uint8_t *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
1149 }
1150
1151 return VINF_SUCCESS;
1152}
1153
1154
1155/**
1156 * Lookup a name table entry by ordinal.
1157 *
1158 * @returns Pointer to the name table entry if found.
1159 * @returns NULL if not found.
1160 * @param pbNameTable Pointer to the name table that should be searched.
1161 * @param cbNameTable The size of the name table.
1162 * @param iOrdinal The ordinal to search for.
1163 */
1164static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, ssize_t cbNameTable, uint32_t iOrdinal)
1165{
1166 while (*pbNameTable != 0 && cbNameTable > 0)
1167 {
1168 const uint8_t cbName = *pbNameTable;
1169 uint32_t iName;
1170
1171 cbNameTable -= cbName + 1 + 2;
1172 if (cbNameTable < 0)
1173 break;
1174
1175 iName = *(pbNameTable + cbName + 1)
1176 | ((unsigned)*(pbNameTable + cbName + 2) << 8);
1177 if (iName == iOrdinal)
1178 return pbNameTable;
1179
1180 /* next entry */
1181 pbNameTable += cbName + 1 + 2;
1182 }
1183
1184 return NULL;
1185}
1186
1187
1188static int kldrModLXGetImport(PKLDRMODLX pModLX, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName,
1189 size_t *pcbNeeded)
1190{
1191 const uint8_t *pb;
1192 int rc;
1193 RT_NOREF(pvBits);
1194
1195 /*
1196 * Validate
1197 */
1198 if (iImport >= pModLX->Hdr.e32_impmodcnt)
1199 return VERR_LDRLX_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1200
1201 /*
1202 * Lazy loading the fixup section.
1203 */
1204 if (!pModLX->pbImportMods)
1205 {
1206 rc = kldrModLXDoLoadFixupSection(pModLX);
1207 if (RT_FAILURE(rc))
1208 return rc;
1209 }
1210
1211 /*
1212 * Iterate the module import table until we reach the requested import ordinal.
1213 */
1214 pb = pModLX->pbImportMods;
1215 while (iImport-- > 0)
1216 pb += *pb + 1;
1217
1218 /*
1219 * Copy out the result.
1220 */
1221 if (pcbNeeded)
1222 *pcbNeeded = *pb + 1;
1223 if (*pb < cchName)
1224 {
1225 memcpy(pszName, pb + 1, *pb);
1226 pszName[*pb] = '\0';
1227 rc = VINF_SUCCESS;
1228 }
1229 else
1230 {
1231 memcpy(pszName, pb + 1, cchName);
1232 if (cchName)
1233 pszName[cchName - 1] = '\0';
1234 rc = VERR_BUFFER_OVERFLOW;
1235 }
1236
1237 return rc;
1238}
1239
1240#if 0
1241
1242/** @copydoc kLdrModNumberOfImports */
1243static int32_t kldrModLXNumberOfImports(PRTLDRMODINTERNAL pMod, const void *pvBits)
1244{
1245 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
1246 RT_NOREF(pvBits);
1247 return pModLX->Hdr.e32_impmodcnt;
1248}
1249
1250
1251/** @copydoc kLdrModGetStackInfo */
1252static int kldrModLXGetStackInfo(PRTLDRMODINTERNAL pMod, const void *pvBits, RTLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1253{
1254 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
1255 const uint32_t i = pModLX->Hdr.e32_stackobj;
1256 RT_NOREF(pvBits);
1257
1258 if ( i
1259 && i <= pModLX->cSegments
1260 && pModLX->Hdr.e32_esp <= pModLX->aSegments[i - 1].LinkAddress + pModLX->aSegments[i - 1].cb
1261 && pModLX->Hdr.e32_stacksize
1262 && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pModLX->aSegments[i - 1].LinkAddress)
1263 {
1264
1265 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1266 pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
1267 pStackInfo->Address = BaseAddress
1268 + pModLX->aSegments[i - 1].RVA
1269 + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pModLX->aSegments[i - 1].LinkAddress;
1270 }
1271 else
1272 {
1273 pSt0ackInfo->Address = NIL_RTLDRADDR;
1274 pStackInfo->LinkAddress = NIL_RTLDRADDR;
1275 }
1276 pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
1277 pStackInfo->cbStackThread = 0;
1278
1279 return VINF_SUCCESS;
1280}
1281
1282
1283/** @copydoc kLdrModQueryMainEntrypoint */
1284static int kldrModLXQueryMainEntrypoint(PRTLDRMODINTERNAL pMod, const void *pvBits, RTLDRADDR BaseAddress, PRTLDRADDR pMainEPAddress)
1285{
1286 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
1287 RT_NOREF(pvBits);
1288
1289 /*
1290 * Convert the address from the header.
1291 */
1292 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1293 *pMainEPAddress = pModLX->Hdr.e32_startobj
1294 && pModLX->Hdr.e32_startobj <= pModLX->cSegments
1295 && pModLX->Hdr.e32_eip < pModLX->aSegments[pModLX->Hdr.e32_startobj - 1].cb
1296 ? BaseAddress + pModLX->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
1297 : NIL_RTLDRADDR;
1298 return VINF_SUCCESS;
1299}
1300
1301#endif
1302
1303/** Helper for rtldrLX_EnumDbgInfo. */
1304static int rtldrLx_EnumDbgInfoHelper(PKLDRMODLX pModLX, PFNRTLDRENUMDBG pfnCallback, void *pvUser,
1305 uint8_t *pbBuf, uint32_t cbRead, uint32_t offDbgInfo, bool *pfReturn)
1306{
1307 RTLDRDBGINFO DbgInfo;
1308 uint32_t iDbgInfo = 0;
1309 uint32_t cbDbgInfo = pModLX->Hdr.e32_debuglen;
1310
1311 /*
1312 * Recent watcom linkers emit PE style IMAGE_DEBUG_MISC for specifying
1313 * external file with CV info.
1314 */
1315 if (cbRead >= sizeof(IMAGE_DEBUG_MISC))
1316 {
1317 PCIMAGE_DEBUG_MISC pMisc = (PCIMAGE_DEBUG_MISC)pbBuf;
1318 if ( pMisc->DataType == IMAGE_DEBUG_MISC_EXENAME
1319 && pMisc->Length <= cbRead
1320 && pMisc->Length >= RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data[4])
1321 && pMisc->Unicode == 0
1322 && pMisc->Reserved[0] == 0
1323 && pMisc->Reserved[1] == 0
1324 && pMisc->Reserved[2] == 0
1325 && pMisc->Data[0] >= 0x20
1326 && pMisc->Data[0] < 0x7f
1327 && pMisc->Data[1] >= 0x20
1328 && pMisc->Data[1] < 0x7f
1329 && pMisc->Data[2] >= 0x20
1330 && pMisc->Data[2] < 0x7f )
1331 {
1332 uint32_t cchMaxName = pMisc->Length - RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data[0]);
1333 for (uint32_t cchName = 3; cchName < cchMaxName; cchName++)
1334 {
1335 char const ch = pMisc->Data[cchName];
1336 if (ch == 0)
1337 {
1338 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW;
1339 DbgInfo.iDbgInfo = iDbgInfo;
1340 DbgInfo.offFile = offDbgInfo;
1341 DbgInfo.LinkAddress = NIL_RTLDRADDR;
1342 DbgInfo.cb = pMisc->Length;
1343 DbgInfo.pszExtFile = (char *)&pMisc->Data[0];
1344 DbgInfo.u.Cv.cbImage = pModLX->Hdr.e32_mpages * pModLX->Hdr.e32_pagesize;
1345 DbgInfo.u.Cv.uTimestamp = 0;
1346 DbgInfo.u.Cv.uMajorVer = 0;
1347 DbgInfo.u.Cv.uMinorVer = 0;
1348
1349 *pfReturn = true;
1350 int rc = pfnCallback(&pModLX->Core, &DbgInfo, pvUser);
1351 if (rc != VINF_SUCCESS)
1352 return rc;
1353 }
1354 else if (ch >= 0x30 && ch < 0x7f)
1355 continue;
1356 break;
1357 }
1358
1359 /* Skip it. */
1360 pbBuf += pMisc->Length;
1361 cbRead -= pMisc->Length;
1362 offDbgInfo += pMisc->Length;
1363 cbDbgInfo -= pMisc->Length;
1364 iDbgInfo++;
1365 }
1366 }
1367
1368 /*
1369 * Look for codeview signature.
1370 */
1371 RTCVHDR const *pCvHdr = (RTCVHDR const *)pbBuf;
1372 if ( cbRead > sizeof(*pCvHdr)
1373 && pCvHdr->off >= sizeof(*pCvHdr)
1374 && pCvHdr->off < cbDbgInfo)
1375 {
1376 switch (pCvHdr->u32Magic)
1377 {
1378 case RTCVHDR_MAGIC_NB11:
1379 case RTCVHDR_MAGIC_NB09:
1380 case RTCVHDR_MAGIC_NB08:
1381 case RTCVHDR_MAGIC_NB07:
1382 case RTCVHDR_MAGIC_NB06:
1383 case RTCVHDR_MAGIC_NB05:
1384 case RTCVHDR_MAGIC_NB04:
1385 case RTCVHDR_MAGIC_NB02:
1386 case RTCVHDR_MAGIC_NB01:
1387 case RTCVHDR_MAGIC_NB00:
1388 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW;
1389 DbgInfo.iDbgInfo = iDbgInfo;
1390 DbgInfo.offFile = offDbgInfo;
1391 DbgInfo.LinkAddress = NIL_RTLDRADDR;
1392 DbgInfo.cb = cbDbgInfo;
1393 DbgInfo.pszExtFile = NULL;
1394 DbgInfo.u.Cv.cbImage = pModLX->Hdr.e32_mpages * pModLX->Hdr.e32_pagesize;
1395 DbgInfo.u.Cv.uTimestamp = 0;
1396 DbgInfo.u.Cv.uMajorVer = 0;
1397 DbgInfo.u.Cv.uMinorVer = 0;
1398
1399 *pfReturn = true;
1400 return pfnCallback(&pModLX->Core, &DbgInfo, pvUser);
1401 }
1402 }
1403
1404 /*
1405 * Watcom wraps its DWARF output in an ELF image, so look for and ELF magic.
1406 */
1407 Elf32_Ehdr const *pElfHdr = (Elf32_Ehdr const *)pbBuf;
1408 if ( cbRead >= sizeof(*pElfHdr)
1409 && pElfHdr->e_ident[EI_MAG0] == ELFMAG0
1410 && pElfHdr->e_ident[EI_MAG1] == ELFMAG1
1411 && pElfHdr->e_ident[EI_MAG2] == ELFMAG2
1412 && pElfHdr->e_ident[EI_MAG3] == ELFMAG3
1413 && pElfHdr->e_ident[EI_CLASS] == ELFCLASS32
1414 && pElfHdr->e_ident[EI_DATA] == ELFDATA2LSB
1415 && pElfHdr->e_ident[EI_VERSION] == EV_CURRENT
1416 && pElfHdr->e_shentsize == sizeof(Elf32_Shdr)
1417 && pElfHdr->e_shnum >= 2
1418 && pElfHdr->e_shnum < _32K + 10
1419 && pElfHdr->e_shstrndx <= pElfHdr->e_shnum
1420 && pElfHdr->e_shstrndx > 0
1421 )
1422 {
1423 /** @todo try use pBuf for reading into and try to read more at once. */
1424 uint32_t const offShdrs = pElfHdr->e_shoff + offDbgInfo;
1425 uint32_t const cShdrs = pElfHdr->e_shnum;
1426 uint32_t const cbShdr = pElfHdr->e_shentsize;
1427 int rc = VINF_SUCCESS;
1428
1429 /* Read the section string table. */
1430 Elf32_Shdr Shdr;
1431 int rc2 = pModLX->Core.pReader->pfnRead(pModLX->Core.pReader, &Shdr, sizeof(Shdr),
1432 offShdrs + pElfHdr->e_shstrndx * cbShdr);
1433 if ( RT_SUCCESS(rc2)
1434 && Shdr.sh_offset > 0
1435 && Shdr.sh_size > 0
1436 && Shdr.sh_size < _256K
1437 && Shdr.sh_type == SHT_STRTAB)
1438 {
1439 uint32_t const cbStrTab = Shdr.sh_size;
1440 char * const pszStrTab = (char *)RTMemTmpAlloc(cbStrTab + 2);
1441 if (pszStrTab)
1442 {
1443 rc2 = pModLX->Core.pReader->pfnRead(pModLX->Core.pReader, pszStrTab, Shdr.sh_size, offDbgInfo + Shdr.sh_offset);
1444 if (RT_SUCCESS(rc2))
1445 {
1446 pszStrTab[cbStrTab] = '\0';
1447
1448 /* Iterate the sections, one by one. */
1449 for (uint32_t i = 1; i < cShdrs; i++)
1450 {
1451 rc = pModLX->Core.pReader->pfnRead(pModLX->Core.pReader, &Shdr, sizeof(Shdr), offShdrs + i * cbShdr);
1452 if ( RT_SUCCESS(rc)
1453 && Shdr.sh_name < cbStrTab
1454 && strncmp(&pszStrTab[Shdr.sh_name], RT_STR_TUPLE(".debug_")) == 0)
1455 {
1456 DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF;
1457 DbgInfo.iDbgInfo = iDbgInfo;
1458 DbgInfo.offFile = offDbgInfo + Shdr.sh_offset;
1459 DbgInfo.LinkAddress = NIL_RTLDRADDR;
1460 DbgInfo.cb = Shdr.sh_size;
1461 DbgInfo.pszExtFile = NULL;
1462 DbgInfo.u.Dwarf.pszSection = &pszStrTab[Shdr.sh_name];
1463
1464 *pfReturn = true;
1465 rc = pfnCallback(&pModLX->Core, &DbgInfo, pvUser);
1466 if (rc != VINF_SUCCESS)
1467 break;
1468 iDbgInfo++;
1469 }
1470 }
1471 }
1472 RTMemTmpFree(pszStrTab);
1473 }
1474 }
1475 return rc;
1476 }
1477
1478 /*
1479 * Watcom debug info? Don't know how to detect it...
1480 */
1481
1482 return VINF_SUCCESS;
1483}
1484
1485
1486/**
1487 * @interface_method_impl{RTLDROPS,pfnEnumDbgInfo}
1488 */
1489static DECLCALLBACK(int) rtldrLX_EnumDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits,
1490 PFNRTLDRENUMDBG pfnCallback, void *pvUser)
1491{
1492 /*PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);*/
1493 RT_NOREF(pfnCallback);
1494 RT_NOREF(pvUser);
1495
1496 /*
1497 * Quit immediately if no debug info.
1498 */
1499 if (kldrModLXHasDbgInfo(pMod, pvBits))
1500 return VINF_SUCCESS;
1501 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
1502
1503 /*
1504 * Read the debug info and look for familiar magics and structures.
1505 */
1506 union
1507 {
1508 uint8_t ab[1024];
1509 IMAGE_DEBUG_MISC Misc;
1510 RTCVHDR CvHdr;
1511 } uBuf;
1512
1513 bool fReturn = false;
1514
1515 /* Try the offset without header displacement first. */
1516 uint32_t cbToRead = RT_MIN(pModLX->Hdr.e32_debuglen, sizeof(uBuf));
1517 int rc = pModLX->Core.pReader->pfnRead(pModLX->Core.pReader, &uBuf, cbToRead, pModLX->Hdr.e32_debuginfo);
1518 if (RT_SUCCESS(rc))
1519 rc = rtldrLx_EnumDbgInfoHelper(pModLX, pfnCallback, pvUser, &uBuf.ab[0], cbToRead, pModLX->Hdr.e32_debuginfo, &fReturn);
1520
1521 /* If that didn't yield anything, try displaying it by the header offset. */
1522 if (!fReturn && pModLX->offHdr > 0)
1523 {
1524 rc = pModLX->Core.pReader->pfnRead(pModLX->Core.pReader, &uBuf, cbToRead, pModLX->Hdr.e32_debuginfo + pModLX->offHdr);
1525 if (RT_SUCCESS(rc))
1526 rc = rtldrLx_EnumDbgInfoHelper(pModLX, pfnCallback, pvUser, &uBuf.ab[0], cbToRead,
1527 pModLX->Hdr.e32_debuginfo + pModLX->offHdr, &fReturn);
1528 }
1529 return rc;
1530}
1531
1532
1533static int kldrModLXHasDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits)
1534{
1535 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
1536 RT_NOREF(pvBits);
1537
1538 /*
1539 * Don't currently bother with linkers which doesn't advertise it in the header.
1540 */
1541 if ( !pModLX->Hdr.e32_debuginfo
1542 || !pModLX->Hdr.e32_debuglen)
1543 return VERR_NOT_FOUND;
1544 return VINF_SUCCESS;
1545}
1546
1547#if 0
1548
1549/** @copydoc kLdrModMap */
1550static int kldrModLXMap(PRTLDRMODINTERNAL pMod)
1551{
1552 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
1553 unsigned fFixed;
1554 void *pvBase;
1555 int rc;
1556
1557 /*
1558 * Already mapped?
1559 */
1560 if (pModLX->pvMapping)
1561 return KLDR_ERR_ALREADY_MAPPED;
1562
1563 /*
1564 * Allocate memory for it.
1565 */
1566 /* fixed image? */
1567 fFixed = pModLX->Core.enmType == RTLDRTYPE_EXECUTABLE_FIXED
1568 || pModLX->Core.enmType == RTLDRTYPE_SHARED_LIBRARY_FIXED;
1569 if (!fFixed)
1570 pvBase = NULL;
1571 else
1572 {
1573 pvBase = (void *)(uintptr_t)pModLX->aSegments[0].LinkAddress;
1574 if ((uintptr_t)pvBase != pModLX->aSegments[0].LinkAddress)
1575 return KLDR_ERR_ADDRESS_OVERFLOW;
1576 }
1577 rc = kHlpPageAlloc(&pvBase, pModLX->cbMapped, KPROT_EXECUTE_READWRITE, fFixed);
1578 if (RT_FAILURE(rc))
1579 return rc;
1580
1581 /*
1582 * Load the bits, apply page protection, and update the segment table.
1583 */
1584 rc = kldrModLXDoLoadBits(pModLX, pvBase);
1585 if (RT_SUCCESS(rc))
1586 rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
1587 if (RT_SUCCESS(rc))
1588 {
1589 uint32_t i;
1590 for (i = 0; i < pModLX->cSegments; i++)
1591 {
1592 if (pModLX->aSegments[i].RVA != NIL_RTLDRADDR)
1593 pModLX->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pModLX->aSegments[i].RVA;
1594 }
1595 pModLX->pvMapping = pvBase;
1596 }
1597 else
1598 kHlpPageFree(pvBase, pModLX->cbMapped);
1599 return rc;
1600}
1601
1602#endif
1603
1604/**
1605 * Loads the LX pages into the specified memory mapping.
1606 *
1607 * @returns IPRT status code.
1608 *
1609 * @param pModLX The LX module interpreter instance.
1610 * @param pvBits Where to load the bits.
1611 */
1612static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
1613{
1614 const PRTLDRREADER pRdr = pModLX->Core.pReader;
1615 uint8_t *pbTmpPage = NULL;
1616 int rc = VINF_SUCCESS;
1617 uint32_t i;
1618
1619 /*
1620 * Iterate the segments.
1621 */
1622 for (i = 0; i < pModLX->Hdr.e32_objcnt; i++)
1623 {
1624 const struct o32_obj * const pObj = &pModLX->paObjs[i];
1625 const uint32_t cPages = (uint32_t)(pModLX->aSegments[i].cbMapped / OBJPAGELEN);
1626 uint32_t iPage;
1627 uint8_t *pbPage = (uint8_t *)pvBits + (uintptr_t)pModLX->aSegments[i].RVA;
1628
1629 /*
1630 * Iterate the page map pages.
1631 */
1632 for (iPage = 0; RT_SUCCESS(rc) && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN)
1633 {
1634 const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1];
1635 switch (pMap->o32_pageflags)
1636 {
1637 case VALID:
1638 if (pMap->o32_pagesize == OBJPAGELEN)
1639 rc = pRdr->pfnRead(pRdr, pbPage, OBJPAGELEN,
1640 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1641 else if (pMap->o32_pagesize < OBJPAGELEN)
1642 {
1643 rc = pRdr->pfnRead(pRdr, pbPage, pMap->o32_pagesize,
1644 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1645 memset(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize);
1646 }
1647 else
1648 rc = VERR_LDRLX_BAD_PAGE_MAP;
1649 break;
1650
1651 case ITERDATA:
1652 case ITERDATA2:
1653 /* make sure we've got a temp page .*/
1654 if (!pbTmpPage)
1655 {
1656 pbTmpPage = (uint8_t *)RTMemAlloc(OBJPAGELEN + 256);
1657 if (!pbTmpPage)
1658 break;
1659 }
1660 /* validate the size. */
1661 if (pMap->o32_pagesize > OBJPAGELEN + 252)
1662 {
1663 rc = VERR_LDRLX_BAD_PAGE_MAP;
1664 break;
1665 }
1666
1667 /* read it and ensure 4 extra zero bytes. */
1668 rc = pRdr->pfnRead(pRdr, pbTmpPage, pMap->o32_pagesize,
1669 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1670 if (RT_FAILURE(rc))
1671 break;
1672 memset(pbTmpPage + pMap->o32_pagesize, 0, 4);
1673
1674 /* unpack it into the image page. */
1675 if (pMap->o32_pageflags == ITERDATA2)
1676 rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1677 else
1678 rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1679 break;
1680
1681 case INVALID: /* we're probably not dealing correctly with INVALID pages... */
1682 case ZEROED:
1683 memset(pbPage, 0, OBJPAGELEN);
1684 break;
1685
1686 case RANGE:
1687 KLDRMODLX_ASSERT(!"RANGE");
1688 RT_FALL_THRU();
1689 default:
1690 rc = VERR_LDRLX_BAD_PAGE_MAP;
1691 break;
1692 }
1693 }
1694 if (RT_FAILURE(rc))
1695 break;
1696
1697 /*
1698 * Zero the remaining pages.
1699 */
1700 if (iPage < cPages)
1701 memset(pbPage, 0, (cPages - iPage) * OBJPAGELEN);
1702 }
1703
1704 if (pbTmpPage)
1705 RTMemFree(pbTmpPage);
1706 return rc;
1707}
1708
1709
1710/**
1711 * Unpacks iterdata (aka EXEPACK).
1712 *
1713 * @returns IPRT status code.
1714 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1715 * @param pbSrc The compressed source data.
1716 * @param cbSrc The file size of the compressed data. The source buffer
1717 * contains 4 additional zero bytes.
1718 */
1719static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1720{
1721 const struct LX_Iter *pIter = (const struct LX_Iter *)pbSrc;
1722 int cbDst = OBJPAGELEN;
1723
1724 /* Validate size of data. */
1725 if (cbSrc >= (int)OBJPAGELEN - 2)
1726 return VERR_LDRLX_BAD_ITERDATA;
1727
1728 /*
1729 * Expand the page.
1730 */
1731 while (cbSrc > 0 && pIter->LX_nIter)
1732 {
1733 if (pIter->LX_nBytes == 1)
1734 {
1735 /*
1736 * Special case - one databyte.
1737 */
1738 cbDst -= pIter->LX_nIter;
1739 if (cbDst < 0)
1740 return VERR_LDRLX_BAD_ITERDATA;
1741
1742 cbSrc -= 4 + 1;
1743 if (cbSrc < -4)
1744 return VERR_LDRLX_BAD_ITERDATA;
1745
1746 memset(pbDst, pIter->LX_Iterdata, pIter->LX_nIter);
1747 pbDst += pIter->LX_nIter;
1748 pIter++;
1749 }
1750 else
1751 {
1752 /*
1753 * General.
1754 */
1755 int i;
1756
1757 cbDst -= pIter->LX_nIter * pIter->LX_nBytes;
1758 if (cbDst < 0)
1759 return VERR_LDRLX_BAD_ITERDATA;
1760
1761 cbSrc -= 4 + pIter->LX_nBytes;
1762 if (cbSrc < -4)
1763 return VERR_LDRLX_BAD_ITERDATA;
1764
1765 for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes)
1766 memcpy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes);
1767 pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
1768 }
1769 }
1770
1771 /*
1772 * Zero remainder of the page.
1773 */
1774 if (cbDst > 0)
1775 memset(pbDst, 0, cbDst);
1776
1777 return VINF_SUCCESS;
1778}
1779
1780
1781/**
1782 * Unpacks iterdata (aka EXEPACK).
1783 *
1784 * @returns IPRT status code.
1785 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1786 * @param pbSrc The compressed source data.
1787 * @param cbSrc The file size of the compressed data. The source buffer
1788 * contains 4 additional zero bytes.
1789 */
1790static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1791{
1792 int cbDst = OBJPAGELEN;
1793
1794 while (cbSrc > 0)
1795 {
1796 /*
1797 * Bit 0 and 1 is the encoding type.
1798 */
1799 switch (*pbSrc & 0x03)
1800 {
1801 /*
1802 *
1803 * 0 1 2 3 4 5 6 7
1804 * type | |
1805 * ----------------
1806 * cb <cb bytes of data>
1807 *
1808 * Bits 2-7 is, if not zero, the length of an uncompressed run
1809 * starting at the following byte.
1810 *
1811 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1812 * type | | | | | |
1813 * ---------------- ---------------------- -----------------------
1814 * zero cb char to multiply
1815 *
1816 * If the bits are zero, the following two bytes describes a 1 byte interation
1817 * run. First byte is count, second is the byte to copy. A count of zero is
1818 * means end of data, and we simply stops. In that case the rest of the data
1819 * should be zero.
1820 */
1821 case 0:
1822 {
1823 if (*pbSrc)
1824 {
1825 const int cb = *pbSrc >> 2;
1826 cbDst -= cb;
1827 if (cbDst < 0)
1828 return VERR_LDRLX_BAD_ITERDATA2;
1829 cbSrc -= cb + 1;
1830 if (cbSrc < 0)
1831 return VERR_LDRLX_BAD_ITERDATA2;
1832 memcpy(pbDst, ++pbSrc, cb);
1833 pbDst += cb;
1834 pbSrc += cb;
1835 }
1836 else if (cbSrc < 2)
1837 return VERR_LDRLX_BAD_ITERDATA2;
1838 else
1839 {
1840 const int cb = pbSrc[1];
1841 if (!cb)
1842 goto l_endloop;
1843 cbDst -= cb;
1844 if (cbDst < 0)
1845 return VERR_LDRLX_BAD_ITERDATA2;
1846 cbSrc -= 3;
1847 if (cbSrc < 0)
1848 return VERR_LDRLX_BAD_ITERDATA2;
1849 memset(pbDst, pbSrc[2], cb);
1850 pbDst += cb;
1851 pbSrc += 3;
1852 }
1853 break;
1854 }
1855
1856
1857 /*
1858 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1859 * type | | | | | |
1860 * ---- ------- -------------------------
1861 * cb1 cb2 - 3 offset <cb1 bytes of data>
1862 *
1863 * Two bytes layed out as described above, followed by cb1 bytes of data to be copied.
1864 * The cb2(+3) and offset describes an amount of data to be copied from the expanded
1865 * data relative to the current position. The data copied as you would expect it to be.
1866 */
1867 case 1:
1868 {
1869 cbSrc -= 2;
1870 if (cbSrc < 0)
1871 return VERR_LDRLX_BAD_ITERDATA2;
1872 else
1873 {
1874 const unsigned off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7);
1875 const int cb1 = (*pbSrc >> 2) & 3;
1876 const int cb2 = ((*pbSrc >> 4) & 7) + 3;
1877
1878 pbSrc += 2;
1879 cbSrc -= cb1;
1880 if (cbSrc < 0)
1881 return VERR_LDRLX_BAD_ITERDATA2;
1882 cbDst -= cb1;
1883 if (cbDst < 0)
1884 return VERR_LDRLX_BAD_ITERDATA2;
1885 memcpy(pbDst, pbSrc, cb1);
1886 pbDst += cb1;
1887 pbSrc += cb1;
1888
1889 if (off > OBJPAGELEN - (unsigned)cbDst)
1890 return VERR_LDRLX_BAD_ITERDATA2;
1891 cbDst -= cb2;
1892 if (cbDst < 0)
1893 return VERR_LDRLX_BAD_ITERDATA2;
1894 memmove(pbDst, pbDst - off, cb2);
1895 pbDst += cb2;
1896 }
1897 break;
1898 }
1899
1900
1901 /*
1902 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1903 * type | | | |
1904 * ---- ----------------------------------
1905 * cb-3 offset
1906 *
1907 * Two bytes layed out as described above.
1908 * The cb(+3) and offset describes an amount of data to be copied from the expanded
1909 * data relative to the current position.
1910 *
1911 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1912 */
1913 case 2:
1914 {
1915 cbSrc -= 2;
1916 if (cbSrc < 0)
1917 return VERR_LDRLX_BAD_ITERDATA2;
1918 else
1919 {
1920 const unsigned off = ((unsigned)pbSrc[1] << 4) | (*pbSrc >> 4);
1921 const int cb = ((*pbSrc >> 2) & 3) + 3;
1922
1923 pbSrc += 2;
1924 if (off > OBJPAGELEN - (unsigned)cbDst)
1925 return VERR_LDRLX_BAD_ITERDATA2;
1926 cbDst -= cb;
1927 if (cbDst < 0)
1928 return VERR_LDRLX_BAD_ITERDATA2;
1929 kLdrModLXMemCopyW(pbDst, pbDst - off, cb);
1930 pbDst += cb;
1931 }
1932 break;
1933 }
1934
1935
1936 /*
1937 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1938 * type | | | | | |
1939 * ---------- ---------------- ----------------------------------
1940 * cb1 cb2 offset <cb1 bytes of data>
1941 *
1942 * Three bytes layed out as described above, followed by cb1 bytes of data to be copied.
1943 * The cb2 and offset describes an amount of data to be copied from the expanded
1944 * data relative to the current position.
1945 *
1946 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1947 */
1948 case 3:
1949 {
1950 cbSrc -= 3;
1951 if (cbSrc < 0)
1952 return VERR_LDRLX_BAD_ITERDATA2;
1953 else
1954 {
1955 const int cb1 = (*pbSrc >> 2) & 0xf;
1956 const int cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6);
1957 const unsigned off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4);
1958
1959 pbSrc += 3;
1960 cbSrc -= cb1;
1961 if (cbSrc < 0)
1962 return VERR_LDRLX_BAD_ITERDATA2;
1963 cbDst -= cb1;
1964 if (cbDst < 0)
1965 return VERR_LDRLX_BAD_ITERDATA2;
1966 memcpy(pbDst, pbSrc, cb1);
1967 pbDst += cb1;
1968 pbSrc += cb1;
1969
1970 if (off > OBJPAGELEN - (unsigned)cbDst)
1971 return VERR_LDRLX_BAD_ITERDATA2;
1972 cbDst -= cb2;
1973 if (cbDst < 0)
1974 return VERR_LDRLX_BAD_ITERDATA2;
1975 kLdrModLXMemCopyW(pbDst, pbDst - off, cb2);
1976 pbDst += cb2;
1977 }
1978 break;
1979 }
1980 } /* type switch. */
1981 } /* unpack loop */
1982
1983l_endloop:
1984
1985
1986 /*
1987 * Zero remainder of the page.
1988 */
1989 if (cbDst > 0)
1990 memset(pbDst, 0, cbDst);
1991
1992 return VINF_SUCCESS;
1993}
1994
1995
1996/**
1997 * Special memcpy employed by the iterdata2 algorithm.
1998 *
1999 * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this
2000 * has if src is very close to the destination.
2001 *
2002 * @param pbDst Destination pointer.
2003 * @param pbSrc Source pointer. Will always be <= pbDst.
2004 * @param cb Amount of data to be copied.
2005 * @remark This assumes that unaligned word and dword access is fine.
2006 */
2007static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb)
2008{
2009 switch (pbDst - pbSrc)
2010 {
2011 case 0:
2012 case 1:
2013 case 2:
2014 case 3:
2015 /* 16-bit copy (unaligned) */
2016 if (cb & 1)
2017 *pbDst++ = *pbSrc++;
2018 for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2)
2019 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
2020 break;
2021
2022 default:
2023 /* 32-bit copy (unaligned) */
2024 if (cb & 1)
2025 *pbDst++ = *pbSrc++;
2026 if (cb & 2)
2027 {
2028 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
2029 pbDst += 2;
2030 pbSrc += 2;
2031 }
2032 for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4)
2033 *(uint32_t *)pbDst = *(const uint32_t *)pbSrc;
2034 break;
2035 }
2036}
2037
2038#if 0
2039
2040/**
2041 * Unprotects or protects the specified image mapping.
2042 *
2043 * @returns IPRT status code.
2044 *
2045 * @param pModLX The LX module interpreter instance.
2046 * @param pvBits The mapping to protect.
2047 * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise
2048 * protect according to the object table.
2049 */
2050static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect)
2051{
2052 uint32_t i;
2053
2054 /*
2055 * Change object protection.
2056 */
2057 for (i = 0; i < pModLX->cSegments; i++)
2058 {
2059 int rc;
2060 void *pv;
2061 KPROT enmProt;
2062
2063 /* calc new protection. */
2064 enmProt = pModLX->aSegments[i].enmProt;
2065 if (fUnprotectOrProtect)
2066 {
2067 switch (enmProt)
2068 {
2069 case KPROT_NOACCESS:
2070 case KPROT_READONLY:
2071 case KPROT_READWRITE:
2072 case KPROT_WRITECOPY:
2073 enmProt = KPROT_READWRITE;
2074 break;
2075 case KPROT_EXECUTE:
2076 case KPROT_EXECUTE_READ:
2077 case KPROT_EXECUTE_READWRITE:
2078 case KPROT_EXECUTE_WRITECOPY:
2079 enmProt = KPROT_EXECUTE_READWRITE;
2080 break;
2081 default:
2082 KLDRMODLX_ASSERT(!"bad enmProt");
2083 return -1;
2084 }
2085 }
2086 else
2087 {
2088 /* copy on write -> normal write. */
2089 if (enmProt == KPROT_EXECUTE_WRITECOPY)
2090 enmProt = KPROT_EXECUTE_READWRITE;
2091 else if (enmProt == KPROT_WRITECOPY)
2092 enmProt = KPROT_READWRITE;
2093 }
2094
2095
2096 /* calc the address and set page protection. */
2097 pv = (uint8_t *)pvBits + pModLX->aSegments[i].RVA;
2098
2099 rc = kHlpPageProtect(pv, pModLX->aSegments[i].cbMapped, enmProt);
2100 if (RT_FAILURE(rc))
2101 break;
2102
2103 /** @todo the gap page should be marked NOACCESS! */
2104 }
2105
2106 return VINF_SUCCESS;
2107}
2108
2109
2110/** @copydoc kLdrModUnmap */
2111static int kldrModLXUnmap(PRTLDRMODINTERNAL pMod)
2112{
2113 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2114 uint32_t i;
2115 int rc;
2116
2117 /*
2118 * Mapped?
2119 */
2120 if (!pModLX->pvMapping)
2121 return KLDR_ERR_NOT_MAPPED;
2122
2123 /*
2124 * Free the mapping and update the segments.
2125 */
2126 rc = kHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
2127 KLDRMODLX_ASSERT(!rc);
2128 pModLX->pvMapping = NULL;
2129
2130 for (i = 0; i < pModLX->cSegments; i++)
2131 pModLX->aSegments[i].MapAddress = 0;
2132
2133 return rc;
2134}
2135
2136
2137/** @copydoc kLdrModAllocTLS */
2138static int kldrModLXAllocTLS(PRTLDRMODINTERNAL pMod, void *pvMapping)
2139{
2140 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2141
2142 /* no tls, just do the error checking. */
2143 if ( pvMapping == KLDRMOD_INT_MAP
2144 && pModLX->pvMapping)
2145 return KLDR_ERR_NOT_MAPPED;
2146 return VINF_SUCCESS;
2147}
2148
2149
2150/** @copydoc kLdrModFreeTLS */
2151static void kldrModLXFreeTLS(PRTLDRMODINTERNAL pMod, void *pvMapping)
2152{
2153 /* no tls. */
2154 RT_NOREF(pMod);
2155 RT_NOREF(pvMapping);
2156
2157}
2158
2159
2160/** @copydoc kLdrModReload */
2161static int kldrModLXReload(PRTLDRMODINTERNAL pMod)
2162{
2163 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2164 int rc, rc2;
2165
2166 /*
2167 * Mapped?
2168 */
2169 if (!pModLX->pvMapping)
2170 return KLDR_ERR_NOT_MAPPED;
2171
2172 /*
2173 * Before doing anything we'll have to make all pages writable.
2174 */
2175 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
2176 if (RT_FAILURE(rc))
2177 return rc;
2178
2179 /*
2180 * Load the bits again.
2181 */
2182 rc = kldrModLXDoLoadBits(pModLX, (void *)pModLX->pvMapping);
2183
2184 /*
2185 * Restore protection.
2186 */
2187 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
2188 if (RT_SUCCESS(rc) && RT_FAILURE(rc2))
2189 rc = rc2;
2190 return rc;
2191}
2192
2193
2194/** @copydoc kLdrModFixupMapping */
2195static int kldrModLXFixupMapping(PRTLDRMODINTERNAL pMod, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
2196{
2197 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2198 int rc, rc2;
2199
2200 /*
2201 * Mapped?
2202 */
2203 if (!pModLX->pvMapping)
2204 return KLDR_ERR_NOT_MAPPED;
2205
2206 /*
2207 * Before doing anything we'll have to make all pages writable.
2208 */
2209 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
2210 if (RT_FAILURE(rc))
2211 return rc;
2212
2213 /*
2214 * Apply fixups and resolve imports.
2215 */
2216 rc = rtldrLX_RelocateBits(pMod, (void *)pModLX->pvMapping, (uintptr_t)pModLX->pvMapping,
2217 pModLX->aSegments[0].LinkAddress, pfnGetImport, pvUser);
2218
2219 /*
2220 * Restore protection.
2221 */
2222 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
2223 if (RT_SUCCESS(rc) && RT_FAILURE(rc2))
2224 rc = rc2;
2225 return rc;
2226}
2227
2228
2229/** @copydoc kLdrModCallInit */
2230static int kldrModLXCallInit(PRTLDRMODINTERNAL pMod, void *pvMapping, uintptr_t uHandle)
2231{
2232 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2233 int rc;
2234
2235 /*
2236 * Mapped?
2237 */
2238 if (pvMapping == KLDRMOD_INT_MAP)
2239 {
2240 pvMapping = (void *)pModLX->pvMapping;
2241 if (!pvMapping)
2242 return KLDR_ERR_NOT_MAPPED;
2243 }
2244
2245 /*
2246 * Do TLS callbacks first and then call the init/term function if it's a DLL.
2247 */
2248 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
2249 rc = kldrModLXDoCallDLL(pModLX, pvMapping, 0 /* attach */, uHandle);
2250 else
2251 rc = VINF_SUCCESS;
2252 return rc;
2253}
2254
2255
2256/**
2257 * Call the DLL entrypoint.
2258 *
2259 * @returns 0 on success.
2260 * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
2261 * @param pModLX The LX module interpreter instance.
2262 * @param pvMapping The module mapping to use (resolved).
2263 * @param uOp The operation (DLL_*).
2264 * @param uHandle The module handle to present.
2265 */
2266static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, uintptr_t uHandle)
2267{
2268 int rc;
2269
2270 /*
2271 * If no entrypoint there isn't anything to be done.
2272 */
2273 if ( !pModLX->Hdr.e32_startobj
2274 || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
2275 return VINF_SUCCESS;
2276
2277 /*
2278 * Invoke the entrypoint and convert the boolean result to a kLdr status code.
2279 */
2280 rc = kldrModLXDoCall((uintptr_t)pvMapping
2281 + (uintptr_t)pModLX->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
2282 + pModLX->Hdr.e32_eip,
2283 uHandle, uOp, NULL);
2284 if (rc)
2285 rc = VINF_SUCCESS;
2286 else if (uOp == 0 /* attach */)
2287 rc = KLDR_ERR_MODULE_INIT_FAILED;
2288 else /* detach: ignore failures */
2289 rc = VINF_SUCCESS;
2290 return rc;
2291}
2292
2293
2294/**
2295 * Do a 3 parameter callback.
2296 *
2297 * @returns 32-bit callback return.
2298 * @param uEntrypoint The address of the function to be called.
2299 * @param uHandle The first argument, the module handle.
2300 * @param uOp The second argumnet, the reason we're calling.
2301 * @param pvReserved The third argument, reserved argument. (figure this one out)
2302 */
2303static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved)
2304{
2305#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
2306 int32_t rc;
2307/** @todo try/except */
2308
2309 /*
2310 * Paranoia.
2311 */
2312# ifdef __GNUC__
2313 __asm__ __volatile__(
2314 "pushl %2\n\t"
2315 "pushl %1\n\t"
2316 "pushl %0\n\t"
2317 "lea 12(%%esp), %2\n\t"
2318 "call *%3\n\t"
2319 "movl %2, %%esp\n\t"
2320 : "=a" (rc)
2321 : "d" (uOp),
2322 "S" (0),
2323 "c" (uEntrypoint),
2324 "0" (uHandle));
2325# elif defined(_MSC_VER)
2326 __asm {
2327 mov eax, [uHandle]
2328 mov edx, [uOp]
2329 mov ecx, 0
2330 mov ebx, [uEntrypoint]
2331 push edi
2332 mov edi, esp
2333 push ecx
2334 push edx
2335 push eax
2336 call ebx
2337 mov esp, edi
2338 pop edi
2339 mov [rc], eax
2340 }
2341# else
2342# error "port me!"
2343# endif
2344 RT_NOREF(pvReserved);
2345 return rc;
2346
2347#else
2348 RT_NOREF(uEntrypoint);
2349 RT_NOREF(uHandle);
2350 RT_NOREF(uOp);
2351 RT_NOREF(pvReserved);
2352 return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
2353#endif
2354}
2355
2356
2357/** @copydoc kLdrModCallTerm */
2358static int kldrModLXCallTerm(PRTLDRMODINTERNAL pMod, void *pvMapping, uintptr_t uHandle)
2359{
2360 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2361
2362 /*
2363 * Mapped?
2364 */
2365 if (pvMapping == KLDRMOD_INT_MAP)
2366 {
2367 pvMapping = (void *)pModLX->pvMapping;
2368 if (!pvMapping)
2369 return KLDR_ERR_NOT_MAPPED;
2370 }
2371
2372 /*
2373 * Do the call.
2374 */
2375 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
2376 kldrModLXDoCallDLL(pModLX, pvMapping, 1 /* detach */, uHandle);
2377
2378 return VINF_SUCCESS;
2379}
2380
2381
2382/** @copydoc kLdrModCallThread */
2383static int kldrModLXCallThread(PRTLDRMODINTERNAL pMod, void *pvMapping, uintptr_t uHandle, unsigned fAttachingOrDetaching)
2384{
2385 /* no thread attach/detach callout. */
2386 RT_NOREF(pMod);
2387 RT_NOREF(pvMapping);
2388 RT_NOREF(uHandle);
2389 RT_NOREF(fAttachingOrDetaching);
2390 return VINF_SUCCESS;
2391}
2392
2393#endif
2394
2395/**
2396 * @interface_method_impl{RTLDROPS,pfnGetImageSize}
2397 */
2398static DECLCALLBACK(size_t) rtldrLX_GetImageSize(PRTLDRMODINTERNAL pMod)
2399{
2400 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2401 return pModLX->cbMapped;
2402}
2403
2404
2405/**
2406 * @interface_method_impl{RTLDROPS,pfnGetBits}
2407 */
2408static DECLCALLBACK(int) rtldrLX_GetBits(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR BaseAddress,
2409 PFNRTLDRIMPORT pfnGetImport, void *pvUser)
2410{
2411 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2412
2413 /*
2414 * Load the image bits.
2415 */
2416 int rc = kldrModLXDoLoadBits(pModLX, pvBits);
2417 if (RT_SUCCESS(rc))
2418 {
2419 /*
2420 * Perform relocations.
2421 */
2422 rc = rtldrLX_RelocateBits(pMod, pvBits, BaseAddress, pModLX->aSegments[0].LinkAddress, pfnGetImport, pvUser);
2423 }
2424 return rc;
2425}
2426
2427
2428/* GCC goes boinkers if we put this inside the function. */
2429union RELOC_VISIBILITY_STUPIDITY
2430{
2431 const uint8_t *pb;
2432 const struct r32_rlc *prlc;
2433};
2434
2435/**
2436 * @interface_method_impl{RTLDROPS,pfnRelocate}
2437 */
2438static DECLCALLBACK(int) rtldrLX_RelocateBits(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress,
2439 RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
2440{
2441 PKLDRMODLX pModLX = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2442 uint32_t iSeg;
2443 int rc;
2444
2445 /*
2446 * Do we need to to *anything*?
2447 */
2448 if ( NewBaseAddress == OldBaseAddress
2449 && NewBaseAddress == pModLX->paObjs[0].o32_base
2450 && !pModLX->Hdr.e32_impmodcnt)
2451 return VINF_SUCCESS;
2452
2453 /*
2454 * Load the fixup section.
2455 */
2456 if (!pModLX->pbFixupSection)
2457 {
2458 rc = kldrModLXDoLoadFixupSection(pModLX);
2459 if (RT_FAILURE(rc))
2460 return rc;
2461 }
2462
2463 /*
2464 * Iterate the segments.
2465 */
2466 for (iSeg = 0; iSeg < pModLX->Hdr.e32_objcnt; iSeg++)
2467 {
2468 const struct o32_obj * const pObj = &pModLX->paObjs[iSeg];
2469 RTLDRADDR PageAddress = NewBaseAddress + pModLX->aSegments[iSeg].RVA;
2470 uint32_t iPage;
2471 uint8_t *pbPage = (uint8_t *)pvBits + (uintptr_t)pModLX->aSegments[iSeg].RVA;
2472
2473 /*
2474 * Iterate the page map pages.
2475 */
2476 for (iPage = 0, rc = VINF_SUCCESS;
2477 RT_SUCCESS(rc) && iPage < pObj->o32_mapsize;
2478 iPage++, pbPage += OBJPAGELEN, PageAddress += OBJPAGELEN)
2479 {
2480 const uint8_t * const pbFixupRecEnd = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap];
2481 const uint8_t *pb = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap - 1];
2482 RTLDRADDR uValue = NIL_RTLDRADDR;
2483 uint32_t fKind = 0;
2484 int iSelector;
2485
2486 /* sanity */
2487 if (pbFixupRecEnd < pb)
2488 return VERR_LDR_BAD_FIXUP;
2489 if (pbFixupRecEnd - 1 > pModLX->pbFixupSectionLast)
2490 return VERR_LDR_BAD_FIXUP;
2491 if (pb < pModLX->pbFixupSection)
2492 return VERR_LDR_BAD_FIXUP;
2493
2494 /*
2495 * Iterate the fixup record.
2496 */
2497 while (pb < pbFixupRecEnd)
2498 {
2499 union RELOC_VISIBILITY_STUPIDITY u;
2500 char szImpModule[256];
2501 u.pb = pb;
2502 pb += 3 + (u.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */
2503
2504 /*
2505 * Figure out the target.
2506 */
2507 switch (u.prlc->nr_flags & NRRTYP)
2508 {
2509 /*
2510 * Internal fixup.
2511 */
2512 case NRRINT:
2513 {
2514 uint16_t iTrgObject;
2515 uint32_t offTrgObject;
2516
2517 /* the object */
2518 if (u.prlc->nr_flags & NR16OBJMOD)
2519 {
2520 iTrgObject = *(const uint16_t *)pb;
2521 pb += 2;
2522 }
2523 else
2524 iTrgObject = *pb++;
2525 iTrgObject--;
2526 if (iTrgObject >= pModLX->Hdr.e32_objcnt)
2527 return VERR_LDR_BAD_FIXUP;
2528
2529 /* the target */
2530 if ((u.prlc->nr_stype & NRSRCMASK) != NRSSEG)
2531 {
2532 if (u.prlc->nr_flags & NR32BITOFF)
2533 {
2534 offTrgObject = *(const uint32_t *)pb;
2535 pb += 4;
2536 }
2537 else
2538 {
2539 offTrgObject = *(const uint16_t *)pb;
2540 pb += 2;
2541 }
2542
2543 /* calculate the symbol info. */
2544 uValue = offTrgObject + NewBaseAddress + pModLX->aSegments[iTrgObject].RVA;
2545 }
2546 else
2547 uValue = NewBaseAddress + pModLX->aSegments[iTrgObject].RVA;
2548 if ( (u.prlc->nr_stype & NRALIAS)
2549 || (pModLX->aSegments[iTrgObject].fFlags & RTLDRSEG_FLAG_16BIT))
2550 iSelector = pModLX->aSegments[iTrgObject].Sel16bit;
2551 else
2552 iSelector = pModLX->aSegments[iTrgObject].SelFlat;
2553 fKind = 0;
2554 break;
2555 }
2556
2557 /*
2558 * Import by symbol ordinal.
2559 */
2560 case NRRORD:
2561 {
2562 uint16_t iModule;
2563 uint32_t iSymbol;
2564
2565 /* the module ordinal */
2566 if (u.prlc->nr_flags & NR16OBJMOD)
2567 {
2568 iModule = *(const uint16_t *)pb;
2569 pb += 2;
2570 }
2571 else
2572 iModule = *pb++;
2573 iModule--;
2574 if (iModule >= pModLX->Hdr.e32_impmodcnt)
2575 return VERR_LDR_BAD_FIXUP;
2576 rc = kldrModLXGetImport(pModLX, NULL, iModule, szImpModule, sizeof(szImpModule), NULL);
2577 if (RT_FAILURE(rc))
2578 return rc;
2579
2580#if 1
2581 if (u.prlc->nr_flags & NRICHAIN)
2582 return VERR_LDR_BAD_FIXUP;
2583#endif
2584
2585 /* . */
2586 if (u.prlc->nr_flags & NR32BITOFF)
2587 {
2588 iSymbol = *(const uint32_t *)pb;
2589 pb += 4;
2590 }
2591 else if (!(u.prlc->nr_flags & NR8BITORD))
2592 {
2593 iSymbol = *(const uint16_t *)pb;
2594 pb += 2;
2595 }
2596 else
2597 iSymbol = *pb++;
2598
2599 /* resolve it. */
2600 rc = pfnGetImport(pMod, szImpModule, NULL, iSymbol, &uValue, /*&fKind,*/ pvUser);
2601 if (RT_FAILURE(rc))
2602 return rc;
2603 iSelector = -1;
2604 break;
2605 }
2606
2607 /*
2608 * Import by symbol name.
2609 */
2610 case NRRNAM:
2611 {
2612 uint32_t iModule;
2613 uint16_t offSymbol;
2614 const uint8_t *pbSymbol;
2615
2616 /* the module ordinal */
2617 if (u.prlc->nr_flags & NR16OBJMOD)
2618 {
2619 iModule = *(const uint16_t *)pb;
2620 pb += 2;
2621 }
2622 else
2623 iModule = *pb++;
2624 iModule--;
2625 if (iModule >= pModLX->Hdr.e32_impmodcnt)
2626 return VERR_LDR_BAD_FIXUP;
2627 rc = kldrModLXGetImport(pModLX, NULL, iModule, szImpModule, sizeof(szImpModule), NULL);
2628 if (RT_FAILURE(rc))
2629 return rc;
2630#if 1
2631 if (u.prlc->nr_flags & NRICHAIN)
2632 return VERR_LDR_BAD_FIXUP;
2633#endif
2634
2635 /* . */
2636 if (u.prlc->nr_flags & NR32BITOFF)
2637 {
2638 offSymbol = *(const uint32_t *)pb;
2639 pb += 4;
2640 }
2641 else if (!(u.prlc->nr_flags & NR8BITORD))
2642 {
2643 offSymbol = *(const uint16_t *)pb;
2644 pb += 2;
2645 }
2646 else
2647 offSymbol = *pb++;
2648 pbSymbol = pModLX->pbImportProcs + offSymbol;
2649 if ( pbSymbol < pModLX->pbImportProcs
2650 || pbSymbol > pModLX->pbFixupSectionLast)
2651 return VERR_LDR_BAD_FIXUP;
2652 char szSymbol[256];
2653 memcpy(szSymbol, pbSymbol + 1, *pbSymbol);
2654 szSymbol[*pbSymbol] = '\0';
2655
2656 /* resolve it. */
2657 rc = pfnGetImport(pMod, szImpModule, szSymbol, UINT32_MAX, &uValue, /*&fKind,*/ pvUser);
2658 if (RT_FAILURE(rc))
2659 return rc;
2660 iSelector = -1;
2661 break;
2662 }
2663
2664 case NRRENT:
2665 KLDRMODLX_ASSERT(!"NRRENT");
2666 RT_FALL_THRU();
2667 default:
2668 iSelector = -1;
2669 break;
2670 }
2671
2672 /* addend */
2673 if (u.prlc->nr_flags & NRADD)
2674 {
2675 if (u.prlc->nr_flags & NR32BITADD)
2676 {
2677 uValue += *(const uint32_t *)pb;
2678 pb += 4;
2679 }
2680 else
2681 {
2682 uValue += *(const uint16_t *)pb;
2683 pb += 2;
2684 }
2685 }
2686
2687
2688 /*
2689 * Deal with the 'source' (i.e. the place that should be modified - very logical).
2690 */
2691 if (!(u.prlc->nr_stype & NRCHAIN))
2692 {
2693 int off = u.prlc->r32_soff;
2694
2695 /* common / simple */
2696 if ( (u.prlc->nr_stype & NRSRCMASK) == NROFF32
2697 && off >= 0
2698 && off <= (int)OBJPAGELEN - 4)
2699 *(uint32_t *)&pbPage[off] = (uint32_t)uValue;
2700 else if ( (u.prlc->nr_stype & NRSRCMASK) == NRSOFF32
2701 && off >= 0
2702 && off <= (int)OBJPAGELEN - 4)
2703 *(uint32_t *)&pbPage[off] = (uint32_t)(uValue - (PageAddress + off + 4));
2704 else
2705 {
2706 /* generic */
2707 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2708 if (RT_FAILURE(rc))
2709 return rc;
2710 }
2711 }
2712 else if (!(u.prlc->nr_flags & NRICHAIN))
2713 {
2714 const int16_t *poffSrc = (const int16_t *)pb;
2715 uint8_t c = u.pb[2];
2716
2717 /* common / simple */
2718 if ((u.prlc->nr_stype & NRSRCMASK) == NROFF32)
2719 {
2720 while (c-- > 0)
2721 {
2722 int off = *poffSrc++;
2723 if (off >= 0 && off <= (int)OBJPAGELEN - 4)
2724 *(uint32_t *)&pbPage[off] = (uint32_t)uValue;
2725 else
2726 {
2727 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2728 if (RT_FAILURE(rc))
2729 return rc;
2730 }
2731 }
2732 }
2733 else if ((u.prlc->nr_stype & NRSRCMASK) == NRSOFF32)
2734 {
2735 while (c-- > 0)
2736 {
2737 int off = *poffSrc++;
2738 if (off >= 0 && off <= (int)OBJPAGELEN - 4)
2739 *(uint32_t *)&pbPage[off] = (uint32_t)(uValue - (PageAddress + off + 4));
2740 else
2741 {
2742 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2743 if (RT_FAILURE(rc))
2744 return rc;
2745 }
2746 }
2747 }
2748 else
2749 {
2750 while (c-- > 0)
2751 {
2752 rc = kldrModLXDoReloc(pbPage, *poffSrc++, PageAddress, u.prlc, iSelector, uValue, fKind);
2753 if (RT_FAILURE(rc))
2754 return rc;
2755 }
2756 }
2757 pb = (const uint8_t *)poffSrc;
2758 }
2759 else
2760 {
2761 /* This is a pain because it will require virgin pages on a relocation. */
2762 KLDRMODLX_ASSERT(!"NRICHAIN");
2763 return VERR_LDRLX_NRICHAIN_NOT_SUPPORTED;
2764 }
2765 }
2766 }
2767 }
2768
2769 return VINF_SUCCESS;
2770}
2771
2772
2773/**
2774 * Applies the relocation to one 'source' in a page.
2775 *
2776 * This takes care of the more esotic case while the common cases
2777 * are dealt with seperately.
2778 *
2779 * @returns IPRT status code.
2780 * @param pbPage The page in which to apply the fixup.
2781 * @param off Page relative offset of where to apply the offset.
2782 * @param PageAddress The page address.
2783 * @param prlc The relocation record.
2784 * @param iSelector Selector value, -1 if flat.
2785 * @param uValue The target value.
2786 * @param fKind The target kind.
2787 */
2788static int kldrModLXDoReloc(uint8_t *pbPage, int off, RTLDRADDR PageAddress, const struct r32_rlc *prlc,
2789 int iSelector, RTLDRADDR uValue, uint32_t fKind)
2790{
2791#pragma pack(1) /* just to be sure */
2792 union
2793 {
2794 uint8_t ab[6];
2795 uint32_t off32;
2796 uint16_t off16;
2797 uint8_t off8;
2798 struct
2799 {
2800 uint16_t off;
2801 uint16_t Sel;
2802 } Far16;
2803 struct
2804 {
2805 uint32_t off;
2806 uint16_t Sel;
2807 } Far32;
2808 } uData;
2809#pragma pack()
2810 const uint8_t *pbSrc;
2811 uint8_t *pbDst;
2812 uint8_t cb;
2813
2814 RT_NOREF(fKind);
2815
2816 /*
2817 * Compose the fixup data.
2818 */
2819 switch (prlc->nr_stype & NRSRCMASK)
2820 {
2821 case NRSBYT:
2822 uData.off8 = (uint8_t)uValue;
2823 cb = 1;
2824 break;
2825 case NRSSEG:
2826 if (iSelector == -1)
2827 {
2828 /* fixme */
2829 }
2830 uData.off16 = iSelector;
2831 cb = 2;
2832 break;
2833 case NRSPTR:
2834 if (iSelector == -1)
2835 {
2836 /* fixme */
2837 }
2838 uData.Far16.off = (uint16_t)uValue;
2839 uData.Far16.Sel = iSelector;
2840 cb = 4;
2841 break;
2842 case NRSOFF:
2843 uData.off16 = (uint16_t)uValue;
2844 cb = 2;
2845 break;
2846 case NRPTR48:
2847 if (iSelector == -1)
2848 {
2849 /* fixme */
2850 }
2851 uData.Far32.off = (uint32_t)uValue;
2852 uData.Far32.Sel = iSelector;
2853 cb = 6;
2854 break;
2855 case NROFF32:
2856 uData.off32 = (uint32_t)uValue;
2857 cb = 4;
2858 break;
2859 case NRSOFF32:
2860 uData.off32 = (uint32_t)(uValue - (PageAddress + off + 4));
2861 cb = 4;
2862 break;
2863 default:
2864 return VERR_LDRLX_BAD_FIXUP_SECTION; /** @todo fix error, add more checks! */
2865 }
2866
2867 /*
2868 * Apply it. This is sloooow...
2869 */
2870 pbSrc = &uData.ab[0];
2871 pbDst = pbPage + off;
2872 while (cb-- > 0)
2873 {
2874 if (off > (int)OBJPAGELEN)
2875 break;
2876 if (off >= 0)
2877 *pbDst = *pbSrc;
2878 pbSrc++;
2879 pbDst++;
2880 }
2881
2882 return VINF_SUCCESS;
2883}
2884
2885
2886/**
2887 * @interface_method_impl{RTLDROPS,pfnEnumSegments}
2888 */
2889static DECLCALLBACK(int) rtldrLX_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
2890{
2891 PKLDRMODLX pThis = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2892 uint32_t const cSegments = pThis->cSegments;
2893 for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++)
2894 {
2895 int rc = pfnCallback(pMod, &pThis->aSegments[iSeg], pvUser);
2896 if (rc != VINF_SUCCESS)
2897 return rc;
2898 }
2899
2900 return VINF_SUCCESS;
2901}
2902
2903
2904/**
2905 * @interface_method_impl{RTLDROPS,pfnLinkAddressToSegOffset}
2906 */
2907static DECLCALLBACK(int) rtldrLX_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
2908 uint32_t *piSeg, PRTLDRADDR poffSeg)
2909{
2910 PKLDRMODLX pThis = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2911 uint32_t const cSegments = pThis->cSegments;
2912 for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++)
2913 {
2914 RTLDRADDR offSeg = LinkAddress - pThis->aSegments[iSeg].LinkAddress;
2915 if ( offSeg < pThis->aSegments[iSeg].cbMapped
2916 || offSeg < pThis->aSegments[iSeg].cb)
2917 {
2918 *piSeg = iSeg;
2919 *poffSeg = offSeg;
2920 return VINF_SUCCESS;
2921 }
2922 }
2923
2924 return VERR_LDR_INVALID_LINK_ADDRESS;
2925}
2926
2927
2928/**
2929 * @interface_method_impl{RTLDROPS,pfnLinkAddressToRva}
2930 */
2931static DECLCALLBACK(int) rtldrLX_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
2932{
2933 PKLDRMODLX pThis = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2934 uint32_t const cSegments = pThis->cSegments;
2935 for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++)
2936 {
2937 RTLDRADDR offSeg = LinkAddress - pThis->aSegments[iSeg].LinkAddress;
2938 if ( offSeg < pThis->aSegments[iSeg].cbMapped
2939 || offSeg < pThis->aSegments[iSeg].cb)
2940 {
2941 *pRva = pThis->aSegments[iSeg].RVA + offSeg;
2942 return VINF_SUCCESS;
2943 }
2944 }
2945
2946 return VERR_LDR_INVALID_RVA;
2947}
2948
2949
2950/**
2951 * @interface_method_impl{RTLDROPS,pfnSegOffsetToRva}
2952 */
2953static DECLCALLBACK(int) rtldrLX_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg, PRTLDRADDR pRva)
2954{
2955 PKLDRMODLX pThis = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2956
2957 if (iSeg >= pThis->cSegments)
2958 return VERR_LDR_INVALID_SEG_OFFSET;
2959 PCRTLDRSEG pSegment = &pThis->aSegments[iSeg];
2960
2961 if ( offSeg > pSegment->cbMapped
2962 && offSeg > pSegment->cb
2963 && ( pSegment->cbFile < 0
2964 || offSeg > (uint64_t)pSegment->cbFile))
2965 return VERR_LDR_INVALID_SEG_OFFSET;
2966
2967 *pRva = pSegment->RVA + offSeg;
2968 return VINF_SUCCESS;
2969}
2970
2971
2972/**
2973 * @interface_method_impl{RTLDROPS,pfnRvaToSegOffset}
2974 */
2975static DECLCALLBACK(int) rtldrLX_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva, uint32_t *piSeg, PRTLDRADDR poffSeg)
2976{
2977 PKLDRMODLX pThis = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
2978 uint32_t const cSegments = pThis->cSegments;
2979 for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++)
2980 {
2981 RTLDRADDR offSeg = Rva - pThis->aSegments[iSeg].RVA;
2982 if ( offSeg < pThis->aSegments[iSeg].cbMapped
2983 || offSeg < pThis->aSegments[iSeg].cb)
2984 {
2985 *piSeg = iSeg;
2986 *poffSeg = offSeg;
2987 return VINF_SUCCESS;
2988 }
2989 }
2990
2991 return VERR_LDR_INVALID_RVA;
2992}
2993
2994
2995/**
2996 * @interface_method_impl{RTLDROPS,pfnReadDbgInfo}
2997 */
2998static DECLCALLBACK(int) rtldrLX_ReadDbgInfo(PRTLDRMODINTERNAL pMod, uint32_t iDbgInfo, RTFOFF off, size_t cb, void *pvBuf)
2999{
3000 PKLDRMODLX pThis = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
3001 RT_NOREF(iDbgInfo);
3002 return pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvBuf, cb, off);
3003}
3004
3005
3006/**
3007 * @interface_method_impl{RTLDROPS,pfnQueryProp}
3008 */
3009static DECLCALLBACK(int) rtldrLX_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void const *pvBits,
3010 void *pvBuf, size_t cbBuf, size_t *pcbRet)
3011{
3012 PKLDRMODLX pThis = RT_FROM_MEMBER(pMod, KLDRMODLX, Core);
3013 int rc;
3014 switch (enmProp)
3015 {
3016 case RTLDRPROP_IMPORT_COUNT:
3017 Assert(cbBuf == sizeof(uint32_t));
3018 Assert(*pcbRet == cbBuf);
3019 *(uint32_t *)pvBuf = pThis->Hdr.e32_impmodcnt;
3020 rc = VINF_SUCCESS;
3021 break;
3022
3023 case RTLDRPROP_IMPORT_MODULE:
3024 rc = kldrModLXGetImport(pThis, pvBits, *(uint32_t const *)pvBuf, (char *)pvBuf, cbBuf, pcbRet);
3025 break;
3026
3027 case RTLDRPROP_INTERNAL_NAME:
3028 *pcbRet = pThis->cchName + 1;
3029 if (cbBuf >= pThis->cchName + 1)
3030 {
3031 memcpy(pvBuf, pThis->pszName, pThis->cchName + 1);
3032 rc = VINF_SUCCESS;
3033 }
3034 else
3035 rc = VERR_BUFFER_OVERFLOW;
3036 break;
3037
3038
3039 default:
3040 rc = VERR_NOT_FOUND;
3041 break;
3042 }
3043 RT_NOREF_PV(pvBits);
3044 return rc;
3045}
3046
3047
3048/**
3049 * Operations for a Mach-O module interpreter.
3050 */
3051static const RTLDROPS s_rtldrLXOps=
3052{
3053 "LX",
3054 rtldrLX_Close,
3055 NULL,
3056 NULL /*pfnDone*/,
3057 rtldrLX_EnumSymbols,
3058 /* ext */
3059 rtldrLX_GetImageSize,
3060 rtldrLX_GetBits,
3061 rtldrLX_RelocateBits,
3062 rtldrLX_GetSymbolEx,
3063 NULL /*pfnQueryForwarderInfo*/,
3064 rtldrLX_EnumDbgInfo,
3065 rtldrLX_EnumSegments,
3066 rtldrLX_LinkAddressToSegOffset,
3067 rtldrLX_LinkAddressToRva,
3068 rtldrLX_SegOffsetToRva,
3069 rtldrLX_RvaToSegOffset,
3070 rtldrLX_ReadDbgInfo,
3071 rtldrLX_QueryProp,
3072 NULL /*pfnVerifySignature*/,
3073 NULL /*pfnHashImage*/,
3074 NULL /*pfnUnwindFrame*/,
3075 42
3076};
3077
3078
3079/**
3080 * Handles opening LX images.
3081 */
3082DECLHIDDEN(int) rtldrLXOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offLxHdr,
3083 PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
3084{
3085
3086 /*
3087 * Create the instance data and do a minimal header validation.
3088 */
3089 PKLDRMODLX pThis = NULL;
3090 int rc = kldrModLXDoCreate(pReader, offLxHdr, fFlags, &pThis, pErrInfo);
3091 if (RT_SUCCESS(rc))
3092 {
3093 /*
3094 * Match up against the requested CPU architecture.
3095 */
3096 if ( enmArch == RTLDRARCH_WHATEVER
3097 || pThis->Core.enmArch == enmArch)
3098 {
3099 pThis->Core.pOps = &s_rtldrLXOps;
3100 pThis->Core.u32Magic = RTLDRMOD_MAGIC;
3101 *phLdrMod = &pThis->Core;
3102 return VINF_SUCCESS;
3103 }
3104 rc = VERR_LDR_ARCH_MISMATCH;
3105 }
3106 if (pThis)
3107 RTMemFree(pThis);
3108 return rc;
3109
3110}
3111
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette