source: trunk/kLdr/kLdrModMachO.c@ 60

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

Mach-O: Set the link address to the address of the first segment we define, simpler that way.

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