source: trunk/kLdr/kLdrModNative.c@ 4

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

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 36.6 KB
Line 
1/* $Id: kLdrModNative.c 2 2007-11-16 16:07:14Z bird $ */
2/** @file
3 * kLdr - The Module Interpreter for the Native Loaders.
4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
8 *
9 * This file is part of kStuff.
10 *
11 * kStuff is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * In addition to the permissions in the GNU Lesser General Public
17 * License, you are granted unlimited permission to link the compiled
18 * version of this file into combinations with other programs, and to
19 * distribute those combinations without any restriction coming from
20 * the use of this file.
21 *
22 * kStuff is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with kStuff; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 * 02110-1301, USA
31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#include <k/kLdr.h>
37#include "kLdrInternal.h"
38
39#if K_OS == K_OS_OS2
40# define INCL_BASE
41# include <os2.h>
42
43# ifndef LIBPATHSTRICT
44# define LIBPATHSTRICT 3
45# endif
46 extern APIRET DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction);
47# define QHINF_EXEINFO 1 /* NE exeinfo. */
48# define QHINF_READRSRCTBL 2 /* Reads from the resource table. */
49# define QHINF_READFILE 3 /* Reads from the executable file. */
50# define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */
51# define QHINF_LIBPATH 5 /* Gets the entire libpath. */
52# define QHINF_FIXENTRY 6 /* NE only */
53# define QHINF_STE 7 /* NE only */
54# define QHINF_MAPSEL 8 /* NE only */
55
56#elif K_OS == K_OS_WINDOWS
57# undef IMAGE_NT_SIGNATURE
58# undef IMAGE_DOS_SIGNATURE
59# include <windows.h>
60# ifndef IMAGE_SCN_TYPE_NOLOAD
61# define IMAGE_SCN_TYPE_NOLOAD 0x00000002
62# endif
63
64/*#elif defined(__NT__)
65#include <winnt.h> */
66
67#elif K_OS == K_OS_DARWIN
68# include <dlfcn.h>
69# include <errno.h>
70
71#else
72# error "port me"
73#endif
74
75
76
77/*******************************************************************************
78* Defined Constants And Macros *
79*******************************************************************************/
80/** @def KLDRMODNATIVE_STRICT
81 * Define KLDRMODNATIVE_STRICT to enabled strict checks in KLDRMODNATIVE. */
82#define KLDRMODNATIVE_STRICT 1
83
84/** @def KLDRMODNATIVE_ASSERT
85 * Assert that an expression is true when KLDR_STRICT is defined.
86 */
87#ifdef KLDRMODNATIVE_STRICT
88# define KLDRMODNATIVE_ASSERT(expr) kHlpAssert(expr)
89#else
90# define KLDRMODNATIVE_ASSERT(expr) do {} while (0)
91#endif
92
93#if K_OS == K_OS_WINDOWS
94/** @def KLDRMODNATIVE_RVA2TYPE
95 * Converts a RVA to a pointer of the specified type.
96 * @param pvBits The bits (image base).
97 * @param uRVA The image relative virtual address.
98 * @param type The type to cast to.
99 */
100# define KLDRMODNATIVE_RVA2TYPE(pvBits, uRVA, type) \
101 ( (type) ((KUPTR)(pvBits) + (uRVA)) )
102
103#endif /* PE OSes */
104
105
106
107/*******************************************************************************
108* Structures and Typedefs *
109*******************************************************************************/
110/**
111 * Instance data for the module interpreter for the Native Loaders.
112 */
113typedef struct KLDRMODNATIVE
114{
115 /** Pointer to the module. (Follows the section table.) */
116 PKLDRMOD pMod;
117 /** Reserved flags. */
118 KU32 f32Reserved;
119 /** The number of imported modules.
120 * If ~(KU32)0 this hasn't been determined yet. */
121 KU32 cImportModules;
122#if K_OS == K_OS_OS2
123 /** The module handle. */
124 HMODULE hmod;
125
126#elif K_OS == K_OS_WINDOWS
127 /** The module handle. */
128 HANDLE hmod;
129 /** Pointer to the NT headers. */
130 const IMAGE_NT_HEADERS *pNtHdrs;
131 /** Pointer to the section header array. */
132 const IMAGE_SECTION_HEADER *paShdrs;
133
134#elif K_OS == K_OS_DARWIN
135 /** The dlopen() handle.*/
136 void *pvMod;
137
138#else
139# error "Port me"
140#endif
141} KLDRMODNATIVE, *PKLDRMODNATIVE;
142
143
144/*******************************************************************************
145* Internal Functions *
146*******************************************************************************/
147static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits);
148
149
150
151/**
152 * Use native loader to load the file opened by pRdr.
153 *
154 * @returns 0 on success and *ppMod pointing to a module instance.
155 * On failure, a non-zero OS specific error code is returned.
156 * @param pOps Pointer to the registered method table.
157 * @param pRdr The file provider instance to use.
158 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
159 * @param ppMod Where to store the module instance pointer.
160 */
161static int kldrModNativeCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
162{
163 int rc = kLdrModOpenNative(kRdrName(pRdr), ppMod);
164 if (rc)
165 return rc;
166 rc = kRdrClose(pRdr);
167 KLDRMODNATIVE_ASSERT(!rc);
168 return 0;
169}
170
171
172/**
173 * Loads a module using the native module loader.
174 *
175 * @returns 0 on success.
176 * @returns non-zero native or kLdr status code on failure.
177 * @param pszFilename The filename or module name to be loaded.
178 * @param ppMod Where to store the module interpreter instance pointer.
179 */
180int kLdrModOpenNative(const char *pszFilename, PPKLDRMOD ppMod)
181{
182 int rc;
183
184 /*
185 * Load the image.
186 */
187#if K_OS == K_OS_OS2
188 HMODULE hmod;
189
190 rc = DosLoadModule(NULL, 0, (PCSZ)pszFilename, &hmod);
191 if (rc)
192 return rc;
193 rc = kLdrModOpenNativeByHandle((KUPTR)hmod, ppMod);
194 if (rc)
195 DosFreeModule(hmod);
196
197#elif K_OS == K_OS_WINDOWS
198 HMODULE hmod;
199
200 hmod = LoadLibrary(pszFilename);
201 if (!hmod)
202 return GetLastError();
203 rc = kLdrModOpenNativeByHandle((KUPTR)hmod, ppMod);
204 if (rc)
205 FreeLibrary(hmod);
206
207#elif K_OS == K_OS_DARWIN
208 void *pvMod;
209
210 pvMod = dlopen(pszFilename, 0);
211 if (!pvMod)
212 return ENOENT;
213 rc = kLdrModOpenNativeByHandle((KUPTR)pvMod, ppMod);
214 if (rc)
215 dlclose(pvMod);
216
217#else
218# error "Port me"
219#endif
220 return rc;
221}
222
223
224/**
225 * Creates a native module interpret for an already module already
226 * loaded by the native loader.
227 *
228 * @returns 0 on success.
229 * @returns non-zero native or kLdr status code on failure.
230 * @param pszFilename The filename or module name to be loaded.
231 * @param ppMod Where to store the module interpreter instance pointer.
232 * @remark This will not make the native loader increment the load count.
233 */
234int kLdrModOpenNativeByHandle(KUPTR uHandle, PPKLDRMOD ppMod)
235{
236 KSIZE cb;
237 KSIZE cchFilename;
238 KU32 cSegments;
239 PKLDRMOD pMod;
240 PKLDRMODNATIVE pModNative;
241
242 /*
243 * Delcare variables, parse the module header or whatever and determin the
244 * size of the module instance.
245 */
246#if K_OS == K_OS_OS2
247 char szFilename[CCHMAXPATH];
248 int rc;
249
250 /* get the filename. */
251 rc = DosQueryModuleName((HMODULE)uHandle, sizeof(szFilename), szFilename);
252 if (rc)
253 {
254 KLDRMODNATIVE_ASSERT(rc);
255 szFilename[0] = '\0';
256 }
257
258 /* get the segment count. */
259 /** @todo DosQueryHeaderInfo should be able to get us what we want on OS/2. */
260 cSegments = 1;
261
262#elif K_OS == K_OS_WINDOWS
263 DWORD dw;
264 char szFilename[MAX_PATH];
265 const IMAGE_NT_HEADERS *pNtHdrs;
266 const IMAGE_SECTION_HEADER *paShdrs;
267 const IMAGE_DOS_HEADER *pDosHdr = (const IMAGE_DOS_HEADER *)uHandle;
268 unsigned i;
269
270 /* get the filename. */
271 dw = GetModuleFileName((HANDLE)uHandle, szFilename, sizeof(szFilename));
272 if (dw <= 0)
273 {
274 KLDRMODNATIVE_ASSERT(dw <= 0);
275 szFilename[0] = '\0';
276 }
277
278 /* get the segment count. */
279 if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
280 pNtHdrs = (const IMAGE_NT_HEADERS *)((KUPTR)pDosHdr + pDosHdr->e_lfanew);
281 else
282 pNtHdrs = (const IMAGE_NT_HEADERS *)pDosHdr;
283 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
284 {
285 KLDRMODNATIVE_ASSERT(!"bad signature");
286 return KLDR_ERR_UNKNOWN_FORMAT;
287 }
288 if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
289 {
290 KLDRMODNATIVE_ASSERT(!"bad optional header size");
291 return KLDR_ERR_UNKNOWN_FORMAT;
292 }
293 cSegments = pNtHdrs->FileHeader.NumberOfSections + 1;
294 paShdrs = (const IMAGE_SECTION_HEADER *)(pNtHdrs + 1);
295
296#elif K_OS == K_OS_DARWIN
297 char szFilename[1] = "";
298 cSegments = 0; /** @todo Figure out the Mac OS X dynamic loader. */
299
300#else
301# error "Port me"
302#endif
303
304 /*
305 * Calc the instance size, allocate and initialize it.
306 */
307 cchFilename = kHlpStrLen(szFilename);
308 cb = K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16)
309 + K_OFFSETOF(KLDRMOD, aSegments[cSegments])
310 + cchFilename + 1;
311 pModNative = (PKLDRMODNATIVE)kHlpAlloc(cb);
312 if (!pModNative)
313 return KERR_NO_MEMORY;
314
315 /* KLDRMOD */
316 pMod = (PKLDRMOD)((KU8 *)pModNative + K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16));
317 pMod->pvData = pModNative;
318 pMod->pRdr = NULL;
319 pMod->pOps = NULL; /* set upon success. */
320 pMod->cSegments = cSegments;
321 pMod->cchFilename = cchFilename;
322 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
323 kHlpMemCopy((char *)pMod->pszFilename, szFilename, cchFilename + 1);
324 pMod->pszName = kHlpGetFilename(pMod->pszFilename); /** @todo get soname */
325 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
326#if defined(__i386__) || defined(__X86__) || defined(_M_IX86)
327 pMod->enmCpu = KCPU_I386;
328 pMod->enmArch = KCPUARCH_X86_32;
329 pMod->enmEndian = KLDRENDIAN_LITTLE;
330#elif defined(__X86_64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_IX64)
331 pMod->enmCpu = KCPU_K8;
332 pMod->enmArch = KCPUARCH_AMD64;
333 pMod->enmEndian = KLDRENDIAN_LITTLE;
334#else
335# error "Port me"
336#endif
337 pMod->enmFmt = KLDRFMT_NATIVE;
338 pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
339 pMod->u32Magic = 0; /* set upon success. */
340
341 /* KLDRMODNATIVE */
342 pModNative->pMod = pMod;
343 pModNative->f32Reserved = 0;
344 pModNative->cImportModules = ~(KU32)0;
345
346 /*
347 * Set native instance data.
348 */
349#if K_OS == K_OS_OS2
350 pModNative->hmod = (HMODULE)uHandle;
351
352 /* just fake a segment for now. */
353 pMod->aSegments[0].pvUser = NULL;
354 pMod->aSegments[0].pchName = "fake";
355 pMod->aSegments[0].cchName = sizeof("fake") - 1;
356 pMod->aSegments[0].enmProt = KPROT_NOACCESS;
357 pMod->aSegments[0].cb = 0;
358 pMod->aSegments[0].Alignment = 0;
359 pMod->aSegments[0].LinkAddress = NIL_KLDRADDR;
360 pMod->aSegments[0].offFile = -1;
361 pMod->aSegments[0].cbFile = 0;
362 pMod->aSegments[0].RVA = NIL_KLDRADDR;
363 pMod->aSegments[0].cbMapped = 0;
364 pMod->aSegments[0].MapAddress = 0;
365
366#elif K_OS == K_OS_WINDOWS
367 pModNative->hmod = (HMODULE)uHandle;
368 pModNative->pNtHdrs = pNtHdrs;
369 pModNative->paShdrs = paShdrs;
370
371 if (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)
372 pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
373 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
374 : KLDRTYPE_SHARED_LIBRARY_FIXED;
375 else
376 pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
377 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
378 : KLDRTYPE_EXECUTABLE_FIXED;
379
380 /* The implied headers section. */
381 pMod->aSegments[0].pvUser = NULL;
382 pMod->aSegments[0].pchName = "TheHeaders";
383 pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1;
384 pMod->aSegments[0].enmProt = KPROT_READONLY;
385 pMod->aSegments[0].cb = pNtHdrs->OptionalHeader.SizeOfHeaders;
386 pMod->aSegments[0].Alignment = pNtHdrs->OptionalHeader.SectionAlignment;
387 pMod->aSegments[0].LinkAddress = pNtHdrs->OptionalHeader.ImageBase;
388 pMod->aSegments[0].offFile = 0;
389 pMod->aSegments[0].cbFile = pNtHdrs->OptionalHeader.SizeOfHeaders;
390 pMod->aSegments[0].RVA = 0;
391 if (pMod->cSegments > 1)
392 pMod->aSegments[0].cbMapped = paShdrs[0].VirtualAddress;
393 else
394 pMod->aSegments[0].cbMapped = pNtHdrs->OptionalHeader.SizeOfHeaders;
395 pMod->aSegments[0].MapAddress = 0;
396
397 /* The section headers. */
398 for (i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
399 {
400 const char *pch;
401
402 /* unused */
403 pMod->aSegments[i + 1].pvUser = NULL;
404 pMod->aSegments[i + 1].MapAddress = 0;
405
406 /* name */
407 pMod->aSegments[i + 1].pchName = pch = &paShdrs[i].Name[0];
408 cb = IMAGE_SIZEOF_SHORT_NAME;
409 while ( cb > 0
410 && (pch[cb - 1] == ' ' || pch[cb - 1] == '\0'))
411 cb--;
412 pMod->aSegments[i + 1].cchName = cb;
413
414 /* size and addresses */
415 if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
416 {
417 pMod->aSegments[i + 1].cb = paShdrs[i].Misc.VirtualSize;
418 pMod->aSegments[i + 1].LinkAddress = paShdrs[i].VirtualAddress
419 + pNtHdrs->OptionalHeader.ImageBase;
420 pMod->aSegments[i + 1].RVA = paShdrs[i].VirtualAddress;
421 pMod->aSegments[i + 1].cbMapped = paShdrs[i].Misc.VirtualSize;
422 if (i + 2 < pMod->cSegments)
423 pMod->aSegments[i + 1].cbMapped= paShdrs[i + 1].VirtualAddress
424 - paShdrs[i].VirtualAddress;
425 }
426 else
427 {
428 pMod->aSegments[i + 1].cb = 0;
429 pMod->aSegments[i + 1].cbMapped = 0;
430 pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR;
431 pMod->aSegments[i + 1].RVA = 0;
432 }
433
434 /* file location */
435 pMod->aSegments[i + 1].offFile = paShdrs[i].PointerToRawData;
436 pMod->aSegments[i + 1].cbFile = paShdrs[i].SizeOfRawData;
437 if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */
438 && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped)
439 pMod->aSegments[i + 1].cbFile = pMod->aSegments[i + 1].cbMapped;
440
441 /* protection */
442 switch ( paShdrs[i].Characteristics
443 & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
444 {
445 case 0:
446 case IMAGE_SCN_MEM_SHARED:
447 pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS;
448 break;
449 case IMAGE_SCN_MEM_READ:
450 case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
451 pMod->aSegments[i + 1].enmProt = KPROT_READONLY;
452 break;
453 case IMAGE_SCN_MEM_WRITE:
454 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
455 pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY;
456 break;
457 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
458 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
459 pMod->aSegments[i + 1].enmProt = KPROT_READWRITE;
460 break;
461 case IMAGE_SCN_MEM_EXECUTE:
462 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED:
463 pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE;
464 break;
465 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ:
466 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
467 pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ;
468 break;
469 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE:
470 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
471 pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY;
472 break;
473 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
474 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
475 pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE;
476 break;
477 }
478
479 /* alignment. */
480 switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
481 {
482 case 0: /* hope this is right... */
483 pMod->aSegments[i + 1].Alignment = pNtHdrs->OptionalHeader.SectionAlignment;
484 break;
485 case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break;
486 case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break;
487 case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break;
488 case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break;
489 case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break;
490 case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break;
491 case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break;
492 case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break;
493 case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break;
494 case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break;
495 case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break;
496 case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break;
497 case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break;
498 case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break;
499 default: kHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break;
500 }
501 }
502
503#elif K_OS == K_OS_DARWIN
504 /** @todo Figure out the Mac OS X dynamic loader. */
505
506#else
507# error "Port me"
508#endif
509
510 /*
511 * We're done.
512 */
513 *ppMod = pMod;
514 return 0;
515}
516
517
518/** @copydoc KLDRMODOPS::pfnDestroy */
519static int kldrModNativeDestroy(PKLDRMOD pMod)
520{
521 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
522 int rc;
523
524#if K_OS == K_OS_OS2
525 rc = DosFreeModule(pModNative->hmod);
526
527#elif K_OS == K_OS_WINDOWS
528 if (FreeLibrary(pModNative->hmod))
529 rc = 0;
530 else
531 rc = GetLastError();
532
533#elif K_OS == K_OS_DARWIN
534 dlclose(pModNative->pvMod);
535
536#else
537# error "Port me"
538#endif
539
540 pMod->u32Magic = 0;
541 pMod->pOps = NULL;
542 kHlpFree(pModNative);
543 return rc;
544}
545
546
547/** @copydoc kLdrModQuerySymbol */
548static int kldrModNativeQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
549 const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
550 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
551{
552 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
553 const char *pszSymbol = pchSymbol;
554#if K_OS == K_OS_OS2
555 APIRET rc;
556 PFN pfn;
557#elif K_OS == K_OS_WINDOWS
558 FARPROC pfn;
559#elif K_OS == K_OS_DARWIN
560 void *pfn;
561#else
562# error "Port me"
563#endif
564
565 /* make stack copy of the symbol if it isn't zero terminated. */
566 if (pszSymbol && pszSymbol[cchSymbol])
567 {
568 char *pszCopy = kHlpAllocA(cchSymbol + 1);
569 kHlpMemCopy(pszCopy, pchSymbol, cchSymbol);
570 pszCopy[cchSymbol] = '\0';
571 pszSymbol = pszCopy;
572 }
573
574#if K_OS == K_OS_OS2
575 if (!pchSymbol && iSymbol >= 0x10000)
576 return KLDR_ERR_SYMBOL_NOT_FOUND;
577
578 if (puValue)
579 {
580 rc = DosQueryProcAddr(pModNative->hmod,
581 pszSymbol ? 0 : iSymbol,
582 (PCSZ)pszSymbol,
583 &pfn);
584 if (rc)
585 return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc;
586 *puValue = (KUPTR)pfn;
587 }
588 if (pfKind)
589 {
590 ULONG ulProcType;
591 rc = DosQueryProcType(pModNative->hmod,
592 pszSymbol ? 0 : iSymbol,
593 (PCSZ)pszSymbol,
594 &ulProcType);
595 if (rc)
596 {
597 if (puValue)
598 *puValue = 0;
599 return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc;
600 }
601 *pfKind = (ulProcType & PT_32BIT ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT)
602 | KLDRSYMKIND_NO_TYPE;
603 }
604
605#elif K_OS == K_OS_WINDOWS
606 if (!pszSymbol && iSymbol >= 0x10000)
607 return KLDR_ERR_SYMBOL_NOT_FOUND;
608
609 pfn = GetProcAddress(pModNative->hmod, pszSymbol ? pszSymbol : (const char *)(KUPTR)iSymbol);
610 if (puValue)
611 *puValue = (KUPTR)pfn;
612 if (pfKind)
613 *pfKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
614 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT)
615 | KLDRSYMKIND_NO_TYPE;
616
617#elif K_OS == K_OS_DARWIN
618 if (!pszSymbol && iSymbol != NIL_KLDRMOD_SYM_ORDINAL)
619 return KLDR_ERR_SYMBOL_NOT_FOUND;
620
621 pfn = dlsym(pModNative->pvMod, pszSymbol);
622 if (!pfn)
623 return KLDR_ERR_SYMBOL_NOT_FOUND;
624 if (puValue)
625 *puValue = (KUPTR)pfn;
626 if (pfKind)
627 *pfKind = (sizeof(KUPTR) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
628 | KLDRSYMKIND_NO_TYPE;
629
630#else
631# error "Port me"
632#endif
633
634 return 0;
635}
636
637
638/** @copydoc kLdrModEnumSymbols */
639static int kldrModNativeEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
640 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
641{
642 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
643#if K_OS == K_OS_OS2
644
645 /** @todo implement export enumeration on OS/2. */
646 (void)pModNative;
647 return ERROR_NOT_SUPPORTED;
648
649#elif K_OS == K_OS_WINDOWS || defined(__NT__)
650 const KU32 *paFunctions;
651 const IMAGE_EXPORT_DIRECTORY *pExpDir;
652 const KU32 *paRVANames;
653 const KU16 *paOrdinals;
654 KU32 iFunction;
655 KU32 cFunctions;
656 KU32 cNames;
657 int rc;
658
659 /*
660 * Make sure we've got mapped bits and resolve any base address aliases.
661 */
662 if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
663 < sizeof(IMAGE_EXPORT_DIRECTORY))
664 return 0; /* no exports to enumerate, return success. */
665
666 pExpDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
667 pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
668 PIMAGE_EXPORT_DIRECTORY);
669
670 /*
671 * Enumerate the ordinal exports.
672 */
673 paRVANames = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNames, const KU32 *);
674 paOrdinals = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNameOrdinals, const KU16 *);
675 paFunctions = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfFunctions, const KU32 *);
676 cFunctions = pExpDir->NumberOfFunctions;
677 cNames = pExpDir->NumberOfNames;
678 for (iFunction = 0; iFunction < cFunctions; iFunction++)
679 {
680 unsigned fFoundName;
681 KU32 iName;
682 const KU32 uRVA = paFunctions[iFunction];
683 const KLDRADDR uValue = BaseAddress + uRVA;
684 KU32 fKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
685 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
686 | KLDRSYMKIND_NO_TYPE;
687 if ( uRVA - pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
688 < pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
689 fKind |= KLDRSYMKIND_FORWARDER;
690
691 /*
692 * Any symbol names?
693 */
694 fFoundName = 0;
695 for (iName = 0; iName < cNames; iName++)
696 {
697 const char *pszName;
698 if (paOrdinals[iName] != iFunction)
699 continue;
700 fFoundName = 1;
701
702 pszName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, paRVANames[iName], const char *);
703 rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, strlen(pszName), NULL,
704 uValue, fKind, pvUser);
705 if (rc)
706 return rc;
707 }
708
709 /*
710 * If no names, call once with the ordinal only.
711 */
712 if (!fFoundName)
713 {
714 rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser);
715 if (rc)
716 return rc;
717 }
718 }
719 return 0;
720
721#elif K_OS == K_OS_DARWIN
722 /** @todo implement enumeration on darwin. */
723 (void)pModNative;
724 return KLDR_ERR_TODO;
725
726#else
727# error "Port me"
728#endif
729
730}
731
732
733/** @copydoc kLdrModGetImport */
734static int kldrModNativeGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
735{
736 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
737#if K_OS == K_OS_OS2
738
739 /** @todo implement import enumeration on OS/2. */
740 (void)pModNative;
741 return ERROR_NOT_SUPPORTED;
742
743#elif K_OS == K_OS_WINDOWS || defined(__NT__)
744 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
745 const char *pszImportName;
746 KSIZE cchImportName;
747 int rc;
748
749 /*
750 * Simple bounds check.
751 */
752 if (iImport >= (KU32)kldrModNativeNumberOfImports(pMod, pvBits))
753 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
754
755 /*
756 * Get the name.
757 */
758 pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
759 pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
760 + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport,
761 const IMAGE_IMPORT_DESCRIPTOR *);
762 pszImportName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pImpDesc->Name, const char *);
763 cchImportName = kHlpStrLen(pszImportName);
764 if (cchImportName < cchName)
765 {
766 kHlpMemCopy(pszName, pszImportName, cchImportName + 1);
767 rc = 0;
768 }
769 else
770 {
771 kHlpMemCopy(pszName, pszImportName, cchName);
772 if (cchName)
773 pszName[cchName - 1] = '\0';
774 rc = KERR_BUFFER_OVERFLOW;
775 }
776
777 return rc;
778
779#elif K_OS == K_OS_DARWIN
780 /** @todo Implement import enumeration on darwin. */
781 (void)pModNative;
782 return KLDR_ERR_TODO;
783
784#else
785# error "Port me"
786#endif
787}
788
789
790/** @copydoc kLdrModNumberOfImports */
791static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits)
792{
793 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
794#if K_OS == K_OS_OS2
795
796 /** @todo implement import counting on OS/2. */
797 (void)pModNative;
798 return -1;
799
800#elif K_OS == K_OS_WINDOWS || defined(__NT__)
801 if (pModNative->cImportModules == ~(KU32)0)
802 {
803 /*
804 * We'll have to walk the import descriptors to figure out their number.
805 */
806 pModNative->cImportModules = 0;
807 if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
808 && pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
809 {
810 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
811
812 pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
813 pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
814 const IMAGE_IMPORT_DESCRIPTOR *);
815 while (pImpDesc->Name && pImpDesc->FirstThunk)
816 {
817 pModNative->cImportModules++;
818 pImpDesc++;
819 }
820 }
821 }
822 return pModNative->cImportModules;
823
824#elif K_OS == K_OS_DARWIN
825 /** @todo Implement import counting on Darwin. */
826 (void)pModNative;
827 return -1;
828
829#else
830# error "Port me"
831#endif
832}
833
834
835/** @copydoc kLdrModGetStackInfo */
836static int kldrModNativeGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
837{
838 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
839#if K_OS == K_OS_OS2
840
841 /** @todo implement stack info on OS/2. */
842 (void)pModNative;
843 return ERROR_NOT_SUPPORTED;
844
845#elif K_OS == K_OS_WINDOWS || defined(__NT__)
846 pStackInfo->Address = NIL_KLDRADDR;
847 pStackInfo->LinkAddress = NIL_KLDRADDR;
848 pStackInfo->cbStack = pStackInfo->cbStackThread = pModNative->pNtHdrs->OptionalHeader.SizeOfStackReserve;
849
850 return 0;
851
852#elif K_OS == K_OS_DARWIN
853 /** @todo Implement stack info on Darwin. */
854 (void)pModNative;
855 return KLDR_ERR_TODO;
856
857#else
858# error "Port me"
859#endif
860}
861
862
863/** @copydoc kLdrModQueryMainEntrypoint */
864static int kldrModNativeQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
865{
866 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
867#if K_OS == K_OS_OS2
868
869 /** @todo implement me on OS/2. */
870 (void)pModNative;
871 return ERROR_NOT_SUPPORTED;
872
873#elif K_OS == K_OS_WINDOWS || defined(__NT__)
874 /*
875 * Convert the address from the header.
876 */
877 *pMainEPAddress = pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint
878 ? BaseAddress + pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint
879 : NIL_KLDRADDR;
880 return 0;
881
882#elif K_OS == K_OS_DARWIN
883 /** @todo Implement me on Darwin. */
884 (void)pModNative;
885 return KLDR_ERR_TODO;
886
887#else
888# error "Port me"
889#endif
890}
891
892
893/** @copydoc kLdrModEnumDbgInfo */
894static int kldrModNativeEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
895{
896 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
897#if K_OS == K_OS_OS2
898
899 /** @todo implement me on OS/2. */
900 (void)pModNative;
901 return ERROR_NOT_SUPPORTED;
902
903#elif K_OS == K_OS_WINDOWS || defined(__NT__)
904 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
905 KU32 iDbgInfo;
906 KU32 cb;
907 int rc;
908
909 /*
910 * Check that there is a debug directory first.
911 */
912 cb = pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
913 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
914 || !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
915 return 0;
916
917 /*
918 * Enumerate the debug directory.
919 */
920 pDbgDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
921 pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
922 const IMAGE_DEBUG_DIRECTORY *);
923 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
924 {
925 KLDRDBGINFOTYPE enmDbgInfoType;
926
927 /* convert the type. */
928 switch (pDbgDir->Type)
929 {
930 case IMAGE_DEBUG_TYPE_UNKNOWN:
931 case IMAGE_DEBUG_TYPE_FPO:
932 case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
933 case IMAGE_DEBUG_TYPE_MISC:
934 case IMAGE_DEBUG_TYPE_EXCEPTION:
935 case IMAGE_DEBUG_TYPE_FIXUP:
936 case IMAGE_DEBUG_TYPE_BORLAND:
937 default:
938 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
939 break;
940 case IMAGE_DEBUG_TYPE_CODEVIEW:
941 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
942 break;
943 }
944
945 rc = pfnCallback(pMod, iDbgInfo,
946 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
947 pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
948 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
949 pDbgDir->SizeOfData,
950 NULL,
951 pvUser);
952 if (rc)
953 break;
954
955 /* next */
956 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
957 break;
958 }
959
960 return rc;
961
962#elif K_OS == K_OS_DARWIN
963 /** @todo Implement me on Darwin. */
964 (void)pModNative;
965 return KLDR_ERR_TODO;
966
967#else
968# error "Port me"
969#endif
970}
971
972
973/** @copydoc kLdrModHasDbgInfo */
974static int kldrModNativeHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
975{
976 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
977#if K_OS == K_OS_OS2
978
979 /** @todo implement me on OS/2. */
980 (void)pModNative;
981 return KLDR_ERR_NO_DEBUG_INFO;
982
983#elif K_OS == K_OS_WINDOWS || defined(__NT__)
984 /*
985 * Base this entirely on the presence of a debug directory.
986 */
987 if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
988 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
989 || !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
990 return KLDR_ERR_NO_DEBUG_INFO;
991 return 0;
992
993#elif K_OS == K_OS_DARWIN
994 /** @todo Implement me on Darwin. */
995 (void)pModNative;
996 return KLDR_ERR_NO_DEBUG_INFO;
997
998#else
999# error "Port me"
1000#endif
1001}
1002
1003
1004/** @copydoc kLdrModMap */
1005static int kldrModNativeMap(PKLDRMOD pMod)
1006{
1007 return 0;
1008}
1009
1010
1011/** @copydoc kLdrModUnmap */
1012static int kldrModNativeUnmap(PKLDRMOD pMod)
1013{
1014 return 0;
1015}
1016
1017
1018/** @copydoc kLdrModAllocTLS */
1019static int kldrModNativeAllocTLS(PKLDRMOD pMod)
1020{
1021 return 0;
1022}
1023
1024
1025/** @copydoc kLdrModFreeTLS */
1026static void kldrModNativeFreeTLS(PKLDRMOD pMod)
1027{
1028}
1029
1030
1031/** @copydoc kLdrModReload */
1032static int kldrModNativeReload(PKLDRMOD pMod)
1033{
1034 return 0;
1035}
1036
1037
1038/** @copydoc kLdrModFixupMapping */
1039static int kldrModNativeFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1040{
1041 return 0;
1042}
1043
1044
1045/** @copydoc kLdrModCallInit */
1046static int kldrModNativeCallInit(PKLDRMOD pMod, KUPTR uHandle)
1047{
1048 return 0;
1049}
1050
1051
1052/** @copydoc kLdrModCallTerm */
1053static int kldrModNativeCallTerm(PKLDRMOD pMod, KUPTR uHandle)
1054{
1055 return 0;
1056}
1057
1058
1059/** @copydoc kLdrModCallThread */
1060static int kldrModNativeCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
1061{
1062 return 0;
1063}
1064
1065
1066/** @copydoc kLdrModSize */
1067static KLDRADDR kldrModNativeSize(PKLDRMOD pMod)
1068{
1069#if K_OS == K_OS_OS2
1070 return 0; /* don't bother */
1071
1072#elif K_OS == K_OS_WINDOWS || defined(__NT__)
1073 /* just because we can. */
1074 PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
1075 return pModNative->pNtHdrs->OptionalHeader.SizeOfImage;
1076
1077#elif K_OS == K_OS_DARWIN
1078 /** @todo Implement me on Darwin. */
1079 return 0;
1080
1081#else
1082# error "Port me"
1083#endif
1084}
1085
1086
1087/** @copydoc kLdrModGetBits */
1088static int kldrModNativeGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1089{
1090#if K_OS == K_OS_OS2
1091 return ERROR_NOT_SUPPORTED; /* don't bother */
1092
1093#elif K_OS == K_OS_WINDOWS || defined(__NT__)
1094 return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */
1095
1096#elif K_OS == K_OS_DARWIN
1097 return KLDR_ERR_TODO; /* don't bother. */
1098
1099#else
1100# error "Port me"
1101#endif
1102}
1103
1104
1105/** @copydoc kLdrModRelocateBits */
1106static int kldrModNativeRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
1107 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1108{
1109#if K_OS == K_OS_OS2
1110 return ERROR_NOT_SUPPORTED; /* don't bother */
1111
1112#elif K_OS == K_OS_WINDOWS || defined(__NT__)
1113 return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */
1114
1115#elif K_OS == K_OS_DARWIN
1116 return KLDR_ERR_TODO; /* don't bother. */
1117
1118#else
1119# error "Port me"
1120#endif
1121}
1122
1123
1124/**
1125 * The native module interpreter method table.
1126 */
1127KLDRMODOPS g_kLdrModNativeOps =
1128{
1129 "Native",
1130 NULL,
1131 kldrModNativeCreate,
1132 kldrModNativeDestroy,
1133 kldrModNativeQuerySymbol,
1134 kldrModNativeEnumSymbols,
1135 kldrModNativeGetImport,
1136 kldrModNativeNumberOfImports,
1137 NULL /* can execute one is optional */,
1138 kldrModNativeGetStackInfo,
1139 kldrModNativeQueryMainEntrypoint,
1140 NULL /* fixme */,
1141 NULL /* fixme */,
1142 kldrModNativeEnumDbgInfo,
1143 kldrModNativeHasDbgInfo,
1144 kldrModNativeMap,
1145 kldrModNativeUnmap,
1146 kldrModNativeAllocTLS,
1147 kldrModNativeFreeTLS,
1148 kldrModNativeReload,
1149 kldrModNativeFixupMapping,
1150 kldrModNativeCallInit,
1151 kldrModNativeCallTerm,
1152 kldrModNativeCallThread,
1153 kldrModNativeSize,
1154 kldrModNativeGetBits,
1155 kldrModNativeRelocateBits,
1156 NULL /* fixme */,
1157 42 /* the end */
1158};
1159
Note: See TracBrowser for help on using the repository browser.