source: trunk/kLdr/kLdrModLX.c@ 2979

Last change on this file since 2979 was 2979, checked in by bird, 18 years ago

name resolution. fixed some fixup bugs, works for wlink dlls now.

  • Property svn:keywords set to Id
File size: 83.5 KB
Line 
1/* $Id: kLdrModLX.c 2979 2007-03-03 23:27:30Z bird $ */
2/** @file
3 *
4 * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format.
5 *
6 * Copyright (c) 2006-2007 knut st. osmundsen <bird@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include "kLdrHlp.h"
33#include "kLdrInternal.h"
34#include "kLdrModLX.h"
35
36
37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** @def KLDRMODLX_STRICT
41 * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */
42#define KLDRMODLX_STRICT 1
43
44/** @def KLDRMODLX_ASSERT
45 * Assert that an expression is true when KLDR_STRICT is defined.
46 */
47#ifdef KLDRMODLX_STRICT
48# define KLDRMODLX_ASSERT(expr) kldrHlpAssert(expr)
49#else
50# define KLDRMODLX_ASSERT(expr) do {} while (0)
51#endif
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57/**
58 * Instance data for the LX module interpreter.
59 */
60typedef struct KLDRMODLX
61{
62 /** Pointer to the module. (Follows the section table.) */
63 PKLDRMOD pMod;
64 /** Pointer to the user mapping. */
65 const void *pvMapping;
66 /** The size of the mapped LX image. */
67 size_t cbMapped;
68 /** Reserved flags. */
69 uint32_t f32Reserved;
70
71 /** The offset of the LX header. */
72 KLDRFOFF offHdr;
73 /** Copy of the LX header. */
74 struct e32_exe Hdr;
75
76 /** Pointer to the loader section.
77 * Allocated together with this strcture. */
78 const uint8_t *pbLoaderSection;
79 /** Pointer to the last byte in the loader section. */
80 const uint8_t *pbLoaderSectionLast;
81 /** Pointer to the object table in the loader section. */
82 const struct o32_obj *paObjs;
83 /** Pointer to the object page map table in the loader section. */
84 const struct o32_map *paPageMappings;
85 /** Pointer to the resource table in the loader section. */
86 const struct rsrc32 *paRsrcs;
87 /** Pointer to the resident name table in the loader section. */
88 const uint8_t *pbResNameTab;
89 /** Pointer to the entry table in the loader section. */
90 const uint8_t *pbEntryTab;
91
92 /** Pointer to the non-resident name table. */
93 uint8_t *pbNonResNameTab;
94 /** Pointer to the last byte in the non-resident name table. */
95 const uint8_t *pbNonResNameTabLast;
96
97 /** Pointer to the fixup section. */
98 uint8_t *pbFixupSection;
99 /** Pointer to the last byte in the fixup section. */
100 const uint8_t *pbFixupSectionLast;
101 /** Pointer to the fixup page table within pvFixupSection. */
102 const uint32_t *paoffPageFixups;
103 /** Pointer to the fixup record table within pvFixupSection. */
104 const uint8_t *pbFixupRecs;
105 /** Pointer to the import module name table within pvFixupSection. */
106 const uint8_t *pbImportMods;
107 /** Pointer to the import module name table within pvFixupSection. */
108 const uint8_t *pbImportProcs;
109} KLDRMODLX, *PKLDRMODLX;
110
111
112/*******************************************************************************
113* Internal Functions *
114*******************************************************************************/
115static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits);
116static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
117 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
118static int kldrModLXDoCreate(PKLDRRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX);
119static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal);
120static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, uint32_t cchSymbol, uint32_t *piSymbol);
121static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable,
122 const char *pchSymbol, size_t cchSymbol);
123static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
124static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
125static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
126static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb);
127static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
128static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle);
129static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
130 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind);
131static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX);
132static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
133static int kldrModLXDoReloc(uint8_t *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc,
134 int iSelector, KLDRADDR uValue, uint32_t fKind);
135
136
137/**
138 * Create a loader module instance interpreting the executable image found
139 * in the specified file provider instance.
140 *
141 * @returns 0 on success and *ppMod pointing to a module instance.
142 * On failure, a non-zero OS specific error code is returned.
143 * @param pOps Pointer to the registered method table.
144 * @param pRdr The file provider instance to use.
145 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
146 * @param ppMod Where to store the module instance pointer.
147 */
148static int kldrModLXCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
149{
150 PKLDRMODLX pModLX;
151 int rc;
152
153 /*
154 * Create the instance data and do a minimal header validation.
155 */
156 rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX);
157 if (!rc)
158 {
159 pModLX->pMod->pOps = pOps;
160 pModLX->pMod->u32Magic = KLDRMOD_MAGIC;
161 *ppMod = pModLX->pMod;
162 return 0;
163 }
164 kldrHlpFree(pModLX);
165 return rc;
166}
167
168
169/**
170 * Separate function for reading creating the LX module instance to
171 * simplify cleanup on failure.
172 */
173static int kldrModLXDoCreate(PKLDRRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX)
174{
175 struct e32_exe Hdr;
176 PKLDRMODLX pModLX;
177 PKLDRMOD pMod;
178 size_t cb;
179 size_t cchFilename;
180 uint32_t off, offEnd;
181 uint32_t i;
182 int rc;
183 int fCanOptimizeMapping;
184 uint32_t NextRVA;
185 *ppModLX = NULL;
186
187 /*
188 * Read the signature and file header.
189 */
190 rc = kLdrRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
191 if (rc)
192 return rc;
193 if ( Hdr.e32_magic[0] != E32MAGIC1
194 || Hdr.e32_magic[1] != E32MAGIC2)
195 return KLDR_ERR_UNKNOWN_FORMAT;
196
197 /* We're not interested in anything but x86 images. */
198 if ( Hdr.e32_level != E32LEVEL
199 || Hdr.e32_border != E32LEBO
200 || Hdr.e32_worder != E32LEWO
201 || Hdr.e32_cpu < E32CPU286
202 || Hdr.e32_cpu > E32CPU486
203 || Hdr.e32_pagesize != OBJPAGELEN
204 )
205 return KLDR_ERR_LX_BAD_HEADER;
206
207 /* Some rough sanity checks. */
208 offEnd = kLdrRdrSize(pRdr) >= (KLDRFOFF)~(uint32_t)16 ? ~(uint32_t)16 : (uint32_t)kLdrRdrSize(pRdr);
209 if ( Hdr.e32_itermap > offEnd
210 || Hdr.e32_datapage > offEnd
211 || Hdr.e32_nrestab > offEnd
212 || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
213 || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
214 || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
215 || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
216 return KLDR_ERR_LX_BAD_HEADER;
217
218 /* Verify the loader section. */
219 offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
220 if (Hdr.e32_objtab < sizeof(Hdr))
221 return KLDR_ERR_LX_BAD_LOADER_SECTION;
222 off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
223 if (off > offEnd)
224 return KLDR_ERR_LX_BAD_LOADER_SECTION;
225 if ( Hdr.e32_objmap
226 && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
227 return KLDR_ERR_LX_BAD_LOADER_SECTION;
228 if ( Hdr.e32_rsrccnt
229 && ( Hdr.e32_rsrctab < off
230 || Hdr.e32_rsrctab > offEnd
231 || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
232 return KLDR_ERR_LX_BAD_LOADER_SECTION;
233 if ( Hdr.e32_restab
234 && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
235 return KLDR_ERR_LX_BAD_LOADER_SECTION;
236 if ( Hdr.e32_enttab
237 && (Hdr.e32_enttab < off || Hdr.e32_enttab >= offEnd))
238 return KLDR_ERR_LX_BAD_LOADER_SECTION;
239 if ( Hdr.e32_dircnt
240 && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd - 2))
241 return KLDR_ERR_LX_BAD_LOADER_SECTION;
242
243 /* Verify the fixup section. */
244 off = offEnd;
245 offEnd = off + Hdr.e32_fixupsize;
246 if ( Hdr.e32_fpagetab
247 && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
248 {
249 /*
250 * wlink mixes the fixup section and the loader section.
251 */
252 off = Hdr.e32_fpagetab;
253 offEnd = off + Hdr.e32_fixupsize;
254 Hdr.e32_ldrsize = off - Hdr.e32_objtab;
255 }
256 if ( Hdr.e32_frectab
257 && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
258 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
259 if ( Hdr.e32_impmod
260 && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
261 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
262 if ( Hdr.e32_impproc
263 && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
264 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
265
266 /*
267 * Calc the instance size, allocate and initialize it.
268 */
269 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
270 cb = KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8)
271 + KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8)
272 + KLDR_ALIGN_Z(cchFilename + 1, 8)
273 + Hdr.e32_ldrsize + 2; /* +2 for two extra zeros. */
274 pModLX = (PKLDRMODLX)kldrHlpAlloc(cb);
275 if (!pModLX)
276 return KLDR_ERR_NO_MEMORY;
277 *ppModLX = pModLX;
278
279 /* KLDRMOD */
280 pMod = (PKLDRMOD)((uint8_t *)pModLX + KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8));
281 pMod->pvData = pModLX;
282 pMod->pRdr = pRdr;
283 pMod->pOps = NULL; /* set upon success. */
284 pMod->cSegments = Hdr.e32_objcnt;
285 pMod->cchFilename = cchFilename;
286 pMod->pszFilename = (char *)KLDR_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8);
287 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
288 pMod->pszName = NULL; /* finalized further down */
289 pMod->cchName = 0;
290 switch (Hdr.e32_cpu)
291 {
292 case E32CPU286:
293 pMod->enmCpu = KLDRCPU_I80286;
294 pMod->enmArch = KLDRARCH_X86_16;
295 break;
296 case E32CPU386:
297 pMod->enmCpu = KLDRCPU_I386;
298 pMod->enmArch = KLDRARCH_X86_32;
299 break;
300 case E32CPU486:
301 pMod->enmCpu = KLDRCPU_I486;
302 pMod->enmArch = KLDRARCH_X86_32;
303 break;
304 }
305 pMod->enmEndian = KLDRENDIAN_LITTLE;
306 pMod->enmFmt = KLDRFMT_LX;
307 switch (Hdr.e32_mflags & E32MODMASK)
308 {
309 case E32MODEXE:
310 pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX)
311 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
312 : KLDRTYPE_EXECUTABLE_FIXED;
313 break;
314
315 case E32MODDLL:
316 case E32PROTDLL:
317 case E32MODPROTDLL:
318 pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL)
319 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
320 : KLDRTYPE_SHARED_LIBRARY_FIXED;
321 break;
322
323 case E32MODPDEV:
324 case E32MODVDEV:
325 pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
326 break;
327 }
328 pMod->u32Magic = 0; /* set upon success. */
329
330 /* KLDRMODLX */
331 pModLX->pMod = pMod;
332 pModLX->pvMapping = 0;
333 pModLX->cbMapped = 0;
334 pModLX->f32Reserved = 0;
335
336 pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
337 pModLX->Hdr = Hdr;
338
339 pModLX->pbLoaderSection = KLDR_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16);
340 pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize - 1;
341 pModLX->paObjs = NULL;
342 pModLX->paPageMappings = NULL;
343 pModLX->paRsrcs = NULL;
344 pModLX->pbResNameTab = NULL;
345 pModLX->pbEntryTab = NULL;
346
347 pModLX->pbNonResNameTab = NULL;
348 pModLX->pbNonResNameTabLast = NULL;
349
350 pModLX->pbFixupSection = NULL;
351 pModLX->pbFixupSectionLast = NULL;
352 pModLX->paoffPageFixups = NULL;
353 pModLX->pbFixupRecs = NULL;
354 pModLX->pbImportMods = NULL;
355 pModLX->pbImportProcs = NULL;
356
357 /*
358 * Read the loader data.
359 */
360 rc = kLdrRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
361 if (rc)
362 return rc;
363 ((uint8_t *)pModLX->pbLoaderSectionLast)[1] = 0;
364 ((uint8_t *)pModLX->pbLoaderSectionLast)[2] = 0;
365 if (pModLX->Hdr.e32_objcnt)
366 pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
367 if (pModLX->Hdr.e32_objmap)
368 pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
369 if (pModLX->Hdr.e32_rsrccnt)
370 pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
371 if (pModLX->Hdr.e32_restab)
372 pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
373 if (pModLX->Hdr.e32_enttab)
374 pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
375
376 /*
377 * Get the soname from the resident name table.
378 * Very convenient that it's the 0 ordinal, because then we get a
379 * free string terminator.
380 * (The table entry consists of a pascal string followed by a 16-bit ordinal.)
381 */
382 pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab,
383 pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
384 0);
385 if (!pMod->pszName)
386 return KLDR_ERR_LX_NO_SONAME;
387 pMod->cchName = *(const uint8_t *)pMod->pszName++;
388 if (pMod->cchName != kLdrHlpStrLen(pMod->pszName))
389 return KLDR_ERR_LX_BAD_SONAME;
390
391 /*
392 * Quick validation of the object table.
393 */
394 cb = 0;
395 for (i = 0; i < pMod->cSegments; i++)
396 {
397 if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
398 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
399 if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
400 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
401 if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1)))
402 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
403 if ( pModLX->paObjs[i].o32_mapsize
404 && ( (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
405 || (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
406 > pModLX->pbLoaderSectionLast))
407 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
408 if (i > 0 && !(pModLX->paObjs[i].o32_flags & OBJRSRC))
409 {
410 if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
411 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
412 if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
413 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
414 }
415 }
416
417 /*
418 * Check if we can optimize the mapping by using a different
419 * object alignment. The linker typically uses 64KB alignment,
420 * we can easily get away with page alignment in most cases.
421 */
422 fCanOptimizeMapping = !(Hdr.e32_mflags & (E32NOINTFIX | E32SYSDLL));
423 NextRVA = 0;
424
425 /*
426 * Setup the KLDRMOD segment array.
427 */
428 for (i = 0; i < pMod->cSegments; i++)
429 {
430 /* unused */
431 pMod->aSegments[i].pvUser = NULL;
432 pMod->aSegments[i].MapAddress = 0;
433 pMod->aSegments[i].pchName = NULL;
434 pMod->aSegments[i].cchName = 0;
435 pMod->aSegments[i].offFile = -1;
436 pMod->aSegments[i].cbFile = -1;
437 pMod->aSegments[i].SelFlat = 0;
438 pMod->aSegments[i].Sel16bit = 0;
439
440 /* flags */
441 pMod->aSegments[i].fFlags = 0;
442 if (pModLX->paObjs[i].o32_flags & OBJBIGDEF)
443 pMod->aSegments[i].fFlags = KLDRSEG_FLAG_16BIT;
444 if (pModLX->paObjs[i].o32_flags & OBJALIAS16)
445 pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_ALIAS16;
446 if (pModLX->paObjs[i].o32_flags & OBJCONFORM)
447 pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_CONFORM;
448 if (pModLX->paObjs[i].o32_flags & OBJIOPL)
449 pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_IOPL;
450
451 /* size and addresses */
452 pMod->aSegments[i].Alignment = OBJPAGELEN;
453 pMod->aSegments[i].cb = pModLX->paObjs[i].o32_size;
454 pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
455 pMod->aSegments[i].RVA = NextRVA;
456 if ( fCanOptimizeMapping
457 || i + 1 >= pMod->cSegments
458 || (pModLX->paObjs[i].o32_flags & OBJRSRC)
459 || (pModLX->paObjs[i + 1].o32_flags & OBJRSRC))
460 pMod->aSegments[i].cbMapped = KLDR_ALIGN_Z(pModLX->paObjs[i].o32_size, OBJPAGELEN);
461 else
462 pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
463 NextRVA += pMod->aSegments[i].cbMapped;
464
465 /* protection */
466 switch ( pModLX->paObjs[i].o32_flags
467 & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
468 {
469 case 0:
470 case OBJSHARED:
471 pMod->aSegments[i].enmProt = KLDRPROT_NOACCESS;
472 break;
473 case OBJREAD:
474 case OBJREAD | OBJSHARED:
475 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
476 break;
477 case OBJWRITE:
478 case OBJWRITE | OBJREAD:
479 pMod->aSegments[i].enmProt = KLDRPROT_WRITECOPY;
480 break;
481 case OBJWRITE | OBJSHARED:
482 case OBJWRITE | OBJSHARED | OBJREAD:
483 pMod->aSegments[i].enmProt = KLDRPROT_READWRITE;
484 break;
485 case OBJEXEC:
486 case OBJEXEC | OBJSHARED:
487 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE;
488 break;
489 case OBJEXEC | OBJREAD:
490 case OBJEXEC | OBJREAD | OBJSHARED:
491 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READ;
492 break;
493 case OBJEXEC | OBJWRITE:
494 case OBJEXEC | OBJWRITE | OBJREAD:
495 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
496 break;
497 case OBJEXEC | OBJWRITE | OBJSHARED:
498 case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
499 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READWRITE;
500 break;
501 }
502 if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
503 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
504 /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
505 pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
506 pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */
507 }
508
509 /* set the mapping size */
510 pModLX->cbMapped = NextRVA;
511
512 /*
513 * We're done.
514 */
515 *ppModLX = pModLX;
516 return 0;
517}
518
519
520/** @copydoc KLDRMODOPS::pfnDestroy */
521static int kldrModLXDestroy(PKLDRMOD pMod)
522{
523 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
524 int rc = 0;
525 KLDRMODLX_ASSERT(!pModLX->pvMapping);
526
527 if (pMod->pRdr)
528 {
529 rc = kLdrRdrClose(pMod->pRdr);
530 pMod->pRdr = NULL;
531 }
532 if (pModLX->pbNonResNameTab)
533 {
534 kldrHlpFree(pModLX->pbNonResNameTab);
535 pModLX->pbNonResNameTab = NULL;
536 }
537 if (pModLX->pbFixupSection)
538 {
539 kldrHlpFree(pModLX->pbFixupSection);
540 pModLX->pbFixupSection = NULL;
541 }
542 pMod->u32Magic = 0;
543 pMod->pOps = NULL;
544 kldrHlpFree(pModLX);
545 return rc;
546}
547
548
549/**
550 * Resolved base address aliases.
551 *
552 * @param pModLX The interpreter module instance
553 * @param pBaseAddress The base address, IN & OUT.
554 */
555static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress)
556{
557 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
558 *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress;
559 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
560 *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress;
561}
562
563
564/** @copydoc kLdrModQuerySymbol */
565static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
566 const char *pchSymbol, size_t cchSymbol, const char *pszVersion,
567 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
568{
569 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
570 uint32_t iOrdinal;
571 int rc;
572 const struct b32_bundle *pBundle;
573
574
575 /*
576 * Give up at once if there is no entry table.
577 */
578 if (!pModLX->Hdr.e32_enttab)
579 return KLDR_ERR_SYMBOL_NOT_FOUND;
580
581 /*
582 * Translate the symbol name into an ordinal.
583 */
584 if (pchSymbol)
585 {
586 rc = kldrModLXDoNameLookup(pModLX, pchSymbol, cchSymbol, &iSymbol);
587 if (rc)
588 return rc;
589 }
590
591 /*
592 * Iterate the entry table.
593 * (The entry table is made up of bundles of similar exports.)
594 */
595 iOrdinal = 1;
596 pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
597 while (pBundle->b32_cnt && iOrdinal <= iSymbol)
598 {
599 static const size_t s_cbEntry[] = { 0, 3, 5, 5, 7 };
600
601 /*
602 * Check for a hit first.
603 */
604 iOrdinal += pBundle->b32_cnt;
605 if (iSymbol < iOrdinal)
606 {
607 uint32_t offObject;
608 const struct e32_entry *pEntry = (const struct e32_entry *)((uintptr_t)(pBundle + 1)
609 + (iSymbol - (iOrdinal - pBundle->b32_cnt))
610 * s_cbEntry[pBundle->b32_type]);
611
612 /*
613 * Calculate the return address.
614 */
615 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
616 switch (pBundle->b32_type)
617 {
618 /* empty bundles are place holders unused ordinal ranges. */
619 case EMPTY:
620 return KLDR_ERR_SYMBOL_NOT_FOUND;
621
622 /* e32_flags + a 16-bit offset. */
623 case ENTRY16:
624 offObject = pEntry->e32_variant.e32_offset.offset16;
625 if (pfKind)
626 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE;
627 break;
628
629 /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
630 case GATE16:
631 offObject = pEntry->e32_variant.e32_callgate.offset;
632 if (pfKind)
633 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE;
634 break;
635
636 /* e32_flags + a 32-bit offset. */
637 case ENTRY32:
638 offObject = pEntry->e32_variant.e32_offset.offset32;
639 if (pfKind)
640 *pfKind = KLDRSYMKIND_32BIT;
641 break;
642
643 /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
644 case ENTRYFWD:
645 return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind);
646
647 default:
648 /* anyone actually using TYPEINFO will end up here. */
649 KLDRMODLX_ASSERT(!"Bad bundle type");
650 return KLDR_ERR_LX_BAD_BUNDLE;
651 }
652
653 /*
654 * Validate the object number and calc the return address.
655 */
656 if ( pBundle->b32_obj <= 0
657 || pBundle->b32_obj > pMod->cSegments)
658 return KLDR_ERR_LX_BAD_BUNDLE;
659 if (puValue)
660 *puValue = BaseAddress
661 + offObject
662 + pMod->aSegments[pBundle->b32_obj - 1].RVA;
663 return 0;
664 }
665
666 /*
667 * Skip the bundle.
668 */
669 if (pBundle->b32_type > ENTRYFWD)
670 {
671 KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
672 return KLDR_ERR_LX_BAD_BUNDLE;
673 }
674 if (pBundle->b32_type == 0)
675 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + 2);
676 else
677 pBundle = (const struct b32_bundle *)((const uint8_t *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
678 }
679
680 return KLDR_ERR_SYMBOL_NOT_FOUND;
681}
682
683
684/**
685 * Do name lookup.
686 *
687 * @returns See kLdrModQuerySymbol.
688 * @param pModLX The module to lookup the symbol in.
689 * @param pchSymbol The symbol to lookup.
690 * @param cchSymbol The symbol name length.
691 * @param piSymbol Where to store the symbol ordinal.
692 */
693static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, uint32_t cchSymbol, uint32_t *piSymbol)
694{
695
696 /*
697 * First do a hash table lookup.
698 */
699 /** @todo hash name table for speed. */
700
701 /*
702 * Search the name tables.
703 */
704 const uint8_t *pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab,
705 pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
706 pchSymbol, cchSymbol);
707 if (!pbName)
708 {
709 if (!pModLX->pbNonResNameTab)
710 {
711 /* lazy load it */
712 /** @todo non-resident name table. */
713 }
714 if (pModLX->pbNonResNameTab)
715 pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab,
716 pModLX->pbNonResNameTabLast - pModLX->pbResNameTab + 1,
717 pchSymbol, cchSymbol);
718 }
719 if (!pbName)
720 return KLDR_ERR_SYMBOL_NOT_FOUND;
721
722 *piSymbol = *(const uint16_t *)(pbName + 1 + *pbName);
723 return 0;
724}
725
726
727#if 0
728/**
729 * Hash a symbol using the algorithm from sdbm.
730 *
731 * The following was is the documenation of the orignal sdbm functions:
732 *
733 * This algorithm was created for sdbm (a public-domain reimplementation of
734 * ndbm) database library. it was found to do well in scrambling bits,
735 * causing better distribution of the keys and fewer splits. it also happens
736 * to be a good general hashing function with good distribution. the actual
737 * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
738 * is the faster version used in gawk. [there is even a faster, duff-device
739 * version] the magic constant 65599 was picked out of thin air while
740 * experimenting with different constants, and turns out to be a prime.
741 * this is one of the algorithms used in berkeley db (see sleepycat) and
742 * elsewhere.
743 */
744static uint32_t kldrModLXDoHash(const char *pchSymbol, uint8_t cchSymbol)
745{
746 uint32_t hash = 0;
747 int ch;
748
749 while ( cchSymbol-- > 0
750 && (ch = *(unsigned const char *)pchSymbol++))
751 hash = ch + (hash << 6) + (hash << 16) - hash;
752
753 return hash;
754}
755#endif
756
757
758/**
759 * Lookup a name table entry by name.
760 *
761 * @returns Pointer to the name table entry if found.
762 * @returns NULL if not found.
763 * @param pbNameTable Pointer to the name table that should be searched.
764 * @param cbNameTable The size of the name table.
765 * @param pchSymbol The name of the symbol we're looking for.
766 * @param cchSymbol The length of the symbol name.
767 */
768static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable,
769 const char *pchSymbol, size_t cchSymbol)
770{
771 /*
772 * Determin the namelength up front so we can skip anything which doesn't matches the length.
773 */
774 uint8_t cbSymbol8Bit = (uint8_t)cchSymbol;
775 if (cbSymbol8Bit != cchSymbol)
776 return NULL; /* too long. */
777
778 /*
779 * Walk the name table.
780 */
781 while (*pbNameTable != 0 && cbNameTable > 0)
782 {
783 const uint8_t cbName = *pbNameTable;
784
785 cbNameTable -= cbName + 1 + 2;
786 if (cbNameTable < 0)
787 break;
788
789 if ( cbName == cbSymbol8Bit
790 && !kLdrHlpMemComp(pbNameTable + 1, pchSymbol, cbName))
791 return pbNameTable;
792
793 /* next entry */
794 pbNameTable += cbName + 1 + 2;
795 }
796
797 return NULL;
798}
799
800
801/**
802 * Deal with a forwarder entry.
803 *
804 * @returns See kLdrModQuerySymbol.
805 * @param pModLX The PE module interpreter instance.
806 * @param pEntry The forwarder entry.
807 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
808 * @param pvUser The user argument for the callback.
809 * @param puValue Where to put the value. (optional)
810 * @param pfKind Where to put the symbol kind. (optional)
811 */
812static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
813 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
814{
815 int rc;
816 uint32_t iSymbol;
817 const char *pchSymbol;
818 uint8_t cchSymbol;
819
820 if (!pfnGetForwarder)
821 return KLDR_ERR_FORWARDER_SYMBOL;
822
823 /*
824 * Validate the entry import module ordinal.
825 */
826 if ( !pEntry->e32_variant.e32_fwd.modord
827 || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt)
828 return KLDR_ERR_LX_BAD_FORWARDER;
829
830 /*
831 * Figure out the parameters.
832 */
833 if (pEntry->e32_flags & FWD_ORDINAL)
834 {
835 iSymbol = pEntry->e32_variant.e32_fwd.value;
836 pchSymbol = NULL; /* no symbol name. */
837 cchSymbol = 0;
838 }
839 else
840 {
841 const uint8_t *pbName;
842
843 /* load the fixup section if necessary. */
844 if (!pModLX->pbImportProcs)
845 {
846 rc = kldrModLXDoLoadFixupSection(pModLX);
847 if (rc)
848 return rc;
849 }
850
851 /* Make name pointer. */
852 pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value;
853 if ( pbName >= pModLX->pbFixupSectionLast
854 || pbName < pModLX->pbFixupSection
855 || !*pbName)
856 return KLDR_ERR_LX_BAD_FORWARDER;
857
858
859 /* check for '#' name. */
860 if (pbName[1] == '#')
861 {
862 uint8_t cbLeft = *pbName;
863 const uint8_t *pb = pbName + 1;
864 unsigned uBase;
865
866 /* base detection */
867 uBase = 10;
868 if ( cbLeft > 1
869 && pb[1] == '0'
870 && (pb[2] == 'x' || pb[2] == 'X'))
871 {
872 uBase = 16;
873 pb += 2;
874 cbLeft -= 2;
875 }
876
877 /* ascii to integer */
878 iSymbol = 0;
879 while (cbLeft-- > 0)
880 {
881 /* convert char to digit. */
882 unsigned uDigit = *pb++;
883 if (uDigit >= '0' && uDigit <= '9')
884 uDigit -= '0';
885 else if (uDigit >= 'a' && uDigit <= 'z')
886 uDigit -= 'a' + 10;
887 else if (uDigit >= 'A' && uDigit <= 'Z')
888 uDigit -= 'A' + 10;
889 else if (!uDigit)
890 break;
891 else
892 return KLDR_ERR_LX_BAD_FORWARDER;
893 if (uDigit >= uBase)
894 return KLDR_ERR_LX_BAD_FORWARDER;
895
896 /* insert the digit */
897 iSymbol *= uBase;
898 iSymbol += uDigit;
899 }
900 if (!iSymbol)
901 return KLDR_ERR_LX_BAD_FORWARDER;
902
903 pchSymbol = NULL; /* no symbol name. */
904 cchSymbol = 0;
905 }
906 else
907 {
908 pchSymbol = (char *)pbName + 1;
909 cchSymbol = *pbName;
910 iSymbol = NIL_KLDRMOD_SYM_ORDINAL;
911 }
912 }
913
914 /*
915 * Resolve the forwarder.
916 */
917 rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pchSymbol, cchSymbol, NULL, puValue, pfKind, pvUser);
918 if (!rc && pfKind)
919 *pfKind |= KLDRSYMKIND_FORWARDER;
920 return rc;
921}
922
923
924/**
925 * Loads the fixup section from the executable image.
926 *
927 * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone().
928 *
929 * @returns 0 on success, non-zero kLdr or native status code on failure.
930 * @param pModLX The PE module interpreter instance.
931 */
932static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX)
933{
934 int rc;
935 uint32_t off;
936 void *pv;
937
938 pv = kldrHlpAlloc(pModLX->Hdr.e32_fixupsize);
939 if (!pv)
940 return KLDR_ERR_NO_MEMORY;
941
942 off = pModLX->Hdr.e32_objtab + pModLX->Hdr.e32_ldrsize;
943 rc = kLdrRdrRead(pModLX->pMod->pRdr, pv, pModLX->Hdr.e32_fixupsize,
944 off + pModLX->offHdr);
945 if (!rc)
946 {
947 pModLX->pbFixupSection = 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 kldrHlpFree(pv);
964 return rc;
965}
966
967
968/** @copydoc kLdrModEnumSymbols */
969static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
970 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
971{
972 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
973/* int rc; */
974
975 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
976
977 return 0;
978}
979
980
981/**
982 * Lookup a name table entry by ordinal.
983 *
984 * @returns Pointer to the name table entry if found.
985 * @returns NULL if not found.
986 * @param pbNameTable Pointer to the name table that should be searched.
987 * @param cbNameTable The size of the name table.
988 * @param iOrdinal The ordinal to search for.
989 */
990static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal)
991{
992 while (*pbNameTable != 0 && cbNameTable > 0)
993 {
994 const uint8_t cbName = *pbNameTable;
995 uint32_t iName;
996
997 cbNameTable -= cbName + 1 + 2;
998 if (cbNameTable < 0)
999 break;
1000
1001 iName = *(pbNameTable + cbName + 1)
1002 | ((unsigned)*(pbNameTable + cbName + 2) << 8);
1003 if (iName == iOrdinal)
1004 return pbNameTable;
1005
1006 /* next entry */
1007 pbNameTable += cbName + 1 + 2;
1008 }
1009
1010 return NULL;
1011}
1012
1013
1014/** @copydoc kLdrModGetImport */
1015static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
1016{
1017 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1018 const uint8_t * pb;
1019 int rc;
1020
1021 /*
1022 * Validate
1023 */
1024 if (iImport >= pModLX->Hdr.e32_impmodcnt)
1025 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1026
1027 /*
1028 * Lazy loading the fixup section.
1029 */
1030 if (!pModLX->pbImportMods)
1031 {
1032 rc = kldrModLXDoLoadFixupSection(pModLX);
1033 if (rc)
1034 return rc;
1035 }
1036
1037 /*
1038 * Iterate the module import table until we reach the requested import ordinal.
1039 */
1040 pb = pModLX->pbImportMods;
1041 while (iImport-- > 0)
1042 pb += *pb + 1;
1043
1044 /*
1045 * Copy out the result.
1046 */
1047 if (*pb < cchName)
1048 {
1049 kLdrHlpMemCopy(pszName, pb + 1, *pb);
1050 pszName[*pb] = '\0';
1051 rc = 0;
1052 }
1053 else
1054 {
1055 kLdrHlpMemCopy(pszName, pb + 1, cchName);
1056 if (cchName)
1057 pszName[cchName - 1] = '\0';
1058 rc = KLDR_ERR_BUFFER_OVERFLOW;
1059 }
1060
1061 return rc;
1062}
1063
1064
1065/** @copydoc kLdrModNumberOfImports */
1066static int32_t kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits)
1067{
1068 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1069 return pModLX->Hdr.e32_impmodcnt;
1070}
1071
1072
1073/** @copydoc kLdrModGetStackInfo */
1074static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1075{
1076 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1077 const uint32_t i = pModLX->Hdr.e32_stackobj;
1078
1079 if ( i
1080 && i <= pMod->cSegments
1081 && pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb
1082 && pModLX->Hdr.e32_stacksize
1083 && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress)
1084 {
1085
1086 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1087 pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
1088 pStackInfo->Address = BaseAddress
1089 + pMod->aSegments[i - 1].RVA
1090 + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress;
1091 }
1092 else
1093 {
1094 pStackInfo->Address = NIL_KLDRADDR;
1095 pStackInfo->LinkAddress = NIL_KLDRADDR;
1096 }
1097 pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
1098 pStackInfo->cbStackThread = 0;
1099
1100 return 0;
1101}
1102
1103
1104/** @copydoc kLdrModQueryMainEntrypoint */
1105static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1106{
1107 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1108
1109 /*
1110 * Convert the address from the header.
1111 */
1112 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1113 *pMainEPAddress = pModLX->Hdr.e32_startobj
1114 && pModLX->Hdr.e32_startobj <= pMod->cSegments
1115 && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb
1116 ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
1117 : NIL_KLDRADDR;
1118 return 0;
1119}
1120
1121
1122/** @copydoc kLdrModEnumDbgInfo */
1123static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1124{
1125 /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/
1126
1127 /*
1128 * Quit immediately if no debug info.
1129 */
1130 if (kldrModLXHasDbgInfo(pMod, pvBits))
1131 return 0;
1132#if 0
1133 /*
1134 * Read the debug info and look for familiar magics and structures.
1135 */
1136 /** @todo */
1137#endif
1138
1139 return 0;
1140}
1141
1142
1143/** @copydoc kLdrModHasDbgInfo */
1144static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1145{
1146 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1147
1148 /*
1149 * Don't curretnly bother with linkers which doesn't advertise it in the header.
1150 */
1151 if ( !pModLX->Hdr.e32_debuginfo
1152 || !pModLX->Hdr.e32_debuglen)
1153 return KLDR_ERR_NO_DEBUG_INFO;
1154 return 0;
1155}
1156
1157
1158/** @copydoc kLdrModMap */
1159static int kldrModLXMap(PKLDRMOD pMod)
1160{
1161 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1162 unsigned fFixed;
1163 void *pvBase;
1164 int rc;
1165
1166 /*
1167 * Already mapped?
1168 */
1169 if (pModLX->pvMapping)
1170 return KLDR_ERR_ALREADY_MAPPED;
1171
1172 /*
1173 * Allocate memory for it.
1174 */
1175 /* fixed image? */
1176 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
1177 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1178 if (!fFixed)
1179 pvBase = NULL;
1180 else
1181 {
1182 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
1183 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
1184 return KLDR_ERR_ADDRESS_OVERFLOW;
1185 }
1186 rc = kldrHlpPageAlloc(&pvBase, pModLX->cbMapped, KLDRPROT_EXECUTE_READWRITE, fFixed);
1187 if (rc)
1188 return rc;
1189
1190 /*
1191 * Load the bits, apply page protection, and update the segment table.
1192 */
1193 rc = kldrModLXDoLoadBits(pModLX, pvBase);
1194 if (!rc)
1195 rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
1196 if (!rc)
1197 {
1198 uint32_t i;
1199 for (i = 0; i < pMod->cSegments; i++)
1200 {
1201 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
1202 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
1203 }
1204 pModLX->pvMapping = pvBase;
1205 }
1206 else
1207 kldrHlpPageFree(pvBase, pModLX->cbMapped);
1208 return rc;
1209}
1210
1211
1212/**
1213 * Loads the LX pages into the specified memory mapping.
1214 *
1215 * @returns 0 on success.
1216 * @returns non-zero kLdr or OS status code on failure.
1217 *
1218 * @param pModLX The LX module interpreter instance.
1219 * @param pvBits Where to load the bits.
1220 */
1221static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
1222{
1223 const PKLDRRDR pRdr = pModLX->pMod->pRdr;
1224 uint8_t *pbTmpPage = NULL;
1225 int rc = 0;
1226 uint32_t i;
1227
1228 /*
1229 * Iterate the segments.
1230 */
1231 for (i = 0; i < pModLX->Hdr.e32_objcnt; i++)
1232 {
1233 const struct o32_obj * const pObj = &pModLX->paObjs[i];
1234 const uint32_t cPages = pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN;
1235 uint32_t iPage;
1236 uint8_t *pbPage = (uint8_t *)pvBits + (uintptr_t)pModLX->pMod->aSegments[i].RVA;
1237
1238 /*
1239 * Iterate the page map pages.
1240 */
1241 for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN)
1242 {
1243 const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1];
1244 switch (pMap->o32_pageflags)
1245 {
1246 case VALID:
1247 if (pMap->o32_pagesize == OBJPAGELEN)
1248 rc = kLdrRdrRead(pRdr, pbPage, OBJPAGELEN,
1249 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1250 else if (pMap->o32_pagesize < OBJPAGELEN)
1251 {
1252 rc = kLdrRdrRead(pRdr, pbPage, pMap->o32_pagesize,
1253 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1254 kLdrHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize);
1255 }
1256 else
1257 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1258 break;
1259
1260 case ITERDATA:
1261 case ITERDATA2:
1262 /* make sure we've got a temp page .*/
1263 if (!pbTmpPage)
1264 {
1265 pbTmpPage = kldrHlpAlloc(OBJPAGELEN + 256);
1266 if (!pbTmpPage)
1267 break;
1268 }
1269 /* validate the size. */
1270 if (pMap->o32_pagesize > OBJPAGELEN + 252)
1271 {
1272 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1273 break;
1274 }
1275
1276 /* read it and ensure 4 extra zero bytes. */
1277 rc = kLdrRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize,
1278 pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
1279 if (rc)
1280 break;
1281 kLdrHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4);
1282
1283 /* unpack it into the image page. */
1284 if (pMap->o32_pageflags == ITERDATA2)
1285 rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1286 else
1287 rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1288 break;
1289
1290 case INVALID: /* we're probably not dealing correctly with INVALID pages... */
1291 case ZEROED:
1292 kLdrHlpMemSet(pbPage, 0, OBJPAGELEN);
1293 break;
1294
1295 case RANGE:
1296 KLDRMODLX_ASSERT(!"RANGE");
1297 default:
1298 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1299 break;
1300 }
1301 }
1302 if (rc)
1303 break;
1304
1305 /*
1306 * Zero the remaining pages.
1307 */
1308 if (iPage < cPages)
1309 kLdrHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN);
1310 }
1311
1312 if (pbTmpPage)
1313 kldrHlpFree(pbTmpPage);
1314 return rc;
1315}
1316
1317
1318/**
1319 * Unpacks iterdata (aka EXEPACK).
1320 *
1321 * @returns 0 on success, non-zero kLdr status code on failure.
1322 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1323 * @param pbSrc The compressed source data.
1324 * @param cbSrc The file size of the compressed data. The source buffer
1325 * contains 4 additional zero bytes.
1326 */
1327static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1328{
1329 const struct LX_Iter *pIter = (const struct LX_Iter *)pbSrc;
1330 int cbDst = OBJPAGELEN;
1331
1332 /* Validate size of data. */
1333 if (cbSrc >= OBJPAGELEN - 2)
1334 return KLDR_ERR_LX_BAD_ITERDATA;
1335
1336 /*
1337 * Expand the page.
1338 */
1339 while (cbSrc > 0 && pIter->LX_nIter)
1340 {
1341 if (pIter->LX_nBytes == 1)
1342 {
1343 /*
1344 * Special case - one databyte.
1345 */
1346 cbDst -= pIter->LX_nIter;
1347 if (cbDst < 0)
1348 return KLDR_ERR_LX_BAD_ITERDATA;
1349
1350 cbSrc -= 4 + 1;
1351 if (cbSrc < -4)
1352 return KLDR_ERR_LX_BAD_ITERDATA;
1353
1354 kLdrHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter);
1355 pbDst += pIter->LX_nIter;
1356 pIter++;
1357 }
1358 else
1359 {
1360 /*
1361 * General.
1362 */
1363 int i;
1364
1365 cbDst -= pIter->LX_nIter * pIter->LX_nBytes;
1366 if (cbDst < 0)
1367 return KLDR_ERR_LX_BAD_ITERDATA;
1368
1369 cbSrc -= 4 + pIter->LX_nBytes;
1370 if (cbSrc < -4)
1371 return KLDR_ERR_LX_BAD_ITERDATA;
1372
1373 for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes)
1374 kLdrHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes);
1375 pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
1376 }
1377 }
1378
1379 /*
1380 * Zero remainder of the page.
1381 */
1382 if (cbDst > 0)
1383 kLdrHlpMemSet(pbDst, 0, cbDst);
1384
1385 return 0;
1386}
1387
1388
1389/**
1390 * Unpacks iterdata (aka EXEPACK).
1391 *
1392 * @returns 0 on success, non-zero kLdr status code on failure.
1393 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1394 * @param pbSrc The compressed source data.
1395 * @param cbSrc The file size of the compressed data. The source buffer
1396 * contains 4 additional zero bytes.
1397 */
1398static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1399{
1400 int cbDst = OBJPAGELEN;
1401
1402 while (cbSrc > 0)
1403 {
1404 /*
1405 * Bit 0 and 1 is the encoding type.
1406 */
1407 switch (*pbSrc & 0x03)
1408 {
1409 /*
1410 *
1411 * 0 1 2 3 4 5 6 7
1412 * type | |
1413 * ----------------
1414 * cb <cb bytes of data>
1415 *
1416 * Bits 2-7 is, if not zero, the length of an uncompressed run
1417 * starting at the following byte.
1418 *
1419 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1420 * type | | | | | |
1421 * ---------------- ---------------------- -----------------------
1422 * zero cb char to multiply
1423 *
1424 * If the bits are zero, the following two bytes describes a 1 byte interation
1425 * run. First byte is count, second is the byte to copy. A count of zero is
1426 * means end of data, and we simply stops. In that case the rest of the data
1427 * should be zero.
1428 */
1429 case 0:
1430 {
1431 if (*pbSrc)
1432 {
1433 const int cb = *pbSrc >> 2;
1434 cbDst -= cb;
1435 if (cbDst < 0)
1436 return KLDR_ERR_LX_BAD_ITERDATA2;
1437 cbSrc -= cb + 1;
1438 if (cbSrc < 0)
1439 return KLDR_ERR_LX_BAD_ITERDATA2;
1440 kLdrHlpMemCopy(pbDst, ++pbSrc, cb);
1441 pbDst += cb;
1442 pbSrc += cb;
1443 }
1444 else if (cbSrc < 2)
1445 return KLDR_ERR_LX_BAD_ITERDATA2;
1446 else
1447 {
1448 const int cb = pbSrc[1];
1449 if (!cb)
1450 goto l_endloop;
1451 cbDst -= cb;
1452 if (cbDst < 0)
1453 return KLDR_ERR_LX_BAD_ITERDATA2;
1454 cbSrc -= 3;
1455 if (cbSrc < 0)
1456 return KLDR_ERR_LX_BAD_ITERDATA2;
1457 kLdrHlpMemSet(pbDst, pbSrc[2], cb);
1458 pbDst += cb;
1459 pbSrc += 3;
1460 }
1461 break;
1462 }
1463
1464
1465 /*
1466 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1467 * type | | | | | |
1468 * ---- ------- -------------------------
1469 * cb1 cb2 - 3 offset <cb1 bytes of data>
1470 *
1471 * Two bytes layed out as described above, followed by cb1 bytes of data to be copied.
1472 * The cb2(+3) and offset describes an amount of data to be copied from the expanded
1473 * data relative to the current position. The data copied as you would expect it to be.
1474 */
1475 case 1:
1476 {
1477 cbSrc -= 2;
1478 if (cbSrc < 0)
1479 return KLDR_ERR_LX_BAD_ITERDATA2;
1480 else
1481 {
1482 const unsigned off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7);
1483 const int cb1 = (*pbSrc >> 2) & 3;
1484 const int cb2 = ((*pbSrc >> 4) & 7) + 3;
1485
1486 pbSrc += 2;
1487 cbSrc -= cb1;
1488 if (cbSrc < 0)
1489 return KLDR_ERR_LX_BAD_ITERDATA2;
1490 cbDst -= cb1;
1491 if (cbDst < 0)
1492 return KLDR_ERR_LX_BAD_ITERDATA2;
1493 kLdrHlpMemCopy(pbDst, pbSrc, cb1);
1494 pbDst += cb1;
1495 pbSrc += cb1;
1496
1497 if (off > OBJPAGELEN - cbDst)
1498 return KLDR_ERR_LX_BAD_ITERDATA2;
1499 cbDst -= cb2;
1500 if (cbDst < 0)
1501 return KLDR_ERR_LX_BAD_ITERDATA2;
1502 kLdrHlpMemMove(pbDst, pbDst - off, cb2);
1503 pbDst += cb2;
1504 }
1505 break;
1506 }
1507
1508
1509 /*
1510 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1511 * type | | | |
1512 * ---- ----------------------------------
1513 * cb-3 offset
1514 *
1515 * Two bytes layed out as described above.
1516 * The cb(+3) and offset describes an amount of data to be copied from the expanded
1517 * data relative to the current position.
1518 *
1519 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1520 */
1521 case 2:
1522 {
1523 cbSrc -= 2;
1524 if (cbSrc < 0)
1525 return KLDR_ERR_LX_BAD_ITERDATA2;
1526 else
1527 {
1528 const unsigned off = ((unsigned)pbSrc[1] << 4) | (*pbSrc >> 4);
1529 const int cb = ((*pbSrc >> 2) & 3) + 3;
1530
1531 pbSrc += 2;
1532 if (off > OBJPAGELEN - cbDst)
1533 return KLDR_ERR_LX_BAD_ITERDATA2;
1534 cbDst -= cb;
1535 if (cbDst < 0)
1536 return KLDR_ERR_LX_BAD_ITERDATA2;
1537 kLdrModLXMemCopyW(pbDst, pbDst - off, cb);
1538 pbDst += cb;
1539 }
1540 break;
1541 }
1542
1543
1544 /*
1545 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1546 * type | | | | | |
1547 * ---------- ---------------- ----------------------------------
1548 * cb1 cb2 offset <cb1 bytes of data>
1549 *
1550 * Three bytes layed out as described above, followed by cb1 bytes of data to be copied.
1551 * The cb2 and offset describes an amount of data to be copied from the expanded
1552 * data relative to the current position.
1553 *
1554 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1555 */
1556 case 3:
1557 {
1558 cbSrc -= 3;
1559 if (cbSrc < 0)
1560 return KLDR_ERR_LX_BAD_ITERDATA2;
1561 else
1562 {
1563 const int cb1 = (*pbSrc >> 2) & 0xf;
1564 const int cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6);
1565 const unsigned off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4);
1566
1567 pbSrc += 3;
1568 cbSrc -= cb1;
1569 if (cbSrc < 0)
1570 return KLDR_ERR_LX_BAD_ITERDATA2;
1571 cbDst -= cb1;
1572 if (cbDst < 0)
1573 return KLDR_ERR_LX_BAD_ITERDATA2;
1574 kLdrHlpMemCopy(pbDst, pbSrc, cb1);
1575 pbDst += cb1;
1576 pbSrc += cb1;
1577
1578 if (off > OBJPAGELEN - cbDst)
1579 return KLDR_ERR_LX_BAD_ITERDATA2;
1580 cbDst -= cb2;
1581 if (cbDst < 0)
1582 return KLDR_ERR_LX_BAD_ITERDATA2;
1583 kLdrModLXMemCopyW(pbDst, pbDst - off, cb2);
1584 pbDst += cb2;
1585 }
1586 break;
1587 }
1588 } /* type switch. */
1589 } /* unpack loop */
1590
1591l_endloop:
1592
1593
1594 /*
1595 * Zero remainder of the page.
1596 */
1597 if (cbDst > 0)
1598 kLdrHlpMemSet(pbDst, 0, cbDst);
1599
1600 return 0;
1601}
1602
1603
1604/**
1605 * Special memcpy employed by the iterdata2 algorithm.
1606 *
1607 * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this
1608 * has if src is very close to the destination.
1609 *
1610 * @param pbDst Destination pointer.
1611 * @param pbSrc Source pointer. Will always be <= pbDst.
1612 * @param cb Amount of data to be copied.
1613 * @remark This assumes that unaligned word and dword access is fine.
1614 */
1615static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb)
1616{
1617 switch (pbDst - pbSrc)
1618 {
1619 case 0:
1620 case 1:
1621 case 2:
1622 case 3:
1623 /* 16-bit copy (unaligned) */
1624 if (cb & 1)
1625 *pbDst++ = *pbSrc++;
1626 for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2)
1627 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
1628 break;
1629
1630 default:
1631 /* 32-bit copy (unaligned) */
1632 if (cb & 1)
1633 *pbDst++ = *pbSrc++;
1634 if (cb & 2)
1635 {
1636 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
1637 pbDst += 2;
1638 pbSrc += 2;
1639 }
1640 for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4)
1641 *(uint32_t *)pbDst = *(const uint32_t *)pbSrc;
1642 break;
1643 }
1644}
1645
1646
1647/**
1648 * Unprotects or protects the specified image mapping.
1649 *
1650 * @returns 0 on success.
1651 * @returns non-zero kLdr or OS status code on failure.
1652 *
1653 * @param pModLX The LX module interpreter instance.
1654 * @param pvBits The mapping to protect.
1655 * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise
1656 * protect according to the object table.
1657 */
1658static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect)
1659{
1660 uint32_t i;
1661 PKLDRMOD pMod = pModLX->pMod;
1662
1663 /*
1664 * Change object protection.
1665 */
1666 for (i = 0; i < pMod->cSegments; i++)
1667 {
1668 int rc;
1669 void *pv;
1670 KLDRPROT enmProt;
1671
1672 /* calc new protection. */
1673 enmProt = pMod->aSegments[i].enmProt;
1674 if (fUnprotectOrProtect)
1675 {
1676 switch (enmProt)
1677 {
1678 case KLDRPROT_NOACCESS:
1679 case KLDRPROT_READONLY:
1680 case KLDRPROT_READWRITE:
1681 case KLDRPROT_WRITECOPY:
1682 enmProt = KLDRPROT_READWRITE;
1683 break;
1684 case KLDRPROT_EXECUTE:
1685 case KLDRPROT_EXECUTE_READ:
1686 case KLDRPROT_EXECUTE_READWRITE:
1687 case KLDRPROT_EXECUTE_WRITECOPY:
1688 enmProt = KLDRPROT_EXECUTE_READWRITE;
1689 break;
1690 default:
1691 KLDRMODLX_ASSERT(!"bad enmProt");
1692 return -1;
1693 }
1694 }
1695 else
1696 {
1697 /* copy on write -> normal write. */
1698 if (enmProt == KLDRPROT_EXECUTE_WRITECOPY)
1699 enmProt = KLDRPROT_EXECUTE_READWRITE;
1700 else if (enmProt == KLDRPROT_WRITECOPY)
1701 enmProt = KLDRPROT_READWRITE;
1702 }
1703
1704
1705 /* calc the address and set page protection. */
1706 pv = (uint8_t *)pvBits + pMod->aSegments[i].RVA;
1707
1708 rc = kldrHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt);
1709 if (rc)
1710 break;
1711
1712 /** @todo the gap page should be marked NOACCESS! */
1713 }
1714
1715 return 0;
1716}
1717
1718
1719/** @copydoc kLdrModUnmap */
1720static int kldrModLXUnmap(PKLDRMOD pMod)
1721{
1722 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1723 uint32_t i;
1724 int rc;
1725
1726 /*
1727 * Mapped?
1728 */
1729 if (!pModLX->pvMapping)
1730 return KLDR_ERR_NOT_MAPPED;
1731
1732 /*
1733 * Free the mapping and update the segments.
1734 */
1735 rc = kldrHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
1736 KLDRMODLX_ASSERT(!rc);
1737 pModLX->pvMapping = NULL;
1738
1739 for (i = 0; i < pMod->cSegments; i++)
1740 pMod->aSegments[i].MapAddress = 0;
1741
1742 return rc;
1743}
1744
1745
1746/** @copydoc kLdrModAllocTLS */
1747static int kldrModLXAllocTLS(PKLDRMOD pMod)
1748{
1749 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1750
1751 /* no tls, just do the error checking. */
1752 if (!pModLX->pvMapping)
1753 return KLDR_ERR_NOT_MAPPED;
1754 return 0;
1755}
1756
1757
1758/** @copydoc kLdrModFreeTLS */
1759static void kldrModLXFreeTLS(PKLDRMOD pMod)
1760{
1761 /* no tls. */
1762}
1763
1764
1765/** @copydoc kLdrModReload */
1766static int kldrModLXReload(PKLDRMOD pMod)
1767{
1768 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1769 int rc, rc2;
1770
1771 /*
1772 * Mapped?
1773 */
1774 if (!pModLX->pvMapping)
1775 return KLDR_ERR_NOT_MAPPED;
1776
1777 /*
1778 * Before doing anything we'll have to make all pages writable.
1779 */
1780 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
1781 if (rc)
1782 return rc;
1783
1784 /*
1785 * Load the bits again.
1786 */
1787 rc = kldrModLXDoLoadBits(pModLX, (void *)pModLX->pvMapping);
1788
1789 /*
1790 * Restore protection.
1791 */
1792 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
1793 if (!rc && rc2)
1794 rc = rc2;
1795 return rc;
1796}
1797
1798
1799/** @copydoc kLdrModFixupMapping */
1800static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1801{
1802 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1803 int rc, rc2;
1804
1805 /*
1806 * Mapped?
1807 */
1808 if (!pModLX->pvMapping)
1809 return KLDR_ERR_NOT_MAPPED;
1810
1811 /*
1812 * Before doing anything we'll have to make all pages writable.
1813 */
1814 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
1815 if (rc)
1816 return rc;
1817
1818 /*
1819 * Apply fixups and resolve imports.
1820 */
1821 rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (uintptr_t)pModLX->pvMapping,
1822 pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
1823
1824 /*
1825 * Restore protection.
1826 */
1827 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
1828 if (!rc && rc2)
1829 rc = rc2;
1830 return rc;
1831}
1832
1833
1834/** @copydoc kLdrModCallInit */
1835static int kldrModLXCallInit(PKLDRMOD pMod, uintptr_t uHandle)
1836{
1837 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1838 int rc;
1839
1840 /*
1841 * Mapped?
1842 */
1843 if (!pModLX->pvMapping)
1844 return KLDR_ERR_NOT_MAPPED;
1845
1846 /*
1847 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1848 */
1849 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
1850 rc = kldrModLXDoCallDLL(pModLX, 0 /* attach */, uHandle);
1851 else
1852 rc = 0;
1853 return rc;
1854}
1855
1856
1857/**
1858 * Call the DLL entrypoint.
1859 *
1860 * @returns 0 on success.
1861 * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
1862 * @param pModLX The LX module interpreter instance.
1863 * @param uOp The operation (DLL_*).
1864 * @param uHandle The module handle to present.
1865 */
1866static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle)
1867{
1868 int rc;
1869
1870 /*
1871 * If no entrypoint there isn't anything to be done.
1872 */
1873 if ( !pModLX->Hdr.e32_startobj
1874 || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
1875 return 0;
1876
1877 /*
1878 * Invoke the entrypoint and convert the boolean result to a kLdr status code.
1879 */
1880 rc = kldrModLXDoCall((uintptr_t)pModLX->pvMapping
1881 + (uintptr_t)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
1882 + pModLX->Hdr.e32_eip,
1883 uHandle, uOp, NULL);
1884 if (rc)
1885 rc = 0;
1886 else if (uOp == 0 /* attach */)
1887 rc = KLDR_ERR_MODULE_INIT_FAILED;
1888 else /* detach: ignore failures */
1889 rc = 0;
1890 return rc;
1891}
1892
1893
1894/**
1895 * Do a 3 parameter callback.
1896 *
1897 * @returns 32-bit callback return.
1898 * @param uEntrypoint The address of the function to be called.
1899 * @param uHandle The first argument, the module handle.
1900 * @param uOp The second argumnet, the reason we're calling.
1901 * @param pvReserved The third argument, reserved argument. (figure this one out)
1902 */
1903static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved)
1904{
1905#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
1906 int32_t rc;
1907/** @todo try/except */
1908
1909 /*
1910 * Paranoia.
1911 */
1912# ifdef __GNUC__
1913 __asm__ __volatile__(
1914 "pushl %2\n\t"
1915 "pushl %1\n\t"
1916 "pushl %0\n\t"
1917 "lea 12(%%esp), %2\n\t"
1918 "call *%3\n\t"
1919 "movl %2, %%esp\n\t"
1920 : "=a" (rc)
1921 : "d" (uOp),
1922 "S" (0),
1923 "c" (uEntrypoint),
1924 "0" (uHandle));
1925# elif defined(_MSC_VER)
1926 __asm {
1927 mov eax, [uHandle]
1928 mov edx, [uOp]
1929 mov ecx, 0
1930 mov ebx, [uEntrypoint]
1931 push edi
1932 mov edi, esp
1933 push ecx
1934 push edx
1935 push eax
1936 call ebx
1937 mov esp, edi
1938 pop edi
1939 mov [rc], eax
1940 }
1941# else
1942# error "port me!"
1943# endif
1944 return rc;
1945
1946#else
1947 return KLDR_ERR_ARCH_CPU_NOT_COMPATIBLE;
1948#endif
1949}
1950
1951
1952/** @copydoc kLdrModCallTerm */
1953static int kldrModLXCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
1954{
1955 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1956
1957 /*
1958 * Mapped?
1959 */
1960 if (!pModLX->pvMapping)
1961 return KLDR_ERR_NOT_MAPPED;
1962
1963 /*
1964 * Do the call.
1965 */
1966 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
1967 kldrModLXDoCallDLL(pModLX, 1 /* detach */, uHandle);
1968
1969 return 0;
1970}
1971
1972
1973/** @copydoc kLdrModCallThread */
1974static int kldrModLXCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
1975{
1976 /* no thread attach/detach callout. */
1977 return 0;
1978}
1979
1980
1981/** @copydoc kLdrModSize */
1982static KLDRADDR kldrModLXSize(PKLDRMOD pMod)
1983{
1984 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1985 return pModLX->cbMapped;
1986}
1987
1988
1989/** @copydoc kLdrModGetBits */
1990static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1991{
1992 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1993 int rc;
1994
1995 /*
1996 * Load the image bits.
1997 */
1998 rc = kldrModLXDoLoadBits(pModLX, pvBits);
1999 if (rc)
2000 return rc;
2001
2002 /*
2003 * Perform relocations.
2004 */
2005 return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
2006
2007}
2008
2009
2010/** @copydoc kLdrModRelocateBits */
2011static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
2012 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2013{
2014 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
2015 uint32_t iSeg;
2016 int rc;
2017
2018 /*
2019 * Do we need to to *anything*?
2020 */
2021 if ( NewBaseAddress == OldBaseAddress
2022 && NewBaseAddress == pModLX->paObjs[0].o32_base
2023 && !pModLX->Hdr.e32_impmodcnt)
2024 return 0;
2025
2026 /*
2027 * Load the fixup section.
2028 */
2029 if (!pModLX->pbFixupSection)
2030 {
2031 rc = kldrModLXDoLoadFixupSection(pModLX);
2032 if (rc)
2033 return rc;
2034 }
2035
2036 /*
2037 * Iterate the segments.
2038 */
2039 for (iSeg = 0; iSeg < pModLX->Hdr.e32_objcnt; iSeg++)
2040 {
2041 const struct o32_obj * const pObj = &pModLX->paObjs[iSeg];
2042 KLDRADDR PageAddress = NewBaseAddress + pModLX->pMod->aSegments[iSeg].RVA;
2043 uint32_t iPage;
2044 uint8_t *pbPage = (uint8_t *)pvBits + (uintptr_t)pModLX->pMod->aSegments[iSeg].RVA;
2045
2046 /*
2047 * Iterate the page map pages.
2048 */
2049 for (iPage = 0, rc = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN, PageAddress += OBJPAGELEN)
2050 {
2051 const uint8_t * const pbFixupRecEnd = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap];
2052 const uint8_t *pb = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap - 1];
2053 KLDRADDR uValue;
2054 int iSelector;
2055 uint32_t fKind;
2056
2057 /* sanity */
2058 if (pbFixupRecEnd < pb)
2059 return KLDR_ERR_BAD_FIXUP;
2060 if (pbFixupRecEnd - 1 > pModLX->pbFixupSectionLast)
2061 return KLDR_ERR_BAD_FIXUP;
2062 if (pb < pModLX->pbFixupSection)
2063 return KLDR_ERR_BAD_FIXUP;
2064
2065 /*
2066 * Iterate the fixup record.
2067 */
2068 while (pb < pbFixupRecEnd)
2069 {
2070 union _rel
2071 {
2072 const uint8_t * pb;
2073 const struct r32_rlc *prlc;
2074 } u;
2075
2076 u.pb = pb;
2077 pb += 3 + (u.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */
2078
2079 /*
2080 * Figure out the target.
2081 */
2082 switch (u.prlc->nr_flags & NRRTYP)
2083 {
2084 /*
2085 * Internal fixup.
2086 */
2087 case NRRINT:
2088 {
2089 uint16_t iTrgObject;
2090 uint32_t offTrgObject;
2091
2092 /* the object */
2093 if (u.prlc->nr_flags & NR16OBJMOD)
2094 {
2095 iTrgObject = *(const uint16_t *)pb;
2096 pb += 2;
2097 }
2098 else
2099 iTrgObject = *pb++;
2100 iTrgObject--;
2101 if (iTrgObject >= pModLX->Hdr.e32_objcnt)
2102 return KLDR_ERR_BAD_FIXUP;
2103
2104 /* the target */
2105 if ((u.prlc->nr_stype & NRSRCMASK) != NRSSEG)
2106 {
2107 if (u.prlc->nr_flags & NR32BITOFF)
2108 {
2109 offTrgObject = *(const uint32_t *)pb;
2110 pb += 4;
2111 }
2112 else
2113 {
2114 offTrgObject = *(const uint16_t *)pb;
2115 pb += 2;
2116 }
2117
2118 /* calculate the symbol info. */
2119 uValue = offTrgObject + NewBaseAddress + pMod->aSegments[iTrgObject].RVA;
2120 }
2121 else
2122 uValue = NewBaseAddress + pMod->aSegments[iTrgObject].RVA;
2123 if ( (u.prlc->nr_stype & NRALIAS)
2124 || (pMod->aSegments[iTrgObject].fFlags & KLDRSEG_FLAG_16BIT))
2125 iSelector = pMod->aSegments[iTrgObject].Sel16bit;
2126 else
2127 iSelector = pMod->aSegments[iTrgObject].SelFlat;
2128 fKind = 0;
2129 break;
2130 }
2131
2132 /*
2133 * Import by symbol ordinal.
2134 */
2135 case NRRORD:
2136 {
2137 uint16_t iModule;
2138 uint32_t iSymbol;
2139
2140 /* the module ordinal */
2141 if (u.prlc->nr_flags & NR16OBJMOD)
2142 {
2143 iModule = *(const uint16_t *)pb;
2144 pb += 2;
2145 }
2146 else
2147 iModule = *pb++;
2148 iModule--;
2149 if (iModule >= pModLX->Hdr.e32_impmodcnt)
2150 return KLDR_ERR_BAD_FIXUP;
2151#if 1
2152 if (u.prlc->nr_flags & NRICHAIN)
2153 return KLDR_ERR_BAD_FIXUP;
2154#endif
2155
2156 /* . */
2157 if (u.prlc->nr_flags & NR32BITOFF)
2158 {
2159 iSymbol = *(const uint32_t *)pb;
2160 pb += 4;
2161 }
2162 else if (!(u.prlc->nr_flags & NR8BITORD))
2163 {
2164 iSymbol = *(const uint16_t *)pb;
2165 pb += 2;
2166 }
2167 else
2168 iSymbol = *pb++;
2169
2170 /* resolve it. */
2171 rc = pfnGetImport(pMod, iModule, iSymbol, NULL, 0, NULL, &uValue, &fKind, pvUser);
2172 if (rc)
2173 return rc;
2174 iSelector = -1;
2175 break;
2176 }
2177
2178 /*
2179 * Import by symbol name.
2180 */
2181 case NRRNAM:
2182 {
2183 uint32_t iModule;
2184 uint16_t offSymbol;
2185 const uint8_t *pbSymbol;
2186
2187 /* the module ordinal */
2188 if (u.prlc->nr_flags & NR16OBJMOD)
2189 {
2190 iModule = *(const uint16_t *)pb;
2191 pb += 2;
2192 }
2193 else
2194 iModule = *pb++;
2195 iModule--;
2196 if (iModule >= pModLX->Hdr.e32_impmodcnt)
2197 return KLDR_ERR_BAD_FIXUP;
2198#if 1
2199 if (u.prlc->nr_flags & NRICHAIN)
2200 return KLDR_ERR_BAD_FIXUP;
2201#endif
2202
2203 /* . */
2204 if (u.prlc->nr_flags & NR32BITOFF)
2205 {
2206 offSymbol = *(const uint32_t *)pb;
2207 pb += 4;
2208 }
2209 else if (!(u.prlc->nr_flags & NR8BITORD))
2210 {
2211 offSymbol = *(const uint16_t *)pb;
2212 pb += 2;
2213 }
2214 else
2215 offSymbol = *pb++;
2216 pbSymbol = pModLX->pbImportProcs + offSymbol;
2217 if ( pbSymbol < pModLX->pbImportProcs
2218 || pbSymbol > pModLX->pbFixupSectionLast)
2219 return KLDR_ERR_BAD_FIXUP;
2220
2221 /* resolve it. */
2222 rc = pfnGetImport(pMod, iModule, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pbSymbol + 1, *pbSymbol, NULL,
2223 &uValue, &fKind, pvUser);
2224 if (rc)
2225 return rc;
2226 iSelector = -1;
2227 break;
2228 }
2229
2230 case NRRENT:
2231 KLDRMODLX_ASSERT(!"NRRENT");
2232 default:
2233 break;
2234 }
2235
2236 /* addend */
2237 if (u.prlc->nr_flags & NRADD)
2238 {
2239 if (u.prlc->nr_flags & NR32BITADD)
2240 {
2241 uValue += *(const uint32_t *)pb;
2242 pb += 4;
2243 }
2244 else
2245 {
2246 uValue += *(const uint16_t *)pb;
2247 pb += 2;
2248 }
2249 }
2250
2251
2252 /*
2253 * Deal with the 'source' (i.e. the place that should be modified - very logical).
2254 */
2255 if (!(u.prlc->nr_stype & NRCHAIN))
2256 {
2257 int off = u.prlc->r32_soff;
2258
2259 /* common / simple */
2260 if ( (u.prlc->nr_stype & NRSRCMASK) == NROFF32
2261 && off >= 0
2262 && off <= OBJPAGELEN - 4)
2263 *(uint32_t *)&pbPage[off] = uValue;
2264 else if ( (u.prlc->nr_stype & NRSRCMASK) == NRSOFF32
2265 && off >= 0
2266 && off <= OBJPAGELEN - 4)
2267 *(uint32_t *)&pbPage[off] = uValue - (PageAddress + off + 4);
2268 else
2269 {
2270 /* generic */
2271 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2272 if (rc)
2273 return rc;
2274 }
2275 }
2276 else if (!(u.prlc->nr_flags & NRICHAIN))
2277 {
2278 const int16_t *poffSrc = (const int16_t *)pb;
2279 uint8_t c = u.pb[2];
2280
2281 /* common / simple */
2282 if ((u.prlc->nr_stype & NRSRCMASK) == NROFF32)
2283 {
2284 while (c-- > 0)
2285 {
2286 int off = *poffSrc++;
2287 if (off >= 0 && off <= OBJPAGELEN - 4)
2288 *(uint32_t *)&pbPage[off] = uValue;
2289 else
2290 {
2291 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2292 if (rc)
2293 return rc;
2294 }
2295 }
2296 }
2297 else if ((u.prlc->nr_stype & NRSRCMASK) == NRSOFF32)
2298 {
2299 while (c-- > 0)
2300 {
2301 int off = *poffSrc++;
2302 if (off >= 0 && off <= OBJPAGELEN - 4)
2303 *(uint32_t *)&pbPage[off] = uValue - (PageAddress + off + 4);
2304 else
2305 {
2306 rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
2307 if (rc)
2308 return rc;
2309 }
2310 }
2311 }
2312 else
2313 {
2314 while (c-- > 0)
2315 {
2316 rc = kldrModLXDoReloc(pbPage, *poffSrc++, PageAddress, u.prlc, iSelector, uValue, fKind);
2317 if (rc)
2318 return rc;
2319 }
2320 }
2321 pb = (const uint8_t *)poffSrc;
2322 }
2323 else
2324 {
2325 /* This is a pain because it will require virgin pages on a relocation. */
2326 KLDRMODLX_ASSERT(!"NRICHAIN");
2327 return KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED;
2328 }
2329 }
2330 }
2331 }
2332
2333 return 0;
2334}
2335
2336
2337/**
2338 * Applies the relocation to one 'source' in a page.
2339 *
2340 * This takes care of the more esotic case while the common cases
2341 * are dealt with seperately.
2342 *
2343 * @returns 0 on success, non-zero kLdr status code on failure.
2344 * @param pbPage The page in which to apply the fixup.
2345 * @param off Page relative offset of where to apply the offset.
2346 * @param uValue The target value.
2347 * @param fKind The target kind.
2348 */
2349static int kldrModLXDoReloc(uint8_t *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc,
2350 int iSelector, KLDRADDR uValue, uint32_t fKind)
2351{
2352#pragma pack(1) /* just to be sure */
2353 union
2354 {
2355 uint8_t ab[6];
2356 uint32_t off32;
2357 uint16_t off16;
2358 uint8_t off8;
2359 struct
2360 {
2361 uint16_t off;
2362 uint16_t Sel;
2363 } Far16;
2364 struct
2365 {
2366 uint32_t off;
2367 uint16_t Sel;
2368 } Far32;
2369 } uData;
2370#pragma pack()
2371 const uint8_t *pbSrc;
2372 uint8_t *pbDst;
2373 uint8_t cb;
2374
2375 /*
2376 * Compose the fixup data.
2377 */
2378 switch (prlc->nr_stype & NRSRCMASK)
2379 {
2380 case NRSBYT:
2381 uData.off8 = (uint8_t)uValue;
2382 cb = 1;
2383 break;
2384 case NRSSEG:
2385 if (iSelector == -1)
2386 {
2387 /* fixme */
2388 }
2389 uData.off16 = iSelector;
2390 cb = 2;
2391 break;
2392 case NRSPTR:
2393 if (iSelector == -1)
2394 {
2395 /* fixme */
2396 }
2397 uData.Far16.off = (uint16_t)uValue;
2398 uData.Far16.Sel = iSelector;
2399 cb = 4;
2400 break;
2401 case NRSOFF:
2402 uData.off16 = (uint16_t)uValue;
2403 cb = 2;
2404 break;
2405 case NRPTR48:
2406 if (iSelector == -1)
2407 {
2408 /* fixme */
2409 }
2410 uData.Far32.off = (uint32_t)uValue;
2411 uData.Far32.Sel = iSelector;
2412 cb = 6;
2413 break;
2414 case NROFF32:
2415 uData.off32 = (uint32_t)uValue;
2416 cb = 4;
2417 break;
2418 case NRSOFF32:
2419 uData.off32 = (uint32_t)uValue - (PageAddress + off + 4);
2420 cb = 4;
2421 break;
2422 default:
2423 return KLDR_ERR_LX_BAD_FIXUP_SECTION; /** @todo fix error, add more checks! */
2424 }
2425
2426 /*
2427 * Apply it. This is sloooow...
2428 */
2429 pbSrc = &uData.ab[0];
2430 pbDst = pbPage + off;
2431 while (cb-- > 0)
2432 {
2433 if (off > OBJPAGELEN)
2434 break;
2435 if (off >= 0)
2436 *pbDst = *pbSrc;
2437 pbSrc++;
2438 pbDst++;
2439 }
2440
2441 return 0;
2442}
2443
2444
2445/**
2446 * The LX module interpreter method table.
2447 */
2448KLDRMODOPS g_kLdrModLXOps =
2449{
2450 "LX",
2451 NULL,
2452 kldrModLXCreate,
2453 kldrModLXDestroy,
2454 kldrModLXQuerySymbol,
2455 kldrModLXEnumSymbols,
2456 kldrModLXGetImport,
2457 kldrModLXNumberOfImports,
2458 NULL /* can execute one is optional */,
2459 kldrModLXGetStackInfo,
2460 kldrModLXQueryMainEntrypoint,
2461 NULL /* fixme */,
2462 NULL /* fixme */,
2463 kldrModLXEnumDbgInfo,
2464 kldrModLXHasDbgInfo,
2465 kldrModLXMap,
2466 kldrModLXUnmap,
2467 kldrModLXAllocTLS,
2468 kldrModLXFreeTLS,
2469 kldrModLXReload,
2470 kldrModLXFixupMapping,
2471 kldrModLXCallInit,
2472 kldrModLXCallTerm,
2473 kldrModLXCallThread,
2474 kldrModLXSize,
2475 kldrModLXGetBits,
2476 kldrModLXRelocateBits,
2477 NULL /* fixme: pfnMostlyDone */,
2478 42 /* the end */
2479};
2480
Note: See TracBrowser for help on using the repository browser.