source: trunk/kLdr/kLdrModMachO.c@ 51

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

mach_kernel doesn't have segments sorted by link address, but rather file offset, so counter that by sorting the segment array. Fixed RVA calc.

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