VirtualBox

source: kStuff/trunk/kLdr/kLdrModMachO.c@ 65

Last change on this file since 65 was 65, checked in by bird, 11 years ago

CTF skipping fixes.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette