source: trunk/kLdr/kLdrModMachO.c@ 64

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

kLdrModMachO.c: Don't load LINKEDIT.

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