source: trunk/kLdr/kLdrModMachO.c@ 68

Last change on this file since 68 was 68, checked in by bird, 10 years ago

kLdrModMachO.c: Relocation fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 142.3 KB
RevLine 
[2]1/* $Id: kLdrModMachO.c 68 2015-04-29 11:59:02Z 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;
307 KU32 cSegments;
308 KU32 cSections;
309 KU32 cbStringPool;
310 KSIZE cchFilename;
311 KSIZE cb;
[22]312 KBOOL fMakeGot;
[43]313 KBOOL fCanLoad = K_TRUE;
[51]314 KLDRADDR LinkAddress;
[23]315 KU8 cbJmpStub;
[62]316 KU8 uEffFileType;
[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;
[2]1122
1123 while (cLeft-- > 0)
1124 {
1125 u.pb = pb;
1126 cbLeft -= u.pLoadCmd->cmdsize;
1127 pb += u.pLoadCmd->cmdsize;
1128
1129 /*
1130 * Convert endian if needed, parse and validate the command.
1131 */
1132 switch (u.pLoadCmd->cmd)
1133 {
1134 case LC_SEGMENT_32:
1135 {
[58]1136 const segment_command_32_t *pSrcSeg = (const segment_command_32_t *)u.pLoadCmd;
1137 section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1);
1138 section_32_t *pSect = pFirstSect;
1139 KU32 cSectionsLeft = pSrcSeg->nsects;
[2]1140
[59]1141 /* Adds a segment, used by the macro below and thus shared with the 64-bit segment variant. */
1142 #define NEW_SEGMENT(a_cBits, a_achName1, a_fObjFile, a_achName2, a_SegAddr, a_cbSeg, a_fFileBits, a_offFile, a_cbFile) \
1143 do { \
1144 pDstSeg->pvUser = NULL; \
1145 pDstSeg->pchName = pbStringPool; \
1146 pDstSeg->cchName = (KU32)kHlpStrNLen(a_achName1, sizeof(a_achName1)); \
1147 kHlpMemCopy(pbStringPool, a_achName1, pDstSeg->cchName); \
1148 pbStringPool += pDstSeg->cchName; \
1149 if (a_fObjFile) \
1150 { /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \
1151 KSIZE cchName2 = kHlpStrNLen(a_achName2, sizeof(a_achName2)); \
1152 *pbStringPool++ = '.'; \
1153 kHlpMemCopy(pbStringPool, a_achName2, cchName2); \
1154 pbStringPool += cchName2; \
1155 pDstSeg->cchName += cchName2; \
1156 } \
1157 *pbStringPool++ = '\0'; \
1158 pDstSeg->SelFlat = 0; \
1159 pDstSeg->Sel16bit = 0; \
1160 pDstSeg->fFlags = 0; \
1161 pDstSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */ \
1162 pDstSeg->cb = (a_cbSeg); \
1163 pDstSeg->Alignment = 1; /* updated while parsing sections. */ \
1164 pDstSeg->LinkAddress = (a_SegAddr); \
1165 if (a_fFileBits) \
1166 { \
1167 pDstSeg->offFile = (a_offFile) + pModMachO->offImage; \
1168 pDstSeg->cbFile = (a_cbFile); \
1169 } \
1170 else \
1171 { \
1172 pDstSeg->offFile = -1; \
1173 pDstSeg->cbFile = -1; \
1174 } \
1175 pDstSeg->RVA = (a_SegAddr) - pModMachO->LinkAddress; \
1176 pDstSeg->cbMapped = 0; \
1177 pDstSeg->MapAddress = 0; \
1178 \
1179 pSegExtra->iOrgSegNo = pSegExtra - &pModMachO->aSegments[0]; \
1180 pSegExtra->cSections = 0; \
1181 pSegExtra->paSections = pSectExtra; \
1182 } while (0)
1183
1184 /* Closes the new segment - parter of NEW_SEGMENT. */
1185 #define CLOSE_SEGMENT() \
1186 do { \
1187 pSegExtra->cSections = pSectExtra - pSegExtra->paSections; \
1188 pSegExtra++; \
1189 pDstSeg++; \
1190 } while (0)
1191
1192
[58]1193 /* Shared with the 64-bit variant. */
1194 #define ADD_SEGMENT_AND_ITS_SECTIONS(a_cBits) \
1195 do { \
[59]1196 KBOOL fAddSegOuter = K_FALSE; \
[58]1197 \
1198 /* \
1199 * Check that the segment name is unique. We couldn't do that \
1200 * in the preparsing stage. \
1201 */ \
[62]1202 if (pModMachO->uEffFileType != MH_OBJECT) \
[59]1203 for (pSegItr = &pModMachO->pMod->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \
1204 if (!kHlpStrNComp(pSegItr->pchName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \
1205 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_DUPLICATE_SEGMENT_NAME); \
[58]1206 \
1207 /* \
1208 * Create a new segment, unless we're supposed to skip this one. \
1209 */ \
[62]1210 if ( pModMachO->uEffFileType != MH_OBJECT \
[59]1211 && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \
[65]1212 && kHlpStrComp(pSrcSeg->segname, "__DWARF") \
1213 && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \
[58]1214 { \
[59]1215 NEW_SEGMENT(a_cBits, pSrcSeg->segname, K_FALSE /*a_fObjFile*/, 0 /*a_achName2*/, \
1216 pSrcSeg->vmaddr, pSrcSeg->vmsize, \
1217 pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \
1218 fAddSegOuter = K_TRUE; \
[58]1219 } \
1220 \
1221 /* \
1222 * Convert and parse the sections. \
1223 */ \
1224 while (cSectionsLeft-- > 0) \
1225 { \
[59]1226 /* New segment if object file. */ \
1227 KBOOL fAddSegInner = K_FALSE; \
[62]1228 if ( pModMachO->uEffFileType == MH_OBJECT \
[59]1229 && !(pSect->flags & S_ATTR_DEBUG) \
[65]1230 && kHlpStrComp(pSrcSeg->segname, "__DWARF") \
1231 && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \
[59]1232 { \
1233 kHlpAssert(!fAddSegOuter); \
1234 NEW_SEGMENT(a_cBits, pSect->segname, K_TRUE /*a_fObjFile*/, pSect->sectname, \
1235 pSect->addr, pSect->size, \
1236 pSect->offset != 0, pSect->offset, pSect->size); \
1237 fAddSegInner = K_TRUE; \
1238 } \
1239 \
[58]1240 /* Section data extract. */ \
1241 pSectExtra->cb = pSect->size; \
[61]1242 pSectExtra->RVA = pSect->addr - pDstSeg->LinkAddress; \
[58]1243 pSectExtra->LinkAddress = pSect->addr; \
1244 if (pSect->offset) \
1245 pSectExtra->offFile = pSect->offset + pModMachO->offImage; \
1246 else \
1247 pSectExtra->offFile = -1; \
1248 pSectExtra->cFixups = pSect->nreloc; \
1249 pSectExtra->paFixups = NULL; \
1250 if (pSect->nreloc) \
1251 pSectExtra->offFixups = pSect->reloff + pModMachO->offImage; \
1252 else \
1253 pSectExtra->offFixups = -1; \
1254 pSectExtra->fFlags = pSect->flags; \
1255 pSectExtra->iSegment = pSegExtra - &pModMachO->aSegments[0]; \
1256 pSectExtra->pvMachoSection = pSect; \
1257 \
1258 /* Update the segment alignment, if we're not skipping it. */ \
[59]1259 if ( (fAddSegOuter || fAddSegInner) \
1260 && pDstSeg->Alignment < ((KLDRADDR)1 << pSect->align)) \
[58]1261 pDstSeg->Alignment = (KLDRADDR)1 << pSect->align; \
1262 \
[59]1263 /* Next section, and if object file next segment. */ \
[58]1264 pSectExtra++; \
1265 pSect++; \
[59]1266 if (fAddSegInner) \
1267 CLOSE_SEGMENT(); \
[58]1268 } \
1269 \
1270 /* Close the segment and advance. */ \
[59]1271 if (fAddSegOuter) \
1272 CLOSE_SEGMENT(); \
[58]1273 } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */
[2]1274
[58]1275 ADD_SEGMENT_AND_ITS_SECTIONS(32);
[2]1276 break;
1277 }
1278
[22]1279 case LC_SEGMENT_64:
1280 {
[58]1281 const segment_command_64_t *pSrcSeg = (const segment_command_64_t *)u.pLoadCmd;
1282 section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1);
1283 section_64_t *pSect = pFirstSect;
1284 KU32 cSectionsLeft = pSrcSeg->nsects;
[22]1285
[58]1286 ADD_SEGMENT_AND_ITS_SECTIONS(64);
[22]1287 break;
1288 }
1289
[2]1290 case LC_SYMTAB:
[62]1291 switch (pModMachO->uEffFileType)
[2]1292 {
1293 case MH_OBJECT:
[41]1294 case MH_EXECUTE:
1295 case MH_DYLIB: /** @todo ??? */
[61]1296 case MH_BUNDLE: /** @todo ??? */
[41]1297 case MH_DSYM:
[55]1298 case MH_KEXT_BUNDLE:
[25]1299 pModMachO->offSymbols = u.pSymTab->symoff + pModMachO->offImage;
[2]1300 pModMachO->cSymbols = u.pSymTab->nsyms;
[25]1301 pModMachO->offStrings = u.pSymTab->stroff + pModMachO->offImage;
[2]1302 pModMachO->cchStrings = u.pSymTab->strsize;
1303 break;
1304 }
1305 break;
1306
[54]1307 case LC_UUID:
1308 kHlpMemCopy(pModMachO->abImageUuid, u.pUuid->uuid, sizeof(pModMachO->abImageUuid));
1309 break;
1310
[2]1311 default:
1312 break;
1313 } /* command switch */
1314 } /* while more commands */
1315
[58]1316 kHlpAssert(pDstSeg == &pModMachO->pMod->aSegments[cSegments - pModMachO->fMakeGot]);
[2]1317
1318 /*
[58]1319 * Adjust mapping addresses calculating the image size.
[51]1320 */
1321 {
[64]1322 KBOOL fLoadLinkEdit = K_FALSE;
[61]1323 PKLDRMODMACHOSECT pSectExtraItr;
1324 KLDRADDR uNextRVA = 0;
1325 KLDRADDR cb;
[64]1326 KU32 cSegmentsToAdjust = cSegments - pModMachO->fMakeGot;
[61]1327 KU32 c;
[58]1328
[64]1329 for (;;)
1330 {
1331 /* Check if there is __DWARF segment at the end and make sure it's left
1332 out of the RVA negotiations and image loading. */
1333 if ( cSegmentsToAdjust > 0
1334 && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__DWARF"))
1335 {
1336 cSegmentsToAdjust--;
1337 pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR;
1338 pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0;
1339 continue;
1340 }
1341
1342 /* If we're skipping the __LINKEDIT segment, check for it and adjust
1343 the number of segments we'll be messing with here. ASSUMES it's
1344 last (by now anyway). */
1345 if ( !fLoadLinkEdit
1346 && cSegmentsToAdjust > 0
1347 && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__LINKEDIT"))
1348 {
1349 cSegmentsToAdjust--;
1350 pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR;
1351 pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0;
1352 continue;
1353 }
1354 break;
1355 }
1356
[58]1357 /* Adjust RVAs. */
[64]1358 c = cSegmentsToAdjust;
[58]1359 for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 0; pDstSeg++)
[51]1360 {
[58]1361 cb = pDstSeg->RVA - uNextRVA;
1362 if (cb >= 0x00100000) /* 1MB */
1363 {
1364 pDstSeg->RVA = uNextRVA;
1365 pModMachO->pMod->fFlags |= KLDRMOD_FLAGS_NON_CONTIGUOUS_LINK_ADDRS;
1366 }
1367 uNextRVA = pDstSeg->RVA + KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment);
1368 }
[51]1369
[58]1370 /* Calculate the cbMapping members. */
[64]1371 c = cSegmentsToAdjust;
[58]1372 for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 1; pDstSeg++)
1373 {
[64]1374
[58]1375 cb = pDstSeg[1].RVA - pDstSeg->RVA;
1376 pDstSeg->cbMapped = (KSIZE)cb == cb ? cb : KSIZE_MAX;
1377 }
[51]1378
[58]1379 cb = KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment);
1380 pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX;
[51]1381
[61]1382 /* Set the image size. */
[58]1383 pModMachO->cbImage = pDstSeg->RVA + cb;
[61]1384
[64]1385 /* Fixup the section RVAs (internal). */
1386 c = cSegmentsToAdjust;
[61]1387 uNextRVA = pModMachO->cbImage;
1388 pDstSeg = &pModMachO->pMod->aSegments[0];
1389 for (pSectExtraItr = pModMachO->paSections; pSectExtraItr != pSectExtra; pSectExtraItr++)
1390 {
1391 if (pSectExtraItr->iSegment < c)
1392 pSectExtraItr->RVA += pDstSeg[pSectExtraItr->iSegment].RVA;
1393 else
1394 {
1395 pSectExtraItr->RVA = uNextRVA;
1396 uNextRVA += KLDR_ALIGN_ADDR(pSectExtraItr->cb, 64);
1397 }
1398 }
[51]1399 }
1400
1401 /*
[22]1402 * Make the GOT segment if necessary.
1403 */
1404 if (pModMachO->fMakeGot)
1405 {
1406 KSIZE cbPtr = ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1407 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1408 ? sizeof(KU32)
1409 : sizeof(KU64);
[23]1410 KU32 cbGot = pModMachO->cSymbols * cbPtr;
1411 KU32 cbJmpStubs;
[22]1412
[58]1413 pModMachO->GotRVA = pModMachO->cbImage;
[22]1414
[23]1415 if (pModMachO->cbJmpStub)
1416 {
1417 cbGot = K_ALIGN_Z(cbGot, 64);
1418 pModMachO->JmpStubsRVA = pModMachO->GotRVA + cbGot;
1419 cbJmpStubs = pModMachO->cbJmpStub * pModMachO->cSymbols;
1420 }
1421 else
1422 {
1423 pModMachO->JmpStubsRVA = NIL_KLDRADDR;
1424 cbJmpStubs = 0;
1425 }
1426
[58]1427 pDstSeg = &pModMachO->pMod->aSegments[cSegments - 1];
1428 pDstSeg->pvUser = NULL;
1429 pDstSeg->pchName = "GOT";
1430 pDstSeg->cchName = 3;
1431 pDstSeg->SelFlat = 0;
1432 pDstSeg->Sel16bit = 0;
1433 pDstSeg->fFlags = 0;
1434 pDstSeg->enmProt = KPROT_READONLY;
1435 pDstSeg->cb = cbGot + cbJmpStubs;
1436 pDstSeg->Alignment = 64;
1437 pDstSeg->LinkAddress = pModMachO->LinkAddress + pModMachO->GotRVA;
1438 pDstSeg->offFile = -1;
1439 pDstSeg->cbFile = -1;
1440 pDstSeg->RVA = pModMachO->GotRVA;
1441 pDstSeg->cbMapped = KLDR_ALIGN_ADDR(cbGot + cbJmpStubs, pDstSeg->Alignment);
1442 pDstSeg->MapAddress = 0;
[22]1443
[51]1444 pSegExtra->iOrgSegNo = KU32_MAX;
[22]1445 pSegExtra->cSections = 0;
1446 pSegExtra->paSections = NULL;
1447
[58]1448 pModMachO->cbImage += pDstSeg->cbMapped;
[2]1449 }
1450
1451 return 0;
1452}
1453
1454
1455/** @copydoc KLDRMODOPS::pfnDestroy */
1456static int kldrModMachODestroy(PKLDRMOD pMod)
1457{
1458 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1459 int rc = 0;
1460 KU32 i, j;
1461 KLDRMODMACHO_ASSERT(!pModMachO->pvMapping);
1462
1463 i = pMod->cSegments;
1464 while (i-- > 0)
1465 {
1466 j = pModMachO->aSegments[i].cSections;
1467 while (j-- > 0)
1468 {
1469 kHlpFree(pModMachO->aSegments[i].paSections[j].paFixups);
1470 pModMachO->aSegments[i].paSections[j].paFixups = NULL;
1471 }
1472 }
1473
1474 if (pMod->pRdr)
1475 {
1476 rc = kRdrClose(pMod->pRdr);
1477 pMod->pRdr = NULL;
1478 }
1479 pMod->u32Magic = 0;
1480 pMod->pOps = NULL;
1481 kHlpFree(pModMachO->pbLoadCommands);
1482 pModMachO->pbLoadCommands = NULL;
1483 kHlpFree(pModMachO->pchStrings);
1484 pModMachO->pchStrings = NULL;
1485 kHlpFree(pModMachO->pvaSymbols);
1486 pModMachO->pvaSymbols = NULL;
1487 kHlpFree(pModMachO);
1488 return rc;
1489}
1490
1491
1492/**
1493 * Gets the right base address.
1494 *
1495 * @returns 0 on success.
1496 * @returns A non-zero status code if the BaseAddress isn't right.
1497 * @param pModMachO The interpreter module instance
1498 * @param pBaseAddress The base address, IN & OUT. Optional.
1499 */
1500static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress)
1501{
1502 /*
1503 * Adjust the base address.
1504 */
1505 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
1506 *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress;
1507 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
1508 *pBaseAddress = pModMachO->LinkAddress;
1509
1510 return 0;
1511}
1512
1513
[47]1514/**
1515 * Resolves a linker generated symbol.
1516 *
1517 * The Apple linker generates symbols indicating the start and end of sections
1518 * and segments. This function checks for these and returns the right value.
1519 *
1520 * @returns 0 or KLDR_ERR_SYMBOL_NOT_FOUND.
1521 * @param pModMachO The interpreter module instance.
1522 * @param pMod The generic module instance.
1523 * @param pchSymbol The symbol.
1524 * @param cchSymbol The length of the symbol.
1525 * @param BaseAddress The base address to apply when calculating the
1526 * value.
1527 * @param puValue Where to return the symbol value.
1528 */
1529static int kldrModMachOQueryLinkerSymbol(PKLDRMODMACHO pModMachO, PKLDRMOD pMod, const char *pchSymbol, KSIZE cchSymbol,
1530 KLDRADDR BaseAddress, PKLDRADDR puValue)
1531{
1532 /*
1533 * Match possible name prefixes.
1534 */
1535 static const struct
1536 {
1537 const char *pszPrefix;
1538 KU8 cchPrefix;
1539 KBOOL fSection;
1540 KBOOL fStart;
1541 } s_aPrefixes[] =
1542 {
1543 { "section$start$", (KU8)sizeof("section$start$") - 1, K_TRUE, K_TRUE },
1544 { "section$end$", (KU8)sizeof("section$end$") - 1, K_TRUE, K_FALSE},
1545 { "segment$start$", (KU8)sizeof("segment$start$") - 1, K_FALSE, K_TRUE },
1546 { "segment$end$", (KU8)sizeof("segment$end$") - 1, K_FALSE, K_FALSE},
1547 };
1548 KSIZE cchSectName = 0;
1549 const char *pchSectName = "";
1550 KSIZE cchSegName = 0;
1551 const char *pchSegName = NULL;
1552 KU32 iPrefix = K_ELEMENTS(s_aPrefixes) - 1;
1553 KU32 iSeg;
1554 KLDRADDR uValue;
[2]1555
[47]1556 for (;;)
1557 {
1558 KU8 const cchPrefix = s_aPrefixes[iPrefix].cchPrefix;
1559 if ( cchSymbol > cchPrefix
1560 && kHlpStrNComp(pchSymbol, s_aPrefixes[iPrefix].pszPrefix, cchPrefix) == 0)
1561 {
1562 pchSegName = pchSymbol + cchPrefix;
1563 cchSegName = cchSymbol - cchPrefix;
1564 break;
1565 }
1566
1567 /* next */
1568 if (!iPrefix)
1569 return KLDR_ERR_SYMBOL_NOT_FOUND;
1570 iPrefix--;
1571 }
1572
1573 /*
1574 * Split the remainder into segment and section name, if necessary.
1575 */
1576 if (s_aPrefixes[iPrefix].fSection)
1577 {
1578 pchSectName = kHlpMemChr(pchSegName, '$', cchSegName);
1579 if (!pchSectName)
1580 return KLDR_ERR_SYMBOL_NOT_FOUND;
1581 cchSegName = pchSectName - pchSegName;
1582 pchSectName++;
1583 cchSectName = cchSymbol - (pchSectName - pchSymbol);
1584 }
1585
1586 /*
1587 * Locate the segment.
1588 */
[62]1589 if (!pMod->cSegments)
[47]1590 return KLDR_ERR_SYMBOL_NOT_FOUND;
[62]1591 for (iSeg = 0; iSeg < pMod->cSegments; iSeg++)
[47]1592 {
[62]1593 if ( pMod->aSegments[iSeg].cchName >= cchSegName
1594 && kHlpMemComp(pMod->aSegments[iSeg].pchName, pchSegName, cchSegName) == 0)
1595 {
1596 section_32_t const *pSect;
1597 if ( pMod->aSegments[iSeg].cchName == cchSegName
1598 && pModMachO->Hdr.filetype != MH_OBJECT /* Good enough for __DWARF segs in MH_DHSYM, I hope. */)
1599 break;
1600
1601 pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[0].pvMachoSection;
1602 if ( pModMachO->uEffFileType == MH_OBJECT
1603 && pMod->aSegments[iSeg].cchName > cchSegName + 1
1604 && pMod->aSegments[iSeg].pchName[cchSegName] == '.'
1605 && kHlpStrNComp(&pMod->aSegments[iSeg].pchName[cchSegName + 1], pSect->sectname, sizeof(pSect->sectname)) == 0
1606 && pMod->aSegments[iSeg].cchName - cchSegName - 1 <= sizeof(pSect->sectname) )
1607 break;
1608 }
[47]1609 }
[62]1610 if (iSeg >= pMod->cSegments)
1611 return KLDR_ERR_SYMBOL_NOT_FOUND;
[47]1612
1613 if (!s_aPrefixes[iPrefix].fSection)
1614 {
1615 /*
1616 * Calculate the segment start/end address.
1617 */
[62]1618 uValue = pMod->aSegments[iSeg].RVA;
[47]1619 if (!s_aPrefixes[iPrefix].fStart)
1620 uValue += pMod->aSegments[iSeg].cb;
1621 }
1622 else
1623 {
1624 /*
1625 * Locate the section.
1626 */
1627 KU32 iSect = pModMachO->aSegments[iSeg].cSections;
1628 if (!iSect)
1629 return KLDR_ERR_SYMBOL_NOT_FOUND;
1630 for (;;)
1631 {
1632 section_32_t *pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[iSect].pvMachoSection;
1633 if ( cchSectName <= sizeof(pSect->sectname)
1634 && kHlpMemComp(pSect->sectname, pchSectName, cchSectName) == 0
1635 && ( cchSectName == sizeof(pSect->sectname)
1636 || pSect->sectname[cchSectName] == '\0') )
1637 break;
1638 /* next */
1639 if (!iSect)
1640 return KLDR_ERR_SYMBOL_NOT_FOUND;
1641 iSect--;
1642 }
1643
[62]1644 uValue = pModMachO->aSegments[iSeg].paSections[iSect].RVA;
1645 if (!s_aPrefixes[iPrefix].fStart)
1646 uValue += pModMachO->aSegments[iSeg].paSections[iSect].cb;
[47]1647 }
1648
1649 /*
[62]1650 * Convert from RVA to load address.
[47]1651 */
1652 uValue += BaseAddress;
1653 if (puValue)
1654 *puValue = uValue;
1655
1656 return 0;
1657}
1658
1659
[2]1660/** @copydoc kLdrModQuerySymbol */
1661static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
1662 const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
1663 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
1664{
1665 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1666 int rc;
1667
1668 /*
1669 * Resolve defaults.
1670 */
1671 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
1672 if (rc)
1673 return rc;
1674
1675 /*
1676 * Refuse segmented requests for now.
1677 */
[22]1678 KLDRMODMACHO_CHECK_RETURN( !pfKind
1679 || (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) == KLDRSYMKIND_REQ_FLAT,
1680 KLDR_ERR_TODO);
[2]1681
1682 /*
1683 * Take action according to file type.
1684 */
[41]1685 if ( pModMachO->Hdr.filetype == MH_OBJECT
1686 || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */
1687 || pModMachO->Hdr.filetype == MH_DYLIB
[61]1688 || pModMachO->Hdr.filetype == MH_BUNDLE
[55]1689 || pModMachO->Hdr.filetype == MH_DSYM
1690 || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE)
[2]1691 {
1692 rc = kldrModMachOLoadObjSymTab(pModMachO);
1693 if (!rc)
1694 {
1695 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1696 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1697 rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1698 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
1699 cchSymbol, puValue, pfKind);
1700 else
[22]1701 rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
[2]1702 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
[22]1703 cchSymbol, puValue, pfKind);
[2]1704 }
[47]1705
1706 /*
1707 * Check for link-editor generated symbols and supply what we can.
1708 *
1709 * As small service to clients that insists on adding a '_' prefix
1710 * before querying symbols, we will ignore the prefix.
1711 */
1712 if ( rc == KLDR_ERR_SYMBOL_NOT_FOUND
1713 && cchSymbol > sizeof("section$end$") - 1
1714 && ( pchSymbol[0] == 's'
1715 || (pchSymbol[1] == 's' && pchSymbol[0] == '_') )
1716 && kHlpMemChr(pchSymbol, '$', cchSymbol) )
1717 {
1718 if (pchSymbol[0] == '_')
1719 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol + 1, cchSymbol - 1, BaseAddress, puValue);
1720 else
1721 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol, cchSymbol, BaseAddress, puValue);
1722 }
[2]1723 }
1724 else
1725 rc = KLDR_ERR_TODO;
1726
1727 return rc;
1728}
1729
1730
1731/**
1732 * Lookup a symbol in a 32-bit symbol table.
1733 *
1734 * @returns See kLdrModQuerySymbol.
1735 * @param pModMachO
1736 * @param paSyms Pointer to the symbol table.
1737 * @param cSyms Number of symbols in the table.
1738 * @param pchStrings Pointer to the string table.
1739 * @param cchStrings Size of the string table.
1740 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
1741 * @param iSymbol See kLdrModQuerySymbol.
1742 * @param pchSymbol See kLdrModQuerySymbol.
1743 * @param cchSymbol See kLdrModQuerySymbol.
1744 * @param puValue See kLdrModQuerySymbol.
1745 * @param pfKind See kLdrModQuerySymbol.
1746 */
1747static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings,
1748 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
1749 PKLDRADDR puValue, KU32 *pfKind)
1750{
1751 /*
1752 * Find a valid symbol matching the search criteria.
1753 */
1754 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
1755 {
1756 /* simplify validation. */
1757 if (cchStrings <= cchSymbol)
1758 return KLDR_ERR_SYMBOL_NOT_FOUND;
1759 cchStrings -= cchSymbol;
1760
1761 /* external symbols are usually at the end, so search the other way. */
1762 for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
1763 {
1764 const char *psz;
1765
1766 /* Skip irrellevant and non-public symbols. */
1767 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1768 continue;
1769 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1770 continue;
1771 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1772 continue;
1773 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1774 continue;
1775
1776 /* get name */
1777 if (!paSyms[iSymbol].n_un.n_strx)
1778 continue;
1779 if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1780 continue;
1781 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1782 if (psz[cchSymbol])
1783 continue;
1784 if (kHlpMemComp(psz, pchSymbol, cchSymbol))
1785 continue;
1786
1787 /* match! */
1788 break;
1789 }
1790 if (iSymbol == KU32_MAX)
1791 return KLDR_ERR_SYMBOL_NOT_FOUND;
1792 }
1793 else
1794 {
1795 if (iSymbol >= cSyms)
1796 return KLDR_ERR_SYMBOL_NOT_FOUND;
1797 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1798 return KLDR_ERR_SYMBOL_NOT_FOUND;
1799 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1800 return KLDR_ERR_SYMBOL_NOT_FOUND;
1801 }
1802
1803 /*
1804 * Calc the return values.
1805 */
1806 if (pfKind)
1807 {
1808 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1809 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1810 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
1811 else
1812 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1813 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1814 *pfKind |= KLDRSYMKIND_WEAK;
1815 }
1816
1817 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1818 {
1819 case MACHO_N_SECT:
1820 {
1821 PKLDRMODMACHOSECT pSect;
[61]1822 KLDRADDR offSect;
1823 KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]1824 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1825
[61]1826 offSect = paSyms[iSymbol].n_value - pSect->LinkAddress;
1827 KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb
1828 || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */
1829 && offSect == 0U - pSect->RVA
[62]1830 && pModMachO->uEffFileType != MH_OBJECT),
[61]1831 KLDR_ERR_MACHO_BAD_SYMBOL);
[2]1832 if (puValue)
[61]1833 *puValue = BaseAddress + pSect->RVA + offSect;
[2]1834
1835 if ( pfKind
1836 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1837 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1838 break;
1839 }
1840
1841 case MACHO_N_ABS:
1842 if (puValue)
1843 *puValue = paSyms[iSymbol].n_value;
1844 /*if (pfKind)
1845 pfKind |= KLDRSYMKIND_ABS;*/
1846 break;
1847
1848 case MACHO_N_PBUD:
1849 case MACHO_N_INDR:
1850 /** @todo implement indirect and prebound symbols. */
1851 default:
[22]1852 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]1853 }
1854
1855 return 0;
1856}
1857
1858
[22]1859/**
1860 * Lookup a symbol in a 64-bit symbol table.
1861 *
1862 * @returns See kLdrModQuerySymbol.
1863 * @param pModMachO
1864 * @param paSyms Pointer to the symbol table.
1865 * @param cSyms Number of symbols in the table.
1866 * @param pchStrings Pointer to the string table.
1867 * @param cchStrings Size of the string table.
1868 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
1869 * @param iSymbol See kLdrModQuerySymbol.
1870 * @param pchSymbol See kLdrModQuerySymbol.
1871 * @param cchSymbol See kLdrModQuerySymbol.
1872 * @param puValue See kLdrModQuerySymbol.
1873 * @param pfKind See kLdrModQuerySymbol.
1874 */
1875static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings,
1876 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
1877 PKLDRADDR puValue, KU32 *pfKind)
1878{
1879 /*
1880 * Find a valid symbol matching the search criteria.
1881 */
1882 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
1883 {
1884 /* simplify validation. */
1885 if (cchStrings <= cchSymbol)
1886 return KLDR_ERR_SYMBOL_NOT_FOUND;
1887 cchStrings -= cchSymbol;
1888
1889 /* external symbols are usually at the end, so search the other way. */
1890 for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
1891 {
1892 const char *psz;
1893
1894 /* Skip irrellevant and non-public symbols. */
1895 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1896 continue;
1897 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1898 continue;
1899 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1900 continue;
1901 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1902 continue;
1903
1904 /* get name */
1905 if (!paSyms[iSymbol].n_un.n_strx)
1906 continue;
1907 if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1908 continue;
1909 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1910 if (psz[cchSymbol])
1911 continue;
1912 if (kHlpMemComp(psz, pchSymbol, cchSymbol))
1913 continue;
1914
1915 /* match! */
1916 break;
1917 }
1918 if (iSymbol == KU32_MAX)
1919 return KLDR_ERR_SYMBOL_NOT_FOUND;
1920 }
1921 else
1922 {
1923 if (iSymbol >= cSyms)
1924 return KLDR_ERR_SYMBOL_NOT_FOUND;
1925 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1926 return KLDR_ERR_SYMBOL_NOT_FOUND;
1927 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1928 return KLDR_ERR_SYMBOL_NOT_FOUND;
1929 }
1930
1931 /*
1932 * Calc the return values.
1933 */
1934 if (pfKind)
1935 {
1936 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1937 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1938 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
1939 else
1940 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1941 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1942 *pfKind |= KLDRSYMKIND_WEAK;
1943 }
1944
1945 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1946 {
1947 case MACHO_N_SECT:
1948 {
1949 PKLDRMODMACHOSECT pSect;
[61]1950 KLDRADDR offSect;
1951 KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
[22]1952 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1953
[61]1954 offSect = paSyms[iSymbol].n_value - pSect->LinkAddress;
1955 KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb
1956 || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */
1957 && offSect == 0U - pSect->RVA
[62]1958 && pModMachO->uEffFileType != MH_OBJECT),
[61]1959 KLDR_ERR_MACHO_BAD_SYMBOL);
[22]1960 if (puValue)
[61]1961 *puValue = BaseAddress + pSect->RVA + offSect;
[22]1962
1963 if ( pfKind
1964 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1965 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1966 break;
1967 }
1968
1969 case MACHO_N_ABS:
1970 if (puValue)
1971 *puValue = paSyms[iSymbol].n_value;
1972 /*if (pfKind)
1973 pfKind |= KLDRSYMKIND_ABS;*/
1974 break;
1975
1976 case MACHO_N_PBUD:
1977 case MACHO_N_INDR:
1978 /** @todo implement indirect and prebound symbols. */
1979 default:
1980 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
1981 }
1982
1983 return 0;
1984}
1985
1986
[2]1987/** @copydoc kLdrModEnumSymbols */
1988static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
1989 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
1990{
1991 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1992 int rc;
1993
1994 /*
1995 * Resolve defaults.
1996 */
1997 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
1998 if (rc)
1999 return rc;
2000
2001 /*
2002 * Take action according to file type.
2003 */
[41]2004 if ( pModMachO->Hdr.filetype == MH_OBJECT
2005 || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */
2006 || pModMachO->Hdr.filetype == MH_DYLIB
[61]2007 || pModMachO->Hdr.filetype == MH_BUNDLE
[55]2008 || pModMachO->Hdr.filetype == MH_DSYM
2009 || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE)
[2]2010 {
2011 rc = kldrModMachOLoadObjSymTab(pModMachO);
2012 if (!rc)
2013 {
2014 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2015 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2016 rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
2017 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
2018 fFlags, pfnCallback, pvUser);
2019 else
[22]2020 rc = kldrModMachODoEnumSymbols64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
2021 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
2022 fFlags, pfnCallback, pvUser);
[2]2023 }
2024 }
2025 else
[22]2026 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2027
2028 return rc;
2029}
2030
2031
2032/**
2033 * Enum a 32-bit symbol table.
2034 *
2035 * @returns See kLdrModQuerySymbol.
2036 * @param pModMachO
2037 * @param paSyms Pointer to the symbol table.
2038 * @param cSyms Number of symbols in the table.
2039 * @param pchStrings Pointer to the string table.
2040 * @param cchStrings Size of the string table.
2041 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
2042 * @param fFlags See kLdrModEnumSymbols.
2043 * @param pfnCallback See kLdrModEnumSymbols.
2044 * @param pvUser See kLdrModEnumSymbols.
2045 */
2046static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
2047 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
2048 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
2049{
[22]2050 const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2051 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
2052 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT;
[2]2053 KU32 iSym;
2054 int rc;
2055
2056 /*
2057 * Iterate the symbol table.
2058 */
2059 for (iSym = 0; iSym < cSyms; iSym++)
2060 {
2061 KU32 fKind;
2062 KLDRADDR uValue;
2063 const char *psz;
2064 KSIZE cch;
2065
2066 /* Skip debug symbols and undefined symbols. */
2067 if (paSyms[iSym].n_type & MACHO_N_STAB)
2068 continue;
2069 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2070 continue;
2071
2072 /* Skip non-public symbols unless they are requested explicitly. */
2073 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
2074 {
2075 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
2076 continue;
2077 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
2078 continue;
2079 if (!paSyms[iSym].n_un.n_strx)
2080 continue;
2081 }
2082
2083 /*
2084 * Gather symbol info
2085 */
2086
2087 /* name */
[61]2088 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]2089 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
2090 cch = kHlpStrLen(psz);
2091 if (!cch)
2092 psz = NULL;
2093
2094 /* kind & value */
2095 fKind = fKindBase;
2096 if (paSyms[iSym].n_desc & N_WEAK_DEF)
2097 fKind |= KLDRSYMKIND_WEAK;
2098 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
2099 {
2100 case MACHO_N_SECT:
2101 {
2102 PKLDRMODMACHOSECT pSect;
[61]2103 KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]2104 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
2105
[61]2106 uValue = paSyms[iSym].n_value - pSect->LinkAddress;
2107 KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb
2108 || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */
2109 && uValue == 0U - pSect->RVA
[62]2110 && pModMachO->uEffFileType != MH_OBJECT),
[61]2111 KLDR_ERR_MACHO_BAD_SYMBOL);
2112 uValue += BaseAddress + pSect->RVA;
[2]2113
2114 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
2115 fKind |= KLDRSYMKIND_CODE;
2116 else
2117 fKind |= KLDRSYMKIND_NO_TYPE;
2118 break;
2119 }
2120
2121 case MACHO_N_ABS:
2122 uValue = paSyms[iSym].n_value;
2123 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
2124 break;
2125
2126 case MACHO_N_PBUD:
2127 case MACHO_N_INDR:
2128 /** @todo implement indirect and prebound symbols. */
2129 default:
[22]2130 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2131 }
2132
2133 /*
2134 * Do callback.
2135 */
2136 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
2137 if (rc)
2138 return rc;
2139 }
2140 return 0;
2141}
2142
2143
[22]2144/**
2145 * Enum a 64-bit symbol table.
2146 *
2147 * @returns See kLdrModQuerySymbol.
2148 * @param pModMachO
2149 * @param paSyms Pointer to the symbol table.
2150 * @param cSyms Number of symbols in the table.
2151 * @param pchStrings Pointer to the string table.
2152 * @param cchStrings Size of the string table.
2153 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
2154 * @param fFlags See kLdrModEnumSymbols.
2155 * @param pfnCallback See kLdrModEnumSymbols.
2156 * @param pvUser See kLdrModEnumSymbols.
2157 */
2158static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms,
2159 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
2160 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
2161{
2162 const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE
2163 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE
2164 ? KLDRSYMKIND_64BIT : KLDRSYMKIND_32BIT;
2165 KU32 iSym;
2166 int rc;
2167
2168 /*
2169 * Iterate the symbol table.
2170 */
2171 for (iSym = 0; iSym < cSyms; iSym++)
2172 {
2173 KU32 fKind;
2174 KLDRADDR uValue;
2175 const char *psz;
2176 KSIZE cch;
2177
2178 /* Skip debug symbols and undefined symbols. */
2179 if (paSyms[iSym].n_type & MACHO_N_STAB)
2180 continue;
2181 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2182 continue;
2183
2184 /* Skip non-public symbols unless they are requested explicitly. */
2185 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
2186 {
2187 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
2188 continue;
2189 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
2190 continue;
2191 if (!paSyms[iSym].n_un.n_strx)
2192 continue;
2193 }
2194
2195 /*
2196 * Gather symbol info
2197 */
2198
2199 /* name */
[61]2200 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL);
[22]2201 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
2202 cch = kHlpStrLen(psz);
2203 if (!cch)
2204 psz = NULL;
2205
2206 /* kind & value */
2207 fKind = fKindBase;
2208 if (paSyms[iSym].n_desc & N_WEAK_DEF)
2209 fKind |= KLDRSYMKIND_WEAK;
2210 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
2211 {
2212 case MACHO_N_SECT:
2213 {
2214 PKLDRMODMACHOSECT pSect;
[61]2215 KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
[22]2216 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
2217
[61]2218 uValue = paSyms[iSym].n_value - pSect->LinkAddress;
2219 KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb
2220 || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */
2221 && uValue == 0U - pSect->RVA
[62]2222 && pModMachO->uEffFileType != MH_OBJECT),
[61]2223 KLDR_ERR_MACHO_BAD_SYMBOL);
2224 uValue += BaseAddress + pSect->RVA;
[22]2225
2226 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
2227 fKind |= KLDRSYMKIND_CODE;
2228 else
2229 fKind |= KLDRSYMKIND_NO_TYPE;
2230 break;
2231 }
2232
2233 case MACHO_N_ABS:
2234 uValue = paSyms[iSym].n_value;
2235 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
2236 break;
2237
2238 case MACHO_N_PBUD:
2239 case MACHO_N_INDR:
2240 /** @todo implement indirect and prebound symbols. */
2241 default:
2242 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
2243 }
2244
2245 /*
2246 * Do callback.
2247 */
2248 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
2249 if (rc)
2250 return rc;
2251 }
2252 return 0;
2253}
2254
2255
[2]2256/** @copydoc kLdrModGetImport */
2257static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
2258{
2259 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2260 if (pModMachO->Hdr.filetype == MH_OBJECT)
2261 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
2262
2263 /* later */
2264 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
2265}
2266
2267
2268/** @copydoc kLdrModNumberOfImports */
2269static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits)
2270{
2271 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2272 if (pModMachO->Hdr.filetype == MH_OBJECT)
2273 return 0;
2274
2275 /* later */
2276 return 0;
2277}
2278
2279
2280/** @copydoc kLdrModGetStackInfo */
2281static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
2282{
2283 /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
2284
2285 pStackInfo->Address = NIL_KLDRADDR;
2286 pStackInfo->LinkAddress = NIL_KLDRADDR;
2287 pStackInfo->cbStack = pStackInfo->cbStackThread = 0;
2288 /* later */
2289
2290 return 0;
2291}
2292
2293
2294/** @copydoc kLdrModQueryMainEntrypoint */
2295static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
2296{
2297#if 0
2298 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2299 int rc;
2300
2301 /*
2302 * Resolve base address alias if any.
2303 */
2304 rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress);
2305 if (rc)
2306 return rc;
2307
2308 /*
2309 * Convert the address from the header.
2310 */
2311 *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
2312 ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
2313 : NIL_KLDRADDR;
2314#else
2315 *pMainEPAddress = NIL_KLDRADDR;
2316#endif
2317 return 0;
2318}
2319
2320
[54]2321/** @copydoc kLdrModQueryImageUuid */
2322static int kldrModMachOQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid)
2323{
2324 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2325 kHlpMemSet(pvUuid, 0, cbUuid);
2326 if (kHlpMemComp(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)) == 0)
2327 return KLDR_ERR_NO_IMAGE_UUID;
2328 kHlpMemCopy(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid));
2329 return 0;
2330}
2331
2332
[2]2333/** @copydoc kLdrModEnumDbgInfo */
2334static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
2335{
[41]2336 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2337 int rc = 0;
2338 KU32 iSect;
[2]2339
[41]2340 for (iSect = 0; iSect < pModMachO->cSections; iSect++)
[2]2341 {
[41]2342 section_32_t *pMachOSect = pModMachO->paSections[iSect].pvMachoSection; /* (32-bit & 64-bit starts the same way) */
[42]2343 char szTmp[sizeof(pMachOSect->sectname) + 1];
2344
2345 if (kHlpStrComp(pMachOSect->segname, "__DWARF"))
[41]2346 continue;
[2]2347
[42]2348 kHlpMemCopy(szTmp, pMachOSect->sectname, sizeof(pMachOSect->sectname));
2349 szTmp[sizeof(pMachOSect->sectname)] = '\0';
2350
2351 rc = pfnCallback(pMod, iSect, KLDRDBGINFOTYPE_DWARF, 0, 0, szTmp,
[41]2352 pModMachO->paSections[iSect].offFile,
2353 pModMachO->paSections[iSect].LinkAddress,
2354 pModMachO->paSections[iSect].cb,
2355 NULL, pvUser);
2356 if (rc != 0)
[2]2357 break;
2358 }
2359
2360 return rc;
2361}
2362
2363
2364/** @copydoc kLdrModHasDbgInfo */
2365static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
2366{
2367 /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
2368
2369#if 0
2370 /*
2371 * Base this entirely on the presence of a debug directory.
2372 */
2373 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
2374 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
2375 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
2376 return KLDR_ERR_NO_DEBUG_INFO;
2377 return 0;
2378#else
2379 return KLDR_ERR_NO_DEBUG_INFO;
2380#endif
2381}
2382
2383
2384/** @copydoc kLdrModMap */
2385static int kldrModMachOMap(PKLDRMOD pMod)
2386{
2387 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2388 unsigned fFixed;
2389 KU32 i;
2390 void *pvBase;
2391 int rc;
2392
[43]2393 if (!pModMachO->fCanLoad)
2394 return KLDR_ERR_TODO;
2395
[2]2396 /*
2397 * Already mapped?
2398 */
2399 if (pModMachO->pvMapping)
2400 return KLDR_ERR_ALREADY_MAPPED;
2401
2402 /*
2403 * Map it.
2404 */
2405 /* fixed image? */
2406 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
2407 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
2408 if (!fFixed)
2409 pvBase = NULL;
2410 else
2411 {
2412 pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
2413 if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
2414 return KLDR_ERR_ADDRESS_OVERFLOW;
2415 }
2416
2417 /* try do the prepare */
[62]2418 rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
2419 if (rc)
2420 return rc;
[2]2421
2422 /*
2423 * Update the segments with their map addresses.
2424 */
2425 for (i = 0; i < pMod->cSegments; i++)
2426 {
2427 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
2428 pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
2429 }
2430 pModMachO->pvMapping = pvBase;
2431
2432 return 0;
2433}
2434
2435
2436/** @copydoc kLdrModUnmap */
2437static int kldrModMachOUnmap(PKLDRMOD pMod)
2438{
2439 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2440 KU32 i;
2441 int rc;
2442
2443 /*
2444 * Mapped?
2445 */
2446 if (!pModMachO->pvMapping)
2447 return KLDR_ERR_NOT_MAPPED;
2448
2449 /*
2450 * Try unmap the image.
2451 */
[62]2452 rc = kRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
2453 if (rc)
2454 return rc;
[2]2455
2456 /*
2457 * Update the segments to reflect that they aren't mapped any longer.
2458 */
2459 pModMachO->pvMapping = NULL;
2460 for (i = 0; i < pMod->cSegments; i++)
2461 pMod->aSegments[i].MapAddress = 0;
2462
2463 return 0;
2464}
2465
2466
2467/** @copydoc kLdrModAllocTLS */
2468static int kldrModMachOAllocTLS(PKLDRMOD pMod)
2469{
2470 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2471
2472 /*
2473 * Mapped?
2474 */
2475 if (!pModMachO->pvMapping)
2476 return KLDR_ERR_NOT_MAPPED;
2477 return 0;
2478}
2479
2480
2481/** @copydoc kLdrModFreeTLS */
2482static void kldrModMachOFreeTLS(PKLDRMOD pMod)
2483{
2484}
2485
2486
2487/** @copydoc kLdrModReload */
2488static int kldrModMachOReload(PKLDRMOD pMod)
2489{
2490 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2491
2492 /*
2493 * Mapped?
2494 */
2495 if (!pModMachO->pvMapping)
2496 return KLDR_ERR_NOT_MAPPED;
2497
2498 /* the file provider does it all */
2499 return kRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
2500}
2501
2502
2503/** @copydoc kLdrModFixupMapping */
2504static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2505{
2506 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2507 int rc, rc2;
2508
2509 /*
2510 * Mapped?
2511 */
2512 if (!pModMachO->pvMapping)
2513 return KLDR_ERR_NOT_MAPPED;
2514
2515 /*
2516 * Before doing anything we'll have to make all pages writable.
2517 */
[62]2518 rc = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
2519 if (rc)
2520 return rc;
[2]2521
2522 /*
2523 * Resolve imports and apply base relocations.
2524 */
2525 rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (KUPTR)pModMachO->pvMapping, pModMachO->LinkAddress,
2526 pfnGetImport, pvUser);
2527
2528 /*
2529 * Restore protection.
2530 */
[62]2531 rc2 = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
[2]2532 if (!rc && rc2)
2533 rc = rc2;
2534 return rc;
2535}
2536
2537
2538/**
2539 * MH_OBJECT: Resolves undefined symbols (imports).
2540 *
2541 * @returns 0 on success, non-zero kLdr status code on failure.
2542 * @param pModMachO The Mach-O module interpreter instance.
2543 * @param pfnGetImport The callback for resolving an imported symbol.
2544 * @param pvUser User argument to the callback.
2545 */
[47]2546static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
[2]2547{
2548 const KU32 cSyms = pModMachO->cSymbols;
2549 KU32 iSym;
2550 int rc;
2551
2552 /*
2553 * Ensure that we've got the symbol table and section fixups handy.
2554 */
2555 rc = kldrModMachOLoadObjSymTab(pModMachO);
2556 if (rc)
2557 return rc;
2558
2559 /*
2560 * Iterate the symbol table and resolve undefined symbols.
2561 * We currently ignore REFERENCE_TYPE.
2562 */
2563 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2564 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2565 {
2566 macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols;
2567 for (iSym = 0; iSym < cSyms; iSym++)
2568 {
2569 /* skip stabs */
2570 if (paSyms[iSym].n_type & MACHO_N_STAB)
2571 continue;
2572
2573 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2574 {
2575 const char *pszSymbol;
2576 KSIZE cchSymbol;
2577 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
2578 KLDRADDR Value;
2579
2580 /** @todo Implement N_REF_TO_WEAK. */
[22]2581 KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO);
[2]2582
[47]2583 /* Get the symbol name. */
[61]2584 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]2585 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
2586 cchSymbol = kHlpStrLen(pszSymbol);
[47]2587
2588 /* Check for linker defined symbols relating to sections and segments. */
2589 if ( cchSymbol > sizeof("section$end$") - 1
2590 && *pszSymbol == 's'
2591 && kHlpMemChr(pszSymbol, '$', cchSymbol))
2592 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value);
2593 else
2594 rc = KLDR_ERR_SYMBOL_NOT_FOUND;
2595
2596 /* Ask the user for an address to the symbol. */
[2]2597 if (rc)
[47]2598 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
2599 &Value, &fKind, pvUser);
2600 if (rc)
[2]2601 {
2602 /* weak reference? */
2603 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
2604 break;
2605 Value = 0;
2606 }
2607
2608 /* Update the symbol. */
2609 paSyms[iSym].n_value = (KU32)Value;
2610 if (paSyms[iSym].n_value != Value)
2611 {
2612 rc = KLDR_ERR_ADDRESS_OVERFLOW;
2613 break;
2614 }
2615 }
2616 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
2617 {
2618 /** @todo implement weak symbols. */
2619 /*return KLDR_ERR_TODO; - ignored for now. */
2620 }
2621 }
2622 }
2623 else
2624 {
2625 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
2626 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols;
2627 for (iSym = 0; iSym < cSyms; iSym++)
2628 {
2629 /* skip stabs */
2630 if (paSyms[iSym].n_type & MACHO_N_STAB)
2631 continue;
2632
2633 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2634 {
2635 const char *pszSymbol;
2636 KSIZE cchSymbol;
2637 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
2638 KLDRADDR Value;
2639
2640 /** @todo Implement N_REF_TO_WEAK. */
[22]2641 KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO);
[2]2642
[47]2643 /* Get the symbol name. */
[61]2644 KLDRMODMACHO_CHECK_RETURN(paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]2645 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
2646 cchSymbol = kHlpStrLen(pszSymbol);
[47]2647
2648 /* Check for linker defined symbols relating to sections and segments. */
2649 if ( cchSymbol > sizeof("section$end$") - 1
2650 && *pszSymbol == 's'
2651 && kHlpMemChr(pszSymbol, '$', cchSymbol))
2652 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value);
2653 else
2654 rc = KLDR_ERR_SYMBOL_NOT_FOUND;
2655
2656 /* Ask the user for an address to the symbol. */
[2]2657 if (rc)
[47]2658 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
2659 &Value, &fKind, pvUser);
2660 if (rc)
[2]2661 {
2662 /* weak reference? */
2663 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
2664 break;
2665 Value = 0;
2666 }
2667
2668 /* Update the symbol. */
2669 paSyms[iSym].n_value = Value;
2670 if (paSyms[iSym].n_value != Value)
2671 {
2672 rc = KLDR_ERR_ADDRESS_OVERFLOW;
2673 break;
2674 }
2675 }
2676 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
2677 {
2678 /** @todo implement weak symbols. */
2679 /*return KLDR_ERR_TODO; - ignored for now. */
2680 }
2681 }
2682 }
2683
2684 return rc;
2685}
2686
2687
2688/**
2689 * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
2690 *
2691 * @returns 0 on success, non-zero kLdr status code on failure.
2692 * @param pModMachO The Mach-O module interpreter instance.
2693 * @param pvMapping The mapping to fixup.
2694 * @param NewBaseAddress The address to fixup the mapping to.
2695 * @param OldBaseAddress The address the mapping is currently fixed up to.
2696 */
2697static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress)
2698{
2699 KU32 iSeg;
2700 int rc;
2701
2702
2703 /*
2704 * Ensure that we've got the symbol table and section fixups handy.
2705 */
2706 rc = kldrModMachOLoadObjSymTab(pModMachO);
2707 if (rc)
2708 return rc;
2709
2710 /*
2711 * Iterate over the segments and their sections and apply fixups.
2712 */
2713 for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++)
2714 {
2715 PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg];
2716 KU32 iSect;
2717
2718 for (iSect = 0; iSect < pSeg->cSections; iSect++)
2719 {
2720 PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect];
2721 KU8 *pbSectBits;
2722
2723 /* skip sections without fixups. */
2724 if (!pSect->cFixups)
2725 continue;
2726
2727 /* lazy load (and endian convert) the fixups. */
2728 if (!pSect->paFixups)
2729 {
2730 rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
2731 if (rc)
2732 break;
2733 }
2734
2735 /*
2736 * Apply the fixups.
2737 */
2738 pbSectBits = (KU8 *)pvMapping + (KUPTR)pSect->RVA;
2739 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
2740 rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect,
2741 (macho_nlist_32_t *)pModMachO->pvaSymbols,
2742 pModMachO->cSymbols, NewBaseAddress);
[22]2743 else if ( pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE
2744 && pModMachO->Hdr.cputype == CPU_TYPE_X86_64)
2745 rc = kldrModMachOFixupSectionAMD64(pModMachO, pbSectBits, pSect,
2746 (macho_nlist_64_t *)pModMachO->pvaSymbols,
2747 pModMachO->cSymbols, NewBaseAddress);
[2]2748 else
[22]2749 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2750 if (rc)
2751 break;
2752 }
2753 }
2754
2755 return rc;
2756}
2757
2758
2759/**
2760 * Applies generic fixups to a section in an image of the same endian-ness
2761 * as the host CPU.
2762 *
2763 * @returns 0 on success, non-zero kLdr status code on failure.
2764 * @param pModMachO The Mach-O module interpreter instance.
2765 * @param pbSectBits Pointer to the section bits.
2766 * @param pFixupSect The section being fixed up.
2767 * @param NewBaseAddress The new base image address.
2768 */
2769static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
2770 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
2771{
2772 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
2773 const KU32 cFixups = pFixupSect->cFixups;
2774 KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
2775 const KU8 *pbSectVirginBits;
2776 KU32 iFixup;
2777 KLDRPU uFixVirgin;
2778 KLDRPU uFix;
[28]2779 KLDRADDR SymAddr = ~(KLDRADDR)0;
[2]2780 int rc;
2781
2782 /*
2783 * Find the virgin bits.
2784 */
2785 if (pFixupSect->offFile != -1)
2786 {
2787 rc = kldrModMachOMapVirginBits(pModMachO);
2788 if (rc)
2789 return rc;
2790 pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
2791 }
2792 else
2793 pbSectVirginBits = NULL;
2794
2795 /*
2796 * Iterate the fixups and apply them.
2797 */
2798 for (iFixup = 0; iFixup < cFixups; iFixup++)
2799 {
2800 union
2801 {
2802 macho_relocation_info_t r;
2803 scattered_relocation_info_t s;
2804 } Fixup;
2805 Fixup.r = paFixups[iFixup];
2806
2807 if (!(Fixup.r.r_address & R_SCATTERED))
2808 {
2809 /* sanity */
2810 if ((KU32)Fixup.r.r_address >= cbSectBits)
2811 return KLDR_ERR_BAD_FIXUP;
2812
2813 /* calc fixup addresses. */
2814 uFix.pv = pbSectBits + Fixup.r.r_address;
2815 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
2816
2817 /*
2818 * Calc the symbol value.
2819 */
2820 /* Calc the linked symbol address / addend. */
2821 switch (Fixup.r.r_length)
2822 {
2823 /** @todo Deal with unaligned accesses on non x86 platforms. */
2824 case 0: SymAddr = *uFixVirgin.pi8; break;
2825 case 1: SymAddr = *uFixVirgin.pi16; break;
2826 case 2: SymAddr = *uFixVirgin.pi32; break;
2827 case 3: SymAddr = *uFixVirgin.pi64; break;
2828 }
2829 if (Fixup.r.r_pcrel)
2830 SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress;
2831
2832 /* Add symbol / section address. */
2833 if (Fixup.r.r_extern)
2834 {
2835 const macho_nlist_32_t *pSym;
2836 if (Fixup.r.r_symbolnum >= cSyms)
2837 return KLDR_ERR_BAD_FIXUP;
2838 pSym = &paSyms[Fixup.r.r_symbolnum];
2839
2840 if (pSym->n_type & MACHO_N_STAB)
2841 return KLDR_ERR_BAD_FIXUP;
2842
2843 switch (pSym->n_type & MACHO_N_TYPE)
2844 {
2845 case MACHO_N_SECT:
2846 {
2847 PKLDRMODMACHOSECT pSymSect;
[61]2848 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]2849 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
2850
2851 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2852 break;
2853 }
2854
2855 case MACHO_N_UNDF:
2856 case MACHO_N_ABS:
2857 SymAddr += pSym->n_value;
2858 break;
2859
2860 case MACHO_N_INDR:
2861 case MACHO_N_PBUD:
[22]2862 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2863 default:
[22]2864 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]2865 }
2866 }
2867 else if (Fixup.r.r_symbolnum != R_ABS)
2868 {
2869 PKLDRMODMACHOSECT pSymSect;
2870 if (Fixup.r.r_symbolnum > pModMachO->cSections)
2871 return KLDR_ERR_BAD_FIXUP;
2872 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
2873
2874 SymAddr -= pSymSect->LinkAddress;
2875 SymAddr += pSymSect->RVA + NewBaseAddress;
2876 }
2877
2878 /* adjust for PC relative */
2879 if (Fixup.r.r_pcrel)
2880 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
2881 }
2882 else
2883 {
2884 PKLDRMODMACHOSECT pSymSect;
2885 KU32 iSymSect;
2886 KLDRADDR Value;
2887
2888 /* sanity */
2889 KLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
2890 if ((KU32)Fixup.s.r_address >= cbSectBits)
2891 return KLDR_ERR_BAD_FIXUP;
2892
2893 /* calc fixup addresses. */
2894 uFix.pv = pbSectBits + Fixup.s.r_address;
2895 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.s.r_address : 0;
2896
2897 /*
2898 * Calc the symbol value.
2899 */
2900 /* The addend is stored in the code. */
2901 switch (Fixup.s.r_length)
2902 {
2903 case 0: SymAddr = *uFixVirgin.pi8; break;
2904 case 1: SymAddr = *uFixVirgin.pi16; break;
2905 case 2: SymAddr = *uFixVirgin.pi32; break;
2906 case 3: SymAddr = *uFixVirgin.pi64; break;
2907 }
2908 if (Fixup.s.r_pcrel)
2909 SymAddr += Fixup.s.r_address;
2910 Value = Fixup.s.r_value;
2911 SymAddr -= Value; /* (-> addend only) */
2912
2913 /* Find the section number from the r_value. */
2914 pSymSect = NULL;
2915 for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++)
2916 {
2917 KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress;
2918 if (off < pModMachO->paSections[iSymSect].cb)
2919 {
2920 pSymSect = &pModMachO->paSections[iSymSect];
2921 break;
2922 }
2923 else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */
2924 pSymSect = &pModMachO->paSections[iSymSect];
2925 }
2926 if (!pSymSect)
2927 return KLDR_ERR_BAD_FIXUP;
2928
2929 /* Calc the symbol address. */
2930 SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2931 if (Fixup.s.r_pcrel)
2932 SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
2933
2934 Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
2935 Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type;
2936 }
2937
2938 /*
2939 * Write back the fixed up value.
2940 */
2941 if (Fixup.r.r_type == GENERIC_RELOC_VANILLA)
2942 {
2943 switch (Fixup.r.r_length)
2944 {
2945 case 0: *uFix.pu8 = (KU8)SymAddr; break;
2946 case 1: *uFix.pu16 = (KU16)SymAddr; break;
2947 case 2: *uFix.pu32 = (KU32)SymAddr; break;
2948 case 3: *uFix.pu64 = (KU64)SymAddr; break;
2949 }
2950 }
2951 else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF)
2952 return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE;
2953 else
2954 return KLDR_ERR_BAD_FIXUP;
2955 }
2956
2957 return 0;
2958}
2959
2960
2961/**
[22]2962 * Applies AMD64 fixups to a section.
2963 *
2964 * @returns 0 on success, non-zero kLdr status code on failure.
2965 * @param pModMachO The Mach-O module interpreter instance.
2966 * @param pbSectBits Pointer to the section bits.
2967 * @param pFixupSect The section being fixed up.
2968 * @param NewBaseAddress The new base image address.
2969 */
2970static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
2971 macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
2972{
2973 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
2974 const KU32 cFixups = pFixupSect->cFixups;
2975 KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
2976 const KU8 *pbSectVirginBits;
2977 KU32 iFixup;
2978 KLDRPU uFixVirgin;
2979 KLDRPU uFix;
2980 KLDRADDR SymAddr;
2981 int rc;
2982
2983 /*
2984 * Find the virgin bits.
2985 */
2986 if (pFixupSect->offFile != -1)
2987 {
2988 rc = kldrModMachOMapVirginBits(pModMachO);
2989 if (rc)
2990 return rc;
2991 pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
2992 }
2993 else
2994 pbSectVirginBits = NULL;
2995
2996 /*
2997 * Iterate the fixups and apply them.
2998 */
2999 for (iFixup = 0; iFixup < cFixups; iFixup++)
3000 {
3001 union
3002 {
3003 macho_relocation_info_t r;
3004 scattered_relocation_info_t s;
3005 } Fixup;
3006 Fixup.r = paFixups[iFixup];
3007
3008 /* AMD64 doesn't use scattered fixups. */
3009 KLDRMODMACHO_CHECK_RETURN(!(Fixup.r.r_address & R_SCATTERED), KLDR_ERR_BAD_FIXUP);
3010
3011 /* sanity */
3012 KLDRMODMACHO_CHECK_RETURN((KU32)Fixup.r.r_address < cbSectBits, KLDR_ERR_BAD_FIXUP);
3013
3014 /* calc fixup addresses. */
3015 uFix.pv = pbSectBits + Fixup.r.r_address;
3016 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
3017
3018 /*
3019 * Calc the symbol value.
3020 */
3021 /* Calc the linked symbol address / addend. */
3022 switch (Fixup.r.r_length)
3023 {
3024 /** @todo Deal with unaligned accesses on non x86 platforms. */
3025 case 2: SymAddr = *uFixVirgin.pi32; break;
3026 case 3: SymAddr = *uFixVirgin.pi64; break;
3027 default:
3028 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
3029 }
3030
3031 /* Add symbol / section address. */
3032 if (Fixup.r.r_extern)
3033 {
3034 const macho_nlist_64_t *pSym;
3035
3036 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP);
3037 pSym = &paSyms[Fixup.r.r_symbolnum];
3038 KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP);
3039
3040 switch (Fixup.r.r_type)
3041 {
3042 /* GOT references just needs to have their symbol verified.
3043 Later, we'll optimize GOT building here using a parallel sym->got array. */
3044 case X86_64_RELOC_GOT_LOAD:
3045 case X86_64_RELOC_GOT:
3046 switch (pSym->n_type & MACHO_N_TYPE)
3047 {
3048 case MACHO_N_SECT:
3049 case MACHO_N_UNDF:
3050 case MACHO_N_ABS:
3051 break;
3052 case MACHO_N_INDR:
3053 case MACHO_N_PBUD:
3054 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
3055 default:
3056 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
3057 }
3058 SymAddr = sizeof(KU64) * Fixup.r.r_symbolnum + pModMachO->GotRVA + NewBaseAddress;
[23]3059 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP);
3060 SymAddr -= 4;
[22]3061 break;
3062
3063 /* Verify the r_pcrel field for signed fixups on the way into the default case. */
3064 case X86_64_RELOC_BRANCH:
3065 case X86_64_RELOC_SIGNED:
3066 case X86_64_RELOC_SIGNED_1:
3067 case X86_64_RELOC_SIGNED_2:
3068 case X86_64_RELOC_SIGNED_4:
3069 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3070 default:
3071 {
3072 /* Adjust with fixup specific addend and vierfy unsigned/r_pcrel. */
3073 switch (Fixup.r.r_type)
3074 {
3075 case X86_64_RELOC_UNSIGNED:
3076 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3077 break;
3078 case X86_64_RELOC_BRANCH:
[23]3079 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP);
3080 SymAddr -= 4;
[22]3081 break;
[23]3082 case X86_64_RELOC_SIGNED:
[67]3083 case X86_64_RELOC_SIGNED_1:
3084 case X86_64_RELOC_SIGNED_2:
3085 case X86_64_RELOC_SIGNED_4:
[68]3086 SymAddr -= 4;
[67]3087 break;
[22]3088 default:
3089 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
3090 }
3091
3092 switch (pSym->n_type & MACHO_N_TYPE)
3093 {
3094 case MACHO_N_SECT:
3095 {
3096 PKLDRMODMACHOSECT pSymSect;
3097 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3098 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3099 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3100 break;
3101 }
3102
3103 case MACHO_N_UNDF:
[23]3104 /* branch to an external symbol may have to take a short detour. */
[61]3105 if ( Fixup.r.r_type == X86_64_RELOC_BRANCH
3106 && SymAddr + Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress
3107 - pSym->n_value
3108 + KU64_C(0x80000000)
[23]3109 >= KU64_C(0xffffff20))
3110 SymAddr += pModMachO->cbJmpStub * Fixup.r.r_symbolnum + pModMachO->JmpStubsRVA + NewBaseAddress;
3111 else
3112 SymAddr += pSym->n_value;
3113 break;
3114
[22]3115 case MACHO_N_ABS:
3116 SymAddr += pSym->n_value;
3117 break;
3118
3119 case MACHO_N_INDR:
3120 case MACHO_N_PBUD:
3121 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
3122 default:
3123 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
3124 }
3125 break;
3126 }
3127
3128 /*
3129 * This is a weird customer, it will always be follows by an UNSIGNED fixup.
3130 */
3131 case X86_64_RELOC_SUBTRACTOR:
3132 {
3133 macho_relocation_info_t Fixup2;
3134
3135 /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */
3136 switch (pSym->n_type & MACHO_N_TYPE)
3137 {
3138 case MACHO_N_SECT:
3139 {
3140 PKLDRMODMACHOSECT pSymSect;
3141 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3142 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3143 SymAddr -= pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3144 break;
3145 }
3146
3147 case MACHO_N_UNDF:
3148 case MACHO_N_ABS:
3149 SymAddr -= pSym->n_value;
3150 break;
3151
3152 case MACHO_N_INDR:
3153 case MACHO_N_PBUD:
3154 KLDRMODMACHO_CHECK_RETURN(0,KLDR_ERR_TODO);
3155 default:
3156 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
3157 }
3158
3159 /* Load the 2nd fixup, check sanity. */
3160 iFixup++;
3161 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, KLDR_ERR_BAD_FIXUP);
3162 Fixup2 = paFixups[iFixup];
3163 KLDRMODMACHO_CHECK_RETURN( Fixup2.r_address == Fixup.r.r_address
3164 && Fixup2.r_length == Fixup.r.r_length
3165 && Fixup2.r_type == X86_64_RELOC_UNSIGNED
3166 && !Fixup2.r_pcrel
3167 && Fixup2.r_symbolnum < cSyms,
3168 KLDR_ERR_BAD_FIXUP);
3169
[68]3170 if (Fixup2.r_extern)
3171 {
3172 KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP);
3173 pSym = &paSyms[Fixup2.r_symbolnum];
3174 KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP);
[22]3175
[68]3176 /* Add it's value to SymAddr. */
3177 switch (pSym->n_type & MACHO_N_TYPE)
[22]3178 {
[68]3179 case MACHO_N_SECT:
3180 {
3181 PKLDRMODMACHOSECT pSymSect;
3182 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3183 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3184 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3185 break;
3186 }
[22]3187
[68]3188 case MACHO_N_UNDF:
3189 case MACHO_N_ABS:
3190 SymAddr += pSym->n_value;
3191 break;
[22]3192
[68]3193 case MACHO_N_INDR:
3194 case MACHO_N_PBUD:
3195 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
3196 default:
3197 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
3198 }
[22]3199 }
[68]3200 else if (Fixup2.r_symbolnum != R_ABS)
3201 {
3202 PKLDRMODMACHOSECT pSymSect;
3203 KLDRADDR TmpAddr;
3204 KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP);
3205 pSymSect = &pModMachO->paSections[Fixup2.r_symbolnum - 1];
3206 SymAddr += pSymSect->RVA + NewBaseAddress;
3207 }
3208 else
3209 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
[22]3210 }
3211 break;
3212 }
3213 }
3214 else
3215 {
[68]3216 /* verify against fixup type and make adjustments */
[22]3217 switch (Fixup.r.r_type)
3218 {
3219 case X86_64_RELOC_UNSIGNED:
[68]3220 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3221 break;
3222 case X86_64_RELOC_BRANCH:
3223 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3224 SymAddr += 4; /* dunno what the assmbler/linker really is doing here... */
3225 break;
[22]3226 case X86_64_RELOC_SIGNED:
3227 case X86_64_RELOC_SIGNED_1:
3228 case X86_64_RELOC_SIGNED_2:
3229 case X86_64_RELOC_SIGNED_4:
[68]3230 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
[22]3231 break;
[68]3232 /*case X86_64_RELOC_GOT_LOAD:*/
3233 /*case X86_64_RELOC_GOT: */
3234 /*case X86_64_RELOC_SUBTRACTOR: - must be r_extern=1 says as. */
[22]3235 default:
3236 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
3237 }
3238 if (Fixup.r.r_symbolnum != R_ABS)
3239 {
3240 PKLDRMODMACHOSECT pSymSect;
3241 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP);
3242 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
3243
3244 SymAddr -= pSymSect->LinkAddress;
3245 SymAddr += pSymSect->RVA + NewBaseAddress;
[68]3246 if (Fixup.r.r_pcrel)
3247 SymAddr += Fixup.r.r_address;
[22]3248 }
3249 }
3250
3251 /* adjust for PC relative */
3252 if (Fixup.r.r_pcrel)
3253 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
3254
3255 /*
3256 * Write back the fixed up value.
3257 */
3258 switch (Fixup.r.r_length)
3259 {
3260 case 3:
3261 *uFix.pu64 = (KU64)SymAddr;
3262 break;
3263 case 2:
3264 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel || Fixup.r.r_type == X86_64_RELOC_SUBTRACTOR, KLDR_ERR_BAD_FIXUP);
3265 KLDRMODMACHO_CHECK_RETURN((KI32)SymAddr == (KI64)SymAddr, KLDR_ERR_ADDRESS_OVERFLOW);
3266 *uFix.pu32 = (KU32)SymAddr;
3267 break;
3268 default:
3269 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
3270 }
3271 }
3272
3273 return 0;
3274}
3275
3276
3277/**
[2]3278 * Loads the symbol table for a MH_OBJECT file.
3279 *
3280 * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols.
3281 *
3282 * @returns 0 on success, non-zero kLdr status code on failure.
3283 * @param pModMachO The Mach-O module interpreter instance.
3284 */
3285static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO)
3286{
3287 int rc = 0;
3288
3289 if ( !pModMachO->pvaSymbols
3290 && pModMachO->cSymbols)
3291 {
3292 KSIZE cbSyms;
3293 KSIZE cbSym;
3294 void *pvSyms;
3295 void *pvStrings;
3296
3297 /* sanity */
[22]3298 KLDRMODMACHO_CHECK_RETURN( pModMachO->offSymbols
3299 && (!pModMachO->cchStrings || pModMachO->offStrings),
3300 KLDR_ERR_MACHO_BAD_OBJECT_FILE);
[2]3301
3302 /* allocate */
3303 cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
3304 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
3305 ? sizeof(macho_nlist_32_t)
3306 : sizeof(macho_nlist_64_t);
3307 cbSyms = pModMachO->cSymbols * cbSym;
[22]3308 KLDRMODMACHO_CHECK_RETURN(cbSyms / cbSym == pModMachO->cSymbols, KLDR_ERR_SIZE_OVERFLOW);
[2]3309 rc = KERR_NO_MEMORY;
3310 pvSyms = kHlpAlloc(cbSyms);
3311 if (pvSyms)
3312 {
3313 if (pModMachO->cchStrings)
3314 pvStrings = kHlpAlloc(pModMachO->cchStrings);
3315 else
3316 pvStrings = kHlpAllocZ(4);
3317 if (pvStrings)
3318 {
3319 /* read */
3320 rc = kRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols);
3321 if (!rc && pModMachO->cchStrings)
3322 rc = kRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings);
3323 if (!rc)
3324 {
3325 pModMachO->pvaSymbols = pvSyms;
3326 pModMachO->pchStrings = (char *)pvStrings;
3327
3328 /* perform endian conversion? */
3329 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
3330 {
3331 KU32 cLeft = pModMachO->cSymbols;
3332 macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms;
3333 while (cLeft-- > 0)
3334 {
3335 pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
3336 pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
3337 pSym->n_value = K_E2E_U32(pSym->n_value);
3338 pSym++;
3339 }
3340 }
3341 else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
3342 {
3343 KU32 cLeft = pModMachO->cSymbols;
3344 macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms;
3345 while (cLeft-- > 0)
3346 {
3347 pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
3348 pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
3349 pSym->n_value = K_E2E_U64(pSym->n_value);
3350 pSym++;
3351 }
3352 }
3353
3354 return 0;
3355 }
3356 kHlpFree(pvStrings);
3357 }
3358 kHlpFree(pvSyms);
3359 }
3360 }
3361 else
[66]3362 KLDRMODMACHO_ASSERT(pModMachO->pchStrings || pModMachO->Hdr.filetype == MH_DSYM);
[2]3363
3364 return rc;
3365}
3366
3367
3368/**
3369 * Loads the fixups at the given address and performs endian
3370 * conversion if necessary.
3371 *
3372 * @returns 0 on success, non-zero kLdr status code on failure.
3373 * @param pModMachO The Mach-O module interpreter instance.
3374 * @param offFixups The file offset of the fixups.
3375 * @param cFixups The number of fixups to load.
3376 * @param ppaFixups Where to put the pointer to the allocated fixup array.
3377 */
3378static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups)
3379{
3380 macho_relocation_info_t *paFixups;
3381 KSIZE cbFixups;
3382 int rc;
3383
3384 /* allocate the memory. */
3385 cbFixups = cFixups * sizeof(*paFixups);
[22]3386 KLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, KLDR_ERR_SIZE_OVERFLOW);
[2]3387 paFixups = (macho_relocation_info_t *)kHlpAlloc(cbFixups);
3388 if (!paFixups)
3389 return KERR_NO_MEMORY;
3390
3391 /* read the fixups. */
3392 rc = kRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups);
3393 if (!rc)
3394 {
3395 *ppaFixups = paFixups;
3396
3397 /* do endian conversion if necessary. */
3398 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
3399 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
3400 {
3401 KU32 iFixup;
3402 for (iFixup = 0; iFixup < cFixups; iFixup++)
3403 {
3404 KU32 *pu32 = (KU32 *)&paFixups[iFixup];
3405 pu32[0] = K_E2E_U32(pu32[0]);
3406 pu32[1] = K_E2E_U32(pu32[1]);
3407 }
3408 }
3409 }
3410 else
3411 kHlpFree(paFixups);
3412 return rc;
3413}
3414
3415
3416/**
3417 * Maps the virgin file bits into memory if not already done.
3418 *
3419 * @returns 0 on success, non-zero kLdr status code on failure.
3420 * @param pModMachO The Mach-O module interpreter instance.
3421 */
3422static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO)
3423{
3424 int rc = 0;
3425 if (!pModMachO->pvBits)
3426 rc = kRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits);
3427 return rc;
3428}
3429
3430
3431/** @copydoc kLdrModCallInit */
3432static int kldrModMachOCallInit(PKLDRMOD pMod, KUPTR uHandle)
3433{
3434 /* later */
3435 return 0;
3436}
3437
3438
3439/** @copydoc kLdrModCallTerm */
3440static int kldrModMachOCallTerm(PKLDRMOD pMod, KUPTR uHandle)
3441{
3442 /* later */
3443 return 0;
3444}
3445
3446
3447/** @copydoc kLdrModCallThread */
3448static int kldrModMachOCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
3449{
3450 /* Relevant for Mach-O? */
3451 return 0;
3452}
3453
3454
3455/** @copydoc kLdrModSize */
3456static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
3457{
3458 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3459 return pModMachO->cbImage;
3460}
3461
3462
3463/** @copydoc kLdrModGetBits */
3464static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
3465{
3466 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3467 KU32 i;
3468 int rc;
3469
[43]3470 if (!pModMachO->fCanLoad)
3471 return KLDR_ERR_TODO;
3472
[2]3473 /*
3474 * Zero the entire buffer first to simplify things.
3475 */
3476 kHlpMemSet(pvBits, 0, (KSIZE)pModMachO->cbImage);
3477
3478 /*
3479 * When possible use the segment table to load the data.
3480 */
[62]3481 for (i = 0; i < pMod->cSegments; i++)
[2]3482 {
[62]3483 /* skip it? */
3484 if ( pMod->aSegments[i].cbFile == -1
3485 || pMod->aSegments[i].offFile == -1
3486 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
3487 || !pMod->aSegments[i].Alignment)
3488 continue;
3489 rc = kRdrRead(pMod->pRdr,
3490 (KU8 *)pvBits + pMod->aSegments[i].RVA,
3491 pMod->aSegments[i].cbFile,
3492 pMod->aSegments[i].offFile);
3493 if (rc)
3494 return rc;
[2]3495 }
3496
3497 /*
3498 * Perform relocations.
3499 */
[23]3500 return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
3501}
[22]3502
[23]3503
3504/** @copydoc kLdrModRelocateBits */
3505static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
3506 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
3507{
3508 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3509 int rc;
3510
[22]3511 /*
[23]3512 * Call workers to do the jobs.
3513 */
3514 if (pModMachO->Hdr.filetype == MH_OBJECT)
3515 {
[47]3516 rc = kldrModMachOObjDoImports(pModMachO, NewBaseAddress, pfnGetImport, pvUser);
[23]3517 if (!rc)
3518 rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress);
3519
3520 }
3521 else
3522 rc = KLDR_ERR_TODO;
3523 /*{
3524 rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
3525 if (!rc)
3526 rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
3527 }*/
3528
3529 /*
[22]3530 * Construct the global offset table if necessary, it's always the last
3531 * segment when present.
3532 */
[23]3533 if (!rc && pModMachO->fMakeGot)
3534 rc = kldrModMachOMakeGOT(pModMachO, pvBits, NewBaseAddress);
3535
[22]3536 return rc;
[2]3537}
3538
3539
[22]3540/**
3541 * Builds the GOT.
3542 *
3543 * Assumes the symbol table has all external symbols resolved correctly and that
3544 * the bits has been cleared up front.
3545 */
3546static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress)
3547{
3548 KU32 iSym = pModMachO->cSymbols;
3549 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
3550 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
3551 {
3552 macho_nlist_32_t const *paSyms = (macho_nlist_32_t const *)pModMachO->pvaSymbols;
3553 KU32 *paGOT = (KU32 *)((KU8 *)pvBits + pModMachO->GotRVA);
3554 while (iSym-- > 0)
3555 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
3556 {
3557 case MACHO_N_SECT:
3558 {
3559 PKLDRMODMACHOSECT pSymSect;
3560 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3561 pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
3562 paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3563 break;
3564 }
3565
3566 case MACHO_N_UNDF:
3567 case MACHO_N_ABS:
3568 paGOT[iSym] = paSyms[iSym].n_value;
3569 break;
3570 }
3571 }
3572 else
3573 {
3574 macho_nlist_64_t const *paSyms = (macho_nlist_64_t const *)pModMachO->pvaSymbols;
3575 KU64 *paGOT = (KU64 *)((KU8 *)pvBits + pModMachO->GotRVA);
3576 while (iSym-- > 0)
[23]3577 {
[22]3578 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
3579 {
3580 case MACHO_N_SECT:
3581 {
3582 PKLDRMODMACHOSECT pSymSect;
3583 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3584 pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
3585 paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3586 break;
3587 }
3588
3589 case MACHO_N_UNDF:
3590 case MACHO_N_ABS:
3591 paGOT[iSym] = paSyms[iSym].n_value;
3592 break;
3593 }
[23]3594 }
[22]3595
[23]3596 if (pModMachO->JmpStubsRVA != NIL_KLDRADDR)
3597 {
[42]3598 iSym = pModMachO->cSymbols;
[23]3599 switch (pModMachO->Hdr.cputype)
3600 {
3601 /*
3602 * AMD64 is simple since the GOT and the indirect jmps are parallel
3603 * arrays with entries of the same size. The relative offset will
3604 * be the the same for each entry, kind of nice. :-)
3605 */
3606 case CPU_TYPE_X86_64:
3607 {
3608 KU64 *paJmps = (KU64 *)((KU8 *)pvBits + pModMachO->JmpStubsRVA);
3609 KI32 off;
3610 KU64 u64Tmpl;
3611 union
3612 {
3613 KU8 ab[8];
3614 KU64 u64;
3615 } Tmpl;
[22]3616
[23]3617 /* create the template. */
3618 off = pModMachO->GotRVA - (pModMachO->JmpStubsRVA + 6);
3619 Tmpl.ab[0] = 0xff; /* jmp [GOT-entry wrt RIP] */
3620 Tmpl.ab[1] = 0x25;
3621 Tmpl.ab[2] = off & 0xff;
3622 Tmpl.ab[3] = (off >> 8) & 0xff;
3623 Tmpl.ab[4] = (off >> 16) & 0xff;
3624 Tmpl.ab[5] = (off >> 24) & 0xff;
3625 Tmpl.ab[6] = 0xcc;
3626 Tmpl.ab[7] = 0xcc;
3627 u64Tmpl = Tmpl.u64;
[2]3628
[23]3629 /* copy the template to every jmp table entry. */
3630 while (iSym-- > 0)
3631 paJmps[iSym] = u64Tmpl;
3632 break;
3633 }
[2]3634
[23]3635 default:
3636 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
3637 }
3638 }
[2]3639 }
[23]3640 return 0;
[2]3641}
3642
3643
3644/**
3645 * The Mach-O module interpreter method table.
3646 */
3647KLDRMODOPS g_kLdrModMachOOps =
3648{
3649 "Mach-O",
3650 NULL,
3651 kldrModMachOCreate,
3652 kldrModMachODestroy,
3653 kldrModMachOQuerySymbol,
3654 kldrModMachOEnumSymbols,
3655 kldrModMachOGetImport,
3656 kldrModMachONumberOfImports,
3657 NULL /* can execute one is optional */,
3658 kldrModMachOGetStackInfo,
3659 kldrModMachOQueryMainEntrypoint,
[54]3660 kldrModMachOQueryImageUuid,
[2]3661 NULL,
3662 NULL,
3663 kldrModMachOEnumDbgInfo,
3664 kldrModMachOHasDbgInfo,
3665 kldrModMachOMap,
3666 kldrModMachOUnmap,
3667 kldrModMachOAllocTLS,
3668 kldrModMachOFreeTLS,
3669 kldrModMachOReload,
3670 kldrModMachOFixupMapping,
3671 kldrModMachOCallInit,
3672 kldrModMachOCallTerm,
3673 kldrModMachOCallThread,
3674 kldrModMachOSize,
3675 kldrModMachOGetBits,
3676 kldrModMachORelocateBits,
3677 NULL, /** @todo mostly done */
3678 42 /* the end */
3679};
3680
Note: See TracBrowser for help on using the repository browser.