VirtualBox

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

Last change on this file was 103353, checked in by vboxsync, 3 months ago

IPRT/ldrLX: Try trick parfait so it doesn't complain about inconsistent cast. bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use