source: trunk/kLdr/kLdrModMachO.c@ 55

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

Mach-O: Accept MH_KEXT_BUNDLE (untested for loading purposes).

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