source: trunk/kLdr/kLdrModMachO.c@ 42

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

bug fix

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