source: trunk/kLdr/kLdrModMachO.c@ 61

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

Mach-O: Accept to open MH_BUNDLE file (but not load), symbol enum fixes and hacks.

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