source: trunk/kLdr/kLdrModMachO.c@ 43

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

kLdrModMachO.cpp: detect debug info and be more flexible wrt unimplemented sections.

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