source: trunk/kLdr/kLdrModMachO.c@ 25

Last change on this file since 25 was 25, checked in by bird, 17 years ago

A blind shot at FAT Mach-O images.

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