source: trunk/kLdr/kLdrModMachO.c@ 29

Last change on this file since 29 was 29, checked in by bird, 16 years ago

Finally got around execute the switch to the MIT license.

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