source: trunk/kLdr/kLdrModMachO.c@ 76

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

kLdrModMachO.c: Left a variable behind from debug effort.

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