source: trunk/kLdr/kLdrModMachO.c@ 2963

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

Implemented generic fixups for 32-bit symbol tables.

File size: 85.7 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:
[2954]559 if (pSect->reserved1 || pSect->reserved2)
560 return KLDR_ERR_MACHO_BAD_SECTION;
561 fFileBits = 1;
562 break;
563
564 case S_LITERAL_POINTERS:
565 case S_INTERPOSING:
566 case S_GB_ZEROFILL:
567 case S_NON_LAZY_SYMBOL_POINTERS:
568 case S_LAZY_SYMBOL_POINTERS:
569 case S_4BYTE_LITERALS:
570 case S_8BYTE_LITERALS:
571 case S_16BYTE_LITERALS:
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)
1769 return KLDR_ERR_TODO; /** @todo implement weak symbols. */
1770 }
1771 }
1772 else
1773 {
1774 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
1775 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols;
1776 for (iSym = 0; iSym < cSyms; iSym++)
1777 {
1778 /* skip stabs */
1779 if (paSyms[iSym].n_type & MACHO_N_STAB)
1780 continue;
[2952]1781
[2961]1782 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1783 {
1784 const char *pszSymbol;
1785 size_t cchSymbol;
1786 uint32_t fKind = KLDRSYMKIND_REQ_FLAT;
[2963]1787 KLDRADDR Value;
[2961]1788
1789 /** @todo Implement N_REF_TO_WEAK. */
1790 if (paSyms[iSym].n_desc & N_REF_TO_WEAK)
1791 return KLDR_ERR_TODO;
1792
1793 /* Get the symbol name and try resolve it. */
[2962]1794 if (paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
[2961]1795 return KLDR_ERR_MACHO_BAD_SYMBOL;
1796 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
1797 cchSymbol = kLdrHlpStrLen(pszSymbol);
1798 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
1799 &Value, &fKind, pvUser);
1800 if (rc)
[2952]1801 {
[2961]1802 /* weak reference? */
1803 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
1804 break;
1805 Value = 0;
1806 }
[2952]1807
[2961]1808 /* Update the symbol. */
1809 paSyms[iSym].n_value = Value;
1810 if (paSyms[iSym].n_value != Value)
1811 {
1812 rc = KLDR_ERR_ADDRESS_OVERFLOW;
[2952]1813 break;
1814 }
[2961]1815 }
1816 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
1817 return KLDR_ERR_TODO; /** @todo implement weak symbols. */
1818 }
1819 }
[2952]1820
[2961]1821 return rc;
1822}
[2952]1823
1824
[2961]1825/**
1826 * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
1827 *
1828 * @returns 0 on success, non-zero kLdr status code on failure.
1829 * @param pModMachO The Mach-O module interpreter instance.
1830 * @param pvMapping The mapping to fixup.
1831 * @param NewBaseAddress The address to fixup the mapping to.
1832 * @param OldBaseAddress The address the mapping is currently fixed up to.
1833 */
1834static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress)
1835{
1836 uint32_t iSeg;
1837 int rc;
[2952]1838
1839
[2961]1840 /*
1841 * Ensure that we've got the symbol table and section fixups handy.
1842 */
1843 rc = kldrModMachOLoadObjSymTab(pModMachO);
1844 if (rc)
1845 return rc;
[2952]1846
[2961]1847 /*
1848 * Iterate over the segments and their sections and apply fixups.
1849 */
1850 for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++)
1851 {
1852 PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg];
1853 uint32_t iSect;
1854
1855 for (iSect = 0; iSect < pSeg->cSections; iSect++)
1856 {
1857 PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect];
1858 uint8_t *pbSectBits;
1859
1860 /* skip sections without fixups. */
1861 if (!pSect->cFixups)
1862 continue;
1863
1864 /* lazy load (and endian convert) the fixups. */
1865 if (!pSect->paFixups)
1866 {
1867 rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
1868 if (rc)
[2952]1869 break;
[2961]1870 }
[2952]1871
[2961]1872 /*
1873 * Apply the fixups.
1874 */
1875 pbSectBits = (uint8_t *)pvMapping + (uintptr_t)pSect->RVA;
[2963]1876 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
1877 rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect,
1878 (macho_nlist_32_t *)pModMachO->pvaSymbols,
1879 pModMachO->cSymbols, NewBaseAddress);
1880 else
1881 rc = KLDR_ERR_TODO; /* save space for now. */
[2961]1882 if (rc)
1883 break;
[2952]1884 }
[2961]1885 }
[2952]1886
[2961]1887 return rc;
1888}
[2952]1889
1890
[2963]1891/**
1892 * Applies generic fixups to a section in an image of the same endian-ness
1893 * as the host CPU.
1894 *
1895 * @returns 0 on success, non-zero kLdr status code on failure.
1896 * @param pModMachO The Mach-O module interpreter instance.
1897 * @param pbSectBits Pointer to the section bits.
1898 * @param pFixupSect The section being fixed up.
1899 * @param NewBaseAddress The new base image address.
1900 */
1901static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, uint8_t *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
1902 macho_nlist_32_t *paSyms, uint32_t cSyms, KLDRADDR NewBaseAddress)
[2961]1903{
[2963]1904 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
1905 const uint32_t cFixups = pFixupSect->cFixups;
1906 size_t cbSectBits = (size_t)pFixupSect->cb;
1907 const uint8_t *pbSectVirginBits;
1908 uint32_t iFixup;
1909 KLDRPU uFixVirgin;
1910 KLDRPU uFix;
1911 KLDRADDR SymAddr;
1912 int rc;
[2961]1913
[2963]1914 /*
1915 * Find the virgin bits.
1916 */
1917 if (pFixupSect->offFile != -1)
1918 {
1919 rc = kldrModMachOMapVirginBits(pModMachO);
1920 if (rc)
1921 return rc;
1922 pbSectVirginBits = (const uint8_t *)pModMachO->pvBits + pFixupSect->offFile;
1923 }
1924 else
1925 pbSectVirginBits = NULL;
1926
1927 /*
1928 * Iterate the fixups and apply them.
1929 */
1930 for (iFixup = 0; iFixup < cFixups; iFixup++)
1931 {
1932 union
1933 {
1934 macho_relocation_info_t r;
1935 scattered_relocation_info_t s;
1936 } Fixup;
1937 Fixup.r = paFixups[iFixup];
1938
1939 if (!(Fixup.r.r_address & R_SCATTERED))
1940 {
1941 /* sanity */
1942 if ((uint32_t)Fixup.r.r_address >= cbSectBits)
1943 return KLDR_ERR_BAD_FIXUP;
1944
1945 /* calc fixup addresses. */
1946 uFix.pv = pbSectBits + Fixup.r.r_address;
1947 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.r.r_address : 0;
1948
1949 /*
1950 * Calc the symbol value.
1951 */
1952 /* The addend is stored in the code. */
1953 /** @todo Deal with unaligned accesses on non x86 platforms. */
1954 switch (Fixup.r.r_length)
1955 {
1956 case 0: SymAddr = *uFixVirgin.pi8; break;
1957 case 1: SymAddr = *uFixVirgin.pi16; break;
1958 case 2: SymAddr = *uFixVirgin.pi32; break;
1959 case 3: SymAddr = *uFixVirgin.pi64; break;
1960 }
1961
1962 /* Add symbol / section address. */
1963 if (Fixup.r.r_extern)
1964 {
1965 const macho_nlist_32_t *pSym;
1966 if (Fixup.r.r_symbolnum >= cSyms)
1967 return KLDR_ERR_BAD_FIXUP;
1968 pSym = &paSyms[Fixup.r.r_symbolnum];
1969
1970 if (pSym->n_type & MACHO_N_STAB)
1971 return KLDR_ERR_BAD_FIXUP;
1972
1973 switch (pSym->n_type & MACHO_N_TYPE)
1974 {
1975 case MACHO_N_SECT:
1976 {
1977 PKLDRMODMACHOSECT pSymSect;
1978 if ((uint32_t)pSym->n_sect - 1 > pModMachO->cSections)
1979 return KLDR_ERR_MACHO_BAD_SYMBOL;
1980 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
1981
1982 SymAddr += pSym->n_value - pModMachO->LinkAddress + pSymSect->RVA;
1983 break;
1984 }
1985
1986 case MACHO_N_UNDF:
1987 case MACHO_N_ABS:
1988 SymAddr += pSym->n_value;
1989 break;
1990
1991 case MACHO_N_INDR:
1992 case MACHO_N_PBUD:
1993 return KLDR_ERR_TODO;
1994 default:
1995 return KLDR_ERR_MACHO_BAD_SYMBOL;
1996 }
1997 }
1998 else if (Fixup.r.r_symbolnum != R_ABS)
1999 {
2000 PKLDRMODMACHOSECT pSymSect;
2001 if (Fixup.r.r_symbolnum > pModMachO->cSections)
2002 return KLDR_ERR_BAD_FIXUP;
2003 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
2004 SymAddr += NewBaseAddress + pSymSect->RVA;
2005 }
2006
2007 /* adjust for PC relative */
2008 if (Fixup.r.r_pcrel)
2009 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
2010 }
2011 else
2012 {
2013 PKLDRMODMACHOSECT pSymSect;
2014 uint32_t iSymSect;
2015 KLDRADDR Value;
2016
2017 /* sanity */
2018 KLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
2019 if ((uint32_t)Fixup.s.r_address >= cbSectBits)
2020 return KLDR_ERR_BAD_FIXUP;
2021
2022 /* calc fixup addresses. */
2023 uFix.pv = pbSectBits + Fixup.s.r_address;
2024 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.s.r_address : 0;
2025
2026 /*
2027 * Calc the symbol value.
2028 */
2029 /* The addend is stored in the code. */
2030 switch (Fixup.s.r_length)
2031 {
2032 case 0: SymAddr = *uFixVirgin.pi8; break;
2033 case 1: SymAddr = *uFixVirgin.pi16; break;
2034 case 2: SymAddr = *uFixVirgin.pi32; break;
2035 case 3: SymAddr = *uFixVirgin.pi64; break;
2036 }
2037
2038 /* Calc the section number from the r_value and adjust the value. */
2039 pSymSect = NULL;
2040 Value = Fixup.s.r_value - pModMachO->LinkAddress;
2041 for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++)
2042 {
2043 KLDRADDR off = Value - pModMachO->paSections[iSymSect].RVA;
2044 if (off < pModMachO->paSections[iSymSect].cb)
2045 {
2046 pSymSect = &pModMachO->paSections[iSymSect];
2047 break;
2048 }
2049 else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */
2050 pSymSect = &pModMachO->paSections[iSymSect];
2051 }
2052 if (!pSymSect)
2053 return KLDR_ERR_BAD_FIXUP;
2054
2055 /** @todo this looking up of the r_value section isn't strictly required unless we're going to remove sections from the link. */
2056 SymAddr += NewBaseAddress + pSymSect->RVA + (Value - pSymSect->RVA);
2057
2058 /* adjust for PC relative */
2059 if (Fixup.s.r_pcrel)
2060 SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
2061
2062 Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
2063 Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type;
2064 }
2065
2066 /*
2067 * Write back the fixed up value.
2068 */
2069 if (Fixup.r.r_type == GENERIC_RELOC_VANILLA)
2070 {
2071 switch (Fixup.r.r_length)
2072 {
2073 case 0: *uFix.pu8 = (uint8_t)SymAddr; break;
2074 case 1: *uFix.pu16 = (uint16_t)SymAddr; break;
2075 case 2: *uFix.pu32 = (uint32_t)SymAddr; break;
2076 case 3: *uFix.pu64 = (uint64_t)SymAddr; break;
2077 }
2078 }
2079 else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF)
2080 return KLDR_ERR_TODO;
2081 else
2082 return KLDR_ERR_BAD_FIXUP;
2083 }
2084
[2952]2085 return 0;
2086}
2087
2088
[2961]2089/**
2090 * Loads the symbol table for a MH_OBJECT file.
[2963]2091 *
[2961]2092 * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols.
[2963]2093 *
[2961]2094 * @returns 0 on success, non-zero kLdr status code on failure.
[2963]2095 * @param pModMachO The Mach-O module interpreter instance.
[2961]2096 */
2097static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO)
2098{
2099 int rc = 0;
[2952]2100
[2963]2101 if ( !pModMachO->pvaSymbols
[2961]2102 && pModMachO->cSymbols)
2103 {
2104 size_t cbSyms;
2105 size_t cbSym;
2106 void *pvSyms;
2107 void *pvStrings;
2108
2109 /* sanity */
2110 if ( !pModMachO->offSymbols
[2962]2111 || (pModMachO->cchStrings && !pModMachO->offStrings))
[2961]2112 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
2113
2114 /* allocate */
2115 cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2116 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
2117 ? sizeof(macho_nlist_32_t)
2118 : sizeof(macho_nlist_64_t);
2119 cbSyms = pModMachO->cSymbols * cbSym;
2120 if (cbSyms / cbSym != pModMachO->cSymbols)
2121 return KLDR_ERR_SIZE_OVERFLOW;
2122 rc = KLDR_ERR_NO_MEMORY;
2123 pvSyms = kldrHlpAlloc(cbSyms);
2124 if (pvSyms)
2125 {
[2962]2126 if (pModMachO->cchStrings)
2127 pvStrings = kldrHlpAlloc(pModMachO->cchStrings);
[2961]2128 else
2129 pvStrings = kldrHlpAllocZ(4);
2130 if (pvStrings)
2131 {
2132 /* read */
2133 rc = kLdrRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols);
[2962]2134 if (!rc && pModMachO->cchStrings)
2135 rc = kLdrRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings);
[2961]2136 if (!rc)
2137 {
2138 pModMachO->pvaSymbols = pvSyms;
2139 pModMachO->pchStrings = (char *)pvStrings;
[2963]2140
[2961]2141 /* perform endian conversion? */
2142 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2143 {
2144 uint32_t cLeft = pModMachO->cSymbols;
2145 macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms;
2146 while (cLeft-- > 0)
2147 {
2148 pSym->n_un.n_strx = KLDRHLP_E2E_U32(pSym->n_un.n_strx);
2149 pSym->n_desc = (int16_t)KLDRHLP_E2E_U16(pSym->n_desc);
2150 pSym->n_value = KLDRHLP_E2E_U32(pSym->n_value);
2151 pSym++;
2152 }
[2963]2153 }
[2961]2154 else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
2155 {
2156 uint32_t cLeft = pModMachO->cSymbols;
2157 macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms;
2158 while (cLeft-- > 0)
2159 {
2160 pSym->n_un.n_strx = KLDRHLP_E2E_U32(pSym->n_un.n_strx);
2161 pSym->n_desc = (int16_t)KLDRHLP_E2E_U16(pSym->n_desc);
2162 pSym->n_value = KLDRHLP_E2E_U64(pSym->n_value);
2163 pSym++;
2164 }
2165 }
2166
2167 return 0;
2168 }
2169 kldrHlpFree(pvStrings);
2170 }
2171 kldrHlpFree(pvSyms);
2172 }
2173 }
2174 else
2175 KLDRMODMACHO_ASSERT(pModMachO->pchStrings);
2176
2177 return rc;
2178}
2179
2180
[2952]2181/**
[2963]2182 * Loads the fixups at the given address and performs endian
[2961]2183 * conversion if necessary.
[2963]2184 *
[2952]2185 * @returns 0 on success, non-zero kLdr status code on failure.
[2963]2186 * @param pModMachO The Mach-O module interpreter instance.
[2961]2187 * @param offFixups The file offset of the fixups.
2188 * @param cFixups The number of fixups to load.
2189 * @param ppaFixups Where to put the pointer to the allocated fixup array.
[2952]2190 */
[2961]2191static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, off_t offFixups, uint32_t cFixups, macho_relocation_info_t **ppaFixups)
[2952]2192{
[2961]2193 macho_relocation_info_t *paFixups;
2194 size_t cbFixups;
2195 int rc;
2196
2197 /* allocate the memory. */
2198 cbFixups = cFixups * sizeof(*paFixups);
2199 if (cbFixups / sizeof(*paFixups) != cFixups)
2200 return KLDR_ERR_SIZE_OVERFLOW;
2201 paFixups = (macho_relocation_info_t *)kldrHlpAlloc(cbFixups);
2202 if (!paFixups)
2203 return KLDR_ERR_NO_MEMORY;
2204
2205 /* read the fixups. */
2206 rc = kLdrRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups);
2207 if (!rc)
2208 {
2209 *ppaFixups = paFixups;
2210
2211 /* do endian conversion if necessary. */
[2963]2212 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
[2961]2213 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
2214 {
2215 uint32_t iFixup;
2216 for (iFixup = 0; iFixup < cFixups; iFixup++)
2217 {
2218 uint32_t *pu32 = (uint32_t *)&paFixups[iFixup];
2219 pu32[0] = KLDRHLP_E2E_U32(pu32[0]);
2220 pu32[1] = KLDRHLP_E2E_U32(pu32[1]);
2221 }
2222 }
2223 }
2224 else
2225 kldrHlpFree(paFixups);
2226 return rc;
[2952]2227}
2228
2229
[2963]2230/**
2231 * Maps the virgin file bits into memory if not already done.
2232 *
2233 * @returns 0 on success, non-zero kLdr status code on failure.
2234 * @param pModMachO The Mach-O module interpreter instance.
2235 */
2236static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO)
2237{
2238 int rc = 0;
2239 if (!pModMachO->pvBits)
2240 rc = kLdrRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits);
2241 return rc;
2242}
2243
2244
[2952]2245/** @copydoc kLdrModCallInit */
2246static int kldrModMachOCallInit(PKLDRMOD pMod, uintptr_t uHandle)
2247{
[2956]2248 /* later */
[2952]2249 return 0;
2250}
2251
2252
2253/** @copydoc kLdrModCallTerm */
2254static int kldrModMachOCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
2255{
[2956]2256 /* later */
[2952]2257 return 0;
2258}
2259
2260
2261/** @copydoc kLdrModCallThread */
2262static int kldrModMachOCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
2263{
[2956]2264 /* Relevant for Mach-O? */
[2952]2265 return 0;
2266}
2267
2268
2269/** @copydoc kLdrModSize */
2270static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
2271{
2272 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2955]2273 return pModMachO->cbImage;
[2952]2274}
2275
2276
2277/** @copydoc kLdrModGetBits */
2278static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2279{
2280 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2281 uint32_t i;
2282 int rc;
2283
2284 /*
2285 * Zero the entire buffer first to simplify things.
2286 */
[2956]2287 kLdrHlpMemSet(pvBits, 0, (size_t)pModMachO->cbImage);
[2952]2288
2289 /*
[2956]2290 * When possible use the segment table to load the data.
2291 * If not iterate the load commands and execute the segment / section loads.
[2952]2292 */
[2962]2293 if (pModMachO->fMapUsingLoadCommandSections)
2294 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
2295 else
[2952]2296 {
[2956]2297 for (i = 0; i < pMod->cSegments; i++)
2298 {
2299 /* skip it? */
2300 if ( pMod->aSegments[i].cbFile == -1
2301 || pMod->aSegments[i].offFile == -1
2302 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
2303 || !pMod->aSegments[i].Alignment)
2304 continue;
2305 rc = kLdrRdrRead(pMod->pRdr,
2306 (uint8_t *)pvBits + (pMod->aSegments[i].LinkAddress - pModMachO->LinkAddress),
2307 pMod->aSegments[i].cbFile,
2308 pMod->aSegments[i].offFile);
2309 if (rc)
2310 return rc;
2311 }
[2952]2312 }
2313
2314 /*
2315 * Perform relocations.
2316 */
[2956]2317 return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
[2952]2318}
2319
2320
2321/** @copydoc kLdrModRelocateBits */
2322static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
[2954]2323 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
[2952]2324{
2325 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2326 int rc;
2327
2328 /*
2329 * Call workers to do the jobs.
2330 */
[2961]2331 if (pModMachO->Hdr.filetype == MH_OBJECT)
2332 {
2333 rc = kldrModMachOObjDoImports(pModMachO, pfnGetImport, pvUser);
2334 if (!rc)
2335 rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress);
[2952]2336
[2961]2337 }
2338 else
2339 rc = KLDR_ERR_TODO;
2340 /*{
2341 rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
2342 if (!rc)
2343 rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
2344 }*/
2345
[2952]2346 return rc;
2347}
2348
2349
2350/**
[2954]2351 * The Mach-O module interpreter method table.
[2952]2352 */
[2954]2353KLDRMODOPS g_kLdrModMachOOps =
[2952]2354{
[2954]2355 "Mach-O",
[2952]2356 NULL,
2357 kldrModMachOCreate,
2358 kldrModMachODestroy,
2359 kldrModMachOQuerySymbol,
2360 kldrModMachOEnumSymbols,
2361 kldrModMachOGetImport,
2362 kldrModMachONumberOfImports,
2363 NULL /* can execute one is optional */,
2364 kldrModMachOGetStackInfo,
2365 kldrModMachOQueryMainEntrypoint,
2366 NULL,
2367 NULL,
2368 kldrModMachOEnumDbgInfo,
2369 kldrModMachOHasDbgInfo,
2370 kldrModMachOMap,
2371 kldrModMachOUnmap,
2372 kldrModMachOAllocTLS,
2373 kldrModMachOFreeTLS,
2374 kldrModMachOReload,
2375 kldrModMachOFixupMapping,
2376 kldrModMachOCallInit,
2377 kldrModMachOCallTerm,
2378 kldrModMachOCallThread,
2379 kldrModMachOSize,
2380 kldrModMachOGetBits,
2381 kldrModMachORelocateBits,
2382 NULL, /** @todo mostly done */
2383 42 /* the end */
2384};
2385
Note: See TracBrowser for help on using the repository browser.