VirtualBox

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

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

IPRT/dbg: Fixed a DWARF abbreviation cache bug, was calculating the wrong offSpec values for all but the first compile unit. Implemented LX debug info enumeration, making the embedded ELF info loadable (required disabling a RVA alignment optimization). bugref:3897

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

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