source: trunk/kLdr/kLdrModMachO.c@ 2964

Last change on this file since 2964 was 2964, checked in by bird, 19 years ago

literals and ignore weaks.

File size: 85.9 KB
RevLine 
[2952]1/* $Id: $ */
2/** @file
3 *
4 * kLdr - The Module Interpreter for the MACH-O format.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include "kLdrHlp.h"
33#include "kLdrInternal.h"
34#include "kLdrModMachO.h"
35
36
37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** @def KLDRMODMACHO_STRICT
41 * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */
42#define KLDRMODMACHO_STRICT 1
43
44/** @def KLDRMODMACHO_ASSERT
45 * Assert that an expression is true when KLDR_STRICT is defined.
46 */
47#ifdef KLDRMODMACHO_STRICT
48# define KLDRMODMACHO_ASSERT(expr) kldrHlpAssert(expr)
49#else
50# define KLDRMODMACHO_ASSERT(expr) do {} while (0)
51#endif
52
[2961]53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57/**
58 * Mach-O section details.
[2952]59 */
[2961]60typedef struct KLDRMODMACHOSECT
61{
62 /** The size of the section (in bytes). */
63 KLDRSIZE cb;
64 /** The RVA of this section. */
65 KLDRADDR RVA;
[2963]66 /** The file offset of this section.
[2961]67 * This is -1 if the section doesn't have a file backing. */
68 off_t offFile;
69 /** The number of fixups. */
70 uint32_t cFixups;
71 /** The array of fixups. (lazy loaded) */
72 macho_relocation_info_t *paFixups;
[2963]73 /** The file offset of the fixups for this section.
[2961]74 * This is -1 if the section doesn't have any fixups. */
75 off_t offFixups;
[2962]76 /** Mach-O section flags. */
77 uint32_t fFlags;
78 /** kLdr segment index. */
79 uint32_t iSegment;
[2961]80 /** Pointer to the Mach-O section structure. */
[2963]81 void *pvMachoSection;
[2961]82} KLDRMODMACHOSECT, *PKLDRMODMACHOSECT;
[2952]83
[2961]84/**
85 * Extra per-segment info.
[2963]86 *
[2961]87 * This is corresponds to a kLdr segment, not a Mach-O segment!
[2952]88 */
[2961]89typedef struct KLDRMODMACHOSEG
90{
91 /** The number of sections in the segment. */
92 uint32_t cSections;
[2963]93 /** Pointer to the sections belonging to this segment.
94 * The array resides in the big memory chunk allocated for
[2961]95 * the module handle, so it doesn't need freeing. */
96 PKLDRMODMACHOSECT paSections;
[2952]97
[2961]98} KLDRMODMACHOSEG, *PKLDRMODMACHOSEG;
[2952]99
100/**
[2954]101 * Instance data for the Mach-O MH_OBJECT module interpreter.
[2952]102 * @todo interpret the other MH_* formats.
103 */
104typedef struct KLDRMODMACHO
105{
106 /** Pointer to the module. (Follows the section table.) */
107 PKLDRMOD pMod;
[2962]108 /** Pointer to the RDR file mapping of the raw file bits. NULL if not mapped. */
[2952]109 const void *pvBits;
110 /** Pointer to the user mapping. */
[2962]111 void *pvMapping;
[2952]112
113 /** The link address. */
114 KLDRADDR LinkAddress;
[2955]115 /** The size of the mapped image. */
116 KLDRADDR cbImage;
[2956]117 /** When set the sections in the load command segments must be used when
118 * mapping or loading the image. */
119 int fMapUsingLoadCommandSections;
[2952]120
121 /** Pointer to the load commands. (endian converted) */
122 uint8_t *pbLoadCommands;
123 /** The Mach-O header. (endian converted)
124 * @remark The reserved field is only valid for real 64-bit headers. */
125 mach_header_64_t Hdr;
126
127 /** The offset of the symbol table. */
128 off_t offSymbols;
129 /** The number of symbols. */
130 uint32_t cSymbols;
131 /** The pointer to the loaded symbol table. */
[2961]132 void *pvaSymbols;
[2952]133 /** The offset of the string table. */
134 off_t offStrings;
135 /** The size of the of the string table. */
[2962]136 uint32_t cchStrings;
[2952]137 /** Pointer to the loaded string table. */
[2961]138 char *pchStrings;
[2962]139
140 /** The number of sections. */
141 uint32_t cSections;
142 /** Pointer to the section array running in parallel to the Mach-O one. */
143 PKLDRMODMACHOSECT paSections;
144
[2961]145 /** Array of segments parallel to the one in KLDRMOD. */
146 KLDRMODMACHOSEG aSegments[1];
[2952]147} KLDRMODMACHO, *PKLDRMODMACHO;
148
149
[2961]150
[2952]151/*******************************************************************************
152* Internal Functions *
153*******************************************************************************/
154#if 0
155static int32_t kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits);
156#endif
[2956]157static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
158 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
[2952]159
160static int kldrModMachODoCreate(PKLDRRDR pRdr, PKLDRMODMACHO *ppMod);
[2954]161static int kldrModMachOPreParseLoadCommands(uint8_t *pbLoadCommands, const mach_header_32_t *pHdr, PKLDRRDR pRdr,
[2961]162 uint32_t *pcSegments, uint32_t *pcSections, uint32_t *pcbStringPool);
[2952]163static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, uint32_t cbStringPool);
[2962]164static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress);
165
[2961]166/*static int kldrModMachOLoadLoadCommands(PKLDRMODMACHO pModMachO);*/
[2956]167static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO);
[2961]168static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, off_t offFixups, uint32_t cFixups, void **pvFixups);
[2963]169static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO);
[2952]170
[2962]171static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, uint32_t cSyms, const char *pchStrings,
[2963]172 uint32_t cchStrings, KLDRADDR BaseAddress, uint32_t iSymbol, const char *pchSymbol,
[2962]173 size_t cchSymbol, PKLDRADDR puValue, uint32_t *pfKind);
[2963]174static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, uint32_t cSyms,
[2962]175 const char *pchStrings, uint32_t cchStrings, KLDRADDR BaseAddress,
176 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
[2961]177static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
178static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress);
[2963]179static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, uint8_t *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
180 macho_nlist_32_t *paSyms, uint32_t cSyms, KLDRADDR NewBaseAddress);
[2952]181
[2961]182/*static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
183static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);*/
184
185
[2952]186/**
187 * Create a loader module instance interpreting the executable image found
188 * in the specified file provider instance.
189 *
190 * @returns 0 on success and *ppMod pointing to a module instance.
191 * On failure, a non-zero OS specific error code is returned.
192 * @param pOps Pointer to the registered method table.
193 * @param pRdr The file provider instance to use.
194 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
195 * @param ppMod Where to store the module instance pointer.
196 */
197static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
198{
199 PKLDRMODMACHO pModMachO;
200 int rc;
201
202 /*
203 * Create the instance data and do a minimal header validation.
204 */
205 rc = kldrModMachODoCreate(pRdr, &pModMachO);
206 if (!rc)
207 {
208 pModMachO->pMod->pOps = pOps;
209 pModMachO->pMod->u32Magic = KLDRMOD_MAGIC;
210 *ppMod = pModMachO->pMod;
211 return 0;
212 }
213 if (pModMachO)
214 {
215 kldrHlpFree(pModMachO->pbLoadCommands);
216 kldrHlpFree(pModMachO);
217 }
218 return rc;
219}
220
221
222/**
223 * Separate function for reading creating the PE module instance to
224 * simplify cleanup on failure.
225 */
226static int kldrModMachODoCreate(PKLDRRDR pRdr, PKLDRMODMACHO *ppModMachO)
227{
228 union
229 {
230 mach_header_32_t Hdr32;
231 mach_header_64_t Hdr64;
232 } s;
233 PKLDRMODMACHO pModMachO;
234 PKLDRMOD pMod;
235 uint8_t *pbLoadCommands;
236 uint32_t cSegments;
[2961]237 uint32_t cSections;
[2952]238 uint32_t cbStringPool;
239 size_t cchFilename;
240 size_t cb;
241 int rc;
242 *ppModMachO = NULL;
243
244 /*
245 * Read the Mach-O header.
246 */
247 rc = kLdrRdrRead(pRdr, &s, sizeof(s), 0);
248 if (rc)
249 return rc;
250 if (s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
251 {
252 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
253 || s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE)
254 return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED;
255 if (s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE)
256 return KLDR_ERR_MACHO_64BIT_NOT_SUPPORTED;
257 return KLDR_ERR_UNKNOWN_FORMAT;
258 }
259
260 /* sanity checks. */
261 if ( s.Hdr32.sizeofcmds > kLdrRdrSize(pRdr) - sizeof(mach_header_32_t)
262 || s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds
263 || (s.Hdr32.flags & ~MH_VALID_FLAGS))
264 return KLDR_ERR_MACHO_BAD_HEADER;
265 switch (s.Hdr32.cputype)
266 {
267 case CPU_TYPE_X86:
268 case CPU_TYPE_X86_64:
269 break;
270 default:
271 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
272 }
273 if (s.Hdr32.filetype != MH_OBJECT)
274 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
275
276 /*
277 * Read and pre-parse the load commands to figure out how many segments we'll be needing.
278 */
279 pbLoadCommands = kldrHlpAlloc(s.Hdr32.sizeofcmds);
280 if (!pbLoadCommands)
281 return KLDR_ERR_NO_MEMORY;
282 rc = kLdrRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds,
283 s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
284 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
285 ? sizeof(mach_header_32_t) : sizeof(mach_header_64_t));
286 if (!rc)
[2961]287 rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, &cSegments, &cSections, &cbStringPool);
[2952]288 if (rc)
289 {
290 kldrHlpFree(pbLoadCommands);
291 return rc;
292 }
293
294
295 /*
296 * Calc the instance size, allocate and initialize it.
297 */
298 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
[2963]299 cb = KLDR_ALIGN_Z( KLDR_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
[2961]300 + sizeof(KLDRMODMACHOSECT) * cSections, 16)
[2952]301 + KLDR_OFFSETOF(KLDRMOD, aSegments[cSegments])
302 + cchFilename + 1
303 + cbStringPool;
304 pModMachO = (PKLDRMODMACHO)kldrHlpAlloc(cb);
305 if (!pModMachO)
306 return KLDR_ERR_NO_MEMORY;
307 *ppModMachO = pModMachO;
308 pModMachO->pbLoadCommands = pbLoadCommands;
309
310 /* KLDRMOD */
[2961]311 pMod = (PKLDRMOD)((uint8_t *)pModMachO + KLDR_ALIGN_Z( KLDR_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
312 + sizeof(KLDRMODMACHOSECT) * cSections, 16));
[2952]313 pMod->pvData = pModMachO;
314 pMod->pRdr = pRdr;
315 pMod->pOps = NULL; /* set upon success. */
316 pMod->cSegments = cSegments;
317 pMod->cchFilename = cchFilename;
318 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
319 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
320 pMod->pszName = kldrHlpGetFilename(pMod->pszFilename);
321 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
322 switch (s.Hdr32.cputype)
323 {
324 case CPU_TYPE_X86:
325 pMod->enmArch = KLDRARCH_X86_32;
326 pMod->enmEndian = KLDRENDIAN_LITTLE;
327 switch (s.Hdr32.cpusubtype)
328 {
329 case CPU_SUBTYPE_I386_ALL: pMod->enmCpu = KLDRCPU_X86_32_BLEND; break;
330 /*case CPU_SUBTYPE_386: ^^ pMod->enmCpu = KLDRCPU_I386; break;*/
331 case CPU_SUBTYPE_486: pMod->enmCpu = KLDRCPU_I486; break;
332 case CPU_SUBTYPE_486SX: pMod->enmCpu = KLDRCPU_I486SX; break;
333 /*case CPU_SUBTYPE_586: vv */
334 case CPU_SUBTYPE_PENT: pMod->enmCpu = KLDRCPU_I586; break;
335 case CPU_SUBTYPE_PENTPRO:
336 case CPU_SUBTYPE_PENTII_M3:
337 case CPU_SUBTYPE_PENTII_M5:
338 case CPU_SUBTYPE_CELERON:
339 case CPU_SUBTYPE_CELERON_MOBILE:
340 case CPU_SUBTYPE_PENTIUM_3:
341 case CPU_SUBTYPE_PENTIUM_3_M:
342 case CPU_SUBTYPE_PENTIUM_3_XEON: pMod->enmCpu = KLDRCPU_I686; break;
343 case CPU_SUBTYPE_PENTIUM_M:
344 case CPU_SUBTYPE_PENTIUM_4:
345 case CPU_SUBTYPE_PENTIUM_4_M:
346 case CPU_SUBTYPE_XEON:
347 case CPU_SUBTYPE_XEON_MP: pMod->enmCpu = KLDRCPU_P4; break;
348 break;
349 default:
350 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
351 }
352 break;
353
354 case CPU_TYPE_X86_64:
355 pMod->enmArch = KLDRARCH_AMD64;
356 pMod->enmEndian = KLDRENDIAN_LITTLE;
357 switch (s.Hdr32.cpusubtype)
358 {
359 case CPU_SUBTYPE_X86_64_ALL: pMod->enmCpu = KLDRCPU_AMD64_BLEND; break;
360 default:
361 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
362 }
363 break;
364
365 default:
366 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
367 }
368
369 pMod->enmFmt = KLDRFMT_MACHO;
370 switch (s.Hdr32.filetype)
371 {
372 case MH_OBJECT:
373 pMod->enmType = KLDRTYPE_OBJECT;
374 break;
375 default:
376 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
377 }
378 pMod->u32Magic = 0; /* set upon success. */
379
380 /* KLDRMODMACHO */
381 pModMachO->pMod = pMod;
382 pModMachO->pvBits = NULL;
383 pModMachO->pvMapping = NULL;
384 pModMachO->Hdr = s.Hdr64;
385 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
386 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE)
387 pModMachO->Hdr.reserved = 0;
388 pModMachO->LinkAddress = 0;
[2955]389 pModMachO->cbImage = 0;
[2956]390 pModMachO->fMapUsingLoadCommandSections = 0;
[2952]391 pModMachO->offSymbols = 0;
392 pModMachO->cSymbols = 0;
[2961]393 pModMachO->pvaSymbols = NULL;
[2952]394 pModMachO->offStrings = 0;
[2962]395 pModMachO->cchStrings = 0;
[2961]396 pModMachO->pchStrings = NULL;
[2962]397 pModMachO->cSections = cSections;
398 pModMachO->paSections = (PKLDRMODMACHOSECT)&pModMachO->aSegments[pModMachO->pMod->cSegments];
[2952]399
400 /*
401 * Setup the KLDRMOD segment array.
402 */
403 rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool);
404 if (rc)
405 return rc;
406
407 /*
408 * We're done.
409 */
410 return 0;
411}
412
413
414/**
415 * Converts, validates and preparses the load commands before we carve
416 * out the module instance.
417 *
418 * The conversion that's preformed is format endian to host endian.
[2961]419 * The preparsing has to do with segment counting, section counting and string pool sizing.
[2952]420 *
421 * @returns 0 on success.
422 * @returns KLDR_ERR_MACHO_* on failure.
423 * @param pbLoadCommands The load commands to parse.
424 * @param pHdr The header.
[2954]425 * @param pRdr The file reader.
[2952]426 * @param pcSegments Where to store the segment count.
[2961]427 * @param pcSegments Where to store the section count.
[2952]428 * @param pcbStringPool Where to store the string pool size.
429 */
[2954]430static int kldrModMachOPreParseLoadCommands(uint8_t *pbLoadCommands, const mach_header_32_t *pHdr, PKLDRRDR pRdr,
[2961]431 uint32_t *pcSegments, uint32_t *pcSections, uint32_t *pcbStringPool)
[2952]432{
[2954]433 union
434 {
435 uint8_t *pb;
436 load_command_t *pLoadCmd;
437 segment_command_32_t *pSeg32;
438 segment_command_64_t *pSeg64;
439 thread_command_t *pThread;
440 symtab_command_t *pSymTab;
441 uuid_command_t *pUuid;
442 } u;
443 const uint64_t cbFile = kLdrRdrSize(pRdr);
444 uint32_t cSegments = 0;
[2961]445 uint32_t cSections = 0;
[2954]446 uint32_t cbStringPool = 0;
447 uint32_t cLeft = pHdr->ncmds;
448 uint32_t cbLeft = pHdr->sizeofcmds;
449 uint8_t *pb = pbLoadCommands;
[2956]450 int cSegmentCommands = 0;
451 int cSymbolTabs = 0;
452 int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
453 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
[2954]454
[2952]455 *pcSegments = 0;
[2961]456 *pcSections = 0;
[2952]457 *pcbStringPool = 0;
[2954]458
459 while (cLeft-- > 0)
460 {
461 u.pb = pb;
462
463 /*
464 * Convert and validate command header.
465 */
466 if (cbLeft < sizeof(load_command_t))
467 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
468 if (fConvertEndian)
469 {
470 u.pLoadCmd->cmd = KLDRHLP_E2E_U32(u.pLoadCmd->cmd);
471 u.pLoadCmd->cmdsize = KLDRHLP_E2E_U32(u.pLoadCmd->cmdsize);
472 }
473 if (u.pLoadCmd->cmdsize > cbLeft)
474 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
475 cbLeft -= u.pLoadCmd->cmdsize;
476 pb += u.pLoadCmd->cmdsize;
477
478 /*
479 * Convert endian if needed, parse and validate the command.
480 */
481 switch (u.pLoadCmd->cmd)
482 {
483 case LC_SEGMENT_32:
484 {
485 section_32_t *pSect;
486 section_32_t *pFirstSect;
487 uint32_t cSectionsLeft;
488
489 /* convert and verify*/
490 if (u.pLoadCmd->cmdsize < sizeof(segment_command_32_t))
491 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
[2955]492 if ( pHdr->magic != IMAGE_MACHO32_SIGNATURE_OE
493 && pHdr->magic != IMAGE_MACHO32_SIGNATURE)
494 return KLDR_ERR_MACHO_BIT_MIX;
[2954]495 if (fConvertEndian)
496 {
497 u.pSeg32->vmaddr = KLDRHLP_E2E_U32(u.pSeg32->vmaddr);
498 u.pSeg32->vmsize = KLDRHLP_E2E_U32(u.pSeg32->vmsize);
499 u.pSeg32->fileoff = KLDRHLP_E2E_U32(u.pSeg32->fileoff);
500 u.pSeg32->filesize = KLDRHLP_E2E_U32(u.pSeg32->filesize);
501 u.pSeg32->maxprot = KLDRHLP_E2E_U32(u.pSeg32->maxprot);
502 u.pSeg32->initprot = KLDRHLP_E2E_U32(u.pSeg32->initprot);
503 u.pSeg32->nsects = KLDRHLP_E2E_U32(u.pSeg32->nsects);
504 u.pSeg32->flags = KLDRHLP_E2E_U32(u.pSeg32->flags);
505 }
506
507 if ( u.pSeg32->filesize
508 && ( u.pSeg32->fileoff > cbFile
509 || (uint64_t)u.pSeg32->fileoff + u.pSeg32->filesize > cbFile))
510 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
511 if (!u.pSeg32->filesize && u.pSeg32->fileoff)
512 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
513 if (u.pSeg32->vmsize < u.pSeg32->filesize)
514 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
515 if ((u.pSeg32->maxprot & u.pSeg32->initprot) != u.pSeg32->initprot)
516 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
517 if (u.pSeg32->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
518 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
519 if (u.pSeg32->nsects * sizeof(section_32_t) > u.pLoadCmd->cmdsize - sizeof(segment_command_32_t))
520 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
[2955]521 if ( pHdr->filetype == MH_OBJECT
522 && cSegmentCommands > 0)
523 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
524 cSegmentCommands++;
[2954]525
[2963]526 /*
527 * convert, validate and parse the sections.
[2954]528 */
529 cSectionsLeft = u.pSeg32->nsects;
530 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
531 while (cSectionsLeft-- > 0)
532 {
533 int fFileBits;
534
535 if (fConvertEndian)
536 {
537 pSect->addr = KLDRHLP_E2E_U32(pSect->addr);
538 pSect->size = KLDRHLP_E2E_U32(pSect->size);
539 pSect->offset = KLDRHLP_E2E_U32(pSect->offset);
540 pSect->align = KLDRHLP_E2E_U32(pSect->align);
541 pSect->reloff = KLDRHLP_E2E_U32(pSect->reloff);
542 pSect->nreloc = KLDRHLP_E2E_U32(pSect->nreloc);
543 pSect->flags = KLDRHLP_E2E_U32(pSect->flags);
544 pSect->reserved1 = KLDRHLP_E2E_U32(pSect->reserved1);
545 pSect->reserved2 = KLDRHLP_E2E_U32(pSect->reserved2);
546 }
547
548 /* validate */
549 switch (pSect->flags & SECTION_TYPE)
550 {
551 case S_ZEROFILL:
552 if (pSect->reserved1 || pSect->reserved2)
553 return KLDR_ERR_MACHO_BAD_SECTION;
554 fFileBits = 0;
555 break;
556 case S_REGULAR:
557 case S_CSTRING_LITERALS:
[2963]558 case S_COALESCED:
[2964]559 case S_4BYTE_LITERALS:
560 case S_8BYTE_LITERALS:
561 case S_16BYTE_LITERALS:
[2954]562 if (pSect->reserved1 || pSect->reserved2)
563 return KLDR_ERR_MACHO_BAD_SECTION;
564 fFileBits = 1;
565 break;
566
567 case S_LITERAL_POINTERS:
568 case S_INTERPOSING:
569 case S_GB_ZEROFILL:
570 case S_NON_LAZY_SYMBOL_POINTERS:
571 case S_LAZY_SYMBOL_POINTERS:
572 case S_SYMBOL_STUBS:
573 case S_MOD_INIT_FUNC_POINTERS:
574 case S_MOD_TERM_FUNC_POINTERS:
575 return KLDR_ERR_MACHO_UNSUPPORTED_SECTION;
576
577 default:
578 return KLDR_ERR_MACHO_UNKNOWN_SECTION;
579 }
580 if (pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS
581 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE
582 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC
583 | S_ATTR_LOC_RELOC | SECTION_TYPE))
584 return KLDR_ERR_MACHO_BAD_SECTION;
585 if ( pSect->addr - u.pSeg32->vmaddr > u.pSeg32->vmsize
586 || pSect->addr - u.pSeg32->vmaddr + pSect->size > u.pSeg32->vmsize)
587 return KLDR_ERR_MACHO_BAD_SECTION;
588 if ( pSect->align >= 31
589 || (((1 << pSect->align) - 1) & pSect->addr)
590 || (((1 << pSect->align) - 1) & u.pSeg32->vmaddr))
591 return KLDR_ERR_MACHO_BAD_SECTION;
[2963]592 if ( fFileBits
[2954]593 && ( pSect->offset > cbFile
594 || (uint64_t)pSect->offset + pSect->size > cbFile))
595 return KLDR_ERR_MACHO_BAD_SECTION;
596 if (!fFileBits && pSect->offset)
597 return KLDR_ERR_MACHO_BAD_SECTION;
598 if (!pSect->nreloc && pSect->reloff)
599 return KLDR_ERR_MACHO_BAD_SECTION;
[2963]600 if ( pSect->nreloc
[2954]601 && ( pSect->reloff > cbFile
[2961]602 || (uint64_t)pSect->reloff + (off_t)pSect->nreloc * sizeof(macho_relocation_info_t)) > cbFile)
[2954]603 return KLDR_ERR_MACHO_BAD_SECTION;
604
605
606 /* count segments and strings */
607 switch (pHdr->filetype)
608 {
609 case MH_OBJECT:
610 {
611 /* Don't load debug symbols. (test this) */
612 if (pSect->flags & S_ATTR_DEBUG)
613 break;
614
615 /* a new segment? */
[2955]616 if ( !cSegments
[2954]617 || kLdrHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
618 {
619 /* verify that the linker/assembler has ordered sections correctly. */
620 section_32_t *pCur = (pSect - 2);
621 while ((uintptr_t)pCur >= (uintptr_t)pFirstSect)
622 {
623 if (!kLdrHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
624 return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
625 pCur--;
626 }
627
628 /* ok. count it and the string. */
629 cSegments++;
[2955]630 cbStringPool += kLdrHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1;
[2954]631 }
[2961]632 cSections++;
[2954]633 break;
634 }
635
636 default:
637 return KLDR_ERR_INVALID_PARAMETER;
638 }
639
640 /* next */
641 pSect++;
642 }
643 break;
644 }
645
[2955]646 /*case LC_SEGMENT_64:
[2963]647 copy 32-bit code
[2954]648 break;
[2955]649 */
[2954]650
651 case LC_SYMTAB:
[2961]652 {
653 size_t cbSym;
[2954]654 if (fConvertEndian)
655 {
656 u.pSymTab->symoff = KLDRHLP_E2E_U32(u.pSymTab->symoff);
657 u.pSymTab->nsyms = KLDRHLP_E2E_U32(u.pSymTab->nsyms);
658 u.pSymTab->stroff = KLDRHLP_E2E_U32(u.pSymTab->stroff);
659 u.pSymTab->strsize = KLDRHLP_E2E_U32(u.pSymTab->strsize);
660 }
661
662 /* verify */
[2961]663 cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE
664 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
[2963]665 ? sizeof(macho_nlist_32_t)
[2961]666 : sizeof(macho_nlist_64_t);
[2954]667 if ( u.pSymTab->symoff >= cbFile
[2961]668 || (uint64_t)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > kLdrRdrSize(pRdr))
[2954]669 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
670 if ( u.pSymTab->stroff >= cbFile
671 || (uint64_t)u.pSymTab->stroff + u.pSymTab->strsize > cbFile)
672 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
[2956]673
674 /* only one string in objects, please. */
675 cSymbolTabs++;
676 if ( pHdr->filetype == MH_OBJECT
677 && cSymbolTabs != 1)
678 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
[2954]679 break;
[2961]680 }
[2954]681
[2963]682 case LC_DYSYMTAB:
683 /** @todo deal with this! */
684 break;
685
[2954]686 case LC_THREAD:
687 case LC_UNIXTHREAD:
688 {
689 uint32_t *pu32 = (uint32_t *)(u.pb + sizeof(load_command_t));
690 uint32_t cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(uint32_t);
691 while (cItemsLeft)
692 {
693 /* convert & verify header items ([0] == flavor, [1] == uint32_t count). */
694 if (cItemsLeft < 2)
695 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
696 if (fConvertEndian)
697 {
698 pu32[0] = KLDRHLP_E2E_U32(pu32[0]);
699 pu32[1] = KLDRHLP_E2E_U32(pu32[1]);
700 }
701 if (pu32[1] + 2 > cItemsLeft)
702 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
703
704 /* convert & verify according to flavor. */
705 switch (pu32[0])
706 {
707 /** @todo */
708 default:
709 break;
710 }
711
712 /* next */
713 cItemsLeft -= pu32[1] + 2;
714 pu32 += pu32[1] + 2;
715 }
716 break;
717 }
718
719 case LC_UUID:
720 if (u.pUuid->cmdsize != sizeof(uuid_command_t))
721 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
722 /** @todo Check anything here need converting? */
723 break;
724
[2955]725 case LC_SEGMENT_64:
[2954]726 case LC_LOADFVMLIB:
727 case LC_IDFVMLIB:
728 case LC_IDENT:
729 case LC_FVMFILE:
730 case LC_PREPAGE:
731 case LC_LOAD_DYLIB:
732 case LC_ID_DYLIB:
733 case LC_LOAD_DYLINKER:
734 case LC_ID_DYLINKER:
735 case LC_PREBOUND_DYLIB:
736 case LC_ROUTINES:
737 case LC_ROUTINES_64:
738 case LC_SUB_FRAMEWORK:
739 case LC_SUB_UMBRELLA:
740 case LC_SUB_CLIENT:
741 case LC_SUB_LIBRARY:
742 case LC_TWOLEVEL_HINTS:
743 case LC_PREBIND_CKSUM:
744 case LC_LOAD_WEAK_DYLIB:
745 case LC_SYMSEG:
746 return KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND;
747
748 default:
749 return KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND;
750 }
751 }
752
[2955]753 /* be strict. */
[2954]754 if (cbLeft)
755 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
756
[2955]757 switch (pHdr->filetype)
758 {
759 case MH_OBJECT:
760 if (!cSegments)
761 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
762 break;
763 }
764
[2954]765 *pcSegments = cSegments;
[2961]766 *pcSections = cSections;
[2955]767 *pcbStringPool = cbStringPool;
[2954]768
[2952]769 return 0;
770}
771
772
773/**
774 * Parses the load commands after we've carved out the module instance.
775 *
776 * This fills in the segment table and perhaps some other properties.
777 *
778 * @returns 0 on success.
779 * @returns KLDR_ERR_MACHO_* on failure.
780 * @param pModMachO The module.
781 * @param pbStringPool The string pool
782 * @param cbStringPool The size of the string pool.
783 */
784static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, uint32_t cbStringPool)
785{
[2955]786 union
787 {
788 const uint8_t *pb;
789 const load_command_t *pLoadCmd;
790 const segment_command_32_t *pSeg32;
791 const segment_command_64_t *pSeg64;
792 const symtab_command_t *pSymTab;
793 } u;
794 uint32_t cLeft = pModMachO->Hdr.ncmds;
795 uint32_t cbLeft = pModMachO->Hdr.sizeofcmds;
796 const uint8_t *pb = pModMachO->pbLoadCommands;
797 int fFirstSegment = 1;
798 PKLDRSEG pSeg = &pModMachO->pMod->aSegments[0];
[2961]799 PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0];
[2962]800 PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections;
[2955]801 const uint32_t cSegments = pModMachO->pMod->cSegments;
802 uint32_t i;
803
804 while (cLeft-- > 0)
805 {
806 u.pb = pb;
807 cbLeft -= u.pLoadCmd->cmdsize;
808 pb += u.pLoadCmd->cmdsize;
809
810 /*
811 * Convert endian if needed, parse and validate the command.
812 */
813 switch (u.pLoadCmd->cmd)
814 {
815 case LC_SEGMENT_32:
816 {
817 section_32_t *pSect;
818 section_32_t *pFirstSect;
819 uint32_t cSectionsLeft;
820
821 pModMachO->LinkAddress = u.pSeg32->vmaddr;
822
[2963]823 /*
824 * convert, validate and parse the sections.
[2955]825 */
826 cSectionsLeft = u.pSeg32->nsects;
827 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
828 while (cSectionsLeft-- > 0)
829 {
830 switch (pModMachO->Hdr.filetype)
831 {
832 case MH_OBJECT:
833 {
[2962]834 /* Section data extract. */
835 pSectExtra->cb = pSect->size;
836 pSectExtra->RVA = pSect->addr;
837 pSectExtra->offFile = pSect->offset ? pSect->offset : -1;
838 pSectExtra->cFixups = pSect->nreloc;
839 pSectExtra->paFixups = NULL;
840 pSectExtra->offFixups = pSect->nreloc ? pSect->reloff : -1;
841 pSectExtra->fFlags = pSect->flags;
842 pSectExtra->iSegment = pSegExtra - &pModMachO->aSegments[0];
843 pSectExtra->pvMachoSection = pSect;
844
845 /* Don't load debug symbols. (test this!) */
[2955]846 if (pSect->flags & S_ATTR_DEBUG)
847 break;
848
849 if ( fFirstSegment
850 || kLdrHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
851 {
[2961]852 /* close the previous segment */
[2962]853 if (pSegExtra != &pModMachO->aSegments[0])
[2961]854 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
855
[2955]856 /* new segment. */
857 pSeg->pvUser = NULL;
858 pSeg->pchName = pbStringPool;
859 pSeg->cchName = (uint32_t)kLdrHlpStrNLen(&pSect->segname[0], sizeof(pSect->sectname));
860 kLdrHlpMemCopy(pbStringPool, &pSect->segname[0], pSeg->cchName);
861 pbStringPool += pSeg->cchName;
862 *pbStringPool++ = '\0';
863 pSeg->SelFlat = 0;
864 pSeg->Sel16bit = 0;
865 pSeg->fFlags = 0;
866 pSeg->enmProt = KLDRPROT_EXECUTE_WRITECOPY; /** @todo fixme! */
867 pSeg->cb = pSect->size;
868 pSeg->Alignment = (1 << pSect->align);
869 pSeg->LinkAddress = pSect->addr;
870 pSeg->offFile = pSect->offset ? pSect->offset : -1;
871 pSeg->cbFile = pSect->offset ? pSect->size : -1;
872 pSeg->RVA = pSect->addr - pModMachO->LinkAddress;
873 pSeg->cbMapped = 0;
874 pSeg->MapAddress = 0;
875
[2961]876 pSegExtra->cSections = 0;
877 pSegExtra->paSections = pSectExtra;
878
[2955]879 pSeg++;
[2961]880 pSegExtra++;
[2955]881 fFirstSegment = 0;
882 }
[2961]883 else
[2955]884 {
885 /* update exiting segment */
886 if (pSeg[-1].Alignment < (1 << pSect->align))
887 pSeg[-1].Alignment = (1 << pSect->align);
888 if (pSect->addr < pSeg[-1].LinkAddress)
889 return KLDR_ERR_MACHO_BAD_SECTION; /** @todo move up! */
890
[2963]891 /* If there are file bits, ensure they are in the current flow.
[2956]892 (yes, we are very very careful here, I know.) */
[2963]893 if ( pSect->offset
[2955]894 && pSeg[-1].cbFile == pSeg[-1].cb)
895 {
[2956]896 int fOk = pSeg[-1].offFile + (pSect->addr - pSeg[-1].LinkAddress) == pSect->offset
897 && pSect[-1].offset
898 && pSeg[-1].offFile + pSeg[-1].cbFile == pSect[-1].offset + pSect[-1].size;
899 /* more checks? */
900 if (fOk)
[2955]901 pSeg[-1].cbFile = (off_t)(pSect->addr - pSeg[-1].LinkAddress) + pSect->size;
[2963]902 else
[2955]903 {
[2963]904
[2955]905 pSeg[-1].cbFile = pSeg[-1].offFile = -1;
[2956]906 pModMachO->fMapUsingLoadCommandSections = 1;
[2955]907 }
908 }
909 pSeg[-1].cb = pSect->addr - pSeg[-1].LinkAddress + pSect->size;
910
911 /** @todo update the protection... */
912 }
[2961]913 pSectExtra++;
[2955]914 break;
915 }
916
917 default:
918 return KLDR_ERR_INVALID_PARAMETER;
919 }
920
921 /* next */
922 pSect++;
923 }
924 break;
925 }
926
[2956]927 case LC_SYMTAB:
928 switch (pModMachO->Hdr.filetype)
929 {
930 case MH_OBJECT:
931 pModMachO->offSymbols = u.pSymTab->symoff;
932 pModMachO->cSymbols = u.pSymTab->nsyms;
933 pModMachO->offStrings = u.pSymTab->stroff;
[2962]934 pModMachO->cchStrings = u.pSymTab->strsize;
[2956]935 break;
936 }
937 break;
938
[2955]939 default:
940 break;
[2956]941 } /* command switch */
942 } /* while more commands */
[2955]943
[2961]944 /*
945 * Close the last segment (if any).
946 */
947 if (pSegExtra != &pModMachO->aSegments[1])
948 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
949
[2963]950 /*
[2955]951 * Adjust mapping addresses calculating the image size.
952 */
953 pSeg = &pModMachO->pMod->aSegments[0];
954 switch (pModMachO->Hdr.filetype)
955 {
956 case MH_OBJECT:
957 {
958 KLDRADDR cb1;
959 size_t cb2;
960
961 for (i = 0; i < cSegments - 1; i++)
962 {
963 cb1 = pSeg[i + 1].LinkAddress - pSeg[i].LinkAddress;
964 cb2 = (size_t)cb1;
965 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(size_t)0;
966 }
967 cb1 = KLDR_ALIGN_ADDR(pSeg[i].cb, pSeg[i].Alignment);
968 cb2 = (size_t)cb1;
969 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(size_t)0;
970
971 pModMachO->cbImage = pSeg[i].RVA + cb1;
972 break;
973 }
974 }
975
[2952]976 return 0;
977}
978
979
980/** @copydoc KLDRMODOPS::pfnDestroy */
981static int kldrModMachODestroy(PKLDRMOD pMod)
982{
983 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
984 int rc = 0;
[2961]985 uint32_t i, j;
[2952]986 KLDRMODMACHO_ASSERT(!pModMachO->pvMapping);
987
[2961]988 i = pMod->cSegments;
989 while (i-- > 0)
990 {
991 j = pModMachO->aSegments[i].cSections;
992 while (j-- > 0)
993 {
994 kldrHlpFree(pModMachO->aSegments[i].paSections[j].paFixups);
995 pModMachO->aSegments[i].paSections[j].paFixups = NULL;
996 }
997 }
998
[2952]999 if (pMod->pRdr)
1000 {
1001 rc = kLdrRdrClose(pMod->pRdr);
1002 pMod->pRdr = NULL;
1003 }
1004 pMod->u32Magic = 0;
1005 pMod->pOps = NULL;
1006 kldrHlpFree(pModMachO->pbLoadCommands);
1007 pModMachO->pbLoadCommands = NULL;
[2961]1008 kldrHlpFree(pModMachO->pchStrings);
1009 pModMachO->pchStrings = NULL;
1010 kldrHlpFree(pModMachO->pvaSymbols);
1011 pModMachO->pvaSymbols = NULL;
[2952]1012 kldrHlpFree(pModMachO);
1013 return rc;
1014}
1015
1016
1017/**
[2962]1018 * Gets the right base address.
[2952]1019 *
[2962]1020 * @returns 0 on success.
1021 * @returns A non-zero status code if the BaseAddress isn't right.
1022 * @param pModMachO The interpreter module instance
1023 * @param pBaseAddress The base address, IN & OUT. Optional.
[2952]1024 */
[2962]1025static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress)
[2952]1026{
1027 /*
[2962]1028 * Adjust the base address.
[2952]1029 */
[2962]1030 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
1031 *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress;
1032 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
1033 *pBaseAddress = pModMachO->LinkAddress;
[2952]1034
1035 return 0;
1036}
1037
1038
[2962]1039
1040/** @copydoc kLdrModQuerySymbol */
1041static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
1042 const char *pchSymbol, size_t cchSymbol, const char *pszVersion,
1043 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
[2952]1044{
[2962]1045 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1046 int rc;
[2952]1047
1048 /*
[2962]1049 * Resolve defaults.
[2952]1050 */
[2962]1051 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
[2952]1052 if (rc)
1053 return rc;
1054
1055 /*
[2962]1056 * Refuse segmented requests for now.
[2952]1057 */
[2963]1058 if ( pfKind
[2962]1059 && (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) != KLDRSYMKIND_REQ_FLAT)
1060 return KLDR_ERR_TODO;
1061
1062 /*
1063 * Take action according to file type.
1064 */
1065 if (pModMachO->Hdr.filetype == MH_OBJECT)
[2952]1066 {
[2962]1067 rc = kldrModMachOLoadObjSymTab(pModMachO);
1068 if (!rc)
1069 {
1070 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1071 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
[2963]1072 rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1073 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
[2962]1074 cchSymbol, puValue, pfKind);
1075 else
1076 rc = KLDR_ERR_TODO; /** @todo duplicate kldrModMachOQuerySymbol32 for parsing 64-bit symbols when everything is working. */
[2963]1077 /*rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1078 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
[2962]1079 cchSymbol, puValue, pfKind);*/
1080
1081 }
[2952]1082 }
[2962]1083 else
1084 rc = KLDR_ERR_TODO;
[2952]1085
[2962]1086 return rc;
[2952]1087}
1088
1089
[2962]1090
[2952]1091/**
[2962]1092 * Lookup a symbol in a 32-bit symbol table.
[2963]1093 *
[2962]1094 * @returns See kLdrModQuerySymbol.
[2963]1095 * @param pModMachO
[2962]1096 * @param paSyms Pointer to the symbol table.
1097 * @param cSyms Number of symbols in the table.
1098 * @param pchStrings Pointer to the string table.
1099 * @param cchStrings Size of the string table.
[2963]1100 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
[2962]1101 * @param iSymbol See kLdrModQuerySymbol.
1102 * @param pchSymbol See kLdrModQuerySymbol.
1103 * @param cchSymbol See kLdrModQuerySymbol.
1104 * @param puValue See kLdrModQuerySymbol.
1105 * @param pfKind See kLdrModQuerySymbol.
[2952]1106 */
[2962]1107static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, uint32_t cSyms, const char *pchStrings,
1108 uint32_t cchStrings, KLDRADDR BaseAddress, uint32_t iSymbol, const char *pchSymbol, size_t cchSymbol,
1109 PKLDRADDR puValue, uint32_t *pfKind)
[2952]1110{
1111 /*
[2962]1112 * Find a valid symbol matching the search criteria.
[2952]1113 */
[2962]1114 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
[2952]1115 {
[2962]1116 /* simplify validation. */
1117 if (cchStrings <= cchSymbol)
1118 return KLDR_ERR_SYMBOL_NOT_FOUND;
1119 cchStrings -= cchSymbol;
1120
[2963]1121 /* external symbols are usually at the end, so search the other way. */
1122 for (iSymbol = cSyms - 1; iSymbol != UINT32_MAX; iSymbol--)
[2962]1123 {
1124 const char *psz;
1125
1126 /* Skip irrellevant and non-public symbols. */
1127 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1128 continue;
1129 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1130 continue;
1131 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1132 continue;
1133 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1134 continue;
[2963]1135
[2962]1136 /* get name */
[2963]1137 if (!paSyms[iSymbol].n_un.n_strx)
[2962]1138 continue;
1139 if ((uint32_t)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1140 continue;
1141 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1142 if (psz[cchSymbol])
1143 continue;
1144 if (kLdrHlpMemComp(psz, pchSymbol, cchSymbol))
1145 continue;
1146
1147 /* match! */
1148 break;
1149 }
[2963]1150 if (iSymbol == UINT32_MAX)
[2962]1151 return KLDR_ERR_SYMBOL_NOT_FOUND;
[2952]1152 }
[2962]1153 else
1154 {
1155 if (iSymbol >= cSyms)
1156 return KLDR_ERR_SYMBOL_NOT_FOUND;
1157 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1158 return KLDR_ERR_SYMBOL_NOT_FOUND;
1159 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1160 return KLDR_ERR_SYMBOL_NOT_FOUND;
1161 }
[2952]1162
[2963]1163 /*
[2962]1164 * Calc the return values.
[2952]1165 */
[2962]1166 if (pfKind)
[2952]1167 {
[2963]1168 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
[2962]1169 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1170 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
[2952]1171 else
[2962]1172 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1173 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1174 *pfKind |= KLDRSYMKIND_WEAK;
1175 }
1176
1177 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1178 {
1179 case MACHO_N_SECT:
[2952]1180 {
[2962]1181 PKLDRMODMACHOSECT pSect;
1182 KLDRADDR RVA;
1183 if ((uint32_t)(paSyms[iSymbol].n_sect - 1) >= pModMachO->cSections)
1184 return KLDR_ERR_MACHO_BAD_SYMBOL;
1185 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1186
1187 RVA = paSyms[iSymbol].n_value - pModMachO->LinkAddress;
1188 if (RVA - pSect->RVA >= pSect->cb)
1189 return KLDR_ERR_MACHO_BAD_SYMBOL;
1190 if (puValue)
1191 *puValue = RVA + BaseAddress;
1192
[2963]1193 if ( pfKind
[2962]1194 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1195 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1196 break;
[2952]1197 }
[2962]1198
1199 case MACHO_N_ABS:
1200 if (puValue)
1201 *puValue = paSyms[iSymbol].n_value;
1202 /*if (pfKind)
1203 pfKind |= KLDRSYMKIND_ABS;*/
1204 break;
1205
1206 case MACHO_N_PBUD:
1207 case MACHO_N_INDR:
1208 /** @todo implement indirect and prebound symbols. */
1209 default:
1210 KLDRMODMACHO_ASSERT(0);
1211 return KLDR_ERR_TODO;
[2952]1212 }
1213
1214 return 0;
1215}
1216
1217
[2962]1218/** @copydoc kLdrModEnumSymbols */
1219static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
1220 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
[2952]1221{
[2962]1222 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1223 int rc;
[2952]1224
1225 /*
[2962]1226 * Resolve defaults.
[2952]1227 */
[2962]1228 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
[2952]1229 if (rc)
1230 return rc;
1231
[2962]1232 /*
1233 * Take action according to file type.
1234 */
1235 if (pModMachO->Hdr.filetype == MH_OBJECT)
[2952]1236 {
[2962]1237 rc = kldrModMachOLoadObjSymTab(pModMachO);
1238 if (!rc)
[2952]1239 {
[2962]1240 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1241 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
[2963]1242 rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1243 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
[2962]1244 fFlags, pfnCallback, pvUser);
[2952]1245 else
[2962]1246 rc = KLDR_ERR_TODO; /** @todo duplicate kldrModMachOQuerySymbol32 for parsing 64-bit symbols when everything is working. */
[2963]1247 /*rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
[2962]1248 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, pfnCallback, pvUser);*/
[2952]1249 }
1250 }
[2962]1251 else
1252 rc = KLDR_ERR_TODO;
[2952]1253
[2962]1254 return rc;
[2952]1255}
1256
1257
[2962]1258/**
1259 * Enum a 32-bit symbol table.
[2963]1260 *
[2962]1261 * @returns See kLdrModQuerySymbol.
[2963]1262 * @param pModMachO
[2962]1263 * @param paSyms Pointer to the symbol table.
1264 * @param cSyms Number of symbols in the table.
1265 * @param pchStrings Pointer to the string table.
1266 * @param cchStrings Size of the string table.
[2963]1267 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
[2962]1268 * @param fFlags See kLdrModEnumSymbols.
1269 * @param pfnCallback See kLdrModEnumSymbols.
1270 * @param pvUser See kLdrModEnumSymbols.
1271 */
[2963]1272static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, uint32_t cSyms,
[2962]1273 const char *pchStrings, uint32_t cchStrings, KLDRADDR BaseAddress,
1274 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
[2952]1275{
[2962]1276 const uint32_t fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1277 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
1278 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT;
1279 uint32_t iSym;
1280 int rc;
[2952]1281
1282 /*
[2962]1283 * Iterate the symbol table.
[2952]1284 */
[2962]1285 for (iSym = 0; iSym < cSyms; iSym++)
1286 {
1287 uint32_t fKind;
1288 KLDRADDR uValue;
1289 const char *psz;
1290 size_t cch;
[2952]1291
[2962]1292 /* Skip debug symbols and undefined symbols. */
1293 if (paSyms[iSym].n_type & MACHO_N_STAB)
1294 continue;
1295 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1296 continue;
[2952]1297
[2962]1298 /* Skip non-public symbols unless they are requested explicitly. */
1299 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
1300 {
1301 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
1302 continue;
1303 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
1304 continue;
[2963]1305 if (!paSyms[iSym].n_un.n_strx)
[2962]1306 continue;
1307 }
[2952]1308
[2963]1309 /*
1310 * Gather symbol info
[2962]1311 */
[2952]1312
[2962]1313 /* name */
1314 if ((uint32_t)paSyms[iSym].n_un.n_strx >= cchStrings)
1315 return KLDR_ERR_MACHO_BAD_SYMBOL;
1316 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
1317 cch = kLdrHlpStrLen(psz);
1318 if (!cch)
1319 psz = NULL;
1320
1321 /* kind & value */
1322 fKind = fKindBase;
1323 if (paSyms[iSym].n_desc & N_WEAK_DEF)
1324 fKind |= KLDRSYMKIND_WEAK;
1325 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
[2952]1326 {
[2962]1327 case MACHO_N_SECT:
1328 {
1329 PKLDRMODMACHOSECT pSect;
1330 if ((uint32_t)(paSyms[iSym].n_sect - 1) >= pModMachO->cSections)
1331 return KLDR_ERR_MACHO_BAD_SYMBOL;
1332 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
1333
1334 uValue = paSyms[iSym].n_value - pModMachO->LinkAddress;
1335 if (uValue - pSect->RVA >= pSect->cb)
1336 return KLDR_ERR_MACHO_BAD_SYMBOL;
1337 uValue += BaseAddress;
1338
1339 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
1340 fKind |= KLDRSYMKIND_CODE;
1341 else
1342 fKind |= KLDRSYMKIND_NO_TYPE;
1343 break;
1344 }
1345
1346 case MACHO_N_ABS:
1347 uValue = paSyms[iSym].n_value;
1348 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
1349 break;
1350
1351 case MACHO_N_PBUD:
1352 case MACHO_N_INDR:
1353 /** @todo implement indirect and prebound symbols. */
1354 default:
1355 KLDRMODMACHO_ASSERT(0);
1356 return KLDR_ERR_TODO;
[2952]1357 }
1358
1359 /*
[2962]1360 * Do callback.
[2952]1361 */
[2962]1362 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
1363 if (rc)
1364 return rc;
[2952]1365 }
1366 return 0;
1367}
1368
1369
1370/** @copydoc kLdrModGetImport */
1371static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
1372{
[2956]1373 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1374 if (pModMachO->Hdr.filetype == MH_OBJECT)
[2952]1375 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1376
[2956]1377 /* later */
1378 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
[2952]1379}
1380
1381
1382/** @copydoc kLdrModNumberOfImports */
1383static int32_t kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits)
1384{
1385 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2956]1386 if (pModMachO->Hdr.filetype == MH_OBJECT)
1387 return 0;
[2952]1388
[2956]1389 /* later */
[2952]1390 return 0;
1391}
1392
1393
1394/** @copydoc kLdrModGetStackInfo */
1395static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1396{
1397 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1398
1399 pStackInfo->Address = NIL_KLDRADDR;
1400 pStackInfo->LinkAddress = NIL_KLDRADDR;
[2956]1401 pStackInfo->cbStack = pStackInfo->cbStackThread = 0;
1402 /* later */
[2952]1403
1404 return 0;
1405}
1406
1407
1408/** @copydoc kLdrModQueryMainEntrypoint */
1409static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1410{
1411#if 0
1412 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1413 int rc;
1414
1415 /*
1416 * Resolve base address alias if any.
1417 */
1418 rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress);
1419 if (rc)
1420 return rc;
1421
1422 /*
1423 * Convert the address from the header.
1424 */
1425 *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
1426 ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
1427 : NIL_KLDRADDR;
1428#else
1429 *pMainEPAddress = NIL_KLDRADDR;
1430#endif
1431 return 0;
1432}
1433
1434
1435/** @copydoc kLdrModEnumDbgInfo */
1436static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1437{
1438#if 0
1439 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1440 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
1441 uint32_t iDbgInfo;
1442 uint32_t cb;
1443 int rc;
1444
1445 /*
1446 * Check that there is a debug directory first.
1447 */
1448 cb = pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
1449 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1450 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1451 return 0;
1452
1453 /*
1454 * Make sure we've got mapped bits.
1455 */
1456 rc = kldrModMachOBitsAndBaseAddress(pModMachO, &pvBits, NULL);
1457 if (rc)
1458 return rc;
1459
1460 /*
1461 * Enumerate the debug directory.
1462 */
1463 pDbgDir = KLDRMODMACHO_RVA2TYPE(pvBits,
1464 pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
1465 const IMAGE_DEBUG_DIRECTORY *);
1466 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
1467 {
1468 KLDRDBGINFOTYPE enmDbgInfoType;
1469
1470 /* convert the type. */
1471 switch (pDbgDir->Type)
1472 {
1473 case IMAGE_DEBUG_TYPE_UNKNOWN:
1474 case IMAGE_DEBUG_TYPE_FPO:
1475 case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
1476 case IMAGE_DEBUG_TYPE_MISC:
1477 case IMAGE_DEBUG_TYPE_EXCEPTION:
1478 case IMAGE_DEBUG_TYPE_FIXUP:
1479 case IMAGE_DEBUG_TYPE_BORLAND:
1480 default:
1481 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
1482 break;
1483 case IMAGE_DEBUG_TYPE_CODEVIEW:
1484 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
1485 break;
1486 }
1487
1488 rc = pfnCallback(pMod, iDbgInfo,
1489 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
1490 pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
1491 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
1492 pDbgDir->SizeOfData,
1493 NULL,
1494 pvUser);
1495 if (rc)
1496 break;
1497
1498 /* next */
1499 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
1500 break;
1501 }
1502
1503 return rc;
1504#else
1505 return 0;
1506#endif
1507}
1508
1509
1510/** @copydoc kLdrModHasDbgInfo */
1511static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1512{
1513 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1514
1515#if 0
1516 /*
1517 * Base this entirely on the presence of a debug directory.
1518 */
1519 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
1520 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1521 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1522 return KLDR_ERR_NO_DEBUG_INFO;
1523 return 0;
1524#else
1525 return KLDR_ERR_NO_DEBUG_INFO;
1526#endif
1527}
1528
1529
1530/** @copydoc kLdrModMap */
1531static int kldrModMachOMap(PKLDRMOD pMod)
1532{
[2962]1533 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1534 unsigned fFixed;
1535 uint32_t i;
1536 void *pvBase;
1537 int rc;
[2952]1538
1539 /*
1540 * Already mapped?
1541 */
1542 if (pModMachO->pvMapping)
1543 return KLDR_ERR_ALREADY_MAPPED;
1544
1545 /*
[2962]1546 * Map it.
[2952]1547 */
[2962]1548 /* fixed image? */
1549 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
1550 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1551 if (!fFixed)
1552 pvBase = NULL;
1553 else
1554 {
1555 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
1556 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
1557 return KLDR_ERR_ADDRESS_OVERFLOW;
1558 }
1559
1560 /* try do the prepare */
1561 if (pModMachO->fMapUsingLoadCommandSections)
1562 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
1563 else
1564 {
1565 rc = kLdrRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
1566 if (rc)
1567 return rc;
1568 }
1569
1570 /*
1571 * Update the segments with their map addresses.
1572 */
1573 for (i = 0; i < pMod->cSegments; i++)
1574 {
1575 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
1576 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
1577 }
1578 pModMachO->pvMapping = pvBase;
1579
[2952]1580 return 0;
1581}
1582
1583
1584/** @copydoc kLdrModUnmap */
1585static int kldrModMachOUnmap(PKLDRMOD pMod)
1586{
[2962]1587 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1588 uint32_t i;
1589 int rc;
[2952]1590
1591 /*
1592 * Mapped?
1593 */
1594 if (!pModMachO->pvMapping)
1595 return KLDR_ERR_NOT_MAPPED;
1596
1597 /*
[2962]1598 * Try unmap the image.
[2952]1599 */
[2962]1600 if (pModMachO->fMapUsingLoadCommandSections)
1601 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
1602 else
1603 {
1604 rc = kLdrRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
1605 if (rc)
1606 return rc;
1607 }
1608
1609 /*
1610 * Update the segments to reflect that they aren't mapped any longer.
1611 */
1612 pModMachO->pvMapping = NULL;
1613 for (i = 0; i < pMod->cSegments; i++)
1614 pMod->aSegments[i].MapAddress = 0;
1615
[2952]1616 return 0;
1617}
1618
1619
1620/** @copydoc kLdrModAllocTLS */
1621static int kldrModMachOAllocTLS(PKLDRMOD pMod)
1622{
[2962]1623 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2952]1624
1625 /*
1626 * Mapped?
1627 */
1628 if (!pModMachO->pvMapping)
1629 return KLDR_ERR_NOT_MAPPED;
1630 return 0;
1631}
1632
1633
1634/** @copydoc kLdrModFreeTLS */
1635static void kldrModMachOFreeTLS(PKLDRMOD pMod)
1636{
1637}
1638
1639
1640/** @copydoc kLdrModReload */
1641static int kldrModMachOReload(PKLDRMOD pMod)
1642{
1643 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1644
1645 /*
1646 * Mapped?
1647 */
1648 if (!pModMachO->pvMapping)
1649 return KLDR_ERR_NOT_MAPPED;
1650
1651 /* the file provider does it all */
[2962]1652 return kLdrRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
[2952]1653}
1654
1655
1656/** @copydoc kLdrModFixupMapping */
1657static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1658{
1659 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1660 int rc, rc2;
1661
1662 /*
1663 * Mapped?
1664 */
1665 if (!pModMachO->pvMapping)
1666 return KLDR_ERR_NOT_MAPPED;
1667
1668 /*
1669 * Before doing anything we'll have to make all pages writable.
1670 */
[2962]1671 if (pModMachO->fMapUsingLoadCommandSections)
1672 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
1673 else
1674 {
1675 rc = kLdrRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
1676 if (rc)
1677 return rc;
1678 }
[2952]1679
1680 /*
[2962]1681 * Resolve imports and apply base relocations.
[2952]1682 */
[2963]1683 rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (uintptr_t)pModMachO->pvMapping, pModMachO->LinkAddress,
[2962]1684 pfnGetImport, pvUser);
[2952]1685
1686 /*
1687 * Restore protection.
1688 */
[2962]1689 if (pModMachO->fMapUsingLoadCommandSections)
1690 rc2 = KLDR_ERR_TODO; /* deal with this if it ever occurs. */
1691 else
1692 rc2 = kLdrRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
[2952]1693 if (!rc && rc2)
1694 rc = rc2;
1695 return rc;
1696}
1697
1698
1699/**
[2961]1700 * MH_OBJECT: Resolves undefined symbols (imports).
[2952]1701 *
1702 * @returns 0 on success, non-zero kLdr status code on failure.
[2961]1703 * @param pModMachO The Mach-O module interpreter instance.
1704 * @param pfnGetImport The callback for resolving an imported symbol.
1705 * @param pvUser User argument to the callback.
[2952]1706 */
[2961]1707static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
[2952]1708{
[2961]1709 const uint32_t cSyms = pModMachO->cSymbols;
1710 uint32_t iSym;
1711 int rc;
[2952]1712
1713 /*
[2961]1714 * Ensure that we've got the symbol table and section fixups handy.
[2952]1715 */
[2961]1716 rc = kldrModMachOLoadObjSymTab(pModMachO);
1717 if (rc)
1718 return rc;
[2952]1719
1720 /*
[2961]1721 * Iterate the symbol table and resolve undefined symbols.
1722 * We currently ignore REFERENCE_TYPE.
[2952]1723 */
[2963]1724 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
[2961]1725 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
[2952]1726 {
[2961]1727 macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols;
1728 for (iSym = 0; iSym < cSyms; iSym++)
[2952]1729 {
[2961]1730 /* skip stabs */
1731 if (paSyms[iSym].n_type & MACHO_N_STAB)
1732 continue;
[2952]1733
[2961]1734 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
[2952]1735 {
[2961]1736 const char *pszSymbol;
1737 size_t cchSymbol;
1738 uint32_t fKind = KLDRSYMKIND_REQ_FLAT;
[2963]1739 KLDRADDR Value;
[2952]1740
[2961]1741 /** @todo Implement N_REF_TO_WEAK. */
1742 if (paSyms[iSym].n_desc & N_REF_TO_WEAK)
1743 return KLDR_ERR_TODO;
[2952]1744
[2961]1745 /* Get the symbol name and try resolve it. */
[2962]1746 if ((uint32_t)paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
[2961]1747 return KLDR_ERR_MACHO_BAD_SYMBOL;
1748 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
1749 cchSymbol = kLdrHlpStrLen(pszSymbol);
1750 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
1751 &Value, &fKind, pvUser);
1752 if (rc)
1753 {
1754 /* weak reference? */
1755 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
1756 break;
1757 Value = 0;
1758 }
[2952]1759
[2961]1760 /* Update the symbol. */
1761 paSyms[iSym].n_value = (uint32_t)Value;
1762 if (paSyms[iSym].n_value != Value)
1763 {
1764 rc = KLDR_ERR_ADDRESS_OVERFLOW;
[2952]1765 break;
[2961]1766 }
1767 }
1768 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
[2964]1769 {
1770 /** @todo implement weak symbols. */
1771 /*return KLDR_ERR_TODO; - ignored for now. */
1772 }
[2961]1773 }
1774 }
1775 else
1776 {
1777 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
1778 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols;
1779 for (iSym = 0; iSym < cSyms; iSym++)
1780 {
1781 /* skip stabs */
1782 if (paSyms[iSym].n_type & MACHO_N_STAB)
1783 continue;
[2952]1784
[2961]1785 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1786 {
1787 const char *pszSymbol;
1788 size_t cchSymbol;
1789 uint32_t fKind = KLDRSYMKIND_REQ_FLAT;
[2963]1790 KLDRADDR Value;
[2961]1791
1792 /** @todo Implement N_REF_TO_WEAK. */
1793 if (paSyms[iSym].n_desc & N_REF_TO_WEAK)
1794 return KLDR_ERR_TODO;
1795
1796 /* Get the symbol name and try resolve it. */
[2962]1797 if (paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
[2961]1798 return KLDR_ERR_MACHO_BAD_SYMBOL;
1799 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
1800 cchSymbol = kLdrHlpStrLen(pszSymbol);
1801 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
1802 &Value, &fKind, pvUser);
1803 if (rc)
[2952]1804 {
[2961]1805 /* weak reference? */
1806 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
1807 break;
1808 Value = 0;
1809 }
[2952]1810
[2961]1811 /* Update the symbol. */
1812 paSyms[iSym].n_value = Value;
1813 if (paSyms[iSym].n_value != Value)
1814 {
1815 rc = KLDR_ERR_ADDRESS_OVERFLOW;
[2952]1816 break;
1817 }
[2961]1818 }
1819 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
[2964]1820 {
1821 /** @todo implement weak symbols. */
1822 /*return KLDR_ERR_TODO; - ignored for now. */
1823 }
[2961]1824 }
1825 }
[2952]1826
[2961]1827 return rc;
1828}
[2952]1829
1830
[2961]1831/**
1832 * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
1833 *
1834 * @returns 0 on success, non-zero kLdr status code on failure.
1835 * @param pModMachO The Mach-O module interpreter instance.
1836 * @param pvMapping The mapping to fixup.
1837 * @param NewBaseAddress The address to fixup the mapping to.
1838 * @param OldBaseAddress The address the mapping is currently fixed up to.
1839 */
1840static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress)
1841{
1842 uint32_t iSeg;
1843 int rc;
[2952]1844
1845
[2961]1846 /*
1847 * Ensure that we've got the symbol table and section fixups handy.
1848 */
1849 rc = kldrModMachOLoadObjSymTab(pModMachO);
1850 if (rc)
1851 return rc;
[2952]1852
[2961]1853 /*
1854 * Iterate over the segments and their sections and apply fixups.
1855 */
1856 for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++)
1857 {
1858 PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg];
1859 uint32_t iSect;
1860
1861 for (iSect = 0; iSect < pSeg->cSections; iSect++)
1862 {
1863 PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect];
1864 uint8_t *pbSectBits;
1865
1866 /* skip sections without fixups. */
1867 if (!pSect->cFixups)
1868 continue;
1869
1870 /* lazy load (and endian convert) the fixups. */
1871 if (!pSect->paFixups)
1872 {
1873 rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
1874 if (rc)
[2952]1875 break;
[2961]1876 }
[2952]1877
[2961]1878 /*
1879 * Apply the fixups.
1880 */
1881 pbSectBits = (uint8_t *)pvMapping + (uintptr_t)pSect->RVA;
[2963]1882 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
1883 rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect,
1884 (macho_nlist_32_t *)pModMachO->pvaSymbols,
1885 pModMachO->cSymbols, NewBaseAddress);
1886 else
1887 rc = KLDR_ERR_TODO; /* save space for now. */
[2961]1888 if (rc)
1889 break;
[2952]1890 }
[2961]1891 }
[2952]1892
[2961]1893 return rc;
1894}
[2952]1895
1896
[2963]1897/**
1898 * Applies generic fixups to a section in an image of the same endian-ness
1899 * as the host CPU.
1900 *
1901 * @returns 0 on success, non-zero kLdr status code on failure.
1902 * @param pModMachO The Mach-O module interpreter instance.
1903 * @param pbSectBits Pointer to the section bits.
1904 * @param pFixupSect The section being fixed up.
1905 * @param NewBaseAddress The new base image address.
1906 */
1907static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, uint8_t *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
1908 macho_nlist_32_t *paSyms, uint32_t cSyms, KLDRADDR NewBaseAddress)
[2961]1909{
[2963]1910 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
1911 const uint32_t cFixups = pFixupSect->cFixups;
1912 size_t cbSectBits = (size_t)pFixupSect->cb;
1913 const uint8_t *pbSectVirginBits;
1914 uint32_t iFixup;
1915 KLDRPU uFixVirgin;
1916 KLDRPU uFix;
1917 KLDRADDR SymAddr;
1918 int rc;
[2961]1919
[2963]1920 /*
1921 * Find the virgin bits.
1922 */
1923 if (pFixupSect->offFile != -1)
1924 {
1925 rc = kldrModMachOMapVirginBits(pModMachO);
1926 if (rc)
1927 return rc;
1928 pbSectVirginBits = (const uint8_t *)pModMachO->pvBits + pFixupSect->offFile;
1929 }
1930 else
1931 pbSectVirginBits = NULL;
1932
1933 /*
1934 * Iterate the fixups and apply them.
1935 */
1936 for (iFixup = 0; iFixup < cFixups; iFixup++)
1937 {
1938 union
1939 {
1940 macho_relocation_info_t r;
1941 scattered_relocation_info_t s;
1942 } Fixup;
1943 Fixup.r = paFixups[iFixup];
1944
1945 if (!(Fixup.r.r_address & R_SCATTERED))
1946 {
1947 /* sanity */
1948 if ((uint32_t)Fixup.r.r_address >= cbSectBits)
1949 return KLDR_ERR_BAD_FIXUP;
1950
1951 /* calc fixup addresses. */
1952 uFix.pv = pbSectBits + Fixup.r.r_address;
1953 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.r.r_address : 0;
1954
1955 /*
1956 * Calc the symbol value.
1957 */
1958 /* The addend is stored in the code. */
1959 /** @todo Deal with unaligned accesses on non x86 platforms. */
1960 switch (Fixup.r.r_length)
1961 {
1962 case 0: SymAddr = *uFixVirgin.pi8; break;
1963 case 1: SymAddr = *uFixVirgin.pi16; break;
1964 case 2: SymAddr = *uFixVirgin.pi32; break;
1965 case 3: SymAddr = *uFixVirgin.pi64; break;
1966 }
1967
1968 /* Add symbol / section address. */
1969 if (Fixup.r.r_extern)
1970 {
1971 const macho_nlist_32_t *pSym;
1972 if (Fixup.r.r_symbolnum >= cSyms)
1973 return KLDR_ERR_BAD_FIXUP;
1974 pSym = &paSyms[Fixup.r.r_symbolnum];
1975
1976 if (pSym->n_type & MACHO_N_STAB)
1977 return KLDR_ERR_BAD_FIXUP;
1978
1979 switch (pSym->n_type & MACHO_N_TYPE)
1980 {
1981 case MACHO_N_SECT:
1982 {
1983 PKLDRMODMACHOSECT pSymSect;
1984 if ((uint32_t)pSym->n_sect - 1 > pModMachO->cSections)
1985 return KLDR_ERR_MACHO_BAD_SYMBOL;
1986 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
1987
1988 SymAddr += pSym->n_value - pModMachO->LinkAddress + pSymSect->RVA;
1989 break;
1990 }
1991
1992 case MACHO_N_UNDF:
1993 case MACHO_N_ABS:
1994 SymAddr += pSym->n_value;
1995 break;
1996
1997 case MACHO_N_INDR:
1998 case MACHO_N_PBUD:
1999 return KLDR_ERR_TODO;
2000 default:
2001 return KLDR_ERR_MACHO_BAD_SYMBOL;
2002 }
2003 }
2004 else if (Fixup.r.r_symbolnum != R_ABS)
2005 {
2006 PKLDRMODMACHOSECT pSymSect;
2007 if (Fixup.r.r_symbolnum > pModMachO->cSections)
2008 return KLDR_ERR_BAD_FIXUP;
2009 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
2010 SymAddr += NewBaseAddress + pSymSect->RVA;
2011 }
2012
2013 /* adjust for PC relative */
2014 if (Fixup.r.r_pcrel)
2015 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
2016 }
2017 else
2018 {
2019 PKLDRMODMACHOSECT pSymSect;
2020 uint32_t iSymSect;
2021 KLDRADDR Value;
2022
2023 /* sanity */
2024 KLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
2025 if ((uint32_t)Fixup.s.r_address >= cbSectBits)
2026 return KLDR_ERR_BAD_FIXUP;
2027
2028 /* calc fixup addresses. */
2029 uFix.pv = pbSectBits + Fixup.s.r_address;
2030 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.s.r_address : 0;
2031
2032 /*
2033 * Calc the symbol value.
2034 */
2035 /* The addend is stored in the code. */
2036 switch (Fixup.s.r_length)
2037 {
2038 case 0: SymAddr = *uFixVirgin.pi8; break;
2039 case 1: SymAddr = *uFixVirgin.pi16; break;
2040 case 2: SymAddr = *uFixVirgin.pi32; break;
2041 case 3: SymAddr = *uFixVirgin.pi64; break;
2042 }
2043
2044 /* Calc the section number from the r_value and adjust the value. */
2045 pSymSect = NULL;
2046 Value = Fixup.s.r_value - pModMachO->LinkAddress;
2047 for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++)
2048 {
2049 KLDRADDR off = Value - pModMachO->paSections[iSymSect].RVA;
2050 if (off < pModMachO->paSections[iSymSect].cb)
2051 {
2052 pSymSect = &pModMachO->paSections[iSymSect];
2053 break;
2054 }
2055 else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */
2056 pSymSect = &pModMachO->paSections[iSymSect];
2057 }
2058 if (!pSymSect)
2059 return KLDR_ERR_BAD_FIXUP;
2060
2061 /** @todo this looking up of the r_value section isn't strictly required unless we're going to remove sections from the link. */
2062 SymAddr += NewBaseAddress + pSymSect->RVA + (Value - pSymSect->RVA);
2063
2064 /* adjust for PC relative */
2065 if (Fixup.s.r_pcrel)
2066 SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
2067
2068 Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
2069 Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type;
2070 }
2071
2072 /*
2073 * Write back the fixed up value.
2074 */
2075 if (Fixup.r.r_type == GENERIC_RELOC_VANILLA)
2076 {
2077 switch (Fixup.r.r_length)
2078 {
2079 case 0: *uFix.pu8 = (uint8_t)SymAddr; break;
2080 case 1: *uFix.pu16 = (uint16_t)SymAddr; break;
2081 case 2: *uFix.pu32 = (uint32_t)SymAddr; break;
2082 case 3: *uFix.pu64 = (uint64_t)SymAddr; break;
2083 }
2084 }
2085 else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF)
[2964]2086 return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE;
[2963]2087 else
2088 return KLDR_ERR_BAD_FIXUP;
2089 }
2090
[2952]2091 return 0;
2092}
2093
2094
[2961]2095/**
2096 * Loads the symbol table for a MH_OBJECT file.
[2963]2097 *
[2961]2098 * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols.
[2963]2099 *
[2961]2100 * @returns 0 on success, non-zero kLdr status code on failure.
[2963]2101 * @param pModMachO The Mach-O module interpreter instance.
[2961]2102 */
2103static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO)
2104{
2105 int rc = 0;
[2952]2106
[2963]2107 if ( !pModMachO->pvaSymbols
[2961]2108 && pModMachO->cSymbols)
2109 {
2110 size_t cbSyms;
2111 size_t cbSym;
2112 void *pvSyms;
2113 void *pvStrings;
2114
2115 /* sanity */
2116 if ( !pModMachO->offSymbols
[2962]2117 || (pModMachO->cchStrings && !pModMachO->offStrings))
[2961]2118 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
2119
2120 /* allocate */
2121 cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2122 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
2123 ? sizeof(macho_nlist_32_t)
2124 : sizeof(macho_nlist_64_t);
2125 cbSyms = pModMachO->cSymbols * cbSym;
2126 if (cbSyms / cbSym != pModMachO->cSymbols)
2127 return KLDR_ERR_SIZE_OVERFLOW;
2128 rc = KLDR_ERR_NO_MEMORY;
2129 pvSyms = kldrHlpAlloc(cbSyms);
2130 if (pvSyms)
2131 {
[2962]2132 if (pModMachO->cchStrings)
2133 pvStrings = kldrHlpAlloc(pModMachO->cchStrings);
[2961]2134 else
2135 pvStrings = kldrHlpAllocZ(4);
2136 if (pvStrings)
2137 {
2138 /* read */
2139 rc = kLdrRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols);
[2962]2140 if (!rc && pModMachO->cchStrings)
2141 rc = kLdrRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings);
[2961]2142 if (!rc)
2143 {
2144 pModMachO->pvaSymbols = pvSyms;
2145 pModMachO->pchStrings = (char *)pvStrings;
[2963]2146
[2961]2147 /* perform endian conversion? */
2148 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2149 {
2150 uint32_t cLeft = pModMachO->cSymbols;
2151 macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms;
2152 while (cLeft-- > 0)
2153 {
2154 pSym->n_un.n_strx = KLDRHLP_E2E_U32(pSym->n_un.n_strx);
2155 pSym->n_desc = (int16_t)KLDRHLP_E2E_U16(pSym->n_desc);
2156 pSym->n_value = KLDRHLP_E2E_U32(pSym->n_value);
2157 pSym++;
2158 }
[2963]2159 }
[2961]2160 else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
2161 {
2162 uint32_t cLeft = pModMachO->cSymbols;
2163 macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms;
2164 while (cLeft-- > 0)
2165 {
2166 pSym->n_un.n_strx = KLDRHLP_E2E_U32(pSym->n_un.n_strx);
2167 pSym->n_desc = (int16_t)KLDRHLP_E2E_U16(pSym->n_desc);
2168 pSym->n_value = KLDRHLP_E2E_U64(pSym->n_value);
2169 pSym++;
2170 }
2171 }
2172
2173 return 0;
2174 }
2175 kldrHlpFree(pvStrings);
2176 }
2177 kldrHlpFree(pvSyms);
2178 }
2179 }
2180 else
2181 KLDRMODMACHO_ASSERT(pModMachO->pchStrings);
2182
2183 return rc;
2184}
2185
2186
[2952]2187/**
[2963]2188 * Loads the fixups at the given address and performs endian
[2961]2189 * conversion if necessary.
[2963]2190 *
[2952]2191 * @returns 0 on success, non-zero kLdr status code on failure.
[2963]2192 * @param pModMachO The Mach-O module interpreter instance.
[2961]2193 * @param offFixups The file offset of the fixups.
2194 * @param cFixups The number of fixups to load.
2195 * @param ppaFixups Where to put the pointer to the allocated fixup array.
[2952]2196 */
[2961]2197static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, off_t offFixups, uint32_t cFixups, macho_relocation_info_t **ppaFixups)
[2952]2198{
[2961]2199 macho_relocation_info_t *paFixups;
2200 size_t cbFixups;
2201 int rc;
2202
2203 /* allocate the memory. */
2204 cbFixups = cFixups * sizeof(*paFixups);
2205 if (cbFixups / sizeof(*paFixups) != cFixups)
2206 return KLDR_ERR_SIZE_OVERFLOW;
2207 paFixups = (macho_relocation_info_t *)kldrHlpAlloc(cbFixups);
2208 if (!paFixups)
2209 return KLDR_ERR_NO_MEMORY;
2210
2211 /* read the fixups. */
2212 rc = kLdrRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups);
2213 if (!rc)
2214 {
2215 *ppaFixups = paFixups;
2216
2217 /* do endian conversion if necessary. */
[2963]2218 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
[2961]2219 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
2220 {
2221 uint32_t iFixup;
2222 for (iFixup = 0; iFixup < cFixups; iFixup++)
2223 {
2224 uint32_t *pu32 = (uint32_t *)&paFixups[iFixup];
2225 pu32[0] = KLDRHLP_E2E_U32(pu32[0]);
2226 pu32[1] = KLDRHLP_E2E_U32(pu32[1]);
2227 }
2228 }
2229 }
2230 else
2231 kldrHlpFree(paFixups);
2232 return rc;
[2952]2233}
2234
2235
[2963]2236/**
2237 * Maps the virgin file bits into memory if not already done.
2238 *
2239 * @returns 0 on success, non-zero kLdr status code on failure.
2240 * @param pModMachO The Mach-O module interpreter instance.
2241 */
2242static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO)
2243{
2244 int rc = 0;
2245 if (!pModMachO->pvBits)
2246 rc = kLdrRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits);
2247 return rc;
2248}
2249
2250
[2952]2251/** @copydoc kLdrModCallInit */
2252static int kldrModMachOCallInit(PKLDRMOD pMod, uintptr_t uHandle)
2253{
[2956]2254 /* later */
[2952]2255 return 0;
2256}
2257
2258
2259/** @copydoc kLdrModCallTerm */
2260static int kldrModMachOCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
2261{
[2956]2262 /* later */
[2952]2263 return 0;
2264}
2265
2266
2267/** @copydoc kLdrModCallThread */
2268static int kldrModMachOCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
2269{
[2956]2270 /* Relevant for Mach-O? */
[2952]2271 return 0;
2272}
2273
2274
2275/** @copydoc kLdrModSize */
2276static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
2277{
2278 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2955]2279 return pModMachO->cbImage;
[2952]2280}
2281
2282
2283/** @copydoc kLdrModGetBits */
2284static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2285{
2286 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2287 uint32_t i;
2288 int rc;
2289
2290 /*
2291 * Zero the entire buffer first to simplify things.
2292 */
[2956]2293 kLdrHlpMemSet(pvBits, 0, (size_t)pModMachO->cbImage);
[2952]2294
2295 /*
[2956]2296 * When possible use the segment table to load the data.
2297 * If not iterate the load commands and execute the segment / section loads.
[2952]2298 */
[2962]2299 if (pModMachO->fMapUsingLoadCommandSections)
2300 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
2301 else
[2952]2302 {
[2956]2303 for (i = 0; i < pMod->cSegments; i++)
2304 {
2305 /* skip it? */
2306 if ( pMod->aSegments[i].cbFile == -1
2307 || pMod->aSegments[i].offFile == -1
2308 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
2309 || !pMod->aSegments[i].Alignment)
2310 continue;
2311 rc = kLdrRdrRead(pMod->pRdr,
2312 (uint8_t *)pvBits + (pMod->aSegments[i].LinkAddress - pModMachO->LinkAddress),
2313 pMod->aSegments[i].cbFile,
2314 pMod->aSegments[i].offFile);
2315 if (rc)
2316 return rc;
2317 }
[2952]2318 }
2319
2320 /*
2321 * Perform relocations.
2322 */
[2956]2323 return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
[2952]2324}
2325
2326
2327/** @copydoc kLdrModRelocateBits */
2328static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
[2954]2329 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
[2952]2330{
2331 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2332 int rc;
2333
2334 /*
2335 * Call workers to do the jobs.
2336 */
[2961]2337 if (pModMachO->Hdr.filetype == MH_OBJECT)
2338 {
2339 rc = kldrModMachOObjDoImports(pModMachO, pfnGetImport, pvUser);
2340 if (!rc)
2341 rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress);
[2952]2342
[2961]2343 }
2344 else
2345 rc = KLDR_ERR_TODO;
2346 /*{
2347 rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
2348 if (!rc)
2349 rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
2350 }*/
2351
[2952]2352 return rc;
2353}
2354
2355
2356/**
[2954]2357 * The Mach-O module interpreter method table.
[2952]2358 */
[2954]2359KLDRMODOPS g_kLdrModMachOOps =
[2952]2360{
[2954]2361 "Mach-O",
[2952]2362 NULL,
2363 kldrModMachOCreate,
2364 kldrModMachODestroy,
2365 kldrModMachOQuerySymbol,
2366 kldrModMachOEnumSymbols,
2367 kldrModMachOGetImport,
2368 kldrModMachONumberOfImports,
2369 NULL /* can execute one is optional */,
2370 kldrModMachOGetStackInfo,
2371 kldrModMachOQueryMainEntrypoint,
2372 NULL,
2373 NULL,
2374 kldrModMachOEnumDbgInfo,
2375 kldrModMachOHasDbgInfo,
2376 kldrModMachOMap,
2377 kldrModMachOUnmap,
2378 kldrModMachOAllocTLS,
2379 kldrModMachOFreeTLS,
2380 kldrModMachOReload,
2381 kldrModMachOFixupMapping,
2382 kldrModMachOCallInit,
2383 kldrModMachOCallTerm,
2384 kldrModMachOCallThread,
2385 kldrModMachOSize,
2386 kldrModMachOGetBits,
2387 kldrModMachORelocateBits,
2388 NULL, /** @todo mostly done */
2389 42 /* the end */
2390};
2391
Note: See TracBrowser for help on using the repository browser.