source: trunk/kLdr/kLdrModMachO.c@ 58

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

Mach-O: Carve segments from the mach-o segments instead of the sections inside them. This works better for non-object files.

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