source: trunk/kLdr/kLdrModMachO.c@ 56

Last change on this file since 56 was 56, checked in by bird, 12 years ago

More mach-o debug info loading adjustments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 142.6 KB
RevLine 
[2]1/* $Id: kLdrModMachO.c 56 2013-10-11 02:07:22Z bird $ */
2/** @file
3 * kLdr - The Module Interpreter for the MACH-O format.
4 */
5
6/*
[29]7 * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
[2]8 *
[29]9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
[2]17 *
[29]18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
[2]20 *
[29]21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
[2]29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <k/kLdr.h>
35#include "kLdrInternal.h"
36#include <k/kLdrFmts/mach-o.h>
37
38
39/*******************************************************************************
40* Defined Constants And Macros *
41*******************************************************************************/
42/** @def KLDRMODMACHO_STRICT
43 * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */
44#define KLDRMODMACHO_STRICT 1
45
46/** @def KLDRMODMACHO_ASSERT
47 * Assert that an expression is true when KLDR_STRICT is defined.
48 */
49#ifdef KLDRMODMACHO_STRICT
50# define KLDRMODMACHO_ASSERT(expr) kHlpAssert(expr)
51#else
52# define KLDRMODMACHO_ASSERT(expr) do {} while (0)
53#endif
54
[22]55/** @def KLDRMODMACHO_CHECK_RETURN
56 * Checks that an expression is true and return if it isn't.
57 * This is a debug aid.
58 */
59#ifdef KLDRMODMACHO_STRICT2
60# define KLDRMODMACHO_CHECK_RETURN(expr, rc) kHlpAssertReturn(expr, rc)
61#else
62# define KLDRMODMACHO_CHECK_RETURN(expr, rc) do { if (!(expr)) { return (rc); } } while (0)
63#endif
[2]64
[22]65
[2]66/*******************************************************************************
67* Structures and Typedefs *
68*******************************************************************************/
69/**
70 * Mach-O section details.
71 */
72typedef struct KLDRMODMACHOSECT
73{
74 /** The size of the section (in bytes). */
75 KLDRSIZE cb;
76 /** The link address of this section. */
77 KLDRADDR LinkAddress;
78 /** The RVA of this section. */
79 KLDRADDR RVA;
80 /** The file offset of this section.
81 * This is -1 if the section doesn't have a file backing. */
82 KLDRFOFF offFile;
83 /** The number of fixups. */
84 KU32 cFixups;
85 /** The array of fixups. (lazy loaded) */
86 macho_relocation_info_t *paFixups;
87 /** The file offset of the fixups for this section.
88 * This is -1 if the section doesn't have any fixups. */
89 KLDRFOFF offFixups;
90 /** Mach-O section flags. */
91 KU32 fFlags;
92 /** kLdr segment index. */
93 KU32 iSegment;
94 /** Pointer to the Mach-O section structure. */
95 void *pvMachoSection;
96} KLDRMODMACHOSECT, *PKLDRMODMACHOSECT;
97
98/**
99 * Extra per-segment info.
100 *
101 * This is corresponds to a kLdr segment, not a Mach-O segment!
102 */
103typedef struct KLDRMODMACHOSEG
104{
[51]105 /** The orignal segment number (in case we had to resort it). */
106 KU32 iOrgSegNo;
[2]107 /** The number of sections in the segment. */
108 KU32 cSections;
109 /** Pointer to the sections belonging to this segment.
110 * The array resides in the big memory chunk allocated for
111 * the module handle, so it doesn't need freeing. */
112 PKLDRMODMACHOSECT paSections;
113
114} KLDRMODMACHOSEG, *PKLDRMODMACHOSEG;
115
116/**
117 * Instance data for the Mach-O MH_OBJECT module interpreter.
118 * @todo interpret the other MH_* formats.
119 */
120typedef struct KLDRMODMACHO
121{
122 /** Pointer to the module. (Follows the section table.) */
123 PKLDRMOD pMod;
124 /** Pointer to the RDR file mapping of the raw file bits. NULL if not mapped. */
125 const void *pvBits;
126 /** Pointer to the user mapping. */
127 void *pvMapping;
[52]128 /** The module open flags. */
129 KU32 fOpenFlags;
[2]130
[25]131 /** The offset of the image. (FAT fun.) */
132 KLDRFOFF offImage;
[2]133 /** The link address. */
134 KLDRADDR LinkAddress;
135 /** The size of the mapped image. */
136 KLDRADDR cbImage;
[43]137 /** Whether we're capable of loading the image. */
138 KBOOL fCanLoad;
[22]139 /** Whether we're creating a global offset table segment.
140 * This dependes on the cputype and image type. */
141 KBOOL fMakeGot;
[23]142 /** The size of a indirect GOT jump stub entry.
143 * This is 0 if not needed. */
144 KU8 cbJmpStub;
[2]145 /** When set the sections in the load command segments must be used when
146 * mapping or loading the image. */
[22]147 KBOOL fMapUsingLoadCommandSections;
[2]148 /** Pointer to the load commands. (endian converted) */
149 KU8 *pbLoadCommands;
150 /** The Mach-O header. (endian converted)
151 * @remark The reserved field is only valid for real 64-bit headers. */
152 mach_header_64_t Hdr;
153
154 /** The offset of the symbol table. */
155 KLDRFOFF offSymbols;
156 /** The number of symbols. */
157 KU32 cSymbols;
158 /** The pointer to the loaded symbol table. */
159 void *pvaSymbols;
160 /** The offset of the string table. */
161 KLDRFOFF offStrings;
162 /** The size of the of the string table. */
163 KU32 cchStrings;
164 /** Pointer to the loaded string table. */
165 char *pchStrings;
166
[54]167 /** The image UUID, all zeros if not found. */
168 KU8 abImageUuid[16];
169
[23]170 /** The RVA of the Global Offset Table. */
171 KLDRADDR GotRVA;
172 /** The RVA of the indirect GOT jump stubs. */
173 KLDRADDR JmpStubsRVA;
174
[2]175 /** The number of sections. */
176 KU32 cSections;
177 /** Pointer to the section array running in parallel to the Mach-O one. */
178 PKLDRMODMACHOSECT paSections;
179
180 /** Array of segments parallel to the one in KLDRMOD. */
181 KLDRMODMACHOSEG aSegments[1];
182} KLDRMODMACHO, *PKLDRMODMACHO;
183
184
185
186/*******************************************************************************
187* Internal Functions *
188*******************************************************************************/
189#if 0
190static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits);
191#endif
192static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
193 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
194
[52]195static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppMod);
[25]196static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage,
[52]197 KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool,
198 PKBOOL pfCanLoad, PKLDRADDR pLinkAddress);
[2]199static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool);
200static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress);
201
202/*static int kldrModMachOLoadLoadCommands(PKLDRMODMACHO pModMachO);*/
203static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO);
204static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups);
205static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO);
206
207static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings,
208 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol,
209 KSIZE cchSymbol, PKLDRADDR puValue, KU32 *pfKind);
[22]210static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings,
211 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol,
212 KSIZE cchSymbol, PKLDRADDR puValue, KU32 *pfKind);
[2]213static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
214 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
215 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
[22]216static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms,
217 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
218 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
[47]219static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
[2]220static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress);
221static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
222 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress);
[22]223static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
224 macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress);
[2]225
[22]226static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress);
227
[2]228/*static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
229static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);*/
230
231
232/**
233 * Create a loader module instance interpreting the executable image found
234 * in the specified file provider instance.
235 *
236 * @returns 0 on success and *ppMod pointing to a module instance.
237 * On failure, a non-zero OS specific error code is returned.
238 * @param pOps Pointer to the registered method table.
239 * @param pRdr The file provider instance to use.
[25]240 * @param fFlags Flags, MBZ.
241 * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means
242 * anything goes, but with a preference for the current
243 * host architecture.
[2]244 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
245 * @param ppMod Where to store the module instance pointer.
246 */
[25]247static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
[2]248{
249 PKLDRMODMACHO pModMachO;
250 int rc;
251
252 /*
253 * Create the instance data and do a minimal header validation.
254 */
[52]255 rc = kldrModMachODoCreate(pRdr, offNewHdr == -1 ? 0 : offNewHdr, fFlags, &pModMachO);
[2]256 if (!rc)
257 {
[25]258
259 /*
260 * Match up against the requested CPU architecture.
261 */
262 if ( enmCpuArch == KCPUARCH_UNKNOWN
263 || pModMachO->pMod->enmArch == enmCpuArch)
264 {
265 pModMachO->pMod->pOps = pOps;
266 pModMachO->pMod->u32Magic = KLDRMOD_MAGIC;
267 *ppMod = pModMachO->pMod;
268 return 0;
269 }
270 rc = KLDR_ERR_CPU_ARCH_MISMATCH;
[2]271 }
272 if (pModMachO)
273 {
274 kHlpFree(pModMachO->pbLoadCommands);
275 kHlpFree(pModMachO);
276 }
277 return rc;
278}
279
280
281/**
[22]282 * Separate function for reading creating the Mach-O module instance to
[2]283 * simplify cleanup on failure.
284 */
[52]285static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppModMachO)
[2]286{
287 union
288 {
289 mach_header_32_t Hdr32;
290 mach_header_64_t Hdr64;
291 } s;
292 PKLDRMODMACHO pModMachO;
293 PKLDRMOD pMod;
294 KU8 *pbLoadCommands;
295 KU32 cSegments;
296 KU32 cSections;
297 KU32 cbStringPool;
298 KSIZE cchFilename;
299 KSIZE cb;
[22]300 KBOOL fMakeGot;
[43]301 KBOOL fCanLoad = K_TRUE;
[51]302 KLDRADDR LinkAddress;
[23]303 KU8 cbJmpStub;
[2]304 int rc;
305 *ppModMachO = NULL;
306
[22]307 kHlpAssert(&s.Hdr32.magic == &s.Hdr64.magic);
308 kHlpAssert(&s.Hdr32.flags == &s.Hdr64.flags);
309
[2]310 /*
311 * Read the Mach-O header.
312 */
[25]313 rc = kRdrRead(pRdr, &s, sizeof(s), offImage);
[2]314 if (rc)
315 return rc;
[22]316 if ( s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE
317 && s.Hdr32.magic != IMAGE_MACHO64_SIGNATURE
318 )
[2]319 {
320 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
321 || s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE)
322 return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED;
323 return KLDR_ERR_UNKNOWN_FORMAT;
324 }
325
326 /* sanity checks. */
327 if ( s.Hdr32.sizeofcmds > kRdrSize(pRdr) - sizeof(mach_header_32_t)
328 || s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds
329 || (s.Hdr32.flags & ~MH_VALID_FLAGS))
330 return KLDR_ERR_MACHO_BAD_HEADER;
331 switch (s.Hdr32.cputype)
332 {
333 case CPU_TYPE_X86:
[22]334 fMakeGot = K_FALSE;
[23]335 cbJmpStub = 0;
[22]336 break;
[2]337 case CPU_TYPE_X86_64:
[22]338 fMakeGot = s.Hdr32.filetype == MH_OBJECT;
[23]339 cbJmpStub = fMakeGot ? 8 : 0;
[2]340 break;
341 default:
342 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
343 }
[41]344 if ( s.Hdr32.filetype != MH_OBJECT
345 && s.Hdr32.filetype != MH_EXECUTE
346 && s.Hdr32.filetype != MH_DYLIB
[55]347 && s.Hdr32.filetype != MH_DSYM
348 && s.Hdr32.filetype != MH_KEXT_BUNDLE)
[2]349 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
350
351 /*
352 * Read and pre-parse the load commands to figure out how many segments we'll be needing.
353 */
354 pbLoadCommands = kHlpAlloc(s.Hdr32.sizeofcmds);
355 if (!pbLoadCommands)
356 return KERR_NO_MEMORY;
357 rc = kRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds,
[25]358 s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
359 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
360 ? sizeof(mach_header_32_t) + offImage
361 : sizeof(mach_header_64_t) + offImage);
[2]362 if (!rc)
[52]363 rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, offImage, fOpenFlags,
[51]364 &cSegments, &cSections, &cbStringPool, &fCanLoad, &LinkAddress);
[2]365 if (rc)
366 {
367 kHlpFree(pbLoadCommands);
368 return rc;
369 }
[22]370 cSegments += fMakeGot;
[2]371
372
373 /*
374 * Calc the instance size, allocate and initialize it.
375 */
376 cchFilename = kHlpStrLen(kRdrName(pRdr));
377 cb = K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
378 + sizeof(KLDRMODMACHOSECT) * cSections, 16)
379 + K_OFFSETOF(KLDRMOD, aSegments[cSegments])
380 + cchFilename + 1
381 + cbStringPool;
382 pModMachO = (PKLDRMODMACHO)kHlpAlloc(cb);
383 if (!pModMachO)
384 return KERR_NO_MEMORY;
385 *ppModMachO = pModMachO;
386 pModMachO->pbLoadCommands = pbLoadCommands;
[25]387 pModMachO->offImage = offImage;
[2]388
389 /* KLDRMOD */
390 pMod = (PKLDRMOD)((KU8 *)pModMachO + K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
391 + sizeof(KLDRMODMACHOSECT) * cSections, 16));
392 pMod->pvData = pModMachO;
393 pMod->pRdr = pRdr;
394 pMod->pOps = NULL; /* set upon success. */
395 pMod->cSegments = cSegments;
396 pMod->cchFilename = cchFilename;
397 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
398 kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1);
399 pMod->pszName = kHlpGetFilename(pMod->pszFilename);
400 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
401 switch (s.Hdr32.cputype)
402 {
403 case CPU_TYPE_X86:
404 pMod->enmArch = KCPUARCH_X86_32;
405 pMod->enmEndian = KLDRENDIAN_LITTLE;
406 switch (s.Hdr32.cpusubtype)
407 {
408 case CPU_SUBTYPE_I386_ALL: pMod->enmCpu = KCPU_X86_32_BLEND; break;
409 /*case CPU_SUBTYPE_386: ^^ pMod->enmCpu = KCPU_I386; break;*/
410 case CPU_SUBTYPE_486: pMod->enmCpu = KCPU_I486; break;
411 case CPU_SUBTYPE_486SX: pMod->enmCpu = KCPU_I486SX; break;
412 /*case CPU_SUBTYPE_586: vv */
413 case CPU_SUBTYPE_PENT: pMod->enmCpu = KCPU_I586; break;
414 case CPU_SUBTYPE_PENTPRO:
415 case CPU_SUBTYPE_PENTII_M3:
416 case CPU_SUBTYPE_PENTII_M5:
417 case CPU_SUBTYPE_CELERON:
418 case CPU_SUBTYPE_CELERON_MOBILE:
419 case CPU_SUBTYPE_PENTIUM_3:
420 case CPU_SUBTYPE_PENTIUM_3_M:
421 case CPU_SUBTYPE_PENTIUM_3_XEON: pMod->enmCpu = KCPU_I686; break;
422 case CPU_SUBTYPE_PENTIUM_M:
423 case CPU_SUBTYPE_PENTIUM_4:
424 case CPU_SUBTYPE_PENTIUM_4_M:
425 case CPU_SUBTYPE_XEON:
426 case CPU_SUBTYPE_XEON_MP: pMod->enmCpu = KCPU_P4; break;
427 break;
428 default:
429 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
430 }
431 break;
432
433 case CPU_TYPE_X86_64:
434 pMod->enmArch = KCPUARCH_AMD64;
435 pMod->enmEndian = KLDRENDIAN_LITTLE;
[22]436 switch (s.Hdr32.cpusubtype & ~CPU_SUBTYPE_MASK)
[2]437 {
438 case CPU_SUBTYPE_X86_64_ALL: pMod->enmCpu = KCPU_AMD64_BLEND; break;
439 default:
440 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
441 }
442 break;
443
444 default:
445 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
446 }
447
448 pMod->enmFmt = KLDRFMT_MACHO;
449 switch (s.Hdr32.filetype)
450 {
[41]451 case MH_OBJECT: pMod->enmType = KLDRTYPE_OBJECT; break;
452 case MH_EXECUTE: pMod->enmType = KLDRTYPE_EXECUTABLE_FIXED; break;
453 case MH_DYLIB: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break;
[55]454 case MH_KEXT_BUNDLE:pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break;
[41]455 case MH_DSYM: pMod->enmType = KLDRTYPE_DEBUG_INFO; break;
[2]456 default:
457 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
458 }
459 pMod->u32Magic = 0; /* set upon success. */
460
461 /* KLDRMODMACHO */
462 pModMachO->pMod = pMod;
463 pModMachO->pvBits = NULL;
464 pModMachO->pvMapping = NULL;
[52]465 pModMachO->fOpenFlags = fOpenFlags;
[2]466 pModMachO->Hdr = s.Hdr64;
467 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
468 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE)
469 pModMachO->Hdr.reserved = 0;
[51]470 pModMachO->LinkAddress = LinkAddress;
[2]471 pModMachO->cbImage = 0;
[43]472 pModMachO->fCanLoad = fCanLoad;
[22]473 pModMachO->fMakeGot = fMakeGot;
[23]474 pModMachO->cbJmpStub = cbJmpStub;
[22]475 pModMachO->fMapUsingLoadCommandSections = K_FALSE;
[2]476 pModMachO->offSymbols = 0;
477 pModMachO->cSymbols = 0;
478 pModMachO->pvaSymbols = NULL;
479 pModMachO->offStrings = 0;
480 pModMachO->cchStrings = 0;
481 pModMachO->pchStrings = NULL;
[54]482 kHlpMemSet(pModMachO->abImageUuid, 0, sizeof(pModMachO->abImageUuid));
[23]483 pModMachO->GotRVA = NIL_KLDRADDR;
484 pModMachO->JmpStubsRVA = NIL_KLDRADDR;
[2]485 pModMachO->cSections = cSections;
486 pModMachO->paSections = (PKLDRMODMACHOSECT)&pModMachO->aSegments[pModMachO->pMod->cSegments];
487
488 /*
489 * Setup the KLDRMOD segment array.
490 */
491 rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool);
492 if (rc)
493 return rc;
494
495 /*
496 * We're done.
497 */
498 return 0;
499}
500
501
502/**
503 * Converts, validates and preparses the load commands before we carve
504 * out the module instance.
505 *
506 * The conversion that's preformed is format endian to host endian.
507 * The preparsing has to do with segment counting, section counting and string pool sizing.
508 *
509 * @returns 0 on success.
510 * @returns KLDR_ERR_MACHO_* on failure.
511 * @param pbLoadCommands The load commands to parse.
512 * @param pHdr The header.
513 * @param pRdr The file reader.
[25]514 * @param offImage The image header (FAT fun).
[2]515 * @param pcSegments Where to store the segment count.
516 * @param pcSegments Where to store the section count.
517 * @param pcbStringPool Where to store the string pool size.
[43]518 * @param pfCanLoad Where to store the can-load-image indicator.
[51]519 * @param pLinkAddress Where to store the image link address (i.e. the
520 * lowest segment address).
[2]521 */
[25]522static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage,
[52]523 KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool,
524 PKBOOL pfCanLoad, PKLDRADDR pLinkAddress)
[2]525{
526 union
527 {
528 KU8 *pb;
529 load_command_t *pLoadCmd;
530 segment_command_32_t *pSeg32;
531 segment_command_64_t *pSeg64;
532 thread_command_t *pThread;
533 symtab_command_t *pSymTab;
534 uuid_command_t *pUuid;
535 } u;
[25]536 const KU64 cbFile = kRdrSize(pRdr) - offImage;
[52]537 const char *pchCurSegName = NULL;
[2]538 KU32 cSegments = 0;
539 KU32 cSections = 0;
540 KU32 cbStringPool = 0;
541 KU32 cLeft = pHdr->ncmds;
542 KU32 cbLeft = pHdr->sizeofcmds;
543 KU8 *pb = pbLoadCommands;
544 int cSegmentCommands = 0;
545 int cSymbolTabs = 0;
546 int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
547 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
548
549 *pcSegments = 0;
550 *pcSections = 0;
551 *pcbStringPool = 0;
[43]552 *pfCanLoad = K_TRUE;
[51]553 *pLinkAddress = ~(KLDRADDR)0;
[2]554
555 while (cLeft-- > 0)
556 {
557 u.pb = pb;
558
559 /*
560 * Convert and validate command header.
561 */
562 if (cbLeft < sizeof(load_command_t))
563 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
564 if (fConvertEndian)
565 {
566 u.pLoadCmd->cmd = K_E2E_U32(u.pLoadCmd->cmd);
567 u.pLoadCmd->cmdsize = K_E2E_U32(u.pLoadCmd->cmdsize);
568 }
569 if (u.pLoadCmd->cmdsize > cbLeft)
570 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
571 cbLeft -= u.pLoadCmd->cmdsize;
572 pb += u.pLoadCmd->cmdsize;
573
574 /*
575 * Convert endian if needed, parse and validate the command.
576 */
577 switch (u.pLoadCmd->cmd)
578 {
579 case LC_SEGMENT_32:
580 {
581 section_32_t *pSect;
582 section_32_t *pFirstSect;
583 KU32 cSectionsLeft;
584
585 /* convert and verify*/
586 if (u.pLoadCmd->cmdsize < sizeof(segment_command_32_t))
587 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
588 if ( pHdr->magic != IMAGE_MACHO32_SIGNATURE_OE
589 && pHdr->magic != IMAGE_MACHO32_SIGNATURE)
590 return KLDR_ERR_MACHO_BIT_MIX;
591 if (fConvertEndian)
592 {
593 u.pSeg32->vmaddr = K_E2E_U32(u.pSeg32->vmaddr);
594 u.pSeg32->vmsize = K_E2E_U32(u.pSeg32->vmsize);
595 u.pSeg32->fileoff = K_E2E_U32(u.pSeg32->fileoff);
596 u.pSeg32->filesize = K_E2E_U32(u.pSeg32->filesize);
597 u.pSeg32->maxprot = K_E2E_U32(u.pSeg32->maxprot);
598 u.pSeg32->initprot = K_E2E_U32(u.pSeg32->initprot);
599 u.pSeg32->nsects = K_E2E_U32(u.pSeg32->nsects);
600 u.pSeg32->flags = K_E2E_U32(u.pSeg32->flags);
601 }
602
603 if ( u.pSeg32->filesize
604 && ( u.pSeg32->fileoff > cbFile
605 || (KU64)u.pSeg32->fileoff + u.pSeg32->filesize > cbFile))
606 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
607 if (u.pSeg32->vmsize < u.pSeg32->filesize)
608 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
609 if ((u.pSeg32->maxprot & u.pSeg32->initprot) != u.pSeg32->initprot)
610 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
611 if (u.pSeg32->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
612 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
613 if (u.pSeg32->nsects * sizeof(section_32_t) > u.pLoadCmd->cmdsize - sizeof(segment_command_32_t))
614 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
615 if ( pHdr->filetype == MH_OBJECT
616 && cSegmentCommands > 0)
617 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
618 cSegmentCommands++;
619
620 /*
621 * convert, validate and parse the sections.
622 */
623 cSectionsLeft = u.pSeg32->nsects;
624 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
625 while (cSectionsLeft-- > 0)
626 {
627 int fFileBits;
628
629 if (fConvertEndian)
630 {
631 pSect->addr = K_E2E_U32(pSect->addr);
632 pSect->size = K_E2E_U32(pSect->size);
633 pSect->offset = K_E2E_U32(pSect->offset);
634 pSect->align = K_E2E_U32(pSect->align);
635 pSect->reloff = K_E2E_U32(pSect->reloff);
636 pSect->nreloc = K_E2E_U32(pSect->nreloc);
637 pSect->flags = K_E2E_U32(pSect->flags);
638 pSect->reserved1 = K_E2E_U32(pSect->reserved1);
639 pSect->reserved2 = K_E2E_U32(pSect->reserved2);
640 }
641
642 /* validate */
643 switch (pSect->flags & SECTION_TYPE)
644 {
645 case S_ZEROFILL:
646 if (pSect->reserved1 || pSect->reserved2)
647 return KLDR_ERR_MACHO_BAD_SECTION;
648 fFileBits = 0;
649 break;
650 case S_REGULAR:
651 case S_CSTRING_LITERALS:
652 case S_COALESCED:
653 case S_4BYTE_LITERALS:
654 case S_8BYTE_LITERALS:
655 case S_16BYTE_LITERALS:
656 if (pSect->reserved1 || pSect->reserved2)
657 return KLDR_ERR_MACHO_BAD_SECTION;
658 fFileBits = 1;
659 break;
660
[43]661 case S_SYMBOL_STUBS:
662 if ( pSect->reserved1
663 || pSect->reserved2 < 1
664 || pSect->reserved2 > 64 )
665 return KLDR_ERR_MACHO_BAD_SECTION;
666 fFileBits = 0;
667 break;
668
669 case S_NON_LAZY_SYMBOL_POINTERS:
670 case S_LAZY_SYMBOL_POINTERS:
671 if (pSect->reserved2) /* (reserved 1 is indirect symbol table index)*/
672 return KLDR_ERR_MACHO_BAD_SECTION;
673 *pfCanLoad = K_FALSE;
[53]674 fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */
[43]675 break;
676
[52]677 case S_MOD_INIT_FUNC_POINTERS: /** @todo this requires a query API or flag... (e.g. C++ constructors) */
678 if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO))
679 return KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION;
680 case S_MOD_TERM_FUNC_POINTERS: /** @todo this requires a query API or flag... (e.g. C++ destructors) */
681 if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO))
682 return KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION;
683 if (pSect->reserved1 || pSect->reserved2)
684 return KLDR_ERR_MACHO_BAD_SECTION;
685 fFileBits = 1;
686 break; /* ignored */
687
[2]688 case S_LITERAL_POINTERS:
689 case S_INTERPOSING:
690 case S_GB_ZEROFILL:
[52]691 return KLDR_ERR_MACHO_UNSUPPORTED_SECTION;
[2]692
693 default:
694 return KLDR_ERR_MACHO_UNKNOWN_SECTION;
695 }
696 if (pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS
697 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE
698 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC
699 | S_ATTR_LOC_RELOC | SECTION_TYPE))
700 return KLDR_ERR_MACHO_BAD_SECTION;
701 if ( pSect->addr - u.pSeg32->vmaddr > u.pSeg32->vmsize
702 || pSect->addr - u.pSeg32->vmaddr + pSect->size > u.pSeg32->vmsize)
703 return KLDR_ERR_MACHO_BAD_SECTION;
704 if ( pSect->align >= 31
705 || (((1 << pSect->align) - 1) & pSect->addr)
706 || (((1 << pSect->align) - 1) & u.pSeg32->vmaddr))
707 return KLDR_ERR_MACHO_BAD_SECTION;
708 if ( fFileBits
709 && ( pSect->offset > cbFile
710 || (KU64)pSect->offset + pSect->size > cbFile))
711 return KLDR_ERR_MACHO_BAD_SECTION;
712 if (!fFileBits && pSect->offset)
713 return KLDR_ERR_MACHO_BAD_SECTION;
714 if (!pSect->nreloc && pSect->reloff)
715 return KLDR_ERR_MACHO_BAD_SECTION;
716 if ( pSect->nreloc
717 && ( pSect->reloff > cbFile
718 || (KU64)pSect->reloff + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t)) > cbFile)
719 return KLDR_ERR_MACHO_BAD_SECTION;
720
721
[51]722 /* count segments and strings, calculate image link address. */
[2]723 switch (pHdr->filetype)
724 {
725 case MH_OBJECT:
[41]726 case MH_EXECUTE:
727 case MH_DYLIB:
728 case MH_DSYM:
[55]729 case MH_KEXT_BUNDLE:
[2]730 {
731 cSections++;
732
[43]733 /* Don't load debug symbols. */
734 if ( (pSect->flags & S_ATTR_DEBUG)
735 || !kHlpStrComp(pSect->segname, "__DWARF"))
[2]736 break;
737
738 /* a new segment? */
[52]739 if ( !pchCurSegName
740 || kHlpStrNComp(pSect->segname, pchCurSegName, sizeof(pSect->segname)))
[2]741 {
[22]742#if 0 /** @todo This doesn't work because of BSS. */
[2]743 /* verify that the linker/assembler has ordered sections correctly. */
744 section_32_t *pCur = (pSect - 2);
745 while ((KUPTR)pCur >= (KUPTR)pFirstSect)
746 {
747 if (!kHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
748 return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
749 pCur--;
750 }
751#endif
752
753 /* ok. count it and the string. */
[52]754 pchCurSegName = &pSect->segname[0];
755 cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1;
[2]756 cSegments++;
[51]757
758 /* Link address lower? */
759 if (*pLinkAddress > u.pSeg32->vmaddr)
760 *pLinkAddress = u.pSeg32->vmaddr;
[2]761 }
762 break;
763 }
764
765 default:
766 return KERR_INVALID_PARAMETER;
767 }
768
769 /* next */
770 pSect++;
771 }
772 break;
773 }
774
[22]775 case LC_SEGMENT_64:
776 {
777 section_64_t *pSect;
778 section_64_t *pFirstSect;
779 KU32 cSectionsLeft;
780
781 /* convert and verify*/
782 if (u.pLoadCmd->cmdsize < sizeof(segment_command_64_t))
783 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
784 if ( pHdr->magic != IMAGE_MACHO64_SIGNATURE_OE
785 && pHdr->magic != IMAGE_MACHO64_SIGNATURE)
786 return KLDR_ERR_MACHO_BIT_MIX;
787 if (fConvertEndian)
788 {
789 u.pSeg64->vmaddr = K_E2E_U64(u.pSeg64->vmaddr);
790 u.pSeg64->vmsize = K_E2E_U64(u.pSeg64->vmsize);
791 u.pSeg64->fileoff = K_E2E_U64(u.pSeg64->fileoff);
792 u.pSeg64->filesize = K_E2E_U64(u.pSeg64->filesize);
793 u.pSeg64->maxprot = K_E2E_U32(u.pSeg64->maxprot);
794 u.pSeg64->initprot = K_E2E_U32(u.pSeg64->initprot);
795 u.pSeg64->nsects = K_E2E_U32(u.pSeg64->nsects);
796 u.pSeg64->flags = K_E2E_U32(u.pSeg64->flags);
797 }
798
799 if ( u.pSeg64->filesize
800 && ( u.pSeg64->fileoff > cbFile
801 || u.pSeg64->fileoff + u.pSeg64->filesize > cbFile))
802 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
803 if (u.pSeg64->vmsize < u.pSeg64->filesize)
804 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
805 if ((u.pSeg64->maxprot & u.pSeg64->initprot) != u.pSeg64->initprot)
806 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
807 if (u.pSeg64->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
808 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
809 if (u.pSeg64->nsects * sizeof(section_64_t) > u.pLoadCmd->cmdsize - sizeof(segment_command_64_t))
810 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
811 if ( pHdr->filetype == MH_OBJECT
812 && cSegmentCommands > 0)
813 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
814 cSegmentCommands++;
815
816 /*
817 * convert, validate and parse the sections.
818 */
819 cSectionsLeft = u.pSeg64->nsects;
820 pFirstSect = pSect = (section_64_t *)(u.pSeg64 + 1);
821 while (cSectionsLeft-- > 0)
822 {
823 int fFileBits;
824
825 if (fConvertEndian)
826 {
827 pSect->addr = K_E2E_U64(pSect->addr);
828 pSect->size = K_E2E_U64(pSect->size);
829 pSect->offset = K_E2E_U32(pSect->offset);
830 pSect->align = K_E2E_U32(pSect->align);
831 pSect->reloff = K_E2E_U32(pSect->reloff);
832 pSect->nreloc = K_E2E_U32(pSect->nreloc);
833 pSect->flags = K_E2E_U32(pSect->flags);
834 pSect->reserved1 = K_E2E_U32(pSect->reserved1);
835 pSect->reserved2 = K_E2E_U32(pSect->reserved2);
836 }
837
838 /* validate */
839 switch (pSect->flags & SECTION_TYPE)
840 {
841 case S_ZEROFILL:
842 if (pSect->reserved1 || pSect->reserved2)
843 return KLDR_ERR_MACHO_BAD_SECTION;
844 fFileBits = 0;
845 break;
846 case S_REGULAR:
847 case S_CSTRING_LITERALS:
848 case S_COALESCED:
849 case S_4BYTE_LITERALS:
850 case S_8BYTE_LITERALS:
851 case S_16BYTE_LITERALS:
852 if (pSect->reserved1 || pSect->reserved2)
853 return KLDR_ERR_MACHO_BAD_SECTION;
854 fFileBits = 1;
855 break;
856
[43]857 case S_SYMBOL_STUBS:
858 if ( pSect->reserved1
[56]859 || pSect->reserved2 > 64 /* stub size. 0 has been seen (corecrypto.kext) */ )
[43]860 return KLDR_ERR_MACHO_BAD_SECTION;
861 fFileBits = 1;
862 break;
863
864 case S_NON_LAZY_SYMBOL_POINTERS:
865 case S_LAZY_SYMBOL_POINTERS:
866 if (pSect->reserved2) /* (reserved 1 is indirect symbol table index)*/
867 return KLDR_ERR_MACHO_BAD_SECTION;
868 *pfCanLoad = K_FALSE;
[53]869 fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */
[43]870 break;
871
[52]872 case S_MOD_INIT_FUNC_POINTERS: /** @todo this requires a query API or flag... (e.g. C++ constructors) */
873 if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO))
874 return KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION;
875 case S_MOD_TERM_FUNC_POINTERS: /** @todo this requires a query API or flag... (e.g. C++ destructors) */
876 if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO))
877 return KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION;
878 if (pSect->reserved1 || pSect->reserved2)
879 return KLDR_ERR_MACHO_BAD_SECTION;
880 fFileBits = 1;
881 break; /* ignored */
882
[22]883 case S_LITERAL_POINTERS:
884 case S_INTERPOSING:
885 case S_GB_ZEROFILL:
886 return KLDR_ERR_MACHO_UNSUPPORTED_SECTION;
887
888 default:
889 return KLDR_ERR_MACHO_UNKNOWN_SECTION;
890 }
891 if (pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS
892 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE
893 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC
894 | S_ATTR_LOC_RELOC | SECTION_TYPE))
895 return KLDR_ERR_MACHO_BAD_SECTION;
896 if ( pSect->addr - u.pSeg64->vmaddr > u.pSeg64->vmsize
897 || pSect->addr - u.pSeg64->vmaddr + pSect->size > u.pSeg64->vmsize)
898 return KLDR_ERR_MACHO_BAD_SECTION;
899 if ( pSect->align >= 31
900 || (((1 << pSect->align) - 1) & pSect->addr)
901 || (((1 << pSect->align) - 1) & u.pSeg64->vmaddr))
902 return KLDR_ERR_MACHO_BAD_SECTION;
903 if ( fFileBits
904 && ( pSect->offset > cbFile
905 || (KU64)pSect->offset + pSect->size > cbFile))
906 return KLDR_ERR_MACHO_BAD_SECTION;
907 if (!fFileBits && pSect->offset)
908 return KLDR_ERR_MACHO_BAD_SECTION;
909 if (!pSect->nreloc && pSect->reloff)
910 return KLDR_ERR_MACHO_BAD_SECTION;
911 if ( pSect->nreloc
912 && ( pSect->reloff > cbFile
913 || (KU64)pSect->reloff + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t)) > cbFile)
914 return KLDR_ERR_MACHO_BAD_SECTION;
915
916
[51]917 /* count segments and strings, calculate image link address. */
[22]918 switch (pHdr->filetype)
919 {
920 case MH_OBJECT:
[41]921 case MH_EXECUTE:
922 case MH_DYLIB:
923 case MH_DSYM:
[55]924 case MH_KEXT_BUNDLE:
[22]925 {
926 cSections++;
927
928 /* Don't load debug symbols. (test this) */
[43]929 if ( (pSect->flags & S_ATTR_DEBUG)
930 || !kHlpStrComp(pSect->segname, "__DWARF"))
[22]931 break;
932
933 /* a new segment? */
[52]934 if ( !pchCurSegName
935 || kHlpStrNComp(pSect->segname, pchCurSegName, sizeof(pSect->segname)))
[22]936 {
937#if 0 /** @todo This doesn't work because of BSS. */
938 /* verify that the linker/assembler has ordered sections correctly. */
939 section_64_t *pCur = (pSect - 2);
940 while ((KUPTR)pCur >= (KUPTR)pFirstSect)
941 {
942 if (!kHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
943 return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
944 pCur--;
945 }
946#endif
947
948 /* ok. count it and the string. */
[52]949 pchCurSegName = &pSect->segname[0];
950 cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1;
[22]951 cSegments++;
[51]952
953 /* Link address lower? */
954 if (*pLinkAddress > u.pSeg64->vmaddr)
955 *pLinkAddress = u.pSeg64->vmaddr;
[22]956 }
957 break;
958 }
959
960 default:
961 return KERR_INVALID_PARAMETER;
962 }
963
964 /* next */
965 pSect++;
966 }
[2]967 break;
[22]968 } /* LC_SEGMENT_64 */
[2]969
[22]970
[2]971 case LC_SYMTAB:
972 {
973 KSIZE cbSym;
974 if (fConvertEndian)
975 {
976 u.pSymTab->symoff = K_E2E_U32(u.pSymTab->symoff);
977 u.pSymTab->nsyms = K_E2E_U32(u.pSymTab->nsyms);
978 u.pSymTab->stroff = K_E2E_U32(u.pSymTab->stroff);
979 u.pSymTab->strsize = K_E2E_U32(u.pSymTab->strsize);
980 }
981
982 /* verify */
983 cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE
984 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
985 ? sizeof(macho_nlist_32_t)
986 : sizeof(macho_nlist_64_t);
987 if ( u.pSymTab->symoff >= cbFile
988 || (KU64)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > cbFile)
989 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
990 if ( u.pSymTab->stroff >= cbFile
991 || (KU64)u.pSymTab->stroff + u.pSymTab->strsize > cbFile)
992 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
993
994 /* only one string in objects, please. */
995 cSymbolTabs++;
996 if ( pHdr->filetype == MH_OBJECT
997 && cSymbolTabs != 1)
998 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
999 break;
1000 }
1001
1002 case LC_DYSYMTAB:
1003 /** @todo deal with this! */
1004 break;
1005
1006 case LC_THREAD:
1007 case LC_UNIXTHREAD:
1008 {
1009 KU32 *pu32 = (KU32 *)(u.pb + sizeof(load_command_t));
1010 KU32 cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(KU32);
1011 while (cItemsLeft)
1012 {
1013 /* convert & verify header items ([0] == flavor, [1] == KU32 count). */
1014 if (cItemsLeft < 2)
1015 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
1016 if (fConvertEndian)
1017 {
1018 pu32[0] = K_E2E_U32(pu32[0]);
1019 pu32[1] = K_E2E_U32(pu32[1]);
1020 }
1021 if (pu32[1] + 2 > cItemsLeft)
1022 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
1023
1024 /* convert & verify according to flavor. */
1025 switch (pu32[0])
1026 {
1027 /** @todo */
1028 default:
1029 break;
1030 }
1031
1032 /* next */
1033 cItemsLeft -= pu32[1] + 2;
1034 pu32 += pu32[1] + 2;
1035 }
1036 break;
1037 }
1038
1039 case LC_UUID:
1040 if (u.pUuid->cmdsize != sizeof(uuid_command_t))
1041 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
1042 /** @todo Check anything here need converting? */
1043 break;
1044
[48]1045 case LC_CODE_SIGNATURE:
1046 if (u.pUuid->cmdsize != sizeof(linkedit_data_command_t))
1047 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
1048 break;
1049
1050 case LC_VERSION_MIN_MACOSX:
1051 case LC_VERSION_MIN_IPHONEOS:
1052 if (u.pUuid->cmdsize != sizeof(version_min_command_t))
1053 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
1054 break;
1055
[56]1056 case LC_SOURCE_VERSION: /* Harmless. It just gives a clue regarding the source code revision/version. */
1057 case LC_DATA_IN_CODE: /* Ignore */
1058 case LC_DYLIB_CODE_SIGN_DRS:/* Ignore */
1059 /** @todo valid command size. */
1060 break;
1061
1062 case LC_ID_DYLIB: /** @todo dylib */
1063 case LC_LOAD_DYLIB: /** @todo dylib */
1064 case LC_LOAD_DYLINKER: /** @todo dylib */
1065 case LC_TWOLEVEL_HINTS: /** @todo dylib */
1066 case LC_LOAD_WEAK_DYLIB: /** @todo dylib */
1067 case LC_ID_DYLINKER: /** @todo dylib */
1068 case LC_DYLD_ENVIRONMENT: /** @todo dylib */
1069 case LC_MAIN: /** @todo parse this and find and entry point or smth. */
1070 /** @todo valid command size. */
1071 if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO))
1072 return KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND;
1073 break;
1074
[2]1075 case LC_LOADFVMLIB:
1076 case LC_IDFVMLIB:
1077 case LC_IDENT:
1078 case LC_FVMFILE:
1079 case LC_PREPAGE:
1080 case LC_PREBOUND_DYLIB:
1081 case LC_ROUTINES:
1082 case LC_ROUTINES_64:
1083 case LC_SUB_FRAMEWORK:
1084 case LC_SUB_UMBRELLA:
1085 case LC_SUB_CLIENT:
1086 case LC_SUB_LIBRARY:
1087 case LC_PREBIND_CKSUM:
1088 case LC_SYMSEG:
1089 return KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND;
1090
1091 default:
1092 return KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND;
1093 }
1094 }
1095
1096 /* be strict. */
1097 if (cbLeft)
1098 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
1099
1100 switch (pHdr->filetype)
1101 {
1102 case MH_OBJECT:
[41]1103 case MH_EXECUTE:
1104 case MH_DYLIB:
1105 case MH_DSYM:
[55]1106 case MH_KEXT_BUNDLE:
[2]1107 if (!cSegments)
1108 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
1109 break;
1110 }
1111
1112 *pcSegments = cSegments;
1113 *pcSections = cSections;
1114 *pcbStringPool = cbStringPool;
1115
1116 return 0;
1117}
1118
1119
1120/**
1121 * Parses the load commands after we've carved out the module instance.
1122 *
1123 * This fills in the segment table and perhaps some other properties.
1124 *
1125 * @returns 0 on success.
1126 * @returns KLDR_ERR_MACHO_* on failure.
1127 * @param pModMachO The module.
1128 * @param pbStringPool The string pool
1129 * @param cbStringPool The size of the string pool.
1130 */
1131static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool)
1132{
1133 union
1134 {
1135 const KU8 *pb;
1136 const load_command_t *pLoadCmd;
1137 const segment_command_32_t *pSeg32;
1138 const segment_command_64_t *pSeg64;
1139 const symtab_command_t *pSymTab;
[54]1140 const uuid_command_t *pUuid;
[2]1141 } u;
[52]1142 const char *pchCurSegName = NULL;
[2]1143 KU32 cLeft = pModMachO->Hdr.ncmds;
1144 KU32 cbLeft = pModMachO->Hdr.sizeofcmds;
1145 const KU8 *pb = pModMachO->pbLoadCommands;
1146 PKLDRSEG pSeg = &pModMachO->pMod->aSegments[0];
1147 PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0];
1148 PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections;
1149 const KU32 cSegments = pModMachO->pMod->cSegments;
[51]1150 KU32 i, c;
[2]1151
1152 while (cLeft-- > 0)
1153 {
1154 u.pb = pb;
1155 cbLeft -= u.pLoadCmd->cmdsize;
1156 pb += u.pLoadCmd->cmdsize;
1157
1158 /*
1159 * Convert endian if needed, parse and validate the command.
1160 */
1161 switch (u.pLoadCmd->cmd)
1162 {
1163 case LC_SEGMENT_32:
1164 {
1165 section_32_t *pSect;
1166 section_32_t *pFirstSect;
1167 KU32 cSectionsLeft;
1168
[51]1169 kHlpAssert(u.pSeg32->vmaddr >= pModMachO->LinkAddress);
[2]1170
1171 /*
1172 * convert, validate and parse the sections.
1173 */
1174 cSectionsLeft = u.pSeg32->nsects;
1175 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
1176 while (cSectionsLeft-- > 0)
1177 {
1178 switch (pModMachO->Hdr.filetype)
1179 {
1180 case MH_OBJECT:
[41]1181 case MH_EXECUTE:
1182 case MH_DYLIB:
1183 case MH_DSYM:
[55]1184 case MH_KEXT_BUNDLE:
[2]1185 {
1186 /* Section data extract. */
1187 pSectExtra->cb = pSect->size;
1188 pSectExtra->RVA = pSect->addr;
1189 pSectExtra->LinkAddress = pSect->addr;
[28]1190 if (pSect->offset)
1191 pSectExtra->offFile = pSect->offset + pModMachO->offImage;
1192 else
1193 pSectExtra->offFile = -1;
[2]1194 pSectExtra->cFixups = pSect->nreloc;
1195 pSectExtra->paFixups = NULL;
[28]1196 if (pSect->nreloc)
1197 pSectExtra->offFixups = pSect->reloff + pModMachO->offImage;
1198 else
1199 pSectExtra->offFixups = -1;
[2]1200 pSectExtra->fFlags = pSect->flags;
1201 pSectExtra->iSegment = pSegExtra - &pModMachO->aSegments[0];
1202 pSectExtra->pvMachoSection = pSect;
1203
1204 /* Don't load debug symbols. (test this!) */
[43]1205 if ( (pSect->flags & S_ATTR_DEBUG)
1206 || !kHlpStrComp(pSect->segname, "__DWARF"))
[2]1207 {
1208 pSectExtra++;
1209 /** @todo */
1210 break;
1211 }
1212
[52]1213 if ( !pchCurSegName
1214 || kHlpStrNComp(pSect->segname, pchCurSegName, sizeof(pSect->segname)))
[2]1215 {
1216 /* close the previous segment */
1217 if (pSegExtra != &pModMachO->aSegments[0])
1218 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
1219
1220 /* new segment. */
1221 pSeg->pvUser = NULL;
1222 pSeg->pchName = pbStringPool;
1223 pSeg->cchName = (KU32)kHlpStrNLen(&pSect->segname[0], sizeof(pSect->sectname));
1224 kHlpMemCopy(pbStringPool, &pSect->segname[0], pSeg->cchName);
1225 pbStringPool += pSeg->cchName;
1226 *pbStringPool++ = '\0';
1227 pSeg->SelFlat = 0;
1228 pSeg->Sel16bit = 0;
1229 pSeg->fFlags = 0;
1230 pSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */
1231 pSeg->cb = pSect->size;
[44]1232 pSeg->Alignment = (KLDRADDR)1 << pSect->align;
[2]1233 pSeg->LinkAddress = pSect->addr;
[28]1234 if (pSect->offset)
1235 {
1236 pSeg->offFile = pSect->offset + pModMachO->offImage;
1237 pSeg->cbFile = pSect->size;
1238 }
1239 else
1240 {
1241 pSeg->offFile = -1;
1242 pSeg->cbFile = -1;
1243 }
[2]1244 pSeg->RVA = pSect->addr - pModMachO->LinkAddress;
1245 pSeg->cbMapped = 0;
1246 pSeg->MapAddress = 0;
1247
[52]1248 pSegExtra->iOrgSegNo = pSegExtra - &pModMachO->aSegments[0];
[2]1249 pSegExtra->cSections = 0;
1250 pSegExtra->paSections = pSectExtra;
1251
1252 pSeg++;
1253 pSegExtra++;
[52]1254 pchCurSegName = &pSect->segname[0];
[2]1255 }
1256 else
1257 {
1258 /* update exiting segment */
[28]1259 if (pSeg[-1].Alignment < K_BIT64(pSect->align))
1260 pSeg[-1].Alignment = K_BIT64(pSect->align);
[2]1261 if (pSect->addr < pSeg[-1].LinkAddress)
1262 return KLDR_ERR_MACHO_BAD_SECTION; /** @todo move up! */
1263
1264 /* If there are file bits, ensure they are in the current flow.
1265 (yes, we are very very careful here, I know.) */
1266 if ( pSect->offset
[28]1267 && (KU64)pSeg[-1].cbFile == pSeg[-1].cb)
[2]1268 {
[28]1269 int fOk = (KU64)pSeg[-1].offFile + (pSect->addr - pSeg[-1].LinkAddress) == pSect->offset + (KU64)pModMachO->offImage
[2]1270 && pSect[-1].offset
[28]1271 && (KU64)pSeg[-1].offFile + pSeg[-1].cbFile == pSect[-1].offset + (KU64)pModMachO->offImage + pSect[-1].size;
[2]1272 /* more checks? */
1273 if (fOk)
1274 pSeg[-1].cbFile = (KLDRFOFF)(pSect->addr - pSeg[-1].LinkAddress) + pSect->size;
1275 else
1276 {
1277
1278 pSeg[-1].cbFile = pSeg[-1].offFile = -1;
[22]1279 pModMachO->fMapUsingLoadCommandSections = K_TRUE;
[2]1280 }
1281 }
1282 pSeg[-1].cb = pSect->addr - pSeg[-1].LinkAddress + pSect->size;
1283
1284 /** @todo update the protection... */
1285 }
1286 pSectExtra++;
1287 break;
1288 }
1289
1290 default:
1291 return KERR_INVALID_PARAMETER;
1292 }
1293
1294 /* next */
1295 pSect++;
1296 }
1297 break;
1298 }
1299
[22]1300 case LC_SEGMENT_64:
1301 {
1302 section_64_t *pSect;
1303 section_64_t *pFirstSect;
1304 KU32 cSectionsLeft;
1305
[51]1306 kHlpAssert(u.pSeg64->vmaddr >= pModMachO->LinkAddress);
[22]1307
1308 /*
1309 * convert, validate and parse the sections.
1310 */
1311 cSectionsLeft = u.pSeg64->nsects;
1312 pFirstSect = pSect = (section_64_t *)(u.pSeg64 + 1);
1313 while (cSectionsLeft-- > 0)
1314 {
1315 switch (pModMachO->Hdr.filetype)
1316 {
1317 case MH_OBJECT:
[41]1318 case MH_EXECUTE:
1319 case MH_DYLIB:
1320 case MH_DSYM:
[55]1321 case MH_KEXT_BUNDLE:
[22]1322 {
1323 /* Section data extract. */
1324 pSectExtra->cb = pSect->size;
1325 pSectExtra->RVA = pSect->addr;
1326 pSectExtra->LinkAddress = pSect->addr;
[28]1327 if (pSect->offset)
1328 pSectExtra->offFile = pSect->offset + pModMachO->offImage;
1329 else
1330 pSectExtra->offFile = -1;
[22]1331 pSectExtra->cFixups = pSect->nreloc;
1332 pSectExtra->paFixups = NULL;
[28]1333 if (pSect->nreloc)
1334 pSectExtra->offFixups = pSect->reloff + pModMachO->offImage;
1335 else
1336 pSectExtra->offFixups = -1;
[22]1337 pSectExtra->fFlags = pSect->flags;
1338 pSectExtra->iSegment = pSegExtra - &pModMachO->aSegments[0];
1339 pSectExtra->pvMachoSection = pSect;
1340
1341 /* Don't load debug symbols. (test this!) */
[43]1342 if ( (pSect->flags & S_ATTR_DEBUG)
1343 || !kHlpStrComp(pSect->segname, "__DWARF"))
[22]1344 {
1345 pSectExtra++;
1346 /** @todo */
1347 break;
1348 }
1349
[52]1350 if ( !pchCurSegName
1351 || kHlpStrNComp(pSect->segname, pchCurSegName, sizeof(pSect->segname)))
[22]1352 {
1353 /* close the previous segment */
1354 if (pSegExtra != &pModMachO->aSegments[0])
1355 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
1356
1357 /* new segment. */
1358 pSeg->pvUser = NULL;
1359 pSeg->pchName = pbStringPool;
1360 pSeg->cchName = (KU32)kHlpStrNLen(&pSect->segname[0], sizeof(pSect->sectname));
1361 kHlpMemCopy(pbStringPool, &pSect->segname[0], pSeg->cchName);
1362 pbStringPool += pSeg->cchName;
1363 *pbStringPool++ = '\0';
1364 pSeg->SelFlat = 0;
1365 pSeg->Sel16bit = 0;
1366 pSeg->fFlags = 0;
1367 pSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */
1368 pSeg->cb = pSect->size;
[44]1369 pSeg->Alignment = (KLDRADDR)1 << pSect->align;
[22]1370 pSeg->LinkAddress = pSect->addr;
[28]1371 if (pSect->offset)
1372 {
1373 pSeg->offFile = pSect->offset + pModMachO->offImage;
1374 pSeg->cbFile = pSect->size;
1375 }
1376 else
1377 {
1378 pSeg->offFile = -1;
1379 pSeg->cbFile = -1;
1380 }
[22]1381 pSeg->RVA = pSect->addr - pModMachO->LinkAddress;
1382 pSeg->cbMapped = 0;
1383 pSeg->MapAddress = 0;
1384
[51]1385 pSegExtra->iOrgSegNo = pSegExtra - &pModMachO->aSegments[0];
[22]1386 pSegExtra->cSections = 0;
1387 pSegExtra->paSections = pSectExtra;
1388
1389 pSeg++;
1390 pSegExtra++;
[52]1391 pchCurSegName = &pSect->segname[0];
[22]1392 }
1393 else
1394 {
1395 /* update exiting segment */
[28]1396 if (pSeg[-1].Alignment < K_BIT64(pSect->align))
1397 pSeg[-1].Alignment = K_BIT64(pSect->align);
[22]1398 if (pSect->addr < pSeg[-1].LinkAddress)
1399 return KLDR_ERR_MACHO_BAD_SECTION; /** @todo move up! */
1400
1401 /* If there are file bits, ensure they are in the current flow.
1402 (yes, we are very very careful here, I know.) */
1403 if ( pSect->offset
[28]1404 && (KU64)pSeg[-1].cbFile == pSeg[-1].cb)
[22]1405 {
[28]1406 int fOk = (KU64)pSeg[-1].offFile + (pSect->addr - pSeg[-1].LinkAddress) == pSect->offset + (KU64)pModMachO->offImage
[22]1407 && pSect[-1].offset
[28]1408 && (KU64)pSeg[-1].offFile + pSeg[-1].cbFile == pSect[-1].offset + (KU64)pModMachO->offImage + pSect[-1].size;
[22]1409 /* more checks? */
1410 if (fOk)
1411 pSeg[-1].cbFile = (KLDRFOFF)(pSect->addr - pSeg[-1].LinkAddress) + pSect->size;
1412 else
1413 {
1414
1415 pSeg[-1].cbFile = pSeg[-1].offFile = -1;
1416 pModMachO->fMapUsingLoadCommandSections = K_TRUE;
1417 }
1418 }
1419 pSeg[-1].cb = pSect->addr - pSeg[-1].LinkAddress + pSect->size;
1420
1421 /** @todo update the protection... */
1422 }
1423 pSectExtra++;
1424 break;
1425 }
1426
1427 default:
1428 return KERR_INVALID_PARAMETER;
1429 }
1430
1431 /* next */
1432 pSect++;
1433 }
1434 break;
1435 }
1436
[2]1437 case LC_SYMTAB:
1438 switch (pModMachO->Hdr.filetype)
1439 {
1440 case MH_OBJECT:
[41]1441 case MH_EXECUTE:
1442 case MH_DYLIB: /** @todo ??? */
1443 case MH_DSYM:
[55]1444 case MH_KEXT_BUNDLE:
[25]1445 pModMachO->offSymbols = u.pSymTab->symoff + pModMachO->offImage;
[2]1446 pModMachO->cSymbols = u.pSymTab->nsyms;
[25]1447 pModMachO->offStrings = u.pSymTab->stroff + pModMachO->offImage;
[2]1448 pModMachO->cchStrings = u.pSymTab->strsize;
1449 break;
1450 }
1451 break;
1452
[54]1453 case LC_UUID:
1454 kHlpMemCopy(pModMachO->abImageUuid, u.pUuid->uuid, sizeof(pModMachO->abImageUuid));
1455 break;
1456
[2]1457 default:
1458 break;
1459 } /* command switch */
1460 } /* while more commands */
1461
1462 /*
1463 * Close the last segment (if any).
1464 */
1465 if (pSegExtra != &pModMachO->aSegments[0])
1466 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
1467
1468 /*
[51]1469 * Make sure the segments are sorted, or we'll get screwed further down.
1470 */
1471 c = pSeg - &pModMachO->pMod->aSegments[0];
1472 pSeg = &pModMachO->pMod->aSegments[0];
1473 for (i = 0; i < c - 1; i++)
1474 {
1475 KLDRADDR LinkAddress = pSeg[i + 1].LinkAddress;
1476 if (LinkAddress < pSeg[i].LinkAddress)
1477 {
1478 /* Gotta move the next segment, find the correct location. */
1479 KLDRMODMACHOSEG TmpSegExtra;
1480 KLDRSEG TmpSeg;
1481 KU32 j = i;
1482 KU32 cShift = 1;
1483
1484 while (j > 0 && LinkAddress < pSeg[j - 1].LinkAddress)
1485 j--, cShift++;
1486
1487 TmpSegExtra = pModMachO->aSegments[i + 1];
1488 kHlpMemMove(&pModMachO->aSegments[j + 1], &pModMachO->aSegments[j],
1489 cShift * sizeof(pModMachO->aSegments[0]));
1490 pModMachO->aSegments[j] = TmpSegExtra;
1491
1492 TmpSeg = pSeg[i + 1];
1493 kHlpMemMove(&pSeg[j + 1], &pSeg[j], cShift * sizeof(pSeg[0]));
1494 pSeg[j] = TmpSeg;
1495 }
1496 }
1497 pSeg = &pModMachO->pMod->aSegments[c];
1498
1499 /*
[22]1500 * Make the GOT segment if necessary.
1501 */
1502 if (pModMachO->fMakeGot)
1503 {
1504 KSIZE cbPtr = ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1505 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1506 ? sizeof(KU32)
1507 : sizeof(KU64);
[23]1508 KU32 cbGot = pModMachO->cSymbols * cbPtr;
1509 KU32 cbJmpStubs;
[22]1510
1511 if (pSeg != &pModMachO->pMod->aSegments[0])
1512 pModMachO->GotRVA = pSeg[-1].RVA + KLDR_ALIGN_ADDR(pSeg[-1].cb, pSeg[-1].Alignment);
1513 else
1514 pModMachO->GotRVA = 0;
1515
[23]1516 if (pModMachO->cbJmpStub)
1517 {
1518 cbGot = K_ALIGN_Z(cbGot, 64);
1519 pModMachO->JmpStubsRVA = pModMachO->GotRVA + cbGot;
1520 cbJmpStubs = pModMachO->cbJmpStub * pModMachO->cSymbols;
1521 }
1522 else
1523 {
1524 pModMachO->JmpStubsRVA = NIL_KLDRADDR;
1525 cbJmpStubs = 0;
1526 }
1527
[22]1528 pSeg->pvUser = NULL;
1529 pSeg->pchName = "GOT";
1530 pSeg->cchName = 3;
1531 pSeg->SelFlat = 0;
1532 pSeg->Sel16bit = 0;
1533 pSeg->fFlags = 0;
1534 pSeg->enmProt = KPROT_READONLY;
[23]1535 pSeg->cb = cbGot + cbJmpStubs;
[22]1536 pSeg->Alignment = 64;
1537 pSeg->LinkAddress = pModMachO->LinkAddress + pModMachO->GotRVA;
1538 pSeg->offFile = -1;
1539 pSeg->cbFile = -1;
1540 pSeg->RVA = pModMachO->GotRVA;
1541 pSeg->cbMapped = 0;
1542 pSeg->MapAddress = 0;
1543
[51]1544 pSegExtra->iOrgSegNo = KU32_MAX;
[22]1545 pSegExtra->cSections = 0;
1546 pSegExtra->paSections = NULL;
1547 }
1548
1549 /*
[2]1550 * Adjust mapping addresses calculating the image size.
1551 */
1552 pSeg = &pModMachO->pMod->aSegments[0];
1553 switch (pModMachO->Hdr.filetype)
1554 {
1555 case MH_OBJECT:
[41]1556 case MH_EXECUTE:
1557 case MH_DYLIB: /** @todo dylib */
1558 case MH_DSYM:
[55]1559 case MH_KEXT_BUNDLE:
[2]1560 {
1561 KLDRADDR cb1;
1562 KSIZE cb2;
1563
1564 for (i = 0; i < cSegments - 1; i++)
1565 {
1566 cb1 = pSeg[i + 1].LinkAddress - pSeg[i].LinkAddress;
1567 cb2 = (KSIZE)cb1;
1568 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(KSIZE)0;
1569 }
1570 cb1 = KLDR_ALIGN_ADDR(pSeg[i].cb, pSeg[i].Alignment);
1571 cb2 = (KSIZE)cb1;
1572 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(KSIZE)0;
1573
1574 pModMachO->cbImage = pSeg[i].RVA + cb1;
1575 break;
1576 }
1577 }
1578
[22]1579
[2]1580 return 0;
1581}
1582
1583
1584/** @copydoc KLDRMODOPS::pfnDestroy */
1585static int kldrModMachODestroy(PKLDRMOD pMod)
1586{
1587 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1588 int rc = 0;
1589 KU32 i, j;
1590 KLDRMODMACHO_ASSERT(!pModMachO->pvMapping);
1591
1592 i = pMod->cSegments;
1593 while (i-- > 0)
1594 {
1595 j = pModMachO->aSegments[i].cSections;
1596 while (j-- > 0)
1597 {
1598 kHlpFree(pModMachO->aSegments[i].paSections[j].paFixups);
1599 pModMachO->aSegments[i].paSections[j].paFixups = NULL;
1600 }
1601 }
1602
1603 if (pMod->pRdr)
1604 {
1605 rc = kRdrClose(pMod->pRdr);
1606 pMod->pRdr = NULL;
1607 }
1608 pMod->u32Magic = 0;
1609 pMod->pOps = NULL;
1610 kHlpFree(pModMachO->pbLoadCommands);
1611 pModMachO->pbLoadCommands = NULL;
1612 kHlpFree(pModMachO->pchStrings);
1613 pModMachO->pchStrings = NULL;
1614 kHlpFree(pModMachO->pvaSymbols);
1615 pModMachO->pvaSymbols = NULL;
1616 kHlpFree(pModMachO);
1617 return rc;
1618}
1619
1620
1621/**
1622 * Gets the right base address.
1623 *
1624 * @returns 0 on success.
1625 * @returns A non-zero status code if the BaseAddress isn't right.
1626 * @param pModMachO The interpreter module instance
1627 * @param pBaseAddress The base address, IN & OUT. Optional.
1628 */
1629static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress)
1630{
1631 /*
1632 * Adjust the base address.
1633 */
1634 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
1635 *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress;
1636 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
1637 *pBaseAddress = pModMachO->LinkAddress;
1638
1639 return 0;
1640}
1641
1642
[47]1643/**
1644 * Resolves a linker generated symbol.
1645 *
1646 * The Apple linker generates symbols indicating the start and end of sections
1647 * and segments. This function checks for these and returns the right value.
1648 *
1649 * @returns 0 or KLDR_ERR_SYMBOL_NOT_FOUND.
1650 * @param pModMachO The interpreter module instance.
1651 * @param pMod The generic module instance.
1652 * @param pchSymbol The symbol.
1653 * @param cchSymbol The length of the symbol.
1654 * @param BaseAddress The base address to apply when calculating the
1655 * value.
1656 * @param puValue Where to return the symbol value.
1657 */
1658static int kldrModMachOQueryLinkerSymbol(PKLDRMODMACHO pModMachO, PKLDRMOD pMod, const char *pchSymbol, KSIZE cchSymbol,
1659 KLDRADDR BaseAddress, PKLDRADDR puValue)
1660{
1661 /*
1662 * Match possible name prefixes.
1663 */
1664 static const struct
1665 {
1666 const char *pszPrefix;
1667 KU8 cchPrefix;
1668 KBOOL fSection;
1669 KBOOL fStart;
1670 } s_aPrefixes[] =
1671 {
1672 { "section$start$", (KU8)sizeof("section$start$") - 1, K_TRUE, K_TRUE },
1673 { "section$end$", (KU8)sizeof("section$end$") - 1, K_TRUE, K_FALSE},
1674 { "segment$start$", (KU8)sizeof("segment$start$") - 1, K_FALSE, K_TRUE },
1675 { "segment$end$", (KU8)sizeof("segment$end$") - 1, K_FALSE, K_FALSE},
1676 };
1677 KSIZE cchSectName = 0;
1678 const char *pchSectName = "";
1679 KSIZE cchSegName = 0;
1680 const char *pchSegName = NULL;
1681 KU32 iPrefix = K_ELEMENTS(s_aPrefixes) - 1;
1682 KU32 iSeg;
1683 KLDRADDR uValue;
[2]1684
[47]1685 for (;;)
1686 {
1687 KU8 const cchPrefix = s_aPrefixes[iPrefix].cchPrefix;
1688 if ( cchSymbol > cchPrefix
1689 && kHlpStrNComp(pchSymbol, s_aPrefixes[iPrefix].pszPrefix, cchPrefix) == 0)
1690 {
1691 pchSegName = pchSymbol + cchPrefix;
1692 cchSegName = cchSymbol - cchPrefix;
1693 break;
1694 }
1695
1696 /* next */
1697 if (!iPrefix)
1698 return KLDR_ERR_SYMBOL_NOT_FOUND;
1699 iPrefix--;
1700 }
1701
1702 /*
1703 * Split the remainder into segment and section name, if necessary.
1704 */
1705 if (s_aPrefixes[iPrefix].fSection)
1706 {
1707 pchSectName = kHlpMemChr(pchSegName, '$', cchSegName);
1708 if (!pchSectName)
1709 return KLDR_ERR_SYMBOL_NOT_FOUND;
1710 cchSegName = pchSectName - pchSegName;
1711 pchSectName++;
1712 cchSectName = cchSymbol - (pchSectName - pchSymbol);
1713 }
1714
1715 /*
1716 * Locate the segment.
1717 */
1718 iSeg = pMod->cSegments;
1719 if (!iSeg)
1720 return KLDR_ERR_SYMBOL_NOT_FOUND;
1721 while ( pMod->aSegments[iSeg].cchName != cchSegName
1722 || kHlpMemComp(pMod->aSegments[iSeg].pchName, pchSegName, cchSegName) != 0)
1723 {
1724 if (!iSeg)
1725 return KLDR_ERR_SYMBOL_NOT_FOUND;
1726 iSeg--;
1727 }
1728
1729 if (!s_aPrefixes[iPrefix].fSection)
1730 {
1731 /*
1732 * Calculate the segment start/end address.
1733 */
1734 uValue = pMod->aSegments[iSeg].LinkAddress;
1735 if (!s_aPrefixes[iPrefix].fStart)
1736 uValue += pMod->aSegments[iSeg].cb;
1737 }
1738 else
1739 {
1740 /*
1741 * Locate the section.
1742 */
1743 KU32 iSect = pModMachO->aSegments[iSeg].cSections;
1744 if (!iSect)
1745 return KLDR_ERR_SYMBOL_NOT_FOUND;
1746 for (;;)
1747 {
1748 section_32_t *pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[iSect].pvMachoSection;
1749 if ( cchSectName <= sizeof(pSect->sectname)
1750 && kHlpMemComp(pSect->sectname, pchSectName, cchSectName) == 0
1751 && ( cchSectName == sizeof(pSect->sectname)
1752 || pSect->sectname[cchSectName] == '\0') )
1753 break;
1754 /* next */
1755 if (!iSect)
1756 return KLDR_ERR_SYMBOL_NOT_FOUND;
1757 iSect--;
1758 }
1759
1760 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1761 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1762 {
[49]1763 section_32_t *pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[iSect].pvMachoSection;
[47]1764 uValue = pSect->addr;
1765 if (!s_aPrefixes[iPrefix].fStart)
1766 uValue += pSect->size;
1767 }
1768 else
1769 {
1770 section_64_t *pSect = (section_64_t *)pModMachO->aSegments[iSeg].paSections[iSect].pvMachoSection;
1771 uValue = pSect->addr;
1772 if (!s_aPrefixes[iPrefix].fStart)
1773 uValue += pSect->size;
1774 }
1775 }
1776
1777 /*
1778 * Adjust the value from link to rva + base.
1779 */
1780 uValue -= pMod->aSegments[iSeg].LinkAddress - pMod->aSegments[iSeg].RVA;
1781 uValue += BaseAddress;
1782 if (puValue)
1783 *puValue = uValue;
1784
1785 return 0;
1786}
1787
1788
[2]1789/** @copydoc kLdrModQuerySymbol */
1790static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
1791 const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
1792 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
1793{
1794 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1795 int rc;
1796
1797 /*
1798 * Resolve defaults.
1799 */
1800 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
1801 if (rc)
1802 return rc;
1803
1804 /*
1805 * Refuse segmented requests for now.
1806 */
[22]1807 KLDRMODMACHO_CHECK_RETURN( !pfKind
1808 || (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) == KLDRSYMKIND_REQ_FLAT,
1809 KLDR_ERR_TODO);
[2]1810
1811 /*
1812 * Take action according to file type.
1813 */
[41]1814 if ( pModMachO->Hdr.filetype == MH_OBJECT
1815 || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */
1816 || pModMachO->Hdr.filetype == MH_DYLIB
[55]1817 || pModMachO->Hdr.filetype == MH_DSYM
1818 || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE)
[2]1819 {
1820 rc = kldrModMachOLoadObjSymTab(pModMachO);
1821 if (!rc)
1822 {
1823 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1824 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1825 rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1826 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
1827 cchSymbol, puValue, pfKind);
1828 else
[22]1829 rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
[2]1830 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
[22]1831 cchSymbol, puValue, pfKind);
[2]1832 }
[47]1833
1834 /*
1835 * Check for link-editor generated symbols and supply what we can.
1836 *
1837 * As small service to clients that insists on adding a '_' prefix
1838 * before querying symbols, we will ignore the prefix.
1839 */
1840 if ( rc == KLDR_ERR_SYMBOL_NOT_FOUND
1841 && cchSymbol > sizeof("section$end$") - 1
1842 && ( pchSymbol[0] == 's'
1843 || (pchSymbol[1] == 's' && pchSymbol[0] == '_') )
1844 && kHlpMemChr(pchSymbol, '$', cchSymbol) )
1845 {
1846 if (pchSymbol[0] == '_')
1847 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol + 1, cchSymbol - 1, BaseAddress, puValue);
1848 else
1849 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol, cchSymbol, BaseAddress, puValue);
1850 }
[2]1851 }
1852 else
1853 rc = KLDR_ERR_TODO;
1854
1855 return rc;
1856}
1857
1858
1859/**
1860 * Lookup a symbol in a 32-bit symbol table.
1861 *
1862 * @returns See kLdrModQuerySymbol.
1863 * @param pModMachO
1864 * @param paSyms Pointer to the symbol table.
1865 * @param cSyms Number of symbols in the table.
1866 * @param pchStrings Pointer to the string table.
1867 * @param cchStrings Size of the string table.
1868 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
1869 * @param iSymbol See kLdrModQuerySymbol.
1870 * @param pchSymbol See kLdrModQuerySymbol.
1871 * @param cchSymbol See kLdrModQuerySymbol.
1872 * @param puValue See kLdrModQuerySymbol.
1873 * @param pfKind See kLdrModQuerySymbol.
1874 */
1875static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings,
1876 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
1877 PKLDRADDR puValue, KU32 *pfKind)
1878{
1879 /*
1880 * Find a valid symbol matching the search criteria.
1881 */
1882 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
1883 {
1884 /* simplify validation. */
1885 if (cchStrings <= cchSymbol)
1886 return KLDR_ERR_SYMBOL_NOT_FOUND;
1887 cchStrings -= cchSymbol;
1888
1889 /* external symbols are usually at the end, so search the other way. */
1890 for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
1891 {
1892 const char *psz;
1893
1894 /* Skip irrellevant and non-public symbols. */
1895 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1896 continue;
1897 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1898 continue;
1899 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1900 continue;
1901 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1902 continue;
1903
1904 /* get name */
1905 if (!paSyms[iSymbol].n_un.n_strx)
1906 continue;
1907 if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1908 continue;
1909 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1910 if (psz[cchSymbol])
1911 continue;
1912 if (kHlpMemComp(psz, pchSymbol, cchSymbol))
1913 continue;
1914
1915 /* match! */
1916 break;
1917 }
1918 if (iSymbol == KU32_MAX)
1919 return KLDR_ERR_SYMBOL_NOT_FOUND;
1920 }
1921 else
1922 {
1923 if (iSymbol >= cSyms)
1924 return KLDR_ERR_SYMBOL_NOT_FOUND;
1925 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1926 return KLDR_ERR_SYMBOL_NOT_FOUND;
1927 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1928 return KLDR_ERR_SYMBOL_NOT_FOUND;
1929 }
1930
1931 /*
1932 * Calc the return values.
1933 */
1934 if (pfKind)
1935 {
1936 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1937 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1938 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
1939 else
1940 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1941 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1942 *pfKind |= KLDRSYMKIND_WEAK;
1943 }
1944
1945 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1946 {
1947 case MACHO_N_SECT:
1948 {
1949 PKLDRMODMACHOSECT pSect;
1950 KLDRADDR RVA;
1951 if ((KU32)(paSyms[iSymbol].n_sect - 1) >= pModMachO->cSections)
1952 return KLDR_ERR_MACHO_BAD_SYMBOL;
1953 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1954
1955 RVA = paSyms[iSymbol].n_value - pModMachO->LinkAddress;
1956 if (RVA - pSect->RVA >= pSect->cb)
1957 return KLDR_ERR_MACHO_BAD_SYMBOL;
1958 if (puValue)
1959 *puValue = RVA + BaseAddress;
1960
1961 if ( pfKind
1962 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1963 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1964 break;
1965 }
1966
1967 case MACHO_N_ABS:
1968 if (puValue)
1969 *puValue = paSyms[iSymbol].n_value;
1970 /*if (pfKind)
1971 pfKind |= KLDRSYMKIND_ABS;*/
1972 break;
1973
1974 case MACHO_N_PBUD:
1975 case MACHO_N_INDR:
1976 /** @todo implement indirect and prebound symbols. */
1977 default:
[22]1978 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]1979 }
1980
1981 return 0;
1982}
1983
1984
[22]1985/**
1986 * Lookup a symbol in a 64-bit symbol table.
1987 *
1988 * @returns See kLdrModQuerySymbol.
1989 * @param pModMachO
1990 * @param paSyms Pointer to the symbol table.
1991 * @param cSyms Number of symbols in the table.
1992 * @param pchStrings Pointer to the string table.
1993 * @param cchStrings Size of the string table.
1994 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
1995 * @param iSymbol See kLdrModQuerySymbol.
1996 * @param pchSymbol See kLdrModQuerySymbol.
1997 * @param cchSymbol See kLdrModQuerySymbol.
1998 * @param puValue See kLdrModQuerySymbol.
1999 * @param pfKind See kLdrModQuerySymbol.
2000 */
2001static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings,
2002 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
2003 PKLDRADDR puValue, KU32 *pfKind)
2004{
2005 /*
2006 * Find a valid symbol matching the search criteria.
2007 */
2008 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
2009 {
2010 /* simplify validation. */
2011 if (cchStrings <= cchSymbol)
2012 return KLDR_ERR_SYMBOL_NOT_FOUND;
2013 cchStrings -= cchSymbol;
2014
2015 /* external symbols are usually at the end, so search the other way. */
2016 for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
2017 {
2018 const char *psz;
2019
2020 /* Skip irrellevant and non-public symbols. */
2021 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
2022 continue;
2023 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2024 continue;
2025 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
2026 continue;
2027 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
2028 continue;
2029
2030 /* get name */
2031 if (!paSyms[iSymbol].n_un.n_strx)
2032 continue;
2033 if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
2034 continue;
2035 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
2036 if (psz[cchSymbol])
2037 continue;
2038 if (kHlpMemComp(psz, pchSymbol, cchSymbol))
2039 continue;
2040
2041 /* match! */
2042 break;
2043 }
2044 if (iSymbol == KU32_MAX)
2045 return KLDR_ERR_SYMBOL_NOT_FOUND;
2046 }
2047 else
2048 {
2049 if (iSymbol >= cSyms)
2050 return KLDR_ERR_SYMBOL_NOT_FOUND;
2051 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
2052 return KLDR_ERR_SYMBOL_NOT_FOUND;
2053 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2054 return KLDR_ERR_SYMBOL_NOT_FOUND;
2055 }
2056
2057 /*
2058 * Calc the return values.
2059 */
2060 if (pfKind)
2061 {
2062 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2063 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2064 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
2065 else
2066 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
2067 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
2068 *pfKind |= KLDRSYMKIND_WEAK;
2069 }
2070
2071 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
2072 {
2073 case MACHO_N_SECT:
2074 {
2075 PKLDRMODMACHOSECT pSect;
2076 KLDRADDR RVA;
2077 if ((KU32)(paSyms[iSymbol].n_sect - 1) >= pModMachO->cSections)
2078 return KLDR_ERR_MACHO_BAD_SYMBOL;
2079 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
2080
2081 RVA = paSyms[iSymbol].n_value - pModMachO->LinkAddress;
2082 if (RVA - pSect->RVA >= pSect->cb)
2083 return KLDR_ERR_MACHO_BAD_SYMBOL;
2084 if (puValue)
2085 *puValue = RVA + BaseAddress;
2086
2087 if ( pfKind
2088 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
2089 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
2090 break;
2091 }
2092
2093 case MACHO_N_ABS:
2094 if (puValue)
2095 *puValue = paSyms[iSymbol].n_value;
2096 /*if (pfKind)
2097 pfKind |= KLDRSYMKIND_ABS;*/
2098 break;
2099
2100 case MACHO_N_PBUD:
2101 case MACHO_N_INDR:
2102 /** @todo implement indirect and prebound symbols. */
2103 default:
2104 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
2105 }
2106
2107 return 0;
2108}
2109
2110
[2]2111/** @copydoc kLdrModEnumSymbols */
2112static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
2113 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
2114{
2115 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2116 int rc;
2117
2118 /*
2119 * Resolve defaults.
2120 */
2121 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
2122 if (rc)
2123 return rc;
2124
2125 /*
2126 * Take action according to file type.
2127 */
[41]2128 if ( pModMachO->Hdr.filetype == MH_OBJECT
2129 || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */
2130 || pModMachO->Hdr.filetype == MH_DYLIB
[55]2131 || pModMachO->Hdr.filetype == MH_DSYM
2132 || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE)
[2]2133 {
2134 rc = kldrModMachOLoadObjSymTab(pModMachO);
2135 if (!rc)
2136 {
2137 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2138 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2139 rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
2140 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
2141 fFlags, pfnCallback, pvUser);
2142 else
[22]2143 rc = kldrModMachODoEnumSymbols64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
2144 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
2145 fFlags, pfnCallback, pvUser);
[2]2146 }
2147 }
2148 else
[22]2149 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2150
2151 return rc;
2152}
2153
2154
2155/**
2156 * Enum a 32-bit symbol table.
2157 *
2158 * @returns See kLdrModQuerySymbol.
2159 * @param pModMachO
2160 * @param paSyms Pointer to the symbol table.
2161 * @param cSyms Number of symbols in the table.
2162 * @param pchStrings Pointer to the string table.
2163 * @param cchStrings Size of the string table.
2164 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
2165 * @param fFlags See kLdrModEnumSymbols.
2166 * @param pfnCallback See kLdrModEnumSymbols.
2167 * @param pvUser See kLdrModEnumSymbols.
2168 */
2169static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
2170 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
2171 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
2172{
[22]2173 const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2174 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
2175 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT;
[2]2176 KU32 iSym;
2177 int rc;
2178
2179 /*
2180 * Iterate the symbol table.
2181 */
2182 for (iSym = 0; iSym < cSyms; iSym++)
2183 {
2184 KU32 fKind;
2185 KLDRADDR uValue;
2186 const char *psz;
2187 KSIZE cch;
2188
2189 /* Skip debug symbols and undefined symbols. */
2190 if (paSyms[iSym].n_type & MACHO_N_STAB)
2191 continue;
2192 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2193 continue;
2194
2195 /* Skip non-public symbols unless they are requested explicitly. */
2196 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
2197 {
2198 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
2199 continue;
2200 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
2201 continue;
2202 if (!paSyms[iSym].n_un.n_strx)
2203 continue;
2204 }
2205
2206 /*
2207 * Gather symbol info
2208 */
2209
2210 /* name */
2211 if ((KU32)paSyms[iSym].n_un.n_strx >= cchStrings)
2212 return KLDR_ERR_MACHO_BAD_SYMBOL;
2213 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
2214 cch = kHlpStrLen(psz);
2215 if (!cch)
2216 psz = NULL;
2217
2218 /* kind & value */
2219 fKind = fKindBase;
2220 if (paSyms[iSym].n_desc & N_WEAK_DEF)
2221 fKind |= KLDRSYMKIND_WEAK;
2222 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
2223 {
2224 case MACHO_N_SECT:
2225 {
2226 PKLDRMODMACHOSECT pSect;
2227 if ((KU32)(paSyms[iSym].n_sect - 1) >= pModMachO->cSections)
2228 return KLDR_ERR_MACHO_BAD_SYMBOL;
2229 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
2230
2231 uValue = paSyms[iSym].n_value - pModMachO->LinkAddress;
[47]2232 if (uValue - pSect->RVA > pSect->cb)
[2]2233 return KLDR_ERR_MACHO_BAD_SYMBOL;
2234 uValue += BaseAddress;
2235
2236 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
2237 fKind |= KLDRSYMKIND_CODE;
2238 else
2239 fKind |= KLDRSYMKIND_NO_TYPE;
2240 break;
2241 }
2242
2243 case MACHO_N_ABS:
2244 uValue = paSyms[iSym].n_value;
2245 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
2246 break;
2247
2248 case MACHO_N_PBUD:
2249 case MACHO_N_INDR:
2250 /** @todo implement indirect and prebound symbols. */
2251 default:
[22]2252 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2253 }
2254
2255 /*
2256 * Do callback.
2257 */
2258 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
2259 if (rc)
2260 return rc;
2261 }
2262 return 0;
2263}
2264
2265
[22]2266/**
2267 * Enum a 64-bit symbol table.
2268 *
2269 * @returns See kLdrModQuerySymbol.
2270 * @param pModMachO
2271 * @param paSyms Pointer to the symbol table.
2272 * @param cSyms Number of symbols in the table.
2273 * @param pchStrings Pointer to the string table.
2274 * @param cchStrings Size of the string table.
2275 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
2276 * @param fFlags See kLdrModEnumSymbols.
2277 * @param pfnCallback See kLdrModEnumSymbols.
2278 * @param pvUser See kLdrModEnumSymbols.
2279 */
2280static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms,
2281 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
2282 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
2283{
2284 const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE
2285 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE
2286 ? KLDRSYMKIND_64BIT : KLDRSYMKIND_32BIT;
2287 KU32 iSym;
2288 int rc;
2289
2290 /*
2291 * Iterate the symbol table.
2292 */
2293 for (iSym = 0; iSym < cSyms; iSym++)
2294 {
2295 KU32 fKind;
2296 KLDRADDR uValue;
2297 const char *psz;
2298 KSIZE cch;
2299
2300 /* Skip debug symbols and undefined symbols. */
2301 if (paSyms[iSym].n_type & MACHO_N_STAB)
2302 continue;
2303 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2304 continue;
2305
2306 /* Skip non-public symbols unless they are requested explicitly. */
2307 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
2308 {
2309 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
2310 continue;
2311 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
2312 continue;
2313 if (!paSyms[iSym].n_un.n_strx)
2314 continue;
2315 }
2316
2317 /*
2318 * Gather symbol info
2319 */
2320
2321 /* name */
2322 if ((KU32)paSyms[iSym].n_un.n_strx >= cchStrings)
2323 return KLDR_ERR_MACHO_BAD_SYMBOL;
2324 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
2325 cch = kHlpStrLen(psz);
2326 if (!cch)
2327 psz = NULL;
2328
2329 /* kind & value */
2330 fKind = fKindBase;
2331 if (paSyms[iSym].n_desc & N_WEAK_DEF)
2332 fKind |= KLDRSYMKIND_WEAK;
2333 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
2334 {
2335 case MACHO_N_SECT:
2336 {
2337 PKLDRMODMACHOSECT pSect;
2338 if ((KU32)(paSyms[iSym].n_sect - 1) >= pModMachO->cSections)
2339 return KLDR_ERR_MACHO_BAD_SYMBOL;
2340 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
2341
2342 uValue = paSyms[iSym].n_value - pModMachO->LinkAddress;
[47]2343 if (uValue - pSect->RVA > pSect->cb)
[22]2344 return KLDR_ERR_MACHO_BAD_SYMBOL;
2345 uValue += BaseAddress;
2346
2347 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
2348 fKind |= KLDRSYMKIND_CODE;
2349 else
2350 fKind |= KLDRSYMKIND_NO_TYPE;
2351 break;
2352 }
2353
2354 case MACHO_N_ABS:
2355 uValue = paSyms[iSym].n_value;
2356 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
2357 break;
2358
2359 case MACHO_N_PBUD:
2360 case MACHO_N_INDR:
2361 /** @todo implement indirect and prebound symbols. */
2362 default:
2363 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
2364 }
2365
2366 /*
2367 * Do callback.
2368 */
2369 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
2370 if (rc)
2371 return rc;
2372 }
2373 return 0;
2374}
2375
2376
[2]2377/** @copydoc kLdrModGetImport */
2378static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
2379{
2380 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2381 if (pModMachO->Hdr.filetype == MH_OBJECT)
2382 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
2383
2384 /* later */
2385 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
2386}
2387
2388
2389/** @copydoc kLdrModNumberOfImports */
2390static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits)
2391{
2392 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2393 if (pModMachO->Hdr.filetype == MH_OBJECT)
2394 return 0;
2395
2396 /* later */
2397 return 0;
2398}
2399
2400
2401/** @copydoc kLdrModGetStackInfo */
2402static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
2403{
2404 /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
2405
2406 pStackInfo->Address = NIL_KLDRADDR;
2407 pStackInfo->LinkAddress = NIL_KLDRADDR;
2408 pStackInfo->cbStack = pStackInfo->cbStackThread = 0;
2409 /* later */
2410
2411 return 0;
2412}
2413
2414
2415/** @copydoc kLdrModQueryMainEntrypoint */
2416static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
2417{
2418#if 0
2419 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2420 int rc;
2421
2422 /*
2423 * Resolve base address alias if any.
2424 */
2425 rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress);
2426 if (rc)
2427 return rc;
2428
2429 /*
2430 * Convert the address from the header.
2431 */
2432 *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
2433 ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
2434 : NIL_KLDRADDR;
2435#else
2436 *pMainEPAddress = NIL_KLDRADDR;
2437#endif
2438 return 0;
2439}
2440
2441
[54]2442/** @copydoc kLdrModQueryImageUuid */
2443static int kldrModMachOQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid)
2444{
2445 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2446 kHlpMemSet(pvUuid, 0, cbUuid);
2447 if (kHlpMemComp(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)) == 0)
2448 return KLDR_ERR_NO_IMAGE_UUID;
2449 kHlpMemCopy(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid));
2450 return 0;
2451}
2452
2453
[2]2454/** @copydoc kLdrModEnumDbgInfo */
2455static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
2456{
[41]2457 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2458 int rc = 0;
2459 KU32 iSect;
[2]2460
[41]2461 for (iSect = 0; iSect < pModMachO->cSections; iSect++)
[2]2462 {
[41]2463 section_32_t *pMachOSect = pModMachO->paSections[iSect].pvMachoSection; /* (32-bit & 64-bit starts the same way) */
[42]2464 char szTmp[sizeof(pMachOSect->sectname) + 1];
2465
2466 if (kHlpStrComp(pMachOSect->segname, "__DWARF"))
[41]2467 continue;
[2]2468
[42]2469 kHlpMemCopy(szTmp, pMachOSect->sectname, sizeof(pMachOSect->sectname));
2470 szTmp[sizeof(pMachOSect->sectname)] = '\0';
2471
2472 rc = pfnCallback(pMod, iSect, KLDRDBGINFOTYPE_DWARF, 0, 0, szTmp,
[41]2473 pModMachO->paSections[iSect].offFile,
2474 pModMachO->paSections[iSect].LinkAddress,
2475 pModMachO->paSections[iSect].cb,
2476 NULL, pvUser);
2477 if (rc != 0)
[2]2478 break;
2479 }
2480
2481 return rc;
2482}
2483
2484
2485/** @copydoc kLdrModHasDbgInfo */
2486static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
2487{
2488 /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
2489
2490#if 0
2491 /*
2492 * Base this entirely on the presence of a debug directory.
2493 */
2494 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
2495 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
2496 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
2497 return KLDR_ERR_NO_DEBUG_INFO;
2498 return 0;
2499#else
2500 return KLDR_ERR_NO_DEBUG_INFO;
2501#endif
2502}
2503
2504
2505/** @copydoc kLdrModMap */
2506static int kldrModMachOMap(PKLDRMOD pMod)
2507{
2508 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2509 unsigned fFixed;
2510 KU32 i;
2511 void *pvBase;
2512 int rc;
2513
[43]2514 if (!pModMachO->fCanLoad)
2515 return KLDR_ERR_TODO;
2516
[2]2517 /*
2518 * Already mapped?
2519 */
2520 if (pModMachO->pvMapping)
2521 return KLDR_ERR_ALREADY_MAPPED;
2522
2523 /*
2524 * Map it.
2525 */
2526 /* fixed image? */
2527 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
2528 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
2529 if (!fFixed)
2530 pvBase = NULL;
2531 else
2532 {
2533 pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
2534 if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
2535 return KLDR_ERR_ADDRESS_OVERFLOW;
2536 }
2537
2538 /* try do the prepare */
2539 if (pModMachO->fMapUsingLoadCommandSections)
[22]2540 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO); /* deal with this if it ever occurs. */
[2]2541 else
2542 {
2543 rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
2544 if (rc)
2545 return rc;
2546 }
2547
2548 /*
2549 * Update the segments with their map addresses.
2550 */
2551 for (i = 0; i < pMod->cSegments; i++)
2552 {
2553 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
2554 pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
2555 }
2556 pModMachO->pvMapping = pvBase;
2557
2558 return 0;
2559}
2560
2561
2562/** @copydoc kLdrModUnmap */
2563static int kldrModMachOUnmap(PKLDRMOD pMod)
2564{
2565 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2566 KU32 i;
2567 int rc;
2568
2569 /*
2570 * Mapped?
2571 */
2572 if (!pModMachO->pvMapping)
2573 return KLDR_ERR_NOT_MAPPED;
2574
2575 /*
2576 * Try unmap the image.
2577 */
2578 if (pModMachO->fMapUsingLoadCommandSections)
[22]2579 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO); /* deal with this if it ever occurs. */
[2]2580 else
2581 {
2582 rc = kRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
2583 if (rc)
2584 return rc;
2585 }
2586
2587 /*
2588 * Update the segments to reflect that they aren't mapped any longer.
2589 */
2590 pModMachO->pvMapping = NULL;
2591 for (i = 0; i < pMod->cSegments; i++)
2592 pMod->aSegments[i].MapAddress = 0;
2593
2594 return 0;
2595}
2596
2597
2598/** @copydoc kLdrModAllocTLS */
2599static int kldrModMachOAllocTLS(PKLDRMOD pMod)
2600{
2601 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2602
2603 /*
2604 * Mapped?
2605 */
2606 if (!pModMachO->pvMapping)
2607 return KLDR_ERR_NOT_MAPPED;
2608 return 0;
2609}
2610
2611
2612/** @copydoc kLdrModFreeTLS */
2613static void kldrModMachOFreeTLS(PKLDRMOD pMod)
2614{
2615}
2616
2617
2618/** @copydoc kLdrModReload */
2619static int kldrModMachOReload(PKLDRMOD pMod)
2620{
2621 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2622
2623 /*
2624 * Mapped?
2625 */
2626 if (!pModMachO->pvMapping)
2627 return KLDR_ERR_NOT_MAPPED;
2628
2629 /* the file provider does it all */
2630 return kRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
2631}
2632
2633
2634/** @copydoc kLdrModFixupMapping */
2635static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2636{
2637 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2638 int rc, rc2;
2639
2640 /*
2641 * Mapped?
2642 */
2643 if (!pModMachO->pvMapping)
2644 return KLDR_ERR_NOT_MAPPED;
2645
2646 /*
2647 * Before doing anything we'll have to make all pages writable.
2648 */
2649 if (pModMachO->fMapUsingLoadCommandSections)
[22]2650 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO); /* deal with this if it ever occurs. */
[2]2651 else
2652 {
2653 rc = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
2654 if (rc)
2655 return rc;
2656 }
2657
2658 /*
2659 * Resolve imports and apply base relocations.
2660 */
2661 rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (KUPTR)pModMachO->pvMapping, pModMachO->LinkAddress,
2662 pfnGetImport, pvUser);
2663
2664 /*
2665 * Restore protection.
2666 */
2667 if (pModMachO->fMapUsingLoadCommandSections)
2668 rc2 = KLDR_ERR_TODO; /* deal with this if it ever occurs. */
2669 else
2670 rc2 = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
2671 if (!rc && rc2)
2672 rc = rc2;
2673 return rc;
2674}
2675
2676
2677/**
2678 * MH_OBJECT: Resolves undefined symbols (imports).
2679 *
2680 * @returns 0 on success, non-zero kLdr status code on failure.
2681 * @param pModMachO The Mach-O module interpreter instance.
2682 * @param pfnGetImport The callback for resolving an imported symbol.
2683 * @param pvUser User argument to the callback.
2684 */
[47]2685static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
[2]2686{
2687 const KU32 cSyms = pModMachO->cSymbols;
2688 KU32 iSym;
2689 int rc;
2690
2691 /*
2692 * Ensure that we've got the symbol table and section fixups handy.
2693 */
2694 rc = kldrModMachOLoadObjSymTab(pModMachO);
2695 if (rc)
2696 return rc;
2697
2698 /*
2699 * Iterate the symbol table and resolve undefined symbols.
2700 * We currently ignore REFERENCE_TYPE.
2701 */
2702 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2703 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2704 {
2705 macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols;
2706 for (iSym = 0; iSym < cSyms; iSym++)
2707 {
2708 /* skip stabs */
2709 if (paSyms[iSym].n_type & MACHO_N_STAB)
2710 continue;
2711
2712 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2713 {
2714 const char *pszSymbol;
2715 KSIZE cchSymbol;
2716 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
2717 KLDRADDR Value;
2718
2719 /** @todo Implement N_REF_TO_WEAK. */
[22]2720 KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO);
[2]2721
[47]2722 /* Get the symbol name. */
[2]2723 if ((KU32)paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
2724 return KLDR_ERR_MACHO_BAD_SYMBOL;
2725 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
2726 cchSymbol = kHlpStrLen(pszSymbol);
[47]2727
2728 /* Check for linker defined symbols relating to sections and segments. */
2729 if ( cchSymbol > sizeof("section$end$") - 1
2730 && *pszSymbol == 's'
2731 && kHlpMemChr(pszSymbol, '$', cchSymbol))
2732 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value);
2733 else
2734 rc = KLDR_ERR_SYMBOL_NOT_FOUND;
2735
2736 /* Ask the user for an address to the symbol. */
[2]2737 if (rc)
[47]2738 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
2739 &Value, &fKind, pvUser);
2740 if (rc)
[2]2741 {
2742 /* weak reference? */
2743 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
2744 break;
2745 Value = 0;
2746 }
2747
2748 /* Update the symbol. */
2749 paSyms[iSym].n_value = (KU32)Value;
2750 if (paSyms[iSym].n_value != Value)
2751 {
2752 rc = KLDR_ERR_ADDRESS_OVERFLOW;
2753 break;
2754 }
2755 }
2756 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
2757 {
2758 /** @todo implement weak symbols. */
2759 /*return KLDR_ERR_TODO; - ignored for now. */
2760 }
2761 }
2762 }
2763 else
2764 {
2765 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
2766 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols;
2767 for (iSym = 0; iSym < cSyms; iSym++)
2768 {
2769 /* skip stabs */
2770 if (paSyms[iSym].n_type & MACHO_N_STAB)
2771 continue;
2772
2773 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2774 {
2775 const char *pszSymbol;
2776 KSIZE cchSymbol;
2777 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
2778 KLDRADDR Value;
2779
2780 /** @todo Implement N_REF_TO_WEAK. */
[22]2781 KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO);
[2]2782
[47]2783 /* Get the symbol name. */
[2]2784 if (paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
2785 return KLDR_ERR_MACHO_BAD_SYMBOL;
2786 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
2787 cchSymbol = kHlpStrLen(pszSymbol);
[47]2788
2789 /* Check for linker defined symbols relating to sections and segments. */
2790 if ( cchSymbol > sizeof("section$end$") - 1
2791 && *pszSymbol == 's'
2792 && kHlpMemChr(pszSymbol, '$', cchSymbol))
2793 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value);
2794 else
2795 rc = KLDR_ERR_SYMBOL_NOT_FOUND;
2796
2797 /* Ask the user for an address to the symbol. */
[2]2798 if (rc)
[47]2799 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
2800 &Value, &fKind, pvUser);
2801 if (rc)
[2]2802 {
2803 /* weak reference? */
2804 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
2805 break;
2806 Value = 0;
2807 }
2808
2809 /* Update the symbol. */
2810 paSyms[iSym].n_value = Value;
2811 if (paSyms[iSym].n_value != Value)
2812 {
2813 rc = KLDR_ERR_ADDRESS_OVERFLOW;
2814 break;
2815 }
2816 }
2817 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
2818 {
2819 /** @todo implement weak symbols. */
2820 /*return KLDR_ERR_TODO; - ignored for now. */
2821 }
2822 }
2823 }
2824
2825 return rc;
2826}
2827
2828
2829/**
2830 * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
2831 *
2832 * @returns 0 on success, non-zero kLdr status code on failure.
2833 * @param pModMachO The Mach-O module interpreter instance.
2834 * @param pvMapping The mapping to fixup.
2835 * @param NewBaseAddress The address to fixup the mapping to.
2836 * @param OldBaseAddress The address the mapping is currently fixed up to.
2837 */
2838static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress)
2839{
2840 KU32 iSeg;
2841 int rc;
2842
2843
2844 /*
2845 * Ensure that we've got the symbol table and section fixups handy.
2846 */
2847 rc = kldrModMachOLoadObjSymTab(pModMachO);
2848 if (rc)
2849 return rc;
2850
2851 /*
2852 * Iterate over the segments and their sections and apply fixups.
2853 */
2854 for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++)
2855 {
2856 PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg];
2857 KU32 iSect;
2858
2859 for (iSect = 0; iSect < pSeg->cSections; iSect++)
2860 {
2861 PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect];
2862 KU8 *pbSectBits;
2863
2864 /* skip sections without fixups. */
2865 if (!pSect->cFixups)
2866 continue;
2867
2868 /* lazy load (and endian convert) the fixups. */
2869 if (!pSect->paFixups)
2870 {
2871 rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
2872 if (rc)
2873 break;
2874 }
2875
2876 /*
2877 * Apply the fixups.
2878 */
2879 pbSectBits = (KU8 *)pvMapping + (KUPTR)pSect->RVA;
2880 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
2881 rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect,
2882 (macho_nlist_32_t *)pModMachO->pvaSymbols,
2883 pModMachO->cSymbols, NewBaseAddress);
[22]2884 else if ( pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE
2885 && pModMachO->Hdr.cputype == CPU_TYPE_X86_64)
2886 rc = kldrModMachOFixupSectionAMD64(pModMachO, pbSectBits, pSect,
2887 (macho_nlist_64_t *)pModMachO->pvaSymbols,
2888 pModMachO->cSymbols, NewBaseAddress);
[2]2889 else
[22]2890 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2891 if (rc)
2892 break;
2893 }
2894 }
2895
2896 return rc;
2897}
2898
2899
2900/**
2901 * Applies generic fixups to a section in an image of the same endian-ness
2902 * as the host CPU.
2903 *
2904 * @returns 0 on success, non-zero kLdr status code on failure.
2905 * @param pModMachO The Mach-O module interpreter instance.
2906 * @param pbSectBits Pointer to the section bits.
2907 * @param pFixupSect The section being fixed up.
2908 * @param NewBaseAddress The new base image address.
2909 */
2910static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
2911 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
2912{
2913 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
2914 const KU32 cFixups = pFixupSect->cFixups;
2915 KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
2916 const KU8 *pbSectVirginBits;
2917 KU32 iFixup;
2918 KLDRPU uFixVirgin;
2919 KLDRPU uFix;
[28]2920 KLDRADDR SymAddr = ~(KLDRADDR)0;
[2]2921 int rc;
2922
2923 /*
2924 * Find the virgin bits.
2925 */
2926 if (pFixupSect->offFile != -1)
2927 {
2928 rc = kldrModMachOMapVirginBits(pModMachO);
2929 if (rc)
2930 return rc;
2931 pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
2932 }
2933 else
2934 pbSectVirginBits = NULL;
2935
2936 /*
2937 * Iterate the fixups and apply them.
2938 */
2939 for (iFixup = 0; iFixup < cFixups; iFixup++)
2940 {
2941 union
2942 {
2943 macho_relocation_info_t r;
2944 scattered_relocation_info_t s;
2945 } Fixup;
2946 Fixup.r = paFixups[iFixup];
2947
2948 if (!(Fixup.r.r_address & R_SCATTERED))
2949 {
2950 /* sanity */
2951 if ((KU32)Fixup.r.r_address >= cbSectBits)
2952 return KLDR_ERR_BAD_FIXUP;
2953
2954 /* calc fixup addresses. */
2955 uFix.pv = pbSectBits + Fixup.r.r_address;
2956 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
2957
2958 /*
2959 * Calc the symbol value.
2960 */
2961 /* Calc the linked symbol address / addend. */
2962 switch (Fixup.r.r_length)
2963 {
2964 /** @todo Deal with unaligned accesses on non x86 platforms. */
2965 case 0: SymAddr = *uFixVirgin.pi8; break;
2966 case 1: SymAddr = *uFixVirgin.pi16; break;
2967 case 2: SymAddr = *uFixVirgin.pi32; break;
2968 case 3: SymAddr = *uFixVirgin.pi64; break;
2969 }
2970 if (Fixup.r.r_pcrel)
2971 SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress;
2972
2973 /* Add symbol / section address. */
2974 if (Fixup.r.r_extern)
2975 {
2976 const macho_nlist_32_t *pSym;
2977 if (Fixup.r.r_symbolnum >= cSyms)
2978 return KLDR_ERR_BAD_FIXUP;
2979 pSym = &paSyms[Fixup.r.r_symbolnum];
2980
2981 if (pSym->n_type & MACHO_N_STAB)
2982 return KLDR_ERR_BAD_FIXUP;
2983
2984 switch (pSym->n_type & MACHO_N_TYPE)
2985 {
2986 case MACHO_N_SECT:
2987 {
2988 PKLDRMODMACHOSECT pSymSect;
2989 if ((KU32)pSym->n_sect - 1 > pModMachO->cSections)
2990 return KLDR_ERR_MACHO_BAD_SYMBOL;
2991 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
2992
2993 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2994 break;
2995 }
2996
2997 case MACHO_N_UNDF:
2998 case MACHO_N_ABS:
2999 SymAddr += pSym->n_value;
3000 break;
3001
3002 case MACHO_N_INDR:
3003 case MACHO_N_PBUD:
[22]3004 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]3005 default:
[22]3006 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]3007 }
3008 }
3009 else if (Fixup.r.r_symbolnum != R_ABS)
3010 {
3011 PKLDRMODMACHOSECT pSymSect;
3012 if (Fixup.r.r_symbolnum > pModMachO->cSections)
3013 return KLDR_ERR_BAD_FIXUP;
3014 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
3015
3016 SymAddr -= pSymSect->LinkAddress;
3017 SymAddr += pSymSect->RVA + NewBaseAddress;
3018 }
3019
3020 /* adjust for PC relative */
3021 if (Fixup.r.r_pcrel)
3022 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
3023 }
3024 else
3025 {
3026 PKLDRMODMACHOSECT pSymSect;
3027 KU32 iSymSect;
3028 KLDRADDR Value;
3029
3030 /* sanity */
3031 KLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
3032 if ((KU32)Fixup.s.r_address >= cbSectBits)
3033 return KLDR_ERR_BAD_FIXUP;
3034
3035 /* calc fixup addresses. */
3036 uFix.pv = pbSectBits + Fixup.s.r_address;
3037 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.s.r_address : 0;
3038
3039 /*
3040 * Calc the symbol value.
3041 */
3042 /* The addend is stored in the code. */
3043 switch (Fixup.s.r_length)
3044 {
3045 case 0: SymAddr = *uFixVirgin.pi8; break;
3046 case 1: SymAddr = *uFixVirgin.pi16; break;
3047 case 2: SymAddr = *uFixVirgin.pi32; break;
3048 case 3: SymAddr = *uFixVirgin.pi64; break;
3049 }
3050 if (Fixup.s.r_pcrel)
3051 SymAddr += Fixup.s.r_address;
3052 Value = Fixup.s.r_value;
3053 SymAddr -= Value; /* (-> addend only) */
3054
3055 /* Find the section number from the r_value. */
3056 pSymSect = NULL;
3057 for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++)
3058 {
3059 KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress;
3060 if (off < pModMachO->paSections[iSymSect].cb)
3061 {
3062 pSymSect = &pModMachO->paSections[iSymSect];
3063 break;
3064 }
3065 else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */
3066 pSymSect = &pModMachO->paSections[iSymSect];
3067 }
3068 if (!pSymSect)
3069 return KLDR_ERR_BAD_FIXUP;
3070
3071 /* Calc the symbol address. */
3072 SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3073 if (Fixup.s.r_pcrel)
3074 SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
3075
3076 Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
3077 Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type;
3078 }
3079
3080 /*
3081 * Write back the fixed up value.
3082 */
3083 if (Fixup.r.r_type == GENERIC_RELOC_VANILLA)
3084 {
3085 switch (Fixup.r.r_length)
3086 {
3087 case 0: *uFix.pu8 = (KU8)SymAddr; break;
3088 case 1: *uFix.pu16 = (KU16)SymAddr; break;
3089 case 2: *uFix.pu32 = (KU32)SymAddr; break;
3090 case 3: *uFix.pu64 = (KU64)SymAddr; break;
3091 }
3092 }
3093 else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF)
3094 return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE;
3095 else
3096 return KLDR_ERR_BAD_FIXUP;
3097 }
3098
3099 return 0;
3100}
3101
3102
3103/**
[22]3104 * Applies AMD64 fixups to a section.
3105 *
3106 * @returns 0 on success, non-zero kLdr status code on failure.
3107 * @param pModMachO The Mach-O module interpreter instance.
3108 * @param pbSectBits Pointer to the section bits.
3109 * @param pFixupSect The section being fixed up.
3110 * @param NewBaseAddress The new base image address.
3111 */
3112static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
3113 macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
3114{
3115 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
3116 const KU32 cFixups = pFixupSect->cFixups;
3117 KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
3118 const KU8 *pbSectVirginBits;
3119 KU32 iFixup;
3120 KLDRPU uFixVirgin;
3121 KLDRPU uFix;
3122 KLDRADDR SymAddr;
3123 int rc;
3124
3125 /*
3126 * Find the virgin bits.
3127 */
3128 if (pFixupSect->offFile != -1)
3129 {
3130 rc = kldrModMachOMapVirginBits(pModMachO);
3131 if (rc)
3132 return rc;
3133 pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
3134 }
3135 else
3136 pbSectVirginBits = NULL;
3137
3138 /*
3139 * Iterate the fixups and apply them.
3140 */
3141 for (iFixup = 0; iFixup < cFixups; iFixup++)
3142 {
3143 union
3144 {
3145 macho_relocation_info_t r;
3146 scattered_relocation_info_t s;
3147 } Fixup;
3148 Fixup.r = paFixups[iFixup];
3149
3150 /* AMD64 doesn't use scattered fixups. */
3151 KLDRMODMACHO_CHECK_RETURN(!(Fixup.r.r_address & R_SCATTERED), KLDR_ERR_BAD_FIXUP);
3152
3153 /* sanity */
3154 KLDRMODMACHO_CHECK_RETURN((KU32)Fixup.r.r_address < cbSectBits, KLDR_ERR_BAD_FIXUP);
3155
3156 /* calc fixup addresses. */
3157 uFix.pv = pbSectBits + Fixup.r.r_address;
3158 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
3159
3160 /*
3161 * Calc the symbol value.
3162 */
3163 /* Calc the linked symbol address / addend. */
3164 switch (Fixup.r.r_length)
3165 {
3166 /** @todo Deal with unaligned accesses on non x86 platforms. */
3167 case 2: SymAddr = *uFixVirgin.pi32; break;
3168 case 3: SymAddr = *uFixVirgin.pi64; break;
3169 default:
3170 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
3171 }
3172
3173 /* Add symbol / section address. */
3174 if (Fixup.r.r_extern)
3175 {
3176 const macho_nlist_64_t *pSym;
3177
3178 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP);
3179 pSym = &paSyms[Fixup.r.r_symbolnum];
3180 KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP);
3181
3182 switch (Fixup.r.r_type)
3183 {
3184 /* GOT references just needs to have their symbol verified.
3185 Later, we'll optimize GOT building here using a parallel sym->got array. */
3186 case X86_64_RELOC_GOT_LOAD:
3187 case X86_64_RELOC_GOT:
3188 switch (pSym->n_type & MACHO_N_TYPE)
3189 {
3190 case MACHO_N_SECT:
3191 case MACHO_N_UNDF:
3192 case MACHO_N_ABS:
3193 break;
3194 case MACHO_N_INDR:
3195 case MACHO_N_PBUD:
3196 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
3197 default:
3198 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
3199 }
3200 SymAddr = sizeof(KU64) * Fixup.r.r_symbolnum + pModMachO->GotRVA + NewBaseAddress;
[23]3201 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP);
3202 SymAddr -= 4;
[22]3203 break;
3204
3205 /* Verify the r_pcrel field for signed fixups on the way into the default case. */
3206 case X86_64_RELOC_BRANCH:
3207 case X86_64_RELOC_SIGNED:
3208 case X86_64_RELOC_SIGNED_1:
3209 case X86_64_RELOC_SIGNED_2:
3210 case X86_64_RELOC_SIGNED_4:
3211 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3212 default:
3213 {
3214 /* Adjust with fixup specific addend and vierfy unsigned/r_pcrel. */
3215 switch (Fixup.r.r_type)
3216 {
3217 case X86_64_RELOC_UNSIGNED:
3218 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3219 break;
3220 case X86_64_RELOC_BRANCH:
[23]3221 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP);
3222 SymAddr -= 4;
[22]3223 break;
3224 case X86_64_RELOC_SIGNED_1: SymAddr -= 1; break;
3225 case X86_64_RELOC_SIGNED_2: SymAddr -= 2; break;
[23]3226 case X86_64_RELOC_SIGNED:
[22]3227 case X86_64_RELOC_SIGNED_4: SymAddr -= 4; break;
3228 default:
3229 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
3230 }
3231
3232 switch (pSym->n_type & MACHO_N_TYPE)
3233 {
3234 case MACHO_N_SECT:
3235 {
3236 PKLDRMODMACHOSECT pSymSect;
3237 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3238 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3239 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3240 break;
3241 }
3242
3243 case MACHO_N_UNDF:
[23]3244 /* branch to an external symbol may have to take a short detour. */
3245 if ( Fixup.r.r_type == X86_64_RELOC_BRANCH
3246 && SymAddr + Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress
3247 - pSym->n_value
3248 + KU64_C(0x80000000)
3249 >= KU64_C(0xffffff20))
3250 SymAddr += pModMachO->cbJmpStub * Fixup.r.r_symbolnum + pModMachO->JmpStubsRVA + NewBaseAddress;
3251 else
3252 SymAddr += pSym->n_value;
3253 break;
3254
[22]3255 case MACHO_N_ABS:
3256 SymAddr += pSym->n_value;
3257 break;
3258
3259 case MACHO_N_INDR:
3260 case MACHO_N_PBUD:
3261 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
3262 default:
3263 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
3264 }
3265 break;
3266 }
3267
3268 /*
3269 * This is a weird customer, it will always be follows by an UNSIGNED fixup.
3270 */
3271 case X86_64_RELOC_SUBTRACTOR:
3272 {
3273 macho_relocation_info_t Fixup2;
3274
3275 /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */
3276 switch (pSym->n_type & MACHO_N_TYPE)
3277 {
3278 case MACHO_N_SECT:
3279 {
3280 PKLDRMODMACHOSECT pSymSect;
3281 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3282 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3283 SymAddr -= pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3284 break;
3285 }
3286
3287 case MACHO_N_UNDF:
3288 case MACHO_N_ABS:
3289 SymAddr -= pSym->n_value;
3290 break;
3291
3292 case MACHO_N_INDR:
3293 case MACHO_N_PBUD:
3294 KLDRMODMACHO_CHECK_RETURN(0,KLDR_ERR_TODO);
3295 default:
3296 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
3297 }
3298
3299 /* Load the 2nd fixup, check sanity. */
3300 iFixup++;
3301 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, KLDR_ERR_BAD_FIXUP);
3302 Fixup2 = paFixups[iFixup];
3303 KLDRMODMACHO_CHECK_RETURN( Fixup2.r_address == Fixup.r.r_address
3304 && Fixup2.r_length == Fixup.r.r_length
3305 && Fixup2.r_type == X86_64_RELOC_UNSIGNED
3306 && !Fixup2.r_pcrel
3307 && Fixup2.r_extern /*??*/
3308 && Fixup2.r_symbolnum < cSyms,
3309 KLDR_ERR_BAD_FIXUP);
3310
3311 pSym = &paSyms[Fixup.r.r_symbolnum];
3312 KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP);
3313
3314 /* Add it's value to SymAddr. */
3315 switch (pSym->n_type & MACHO_N_TYPE)
3316 {
3317 case MACHO_N_SECT:
3318 {
3319 PKLDRMODMACHOSECT pSymSect;
3320 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3321 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3322 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3323 break;
3324 }
3325
3326 case MACHO_N_UNDF:
3327 case MACHO_N_ABS:
3328 SymAddr += pSym->n_value;
3329 break;
3330
3331 case MACHO_N_INDR:
3332 case MACHO_N_PBUD:
3333 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
3334 default:
3335 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
3336 }
3337 }
3338 break;
3339 }
3340 }
3341 else
3342 {
3343 /* verify against fixup type */
3344 switch (Fixup.r.r_type)
3345 {
3346 case X86_64_RELOC_UNSIGNED:
3347 case X86_64_RELOC_SIGNED:
3348 case X86_64_RELOC_BRANCH:
3349 /*case X86_64_RELOC_GOT_LOAD:*/
3350 /*case X86_64_RELOC_GOT: */
3351 /*case X86_64_RELOC_SUBTRACTOR: - ???*/
3352 case X86_64_RELOC_SIGNED_1:
3353 case X86_64_RELOC_SIGNED_2:
3354 case X86_64_RELOC_SIGNED_4:
3355 break;
3356 default:
3357 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
3358 }
3359 if (Fixup.r.r_symbolnum != R_ABS)
3360 {
3361 PKLDRMODMACHOSECT pSymSect;
3362 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP);
3363 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
3364
3365 SymAddr -= pSymSect->LinkAddress;
3366 SymAddr += pSymSect->RVA + NewBaseAddress;
3367 }
3368 }
3369
3370 /* adjust for PC relative */
3371 if (Fixup.r.r_pcrel)
3372 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
3373
3374 /*
3375 * Write back the fixed up value.
3376 */
3377 switch (Fixup.r.r_length)
3378 {
3379 case 3:
3380 *uFix.pu64 = (KU64)SymAddr;
3381 break;
3382 case 2:
3383 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel || Fixup.r.r_type == X86_64_RELOC_SUBTRACTOR, KLDR_ERR_BAD_FIXUP);
3384 KLDRMODMACHO_CHECK_RETURN((KI32)SymAddr == (KI64)SymAddr, KLDR_ERR_ADDRESS_OVERFLOW);
3385 *uFix.pu32 = (KU32)SymAddr;
3386 break;
3387 default:
3388 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
3389 }
3390 }
3391
3392 return 0;
3393}
3394
3395
3396/**
[2]3397 * Loads the symbol table for a MH_OBJECT file.
3398 *
3399 * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols.
3400 *
3401 * @returns 0 on success, non-zero kLdr status code on failure.
3402 * @param pModMachO The Mach-O module interpreter instance.
3403 */
3404static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO)
3405{
3406 int rc = 0;
3407
3408 if ( !pModMachO->pvaSymbols
3409 && pModMachO->cSymbols)
3410 {
3411 KSIZE cbSyms;
3412 KSIZE cbSym;
3413 void *pvSyms;
3414 void *pvStrings;
3415
3416 /* sanity */
[22]3417 KLDRMODMACHO_CHECK_RETURN( pModMachO->offSymbols
3418 && (!pModMachO->cchStrings || pModMachO->offStrings),
3419 KLDR_ERR_MACHO_BAD_OBJECT_FILE);
[2]3420
3421 /* allocate */
3422 cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
3423 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
3424 ? sizeof(macho_nlist_32_t)
3425 : sizeof(macho_nlist_64_t);
3426 cbSyms = pModMachO->cSymbols * cbSym;
[22]3427 KLDRMODMACHO_CHECK_RETURN(cbSyms / cbSym == pModMachO->cSymbols, KLDR_ERR_SIZE_OVERFLOW);
[2]3428 rc = KERR_NO_MEMORY;
3429 pvSyms = kHlpAlloc(cbSyms);
3430 if (pvSyms)
3431 {
3432 if (pModMachO->cchStrings)
3433 pvStrings = kHlpAlloc(pModMachO->cchStrings);
3434 else
3435 pvStrings = kHlpAllocZ(4);
3436 if (pvStrings)
3437 {
3438 /* read */
3439 rc = kRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols);
3440 if (!rc && pModMachO->cchStrings)
3441 rc = kRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings);
3442 if (!rc)
3443 {
3444 pModMachO->pvaSymbols = pvSyms;
3445 pModMachO->pchStrings = (char *)pvStrings;
3446
3447 /* perform endian conversion? */
3448 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
3449 {
3450 KU32 cLeft = pModMachO->cSymbols;
3451 macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms;
3452 while (cLeft-- > 0)
3453 {
3454 pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
3455 pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
3456 pSym->n_value = K_E2E_U32(pSym->n_value);
3457 pSym++;
3458 }
3459 }
3460 else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
3461 {
3462 KU32 cLeft = pModMachO->cSymbols;
3463 macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms;
3464 while (cLeft-- > 0)
3465 {
3466 pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
3467 pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
3468 pSym->n_value = K_E2E_U64(pSym->n_value);
3469 pSym++;
3470 }
3471 }
3472
3473 return 0;
3474 }
3475 kHlpFree(pvStrings);
3476 }
3477 kHlpFree(pvSyms);
3478 }
3479 }
3480 else
3481 KLDRMODMACHO_ASSERT(pModMachO->pchStrings);
3482
3483 return rc;
3484}
3485
3486
3487/**
3488 * Loads the fixups at the given address and performs endian
3489 * conversion if necessary.
3490 *
3491 * @returns 0 on success, non-zero kLdr status code on failure.
3492 * @param pModMachO The Mach-O module interpreter instance.
3493 * @param offFixups The file offset of the fixups.
3494 * @param cFixups The number of fixups to load.
3495 * @param ppaFixups Where to put the pointer to the allocated fixup array.
3496 */
3497static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups)
3498{
3499 macho_relocation_info_t *paFixups;
3500 KSIZE cbFixups;
3501 int rc;
3502
3503 /* allocate the memory. */
3504 cbFixups = cFixups * sizeof(*paFixups);
[22]3505 KLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, KLDR_ERR_SIZE_OVERFLOW);
[2]3506 paFixups = (macho_relocation_info_t *)kHlpAlloc(cbFixups);
3507 if (!paFixups)
3508 return KERR_NO_MEMORY;
3509
3510 /* read the fixups. */
3511 rc = kRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups);
3512 if (!rc)
3513 {
3514 *ppaFixups = paFixups;
3515
3516 /* do endian conversion if necessary. */
3517 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
3518 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
3519 {
3520 KU32 iFixup;
3521 for (iFixup = 0; iFixup < cFixups; iFixup++)
3522 {
3523 KU32 *pu32 = (KU32 *)&paFixups[iFixup];
3524 pu32[0] = K_E2E_U32(pu32[0]);
3525 pu32[1] = K_E2E_U32(pu32[1]);
3526 }
3527 }
3528 }
3529 else
3530 kHlpFree(paFixups);
3531 return rc;
3532}
3533
3534
3535/**
3536 * Maps the virgin file bits into memory if not already done.
3537 *
3538 * @returns 0 on success, non-zero kLdr status code on failure.
3539 * @param pModMachO The Mach-O module interpreter instance.
3540 */
3541static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO)
3542{
3543 int rc = 0;
3544 if (!pModMachO->pvBits)
3545 rc = kRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits);
3546 return rc;
3547}
3548
3549
3550/** @copydoc kLdrModCallInit */
3551static int kldrModMachOCallInit(PKLDRMOD pMod, KUPTR uHandle)
3552{
3553 /* later */
3554 return 0;
3555}
3556
3557
3558/** @copydoc kLdrModCallTerm */
3559static int kldrModMachOCallTerm(PKLDRMOD pMod, KUPTR uHandle)
3560{
3561 /* later */
3562 return 0;
3563}
3564
3565
3566/** @copydoc kLdrModCallThread */
3567static int kldrModMachOCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
3568{
3569 /* Relevant for Mach-O? */
3570 return 0;
3571}
3572
3573
3574/** @copydoc kLdrModSize */
3575static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
3576{
3577 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3578 return pModMachO->cbImage;
3579}
3580
3581
3582/** @copydoc kLdrModGetBits */
3583static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
3584{
3585 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3586 KU32 i;
3587 int rc;
3588
[43]3589 if (!pModMachO->fCanLoad)
3590 return KLDR_ERR_TODO;
3591
[2]3592 /*
3593 * Zero the entire buffer first to simplify things.
3594 */
3595 kHlpMemSet(pvBits, 0, (KSIZE)pModMachO->cbImage);
3596
3597 /*
3598 * When possible use the segment table to load the data.
3599 * If not iterate the load commands and execute the segment / section loads.
3600 */
3601 if (pModMachO->fMapUsingLoadCommandSections)
[22]3602 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO); /* deal with this if it ever occurs. */
[2]3603 else
3604 {
3605 for (i = 0; i < pMod->cSegments; i++)
3606 {
3607 /* skip it? */
3608 if ( pMod->aSegments[i].cbFile == -1
3609 || pMod->aSegments[i].offFile == -1
3610 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
3611 || !pMod->aSegments[i].Alignment)
3612 continue;
3613 rc = kRdrRead(pMod->pRdr,
[22]3614 (KU8 *)pvBits + (pMod->aSegments[i].LinkAddress - pModMachO->LinkAddress),
3615 pMod->aSegments[i].cbFile,
3616 pMod->aSegments[i].offFile);
[2]3617 if (rc)
3618 return rc;
3619 }
3620 }
3621
3622 /*
3623 * Perform relocations.
3624 */
[23]3625 return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
3626}
[22]3627
[23]3628
3629/** @copydoc kLdrModRelocateBits */
3630static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
3631 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
3632{
3633 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3634 int rc;
3635
[22]3636 /*
[23]3637 * Call workers to do the jobs.
3638 */
3639 if (pModMachO->Hdr.filetype == MH_OBJECT)
3640 {
[47]3641 rc = kldrModMachOObjDoImports(pModMachO, NewBaseAddress, pfnGetImport, pvUser);
[23]3642 if (!rc)
3643 rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress);
3644
3645 }
3646 else
3647 rc = KLDR_ERR_TODO;
3648 /*{
3649 rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
3650 if (!rc)
3651 rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
3652 }*/
3653
3654 /*
[22]3655 * Construct the global offset table if necessary, it's always the last
3656 * segment when present.
3657 */
[23]3658 if (!rc && pModMachO->fMakeGot)
3659 rc = kldrModMachOMakeGOT(pModMachO, pvBits, NewBaseAddress);
3660
[22]3661 return rc;
[2]3662}
3663
3664
[22]3665/**
3666 * Builds the GOT.
3667 *
3668 * Assumes the symbol table has all external symbols resolved correctly and that
3669 * the bits has been cleared up front.
3670 */
3671static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress)
3672{
3673 KU32 iSym = pModMachO->cSymbols;
3674 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
3675 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
3676 {
3677 macho_nlist_32_t const *paSyms = (macho_nlist_32_t const *)pModMachO->pvaSymbols;
3678 KU32 *paGOT = (KU32 *)((KU8 *)pvBits + pModMachO->GotRVA);
3679 while (iSym-- > 0)
3680 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
3681 {
3682 case MACHO_N_SECT:
3683 {
3684 PKLDRMODMACHOSECT pSymSect;
3685 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3686 pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
3687 paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3688 break;
3689 }
3690
3691 case MACHO_N_UNDF:
3692 case MACHO_N_ABS:
3693 paGOT[iSym] = paSyms[iSym].n_value;
3694 break;
3695 }
3696 }
3697 else
3698 {
3699 macho_nlist_64_t const *paSyms = (macho_nlist_64_t const *)pModMachO->pvaSymbols;
3700 KU64 *paGOT = (KU64 *)((KU8 *)pvBits + pModMachO->GotRVA);
3701 while (iSym-- > 0)
[23]3702 {
[22]3703 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
3704 {
3705 case MACHO_N_SECT:
3706 {
3707 PKLDRMODMACHOSECT pSymSect;
3708 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3709 pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
3710 paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3711 break;
3712 }
3713
3714 case MACHO_N_UNDF:
3715 case MACHO_N_ABS:
3716 paGOT[iSym] = paSyms[iSym].n_value;
3717 break;
3718 }
[23]3719 }
[22]3720
[23]3721 if (pModMachO->JmpStubsRVA != NIL_KLDRADDR)
3722 {
[42]3723 iSym = pModMachO->cSymbols;
[23]3724 switch (pModMachO->Hdr.cputype)
3725 {
3726 /*
3727 * AMD64 is simple since the GOT and the indirect jmps are parallel
3728 * arrays with entries of the same size. The relative offset will
3729 * be the the same for each entry, kind of nice. :-)
3730 */
3731 case CPU_TYPE_X86_64:
3732 {
3733 KU64 *paJmps = (KU64 *)((KU8 *)pvBits + pModMachO->JmpStubsRVA);
3734 KI32 off;
3735 KU64 u64Tmpl;
3736 union
3737 {
3738 KU8 ab[8];
3739 KU64 u64;
3740 } Tmpl;
[22]3741
[23]3742 /* create the template. */
3743 off = pModMachO->GotRVA - (pModMachO->JmpStubsRVA + 6);
3744 Tmpl.ab[0] = 0xff; /* jmp [GOT-entry wrt RIP] */
3745 Tmpl.ab[1] = 0x25;
3746 Tmpl.ab[2] = off & 0xff;
3747 Tmpl.ab[3] = (off >> 8) & 0xff;
3748 Tmpl.ab[4] = (off >> 16) & 0xff;
3749 Tmpl.ab[5] = (off >> 24) & 0xff;
3750 Tmpl.ab[6] = 0xcc;
3751 Tmpl.ab[7] = 0xcc;
3752 u64Tmpl = Tmpl.u64;
[2]3753
[23]3754 /* copy the template to every jmp table entry. */
3755 while (iSym-- > 0)
3756 paJmps[iSym] = u64Tmpl;
3757 break;
3758 }
[2]3759
[23]3760 default:
3761 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
3762 }
3763 }
[2]3764 }
[23]3765 return 0;
[2]3766}
3767
3768
3769/**
3770 * The Mach-O module interpreter method table.
3771 */
3772KLDRMODOPS g_kLdrModMachOOps =
3773{
3774 "Mach-O",
3775 NULL,
3776 kldrModMachOCreate,
3777 kldrModMachODestroy,
3778 kldrModMachOQuerySymbol,
3779 kldrModMachOEnumSymbols,
3780 kldrModMachOGetImport,
3781 kldrModMachONumberOfImports,
3782 NULL /* can execute one is optional */,
3783 kldrModMachOGetStackInfo,
3784 kldrModMachOQueryMainEntrypoint,
[54]3785 kldrModMachOQueryImageUuid,
[2]3786 NULL,
3787 NULL,
3788 kldrModMachOEnumDbgInfo,
3789 kldrModMachOHasDbgInfo,
3790 kldrModMachOMap,
3791 kldrModMachOUnmap,
3792 kldrModMachOAllocTLS,
3793 kldrModMachOFreeTLS,
3794 kldrModMachOReload,
3795 kldrModMachOFixupMapping,
3796 kldrModMachOCallInit,
3797 kldrModMachOCallTerm,
3798 kldrModMachOCallThread,
3799 kldrModMachOSize,
3800 kldrModMachOGetBits,
3801 kldrModMachORelocateBits,
3802 NULL, /** @todo mostly done */
3803 42 /* the end */
3804};
3805
Note: See TracBrowser for help on using the repository browser.