source: trunk/kLdr/kLdrModMachO.c@ 57

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