source: trunk/kLdr/kLdrModMachO.c@ 63

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

kLdrModMachO.c: Workaround for misaligned TEXT.unwind_info found once in VirtualBox.dylib (Xcode 3.2.6, I think). DYLIB debug info loading adjustments.

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