VirtualBox

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

Last change on this file since 96 was 91, checked in by bird, 8 years ago

kLdrModMachO.c: Fixed S_ATTR_DEBUG check (KLDR_ERR_MACHO_MIXED_DEBUG_SECTION_FLAGS).

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