source: trunk/kLdr/kLdrModMachO.c@ 53

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

Made 64-bit mach_kernel (10.7.4) loadable for debug info purposes.

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