source: trunk/kLdr/kLdrModMachO.c@ 52

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

Added KLDRMOD_OPEN_FLAGS_FOR_INFO and fixed more mach-o issues.

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