source: trunk/kLdr/kLdrModMachO.c@ 41

Last change on this file since 41 was 41, checked in by bird, 14 years ago

Debug info enumration adjustments. Working on MH_DSYM support.

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