source: trunk/kLdr/kLdrModMachO.c@ 47

Last change on this file since 47 was 47, checked in by bird, 13 years ago

kLdrModMachO.c: Symbols with an address at the very end of the section/segment is fine. Implemented linker s the standard linker generated symbols.

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