source: trunk/kLdr/kLdrModMachO.c@ 62

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

Mach-O: More MH_OBJECT fixes.

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