VirtualBox

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

最後變更 在這個檔案從83738是 82968,由 vboxsync 提交於 5 年 前

Copyright year updates by scm.

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

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