source: trunk/kLdr/kLdrModMachO.c@ 59

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

Mach-O: Object files only have one LC_SEGMENTxx, one kLdr segment for each Mach-O section (sans debug).

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