source: trunk/kLdr/kLdrModMachO.c@ 54

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

Added kLdrModQueryImageUuid for Mach-O.

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