source: trunk/kLdr/kLdrModMachO.c@ 48

Last change on this file since 48 was 48, checked in by bird, 13 years ago

mach-o: Added new load commands from 10.6 and 10.7. Made the loader ignore version requirements and code signatures.

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