source: trunk/kLdr/kLdrModMachO.c@ 79

Last change on this file since 79 was 79, checked in by bird, 9 years ago

fixing warnings.

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