VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp@ 74636

Last change on this file since 74636 was 74636, checked in by vboxsync, 6 years ago

IPRT: Adding virgin copies of kLdrModMachO.c and kLdrModLX.c from kStuff revision 113. bugref:9232

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