source: trunk/kLdr/kLdrModMachO.c@ 2956

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

Work in progress...

File size: 66.4 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
[2954]36/* quick hack for now. */
37typedef struct nlist
38{
39 uint32_t n_strx;
40 uint8_t n_type;
41 int8_t n_other;
42 int16_t n_desc;
43 uint32_t n_value;
44} nlist_t;
[2952]45
[2954]46
[2952]47/*******************************************************************************
48* Defined Constants And Macros *
49*******************************************************************************/
50/** @def KLDRMODMACHO_STRICT
51 * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */
52#define KLDRMODMACHO_STRICT 1
53
54/** @def KLDRMODMACHO_ASSERT
55 * Assert that an expression is true when KLDR_STRICT is defined.
56 */
57#ifdef KLDRMODMACHO_STRICT
58# define KLDRMODMACHO_ASSERT(expr) kldrHlpAssert(expr)
59#else
60# define KLDRMODMACHO_ASSERT(expr) do {} while (0)
61#endif
62
63/** @def KLDRMODMACHO_RVA2TYPE
64 * Converts a RVA to a pointer of the specified type.
65 * @param pvBits The bits (image base).
66 * @param uRVA The image relative virtual address.
67 * @param type The type to cast to.
68 */
69#define KLDRMODMACHO_RVA2TYPE(pvBits, uRVA, type) \
70 ( (type) ((uintptr_t)(pvBits) + (uintptr_t)(uRVA)) )
71
72/** @def KLDRMODMACHO_VALID_RVA
73 * Checks that the specified RVA value is non-zero and within the bounds of the image.
74 * @returns true/false.
75 * @param pModPE The PE module interpreter instance.
76 * @param uRVA The RVA to validate.
77 */
78#define KLDRMODMACHO_VALID_RVA(pModPE, uRVA) \
79 ( (uRVA) && (uRVA) < (pModPE)->Hdrs.OptionalHeader.SizeOfImage )
80
81
82
83/*******************************************************************************
84* Structures and Typedefs *
85*******************************************************************************/
86/**
[2954]87 * Instance data for the Mach-O MH_OBJECT module interpreter.
[2952]88 * @todo interpret the other MH_* formats.
89 */
90typedef struct KLDRMODMACHO
91{
92 /** Pointer to the module. (Follows the section table.) */
93 PKLDRMOD pMod;
94 /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */
95 const void *pvBits;
96 /** Pointer to the user mapping. */
97 const void *pvMapping;
98
99 /** The link address. */
100 KLDRADDR LinkAddress;
[2955]101 /** The size of the mapped image. */
102 KLDRADDR cbImage;
[2956]103 /** When set the sections in the load command segments must be used when
104 * mapping or loading the image. */
105 int fMapUsingLoadCommandSections;
[2952]106
107 /** Pointer to the load commands. (endian converted) */
108 uint8_t *pbLoadCommands;
109 /** The Mach-O header. (endian converted)
110 * @remark The reserved field is only valid for real 64-bit headers. */
111 mach_header_64_t Hdr;
112
113 /** The offset of the symbol table. */
114 off_t offSymbols;
115 /** The number of symbols. */
116 uint32_t cSymbols;
117 /** The pointer to the loaded symbol table. */
118 void *paSymbols;
119 /** The offset of the string table. */
120 off_t offStrings;
121 /** The size of the of the string table. */
122 uint32_t cbStrings;
123 /** Pointer to the loaded string table. */
124 char *pbStrings;
125} KLDRMODMACHO, *PKLDRMODMACHO;
126
127
128/*******************************************************************************
129* Internal Functions *
130*******************************************************************************/
131#if 0
132static int32_t kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits);
133#endif
[2956]134static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
135 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
[2952]136
137static int kldrModMachODoCreate(PKLDRRDR pRdr, PKLDRMODMACHO *ppMod);
[2954]138static int kldrModMachOPreParseLoadCommands(uint8_t *pbLoadCommands, const mach_header_32_t *pHdr, PKLDRRDR pRdr,
[2952]139 uint32_t *pcSegments, uint32_t *pcbStringPool);
140static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, uint32_t cbStringPool);
[2956]141static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO);
[2952]142static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
143static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
144
145
146/**
147 * Create a loader module instance interpreting the executable image found
148 * in the specified file provider instance.
149 *
150 * @returns 0 on success and *ppMod pointing to a module instance.
151 * On failure, a non-zero OS specific error code is returned.
152 * @param pOps Pointer to the registered method table.
153 * @param pRdr The file provider instance to use.
154 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
155 * @param ppMod Where to store the module instance pointer.
156 */
157static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
158{
159 PKLDRMODMACHO pModMachO;
160 int rc;
161
162 /*
163 * Create the instance data and do a minimal header validation.
164 */
165 rc = kldrModMachODoCreate(pRdr, &pModMachO);
166 if (!rc)
167 {
168 pModMachO->pMod->pOps = pOps;
169 pModMachO->pMod->u32Magic = KLDRMOD_MAGIC;
170 *ppMod = pModMachO->pMod;
171 return 0;
172 }
173 if (pModMachO)
174 {
175 kldrHlpFree(pModMachO->pbLoadCommands);
176 kldrHlpFree(pModMachO);
177 }
178 return rc;
179}
180
181
182/**
183 * Separate function for reading creating the PE module instance to
184 * simplify cleanup on failure.
185 */
186static int kldrModMachODoCreate(PKLDRRDR pRdr, PKLDRMODMACHO *ppModMachO)
187{
188 union
189 {
190 mach_header_32_t Hdr32;
191 mach_header_64_t Hdr64;
192 } s;
193 PKLDRMODMACHO pModMachO;
194 PKLDRMOD pMod;
195 uint8_t *pbLoadCommands;
196 uint32_t cSegments;
197 uint32_t cbStringPool;
198 size_t cchFilename;
199 size_t cb;
200 int rc;
201 *ppModMachO = NULL;
202
203 /*
204 * Read the Mach-O header.
205 */
206 rc = kLdrRdrRead(pRdr, &s, sizeof(s), 0);
207 if (rc)
208 return rc;
209 if (s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
210 {
211 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
212 || s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE)
213 return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED;
214 if (s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE)
215 return KLDR_ERR_MACHO_64BIT_NOT_SUPPORTED;
216 return KLDR_ERR_UNKNOWN_FORMAT;
217 }
218
219 /* sanity checks. */
220 if ( s.Hdr32.sizeofcmds > kLdrRdrSize(pRdr) - sizeof(mach_header_32_t)
221 || s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds
222 || (s.Hdr32.flags & ~MH_VALID_FLAGS))
223 return KLDR_ERR_MACHO_BAD_HEADER;
224 switch (s.Hdr32.cputype)
225 {
226 case CPU_TYPE_X86:
227 case CPU_TYPE_X86_64:
228 break;
229 default:
230 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
231 }
232 if (s.Hdr32.filetype != MH_OBJECT)
233 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
234
235 /*
236 * Read and pre-parse the load commands to figure out how many segments we'll be needing.
237 */
238 pbLoadCommands = kldrHlpAlloc(s.Hdr32.sizeofcmds);
239 if (!pbLoadCommands)
240 return KLDR_ERR_NO_MEMORY;
241 rc = kLdrRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds,
242 s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
243 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
244 ? sizeof(mach_header_32_t) : sizeof(mach_header_64_t));
245 if (!rc)
[2954]246 rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, &cSegments, &cbStringPool);
[2952]247 if (rc)
248 {
249 kldrHlpFree(pbLoadCommands);
250 return rc;
251 }
252
253
254 /*
255 * Calc the instance size, allocate and initialize it.
256 */
257 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
258 cb = KLDR_ALIGN_Z(sizeof(KLDRMODMACHO), 16)
259 + KLDR_OFFSETOF(KLDRMOD, aSegments[cSegments])
260 + cchFilename + 1
261 + cbStringPool;
262 pModMachO = (PKLDRMODMACHO)kldrHlpAlloc(cb);
263 if (!pModMachO)
264 return KLDR_ERR_NO_MEMORY;
265 *ppModMachO = pModMachO;
266 pModMachO->pbLoadCommands = pbLoadCommands;
267
268 /* KLDRMOD */
269 pMod = (PKLDRMOD)((uint8_t *)pModMachO + KLDR_ALIGN_Z(sizeof(KLDRMODMACHO), 16));
270 pMod->pvData = pModMachO;
271 pMod->pRdr = pRdr;
272 pMod->pOps = NULL; /* set upon success. */
273 pMod->cSegments = cSegments;
274 pMod->cchFilename = cchFilename;
275 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
276 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
277 pMod->pszName = kldrHlpGetFilename(pMod->pszFilename);
278 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
279 switch (s.Hdr32.cputype)
280 {
281 case CPU_TYPE_X86:
282 pMod->enmArch = KLDRARCH_X86_32;
283 pMod->enmEndian = KLDRENDIAN_LITTLE;
284 switch (s.Hdr32.cpusubtype)
285 {
286 case CPU_SUBTYPE_I386_ALL: pMod->enmCpu = KLDRCPU_X86_32_BLEND; break;
287 /*case CPU_SUBTYPE_386: ^^ pMod->enmCpu = KLDRCPU_I386; break;*/
288 case CPU_SUBTYPE_486: pMod->enmCpu = KLDRCPU_I486; break;
289 case CPU_SUBTYPE_486SX: pMod->enmCpu = KLDRCPU_I486SX; break;
290 /*case CPU_SUBTYPE_586: vv */
291 case CPU_SUBTYPE_PENT: pMod->enmCpu = KLDRCPU_I586; break;
292 case CPU_SUBTYPE_PENTPRO:
293 case CPU_SUBTYPE_PENTII_M3:
294 case CPU_SUBTYPE_PENTII_M5:
295 case CPU_SUBTYPE_CELERON:
296 case CPU_SUBTYPE_CELERON_MOBILE:
297 case CPU_SUBTYPE_PENTIUM_3:
298 case CPU_SUBTYPE_PENTIUM_3_M:
299 case CPU_SUBTYPE_PENTIUM_3_XEON: pMod->enmCpu = KLDRCPU_I686; break;
300 case CPU_SUBTYPE_PENTIUM_M:
301 case CPU_SUBTYPE_PENTIUM_4:
302 case CPU_SUBTYPE_PENTIUM_4_M:
303 case CPU_SUBTYPE_XEON:
304 case CPU_SUBTYPE_XEON_MP: pMod->enmCpu = KLDRCPU_P4; break;
305 break;
306 default:
307 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
308 }
309 break;
310
311 case CPU_TYPE_X86_64:
312 pMod->enmArch = KLDRARCH_AMD64;
313 pMod->enmEndian = KLDRENDIAN_LITTLE;
314 switch (s.Hdr32.cpusubtype)
315 {
316 case CPU_SUBTYPE_X86_64_ALL: pMod->enmCpu = KLDRCPU_AMD64_BLEND; break;
317 default:
318 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
319 }
320 break;
321
322 default:
323 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
324 }
325
326 pMod->enmFmt = KLDRFMT_MACHO;
327 switch (s.Hdr32.filetype)
328 {
329 case MH_OBJECT:
330 pMod->enmType = KLDRTYPE_OBJECT;
331 break;
332 default:
333 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
334 }
335 pMod->u32Magic = 0; /* set upon success. */
336
337 /* KLDRMODMACHO */
338 pModMachO->pMod = pMod;
339 pModMachO->pvBits = NULL;
340 pModMachO->pvMapping = NULL;
341 pModMachO->Hdr = s.Hdr64;
342 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
343 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE)
344 pModMachO->Hdr.reserved = 0;
345 pModMachO->LinkAddress = 0;
[2955]346 pModMachO->cbImage = 0;
[2956]347 pModMachO->fMapUsingLoadCommandSections = 0;
[2952]348 pModMachO->offSymbols = 0;
349 pModMachO->cSymbols = 0;
350 pModMachO->paSymbols = NULL;
351 pModMachO->offStrings = 0;
352 pModMachO->cbStrings = 0;
353 pModMachO->pbStrings = NULL;
354
355 /*
356 * Setup the KLDRMOD segment array.
357 */
358 rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool);
359 if (rc)
360 return rc;
361
362 /*
363 * We're done.
364 */
365 return 0;
366}
367
368
369/**
370 * Converts, validates and preparses the load commands before we carve
371 * out the module instance.
372 *
373 * The conversion that's preformed is format endian to host endian.
374 * The preparsing has to do with segment counting and string pool sizing.
375 *
376 * @returns 0 on success.
377 * @returns KLDR_ERR_MACHO_* on failure.
378 * @param pbLoadCommands The load commands to parse.
379 * @param pHdr The header.
[2954]380 * @param pRdr The file reader.
[2952]381 * @param pcSegments Where to store the segment count.
382 * @param pcbStringPool Where to store the string pool size.
383 */
[2954]384static int kldrModMachOPreParseLoadCommands(uint8_t *pbLoadCommands, const mach_header_32_t *pHdr, PKLDRRDR pRdr,
[2952]385 uint32_t *pcSegments, uint32_t *pcbStringPool)
386{
[2954]387 union
388 {
389 uint8_t *pb;
390 load_command_t *pLoadCmd;
391 segment_command_32_t *pSeg32;
392 segment_command_64_t *pSeg64;
393 thread_command_t *pThread;
394 symtab_command_t *pSymTab;
395 uuid_command_t *pUuid;
396 } u;
397 const uint64_t cbFile = kLdrRdrSize(pRdr);
398 uint32_t cSegments = 0;
399 uint32_t cbStringPool = 0;
400 uint32_t cLeft = pHdr->ncmds;
401 uint32_t cbLeft = pHdr->sizeofcmds;
402 uint8_t *pb = pbLoadCommands;
[2956]403 int cSegmentCommands = 0;
404 int cSymbolTabs = 0;
405 int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
406 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
[2954]407
[2952]408 *pcSegments = 0;
409 *pcbStringPool = 0;
[2954]410
411 while (cLeft-- > 0)
412 {
413 u.pb = pb;
414
415 /*
416 * Convert and validate command header.
417 */
418 if (cbLeft < sizeof(load_command_t))
419 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
420 if (fConvertEndian)
421 {
422 u.pLoadCmd->cmd = KLDRHLP_E2E_U32(u.pLoadCmd->cmd);
423 u.pLoadCmd->cmdsize = KLDRHLP_E2E_U32(u.pLoadCmd->cmdsize);
424 }
425 if (u.pLoadCmd->cmdsize > cbLeft)
426 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
427 cbLeft -= u.pLoadCmd->cmdsize;
428 pb += u.pLoadCmd->cmdsize;
429
430 /*
431 * Convert endian if needed, parse and validate the command.
432 */
433 switch (u.pLoadCmd->cmd)
434 {
435 case LC_SEGMENT_32:
436 {
437 section_32_t *pSect;
438 section_32_t *pFirstSect;
439 uint32_t cSectionsLeft;
440
441 /* convert and verify*/
442 if (u.pLoadCmd->cmdsize < sizeof(segment_command_32_t))
443 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
[2955]444 if ( pHdr->magic != IMAGE_MACHO32_SIGNATURE_OE
445 && pHdr->magic != IMAGE_MACHO32_SIGNATURE)
446 return KLDR_ERR_MACHO_BIT_MIX;
[2954]447 if (fConvertEndian)
448 {
449 u.pSeg32->vmaddr = KLDRHLP_E2E_U32(u.pSeg32->vmaddr);
450 u.pSeg32->vmsize = KLDRHLP_E2E_U32(u.pSeg32->vmsize);
451 u.pSeg32->fileoff = KLDRHLP_E2E_U32(u.pSeg32->fileoff);
452 u.pSeg32->filesize = KLDRHLP_E2E_U32(u.pSeg32->filesize);
453 u.pSeg32->maxprot = KLDRHLP_E2E_U32(u.pSeg32->maxprot);
454 u.pSeg32->initprot = KLDRHLP_E2E_U32(u.pSeg32->initprot);
455 u.pSeg32->nsects = KLDRHLP_E2E_U32(u.pSeg32->nsects);
456 u.pSeg32->flags = KLDRHLP_E2E_U32(u.pSeg32->flags);
457 }
458
459 if ( u.pSeg32->filesize
460 && ( u.pSeg32->fileoff > cbFile
461 || (uint64_t)u.pSeg32->fileoff + u.pSeg32->filesize > cbFile))
462 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
463 if (!u.pSeg32->filesize && u.pSeg32->fileoff)
464 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
465 if (u.pSeg32->vmsize < u.pSeg32->filesize)
466 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
467 if ((u.pSeg32->maxprot & u.pSeg32->initprot) != u.pSeg32->initprot)
468 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
469 if (u.pSeg32->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
470 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
471 if (u.pSeg32->nsects * sizeof(section_32_t) > u.pLoadCmd->cmdsize - sizeof(segment_command_32_t))
472 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
[2955]473 if ( pHdr->filetype == MH_OBJECT
474 && cSegmentCommands > 0)
475 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
476 cSegmentCommands++;
[2954]477
478 /*
479 * convert, validate and parse the sections.
480 */
481 cSectionsLeft = u.pSeg32->nsects;
482 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
483 while (cSectionsLeft-- > 0)
484 {
485 int fFileBits;
486
487 if (fConvertEndian)
488 {
489 pSect->addr = KLDRHLP_E2E_U32(pSect->addr);
490 pSect->size = KLDRHLP_E2E_U32(pSect->size);
491 pSect->offset = KLDRHLP_E2E_U32(pSect->offset);
492 pSect->align = KLDRHLP_E2E_U32(pSect->align);
493 pSect->reloff = KLDRHLP_E2E_U32(pSect->reloff);
494 pSect->nreloc = KLDRHLP_E2E_U32(pSect->nreloc);
495 pSect->flags = KLDRHLP_E2E_U32(pSect->flags);
496 pSect->reserved1 = KLDRHLP_E2E_U32(pSect->reserved1);
497 pSect->reserved2 = KLDRHLP_E2E_U32(pSect->reserved2);
498 }
499
500 /* validate */
501 switch (pSect->flags & SECTION_TYPE)
502 {
503 case S_ZEROFILL:
504 if (pSect->reserved1 || pSect->reserved2)
505 return KLDR_ERR_MACHO_BAD_SECTION;
506 fFileBits = 0;
507 break;
508 case S_REGULAR:
509 case S_CSTRING_LITERALS:
510 if (pSect->reserved1 || pSect->reserved2)
511 return KLDR_ERR_MACHO_BAD_SECTION;
512 fFileBits = 1;
513 break;
514
515 case S_LITERAL_POINTERS:
516 case S_INTERPOSING:
517 case S_GB_ZEROFILL:
518 case S_NON_LAZY_SYMBOL_POINTERS:
519 case S_LAZY_SYMBOL_POINTERS:
520 case S_4BYTE_LITERALS:
521 case S_8BYTE_LITERALS:
522 case S_16BYTE_LITERALS:
523 case S_SYMBOL_STUBS:
524 case S_COALESCED:
525 case S_MOD_INIT_FUNC_POINTERS:
526 case S_MOD_TERM_FUNC_POINTERS:
527 return KLDR_ERR_MACHO_UNSUPPORTED_SECTION;
528
529 default:
530 return KLDR_ERR_MACHO_UNKNOWN_SECTION;
531 }
532 if (pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS
533 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE
534 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC
535 | S_ATTR_LOC_RELOC | SECTION_TYPE))
536 return KLDR_ERR_MACHO_BAD_SECTION;
537 if (!pSect->size)
538 return KLDR_ERR_MACHO_BAD_SECTION;
539 if ( pSect->addr - u.pSeg32->vmaddr > u.pSeg32->vmsize
540 || pSect->addr - u.pSeg32->vmaddr + pSect->size > u.pSeg32->vmsize)
541 return KLDR_ERR_MACHO_BAD_SECTION;
542 if ( pSect->align >= 31
543 || (((1 << pSect->align) - 1) & pSect->addr)
544 || (((1 << pSect->align) - 1) & u.pSeg32->vmaddr))
545 return KLDR_ERR_MACHO_BAD_SECTION;
546 if ( fFileBits
547 && ( pSect->offset > cbFile
548 || (uint64_t)pSect->offset + pSect->size > cbFile))
549 return KLDR_ERR_MACHO_BAD_SECTION;
550 if (!fFileBits && pSect->offset)
551 return KLDR_ERR_MACHO_BAD_SECTION;
552 if (!pSect->nreloc && pSect->reloff)
553 return KLDR_ERR_MACHO_BAD_SECTION;
554 if ( pSect->nreloc
555 && ( pSect->reloff > cbFile
556 || (uint64_t)pSect->reloff + (off_t)pSect->nreloc * sizeof(nlist_t)) > cbFile)
557 return KLDR_ERR_MACHO_BAD_SECTION;
558
559
560 /* count segments and strings */
561 switch (pHdr->filetype)
562 {
563 case MH_OBJECT:
564 {
565 /* Don't load debug symbols. (test this) */
566 if (pSect->flags & S_ATTR_DEBUG)
567 break;
568
569 /* a new segment? */
[2955]570 if ( !cSegments
[2954]571 || kLdrHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
572 {
573 /* verify that the linker/assembler has ordered sections correctly. */
574 section_32_t *pCur = (pSect - 2);
575 while ((uintptr_t)pCur >= (uintptr_t)pFirstSect)
576 {
577 if (!kLdrHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
578 return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
579 pCur--;
580 }
581
582 /* ok. count it and the string. */
583 cSegments++;
[2955]584 cbStringPool += kLdrHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1;
[2954]585 }
586 break;
587 }
588
589 default:
590 return KLDR_ERR_INVALID_PARAMETER;
591 }
592
593 /* next */
594 pSect++;
595 }
596 break;
597 }
598
[2955]599 /*case LC_SEGMENT_64:
600 copy 32-bit code
[2954]601 break;
[2955]602 */
[2954]603
604 case LC_SYMTAB:
605 if (fConvertEndian)
606 {
607 u.pSymTab->symoff = KLDRHLP_E2E_U32(u.pSymTab->symoff);
608 u.pSymTab->nsyms = KLDRHLP_E2E_U32(u.pSymTab->nsyms);
609 u.pSymTab->stroff = KLDRHLP_E2E_U32(u.pSymTab->stroff);
610 u.pSymTab->strsize = KLDRHLP_E2E_U32(u.pSymTab->strsize);
611 }
612
613 /* verify */
614 if ( u.pSymTab->symoff >= cbFile
615 || (uint64_t)u.pSymTab->symoff + u.pSymTab->nsyms * sizeof(nlist_t) > kLdrRdrSize(pRdr))
616 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
617 if ( u.pSymTab->stroff >= cbFile
618 || (uint64_t)u.pSymTab->stroff + u.pSymTab->strsize > cbFile)
619 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
[2956]620
621 /* only one string in objects, please. */
622 cSymbolTabs++;
623 if ( pHdr->filetype == MH_OBJECT
624 && cSymbolTabs != 1)
625 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
[2954]626 break;
627
628 case LC_THREAD:
629 case LC_UNIXTHREAD:
630 {
631 uint32_t *pu32 = (uint32_t *)(u.pb + sizeof(load_command_t));
632 uint32_t cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(uint32_t);
633 while (cItemsLeft)
634 {
635 /* convert & verify header items ([0] == flavor, [1] == uint32_t count). */
636 if (cItemsLeft < 2)
637 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
638 if (fConvertEndian)
639 {
640 pu32[0] = KLDRHLP_E2E_U32(pu32[0]);
641 pu32[1] = KLDRHLP_E2E_U32(pu32[1]);
642 }
643 if (pu32[1] + 2 > cItemsLeft)
644 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
645
646 /* convert & verify according to flavor. */
647 switch (pu32[0])
648 {
649 /** @todo */
650 default:
651 break;
652 }
653
654 /* next */
655 cItemsLeft -= pu32[1] + 2;
656 pu32 += pu32[1] + 2;
657 }
658 break;
659 }
660
661 case LC_UUID:
662 if (u.pUuid->cmdsize != sizeof(uuid_command_t))
663 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
664 /** @todo Check anything here need converting? */
665 break;
666
[2955]667 case LC_SEGMENT_64:
[2954]668 case LC_LOADFVMLIB:
669 case LC_IDFVMLIB:
670 case LC_IDENT:
671 case LC_FVMFILE:
672 case LC_PREPAGE:
673 case LC_DYSYMTAB:
674 case LC_LOAD_DYLIB:
675 case LC_ID_DYLIB:
676 case LC_LOAD_DYLINKER:
677 case LC_ID_DYLINKER:
678 case LC_PREBOUND_DYLIB:
679 case LC_ROUTINES:
680 case LC_ROUTINES_64:
681 case LC_SUB_FRAMEWORK:
682 case LC_SUB_UMBRELLA:
683 case LC_SUB_CLIENT:
684 case LC_SUB_LIBRARY:
685 case LC_TWOLEVEL_HINTS:
686 case LC_PREBIND_CKSUM:
687 case LC_LOAD_WEAK_DYLIB:
688 case LC_SYMSEG:
689 return KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND;
690
691 default:
692 return KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND;
693 }
694 }
695
[2955]696 /* be strict. */
[2954]697 if (cbLeft)
698 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
699
[2955]700 switch (pHdr->filetype)
701 {
702 case MH_OBJECT:
703 if (!cSegments)
704 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
705 break;
706 }
707
[2954]708 *pcSegments = cSegments;
[2955]709 *pcbStringPool = cbStringPool;
[2954]710
[2952]711 return 0;
712}
713
714
715/**
716 * Parses the load commands after we've carved out the module instance.
717 *
718 * This fills in the segment table and perhaps some other properties.
719 *
720 * @returns 0 on success.
721 * @returns KLDR_ERR_MACHO_* on failure.
722 * @param pModMachO The module.
723 * @param pbStringPool The string pool
724 * @param cbStringPool The size of the string pool.
725 */
726static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, uint32_t cbStringPool)
727{
[2955]728 union
729 {
730 const uint8_t *pb;
731 const load_command_t *pLoadCmd;
732 const segment_command_32_t *pSeg32;
733 const segment_command_64_t *pSeg64;
734 const symtab_command_t *pSymTab;
735 } u;
736 uint32_t cLeft = pModMachO->Hdr.ncmds;
737 uint32_t cbLeft = pModMachO->Hdr.sizeofcmds;
738 const uint8_t *pb = pModMachO->pbLoadCommands;
739 int fFirstSegment = 1;
740 PKLDRSEG pSeg = &pModMachO->pMod->aSegments[0];
741 const uint32_t cSegments = pModMachO->pMod->cSegments;
742 uint32_t i;
743
744 while (cLeft-- > 0)
745 {
746 u.pb = pb;
747 cbLeft -= u.pLoadCmd->cmdsize;
748 pb += u.pLoadCmd->cmdsize;
749
750 /*
751 * Convert endian if needed, parse and validate the command.
752 */
753 switch (u.pLoadCmd->cmd)
754 {
755 case LC_SEGMENT_32:
756 {
757 section_32_t *pSect;
758 section_32_t *pFirstSect;
759 uint32_t cSectionsLeft;
760
761 pModMachO->LinkAddress = u.pSeg32->vmaddr;
762
763 /*
764 * convert, validate and parse the sections.
765 */
766 cSectionsLeft = u.pSeg32->nsects;
767 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
768 while (cSectionsLeft-- > 0)
769 {
770 switch (pModMachO->Hdr.filetype)
771 {
772 case MH_OBJECT:
773 {
774 /* Don't load debug symbols. (test this) */
775 if (pSect->flags & S_ATTR_DEBUG)
776 break;
777
778 if ( fFirstSegment
779 || kLdrHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
780 {
781 /* new segment. */
782 pSeg->pvUser = NULL;
783 pSeg->pchName = pbStringPool;
784 pSeg->cchName = (uint32_t)kLdrHlpStrNLen(&pSect->segname[0], sizeof(pSect->sectname));
785 kLdrHlpMemCopy(pbStringPool, &pSect->segname[0], pSeg->cchName);
786 pbStringPool += pSeg->cchName;
787 *pbStringPool++ = '\0';
788 pSeg->SelFlat = 0;
789 pSeg->Sel16bit = 0;
790 pSeg->fFlags = 0;
791 pSeg->enmProt = KLDRPROT_EXECUTE_WRITECOPY; /** @todo fixme! */
792 pSeg->cb = pSect->size;
793 pSeg->Alignment = (1 << pSect->align);
794 pSeg->LinkAddress = pSect->addr;
795 pSeg->offFile = pSect->offset ? pSect->offset : -1;
796 pSeg->cbFile = pSect->offset ? pSect->size : -1;
797 pSeg->RVA = pSect->addr - pModMachO->LinkAddress;
798 pSeg->cbMapped = 0;
799 pSeg->MapAddress = 0;
800
801 pSeg++;
802 fFirstSegment = 0;
803 }
804 else if (!fFirstSegment)
805 {
806 /* update exiting segment */
807 if (pSeg[-1].Alignment < (1 << pSect->align))
808 pSeg[-1].Alignment = (1 << pSect->align);
809 if (pSect->addr < pSeg[-1].LinkAddress)
810 return KLDR_ERR_MACHO_BAD_SECTION; /** @todo move up! */
811
[2956]812 /* If there are file bits, ensure they are in the current flow.
813 (yes, we are very very careful here, I know.) */
[2955]814 if ( pSect->offset
815 && pSeg[-1].cbFile == pSeg[-1].cb)
816 {
[2956]817 int fOk = pSeg[-1].offFile + (pSect->addr - pSeg[-1].LinkAddress) == pSect->offset
818 && pSect[-1].offset
819 && pSeg[-1].offFile + pSeg[-1].cbFile == pSect[-1].offset + pSect[-1].size;
820 /* more checks? */
821 if (fOk)
[2955]822 pSeg[-1].cbFile = (off_t)(pSect->addr - pSeg[-1].LinkAddress) + pSect->size;
[2956]823 else
[2955]824 {
[2956]825
[2955]826 pSeg[-1].cbFile = pSeg[-1].offFile = -1;
[2956]827 pModMachO->fMapUsingLoadCommandSections = 1;
[2955]828 }
829 }
830 pSeg[-1].cb = pSect->addr - pSeg[-1].LinkAddress + pSect->size;
831
832 /** @todo update the protection... */
833 }
834 break;
835 }
836
837 default:
838 return KLDR_ERR_INVALID_PARAMETER;
839 }
840
841 /* next */
842 pSect++;
843 }
844 break;
845 }
846
[2956]847 case LC_SYMTAB:
848 switch (pModMachO->Hdr.filetype)
849 {
850 case MH_OBJECT:
851 pModMachO->offSymbols = u.pSymTab->symoff;
852 pModMachO->cSymbols = u.pSymTab->nsyms;
853 pModMachO->offStrings = u.pSymTab->stroff;
854 pModMachO->cbStrings = u.pSymTab->strsize;
855 break;
856 }
857 break;
858
[2955]859 default:
860 break;
[2956]861 } /* command switch */
862 } /* while more commands */
[2955]863
864 /*
865 * Adjust mapping addresses calculating the image size.
866 */
867 pSeg = &pModMachO->pMod->aSegments[0];
868 switch (pModMachO->Hdr.filetype)
869 {
870 case MH_OBJECT:
871 {
872 KLDRADDR cb1;
873 size_t cb2;
874
875 for (i = 0; i < cSegments - 1; i++)
876 {
877 cb1 = pSeg[i + 1].LinkAddress - pSeg[i].LinkAddress;
878 cb2 = (size_t)cb1;
879 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(size_t)0;
880 }
881 cb1 = KLDR_ALIGN_ADDR(pSeg[i].cb, pSeg[i].Alignment);
882 cb2 = (size_t)cb1;
883 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(size_t)0;
884
885 pModMachO->cbImage = pSeg[i].RVA + cb1;
886 break;
887 }
888 }
889
[2952]890 return 0;
891}
892
893
894/** @copydoc KLDRMODOPS::pfnDestroy */
895static int kldrModMachODestroy(PKLDRMOD pMod)
896{
897 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
898 int rc = 0;
899 KLDRMODMACHO_ASSERT(!pModMachO->pvMapping);
900
901 if (pMod->pRdr)
902 {
903 rc = kLdrRdrClose(pMod->pRdr);
904 pMod->pRdr = NULL;
905 }
906 pMod->u32Magic = 0;
907 pMod->pOps = NULL;
908 kldrHlpFree(pModMachO->pbLoadCommands);
909 pModMachO->pbLoadCommands = NULL;
910 kldrHlpFree(pModMachO->pbStrings);
911 pModMachO->pbStrings = NULL;
912 kldrHlpFree(pModMachO->paSymbols);
913 pModMachO->paSymbols = NULL;
914 kldrHlpFree(pModMachO);
915 return rc;
916}
917
918
919/**
920 * Performs the mapping of the image.
921 *
922 * This can be used to do the internal mapping as well as the
923 * user requested mapping. fForReal indicates which is desired.
924 *
925 * @returns 0 on success, non-zero OS or kLdr status code on failure.
926 * @param pModMachO The interpreter module instance
927 * @param fForReal If set, do the user mapping. if clear, do the internal mapping.
928 */
929static int kldrModMachODoMap(PKLDRMODMACHO pModMachO, unsigned fForReal)
930{
931#if 0
932 PKLDRMOD pMod = pModMachO->pMod;
933 unsigned fFixed;
934 void *pvBase;
935 int rc;
936 uint32_t i;
937
938 /*
939 * Map it.
940 */
941 /* fixed image? */
942 fFixed = fForReal
943 && ( pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
944 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED);
945 if (!fFixed)
946 pvBase = NULL;
947 else
948 {
949 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
950 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
951 return KLDR_ERR_ADDRESS_OVERFLOW;
952 }
953
954 /* try do the prepare */
955 rc = kLdrRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
956 if (rc)
957 return rc;
958
959 /*
960 * Update the segments with their map addresses.
961 */
962 if (fForReal)
963 {
964 for (i = 0; i < pMod->cSegments; i++)
965 {
966 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
967 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
968 }
969 pModMachO->pvMapping = pvBase;
970 }
971 else
972 pModMachO->pvBits = pvBase;
973#endif
974 return 0;
975}
976
977
978/**
979 * Unmaps a image mapping.
980 *
981 * This can be used to do the internal mapping as well as the
982 * user requested mapping. fForReal indicates which is desired.
983 *
984 * @returns 0 on success, non-zero OS or kLdr status code on failure.
985 * @param pModMachO The interpreter module instance
986 * @param pvMapping The mapping to unmap.
987 */
988static int kldrModMachODoUnmap(PKLDRMODMACHO pModMachO, const void *pvMapping)
989{
990#if 0
991 PKLDRMOD pMod = pModMachO->pMod;
992 int rc;
993 uint32_t i;
994
995 /*
996 * Try unmap the image.
997 */
998 rc = kLdrRdrUnmap(pMod->pRdr, (void *)pvMapping, pMod->cSegments, pMod->aSegments);
999 if (rc)
1000 return rc;
1001
1002 /*
1003 * Update the segments to reflect that they aren't mapped any longer.
1004 */
1005 if (pModMachO->pvMapping == pvMapping)
1006 {
1007 pModMachO->pvMapping = NULL;
1008 for (i = 0; i < pMod->cSegments; i++)
1009 pMod->aSegments[i].MapAddress = 0;
1010 }
1011 if (pModMachO->pvBits == pvMapping)
1012 pModMachO->pvBits = NULL;
1013#endif
1014
1015 return 0;
1016}
1017
1018
1019/**
1020 * Gets usable bits and the right base address.
1021 *
1022 * @returns 0 on success.
1023 * @returns A non-zero status code if the BaseAddress isn't right or some problem is encountered
1024 * featch in a temp mapping the bits.
1025 * @param pModMachO The interpreter module instance
1026 * @param ppvBits The bits address, IN & OUT.
1027 * @param pBaseAddress The base address, IN & OUT. Optional.
1028 */
1029static int kldrModMachOBitsAndBaseAddress(PKLDRMODMACHO pModMachO, const void **ppvBits, PKLDRADDR pBaseAddress)
1030{
1031 int rc = 0;
1032
1033 /*
1034 * Correct the base address.
1035 *
1036 * We don't use the base address for interpreting the bits in this
1037 * interpreter, which makes things relativly simple.
1038 */
1039 if (pBaseAddress)
1040 {
1041 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
1042 *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress;
1043 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
1044 *pBaseAddress = pModMachO->LinkAddress;
1045 }
1046
1047 /*
1048 * Get bits.
1049 */
1050 if (ppvBits && !*ppvBits)
1051 {
1052 if (pModMachO->pvMapping)
1053 *ppvBits = pModMachO->pvMapping;
1054 else if (pModMachO->pvBits)
1055 *ppvBits = pModMachO->pvBits;
1056 else
1057 {
1058 /* create an internal mapping. */
1059 rc = kldrModMachODoMap(pModMachO, 0 /* not for real */);
1060 if (rc)
1061 return rc;
1062 KLDRMODMACHO_ASSERT(pModMachO->pvBits);
1063 *ppvBits = pModMachO->pvBits;
1064 }
1065 }
1066
1067 return 0;
1068}
1069
1070
1071/** @copydoc kLdrModQuerySymbol */
1072static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
[2956]1073 const char *pchSymbol, size_t cchSymbol, const char *pszVersion,
1074 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
[2952]1075
1076{
1077#if 0
1078 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1079 const uint32_t *paExportRVAs;
1080 const IMAGE_EXPORT_DIRECTORY *pExpDir;
1081 uint32_t iExpOrd;
1082 uint32_t uRVA;
1083 int rc;
1084
1085 /*
1086 * Make sure we've got mapped bits and resolve any base address aliases.
1087 */
1088 rc = kldrModMachOBitsAndBaseAddress(pModMachO, &pvBits, &BaseAddress);
1089 if (rc)
1090 return rc;
1091 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
1092 < sizeof(IMAGE_EXPORT_DIRECTORY))
1093 return KLDR_ERR_SYMBOL_NOT_FOUND;
1094 if (pszVersion && *pszVersion)
1095 return KLDR_ERR_SYMBOL_NOT_FOUND;
1096
1097 pExpDir = KLDRMODMACHO_RVA2TYPE(pvBits,
1098 pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
1099 PIMAGE_EXPORT_DIRECTORY);
1100 if (!pchSymbol)
1101 {
1102 /*
1103 * Simple, calculate the unbased ordinal and bounds check it.
1104 */
1105 iExpOrd = iSymbol - pExpDir->Base;
1106 if (iExpOrd >= KLDR_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions))
1107 return KLDR_ERR_SYMBOL_NOT_FOUND;
1108 }
1109 else
1110 {
1111 /*
1112 * Do a binary search for the name.
1113 * (The name table is sorted in ascending ordered by the linker.)
1114 */
1115 const uint32_t *paRVANames = KLDRMODMACHO_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const uint32_t *);
1116 const uint16_t *paOrdinals = KLDRMODMACHO_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const uint16_t *);
1117 int32_t iStart = 1; /* one based binary searching is simpler. */
1118 int32_t iEnd = pExpDir->NumberOfNames;
1119
1120 for (;;)
1121 {
1122 int32_t i;
1123 int diff;
1124 const char *pszName;
1125
1126 /* done? */
1127 if (iStart > iEnd)
1128 {
1129#ifdef KLDRMODMACHO_STRICT /* Make sure the linker and we both did our job right. */
1130 for (i = 0; i < (int32_t)pExpDir->NumberOfNames; i++)
1131
1132 {
1133 pszName = KLDRMODMACHO_RVA2TYPE(pvBits, paRVANames[i], const char *);
1134 KLDRMODMACHO_ASSERT(kLdrHlpStrNComp(pszName, pchSymbol, cchSymbol) || pszName[cchSymbol]);
1135 KLDRMODMACHO_ASSERT(i == 0 || kLdrHlpStrComp(pszName, KLDRMODMACHO_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)));
1136 }
1137#endif
1138 return KLDR_ERR_SYMBOL_NOT_FOUND;
1139 }
1140
1141 i = (iEnd - iStart) / 2 + iStart;
1142 pszName = KLDRMODMACHO_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
1143 diff = kLdrHlpStrNComp(pszName, pchSymbol, cchSymbol);
1144 if (!diff)
1145 diff = pszName[cchSymbol] - 0;
1146 if (diff < 0)
1147 iStart = i + 1; /* The symbol must be after the current name. */
1148 else if (diff)
1149 iEnd = i - 1; /* The symbol must be before the current name. */
1150 else
1151 {
1152 iExpOrd = paOrdinals[i - 1]; /* match! */
1153 break;
1154 }
1155 }
1156 }
1157
1158 /*
1159 * Lookup the address in the 'symbol' table.
1160 */
1161 paExportRVAs = KLDRMODMACHO_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const uint32_t *);
1162 uRVA = paExportRVAs[iExpOrd];
1163 if ( uRVA - pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
1164 < pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
1165 return kldrModMachODoForwarderQuery(pModMachO, pvBits, KLDRMODMACHO_RVA2TYPE(pvBits, uRVA, const char *),
1166 pfnGetForwarder, pvUser, puValue, pfKind);
1167
1168 /*
1169 * Set the return value.
1170 */
1171 if (puValue)
1172 *puValue = BaseAddress + uRVA;
1173 if (pfKind)
1174 *pfKind = (pModMachO->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
1175 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
1176 | KLDRSYMKIND_NO_TYPE;
1177#endif
1178 return 0;
1179}
1180
1181
1182/** @copydoc kLdrModEnumSymbols */
1183static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
1184 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
1185{
1186#if 0
1187 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1188 const uint32_t *paFunctions;
1189 const IMAGE_EXPORT_DIRECTORY *pExpDir;
1190 const uint32_t *paRVANames;
1191 const uint16_t *paOrdinals;
1192 uint32_t iFunction;
1193 uint32_t cFunctions;
1194 uint32_t cNames;
1195 int rc;
1196
1197 /*
1198 * Make sure we've got mapped bits and resolve any base address aliases.
1199 */
1200 rc = kldrModMachOBitsAndBaseAddress(pModMachO, &pvBits, &BaseAddress);
1201 if (rc)
1202 return rc;
1203
1204 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
1205 < sizeof(IMAGE_EXPORT_DIRECTORY))
1206 return 0; /* no exports to enumerate, return success. */
1207
1208 pExpDir = KLDRMODMACHO_RVA2TYPE(pvBits,
1209 pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
1210 PIMAGE_EXPORT_DIRECTORY);
1211
1212 /*
1213 * Enumerate the ordinal exports.
1214 */
1215 paRVANames = KLDRMODMACHO_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const uint32_t *);
1216 paOrdinals = KLDRMODMACHO_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const uint16_t *);
1217 paFunctions = KLDRMODMACHO_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const uint32_t *);
1218 cFunctions = pExpDir->NumberOfFunctions;
1219 cNames = pExpDir->NumberOfNames;
1220 for (iFunction = 0; iFunction < cFunctions; iFunction++)
1221 {
1222 unsigned fFoundName;
1223 uint32_t iName;
1224 const uint32_t uRVA = paFunctions[iFunction];
1225 const KLDRADDR uValue = BaseAddress + uRVA;
1226 uint32_t fKind = (pModMachO->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
1227 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
1228 | KLDRSYMKIND_NO_TYPE;
1229 if ( uRVA - pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
1230 < pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
1231 fKind |= KLDRSYMKIND_FORWARDER;
1232
1233 /*
1234 * Any symbol names?
1235 */
1236 fFoundName = 0;
1237 for (iName = 0; iName < cNames; iName++)
1238 {
1239 const char *pszName;
1240 if (paOrdinals[iName] != iFunction)
1241 continue;
1242 fFoundName = 1;
1243 pszName = KLDRMODMACHO_RVA2TYPE(pvBits, paRVANames[iName], const char *);
1244 rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, kLdrHlpStrLen(pszName), NULL,
1245 uValue, fKind, pvUser);
1246 if (rc)
1247 return rc;
1248 }
1249
1250 /*
1251 * If no names, call once with the ordinal only.
1252 */
1253 if (!fFoundName)
1254 {
1255 rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser);
1256 if (rc)
1257 return rc;
1258 }
1259 }
1260#endif
1261 return 0;
1262}
1263
1264
1265/** @copydoc kLdrModGetImport */
1266static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
1267{
[2956]1268 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1269 if (pModMachO->Hdr.filetype == MH_OBJECT)
[2952]1270 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1271
[2956]1272 /* later */
1273 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
[2952]1274}
1275
1276
1277/** @copydoc kLdrModNumberOfImports */
1278static int32_t kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits)
1279{
1280 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2956]1281 if (pModMachO->Hdr.filetype == MH_OBJECT)
1282 return 0;
[2952]1283
[2956]1284 /* later */
[2952]1285 return 0;
1286}
1287
1288
1289/** @copydoc kLdrModGetStackInfo */
1290static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1291{
1292 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1293
1294 pStackInfo->Address = NIL_KLDRADDR;
1295 pStackInfo->LinkAddress = NIL_KLDRADDR;
[2956]1296 pStackInfo->cbStack = pStackInfo->cbStackThread = 0;
1297 /* later */
[2952]1298
1299 return 0;
1300}
1301
1302
1303/** @copydoc kLdrModQueryMainEntrypoint */
1304static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1305{
1306#if 0
1307 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1308 int rc;
1309
1310 /*
1311 * Resolve base address alias if any.
1312 */
1313 rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress);
1314 if (rc)
1315 return rc;
1316
1317 /*
1318 * Convert the address from the header.
1319 */
1320 *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
1321 ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
1322 : NIL_KLDRADDR;
1323#else
1324 *pMainEPAddress = NIL_KLDRADDR;
1325#endif
1326 return 0;
1327}
1328
1329
1330/** @copydoc kLdrModEnumDbgInfo */
1331static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1332{
1333#if 0
1334 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1335 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
1336 uint32_t iDbgInfo;
1337 uint32_t cb;
1338 int rc;
1339
1340 /*
1341 * Check that there is a debug directory first.
1342 */
1343 cb = pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
1344 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1345 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1346 return 0;
1347
1348 /*
1349 * Make sure we've got mapped bits.
1350 */
1351 rc = kldrModMachOBitsAndBaseAddress(pModMachO, &pvBits, NULL);
1352 if (rc)
1353 return rc;
1354
1355 /*
1356 * Enumerate the debug directory.
1357 */
1358 pDbgDir = KLDRMODMACHO_RVA2TYPE(pvBits,
1359 pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
1360 const IMAGE_DEBUG_DIRECTORY *);
1361 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
1362 {
1363 KLDRDBGINFOTYPE enmDbgInfoType;
1364
1365 /* convert the type. */
1366 switch (pDbgDir->Type)
1367 {
1368 case IMAGE_DEBUG_TYPE_UNKNOWN:
1369 case IMAGE_DEBUG_TYPE_FPO:
1370 case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
1371 case IMAGE_DEBUG_TYPE_MISC:
1372 case IMAGE_DEBUG_TYPE_EXCEPTION:
1373 case IMAGE_DEBUG_TYPE_FIXUP:
1374 case IMAGE_DEBUG_TYPE_BORLAND:
1375 default:
1376 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
1377 break;
1378 case IMAGE_DEBUG_TYPE_CODEVIEW:
1379 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
1380 break;
1381 }
1382
1383 rc = pfnCallback(pMod, iDbgInfo,
1384 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
1385 pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
1386 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
1387 pDbgDir->SizeOfData,
1388 NULL,
1389 pvUser);
1390 if (rc)
1391 break;
1392
1393 /* next */
1394 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
1395 break;
1396 }
1397
1398 return rc;
1399#else
1400 return 0;
1401#endif
1402}
1403
1404
1405/** @copydoc kLdrModHasDbgInfo */
1406static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1407{
1408 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1409
1410#if 0
1411 /*
1412 * Base this entirely on the presence of a debug directory.
1413 */
1414 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
1415 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1416 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1417 return KLDR_ERR_NO_DEBUG_INFO;
1418 return 0;
1419#else
1420 return KLDR_ERR_NO_DEBUG_INFO;
1421#endif
1422}
1423
1424
1425/** @copydoc kLdrModMap */
1426static int kldrModMachOMap(PKLDRMOD pMod)
1427{
1428 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1429 int rc;
1430
1431 /*
1432 * Already mapped?
1433 */
1434 if (pModMachO->pvMapping)
1435 return KLDR_ERR_ALREADY_MAPPED;
1436
1437 /*
1438 * We've got a common worker which does this.
1439 */
1440 rc = kldrModMachODoMap(pModMachO, 1 /* the real thing */);
1441 if (rc)
1442 return rc;
1443 KLDRMODMACHO_ASSERT(pModMachO->pvMapping);
1444 return 0;
1445}
1446
1447
1448/** @copydoc kLdrModUnmap */
1449static int kldrModMachOUnmap(PKLDRMOD pMod)
1450{
1451 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1452 int rc;
1453
1454 /*
1455 * Mapped?
1456 */
1457 if (!pModMachO->pvMapping)
1458 return KLDR_ERR_NOT_MAPPED;
1459
1460 /*
1461 * We've got a common worker which does this.
1462 */
1463 rc = kldrModMachODoUnmap(pModMachO, pModMachO->pvMapping);
1464 if (rc)
1465 return rc;
1466 KLDRMODMACHO_ASSERT(pModMachO->pvMapping);
1467 return 0;
1468
1469}
1470
1471
1472/** @copydoc kLdrModAllocTLS */
1473static int kldrModMachOAllocTLS(PKLDRMOD pMod)
1474{
1475 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1476
1477 /*
1478 * Mapped?
1479 */
1480 if (!pModMachO->pvMapping)
1481 return KLDR_ERR_NOT_MAPPED;
1482
1483 return 0;
1484}
1485
1486
1487/** @copydoc kLdrModFreeTLS */
1488static void kldrModMachOFreeTLS(PKLDRMOD pMod)
1489{
1490}
1491
1492
1493/** @copydoc kLdrModReload */
1494static int kldrModMachOReload(PKLDRMOD pMod)
1495{
1496 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1497
1498 /*
1499 * Mapped?
1500 */
1501 if (!pModMachO->pvMapping)
1502 return KLDR_ERR_NOT_MAPPED;
1503
1504 /* the file provider does it all */
1505 return kLdrRdrRefresh(pMod->pRdr, (void *)pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
1506}
1507
1508
1509/** @copydoc kLdrModFixupMapping */
1510static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1511{
1512 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1513 int rc, rc2;
1514
1515 /*
1516 * Mapped?
1517 */
1518 if (!pModMachO->pvMapping)
1519 return KLDR_ERR_NOT_MAPPED;
1520
1521 /*
1522 * Before doing anything we'll have to make all pages writable.
1523 */
1524 rc = kLdrRdrProtect(pMod->pRdr, (void *)pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
1525 if (rc)
1526 return rc;
1527
1528#if 0
1529 /*
1530 * Apply base relocations.
1531 */
1532 rc = kldrModMachODoFixups(pModMachO, (void *)pModMachO->pvMapping, (uintptr_t)pModMachO->pvMapping,
1533 pModMachO->Hdrs.OptionalHeader.ImageBase);
1534
1535 /*
1536 * Resolve imports.
1537 */
1538 if (!rc)
1539 rc = kldrModMachODoImports(pModMachO, (void *)pModMachO->pvMapping, pfnGetImport, pvUser);
1540#endif
1541
1542 /*
1543 * Restore protection.
1544 */
1545 rc2 = kLdrRdrProtect(pMod->pRdr, (void *)pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
1546 if (!rc && rc2)
1547 rc = rc2;
1548 return rc;
1549}
1550
1551
1552/**
1553 * Applies base relocations to a (unprotected) image mapping.
1554 *
1555 * @returns 0 on success, non-zero kLdr status code on failure.
1556 * @param pModMachO The PE module interpreter instance.
1557 * @param pvMapping The mapping to fixup.
1558 * @param NewBaseAddress The address to fixup the mapping to.
1559 * @param OldBaseAddress The address the mapping is currently fixed up to.
1560 */
1561static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress)
1562{
1563#if 0
1564 const KLDRADDR Delta = NewBaseAddress - OldBaseAddress;
1565 uint32_t cbLeft = pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1566 const IMAGE_BASE_RELOCATION *pBR, *pFirstBR;
1567
1568 /*
1569 * Don't don anything if the delta is 0 or there aren't any relocations.
1570 */
1571 if ( !Delta
1572 || !cbLeft
1573 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
1574 return 0;
1575
1576 /*
1577 * Process the fixups block by block.
1578 * (These blocks appears to be 4KB on all archs despite the native page size.)
1579 */
1580 pBR = pFirstBR = KLDRMODMACHO_RVA2TYPE(pvMapping,
1581 pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
1582 const IMAGE_BASE_RELOCATION *);
1583 while ( cbLeft > sizeof(IMAGE_BASE_RELOCATION)
1584 && pBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION) /* paranoia */)
1585 {
1586 union
1587 {
1588 uint8_t *pu8;
1589 uint16_t *pu16;
1590 uint32_t *pu32;
1591 uint64_t *pu64;
1592 } uChunk,
1593 u;
1594 const uint16_t *poffFixup = (const uint16_t *)(pBR + 1);
1595 const uint32_t cbBlock = KLDR_MIN(cbLeft, pBR->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION); /* more caution... */
1596 uint32_t cFixups = cbBlock / sizeof(poffFixup[0]);
1597 uChunk.pu8 = KLDRMODMACHO_RVA2TYPE(pvMapping, pBR->VirtualAddress, uint8_t *);
1598
1599 /*
1600 * Loop thru the fixups in this chunk.
1601 */
1602 while (cFixups > 0)
1603 {
1604 u.pu8 = uChunk.pu8 + (*poffFixup & 0xfff);
1605 switch (*poffFixup >> 12) /* ordered by value. */
1606 {
1607 /* 0 - Alignment placeholder. */
1608 case IMAGE_REL_BASED_ABSOLUTE:
1609 break;
1610
1611 /* 1 - 16-bit, add 2nd 16-bit part of the delta. (rare) */
1612 case IMAGE_REL_BASED_HIGH:
1613 *u.pu16 += (uint16_t)(Delta >> 16);
1614 break;
1615
1616 /* 2 - 16-bit, add 1st 16-bit part of the delta. (rare) */
1617 case IMAGE_REL_BASED_LOW:
1618 *u.pu16 += (uint16_t)Delta;
1619 break;
1620
1621 /* 3 - 32-bit, add delta. (frequent in 32-bit images) */
1622 case IMAGE_REL_BASED_HIGHLOW:
1623 *u.pu32 += (uint32_t)Delta;
1624 break;
1625
1626 /* 4 - 16-bit, add 2nd 16-bit of the delta, sign adjust for the lower 16-bit. one arg. (rare) */
1627 case IMAGE_REL_BASED_HIGHADJ:
1628 {
1629 int32_t i32;
1630 if (cFixups <= 1)
1631 return KLDR_ERR_PE_BAD_FIXUP;
1632
1633 i32 = (uint32_t)*u.pu16 << 16;
1634 i32 |= *++poffFixup; cFixups--; /* the addend argument */
1635 i32 += (uint32_t)Delta;
1636 i32 += 0x8000;
1637 *u.pu16 = (uint16_t)(i32 >> 16);
1638 break;
1639 }
1640
1641 /* 5 - 32-bit MIPS JMPADDR, no implemented. */
1642 case IMAGE_REL_BASED_MIPS_JMPADDR:
1643 *u.pu32 = (*u.pu32 & 0xc0000000)
1644 | ((uint32_t)((*u.pu32 << 2) + (uint32_t)Delta) >> 2);
1645 break;
1646
1647 /* 6 - Intra section? Reserved value in later specs. Not implemented. */
1648 case IMAGE_REL_BASED_SECTION:
1649 KLDRMODMACHO_ASSERT(!"SECTION");
1650 return KLDR_ERR_PE_BAD_FIXUP;
1651
1652 /* 7 - Relative intra section? Reserved value in later specs. Not implemented. */
1653 case IMAGE_REL_BASED_REL32:
1654 KLDRMODMACHO_ASSERT(!"SECTION");
1655 return KLDR_ERR_PE_BAD_FIXUP;
1656
1657 /* 8 - reserved according to binutils... */
1658 case 8:
1659 KLDRMODMACHO_ASSERT(!"RESERVERED8");
1660 return KLDR_ERR_PE_BAD_FIXUP;
1661
1662 /* 9 - IA64_IMM64 (/ MIPS_JMPADDR16), no specs nor need to support the platform yet.
1663 * Bet this requires more code than all the other fixups put together in good IA64 spirit :-) */
1664 case IMAGE_REL_BASED_IA64_IMM64:
1665 KLDRMODMACHO_ASSERT(!"IA64_IMM64 / MIPS_JMPADDR16");
1666 return KLDR_ERR_PE_BAD_FIXUP;
1667
1668 /* 10 - 64-bit, add delta. (frequently in 64-bit images) */
1669 case IMAGE_REL_BASED_DIR64:
1670 *u.pu64 += (uint64_t)Delta;
1671 break;
1672
1673 /* 11 - 16-bit, add 3rd 16-bit of the delta, sign adjust for the lower 32-bit. two args. (rare) */
1674 case IMAGE_REL_BASED_HIGH3ADJ:
1675 {
1676 int64_t i64;
1677 if (cFixups <= 2)
1678 return KLDR_ERR_PE_BAD_FIXUP;
1679
1680 i64 = (uint64_t)*u.pu16 << 32
1681 | ((uint32_t)poffFixup[2] << 16)
1682 | poffFixup[1];
1683 i64 += Delta;
1684 i64 += 0x80008000UL;
1685 *u.pu16 = (uint16_t)(i64 >> 32);
1686 /* skip the addends arguments */
1687 poffFixup += 2;
1688 cFixups -= 2;
1689 break;
1690 }
1691
1692 /* the rest are yet to be defined.*/
1693 default:
1694 return KLDR_ERR_PE_BAD_FIXUP;
1695 }
1696
1697 /*
1698 * Next relocation.
1699 */
1700 poffFixup++;
1701 cFixups--;
1702 }
1703
1704
1705 /*
1706 * Next block.
1707 */
1708 cbLeft -= pBR->SizeOfBlock;
1709 pBR = (PIMAGE_BASE_RELOCATION)((uintptr_t)pBR + pBR->SizeOfBlock);
1710 }
1711
1712#endif
1713 return 0;
1714}
1715
1716
1717
1718/**
1719 * Resolves imports.
1720 *
1721 * @returns 0 on success, non-zero kLdr status code on failure.
1722 * @param pModMachO The PE module interpreter instance.
1723 * @param pvMapping The mapping which imports should be resolved.
1724 * @param pfnGetImport The callback for resolving an imported symbol.
1725 * @param pvUser User argument to the callback.
1726 */
1727static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1728{
[2956]1729 /* for when loading non-objects. */
[2952]1730 return 0;
1731}
1732
1733
1734/** @copydoc kLdrModCallInit */
1735static int kldrModMachOCallInit(PKLDRMOD pMod, uintptr_t uHandle)
1736{
[2956]1737 /* later */
[2952]1738 return 0;
1739}
1740
1741
1742/** @copydoc kLdrModCallTerm */
1743static int kldrModMachOCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
1744{
[2956]1745 /* later */
[2952]1746 return 0;
1747}
1748
1749
1750/** @copydoc kLdrModCallThread */
1751static int kldrModMachOCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
1752{
[2956]1753 /* Relevant for Mach-O? */
[2952]1754 return 0;
1755}
1756
1757
1758/** @copydoc kLdrModSize */
1759static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
1760{
1761 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2955]1762 return pModMachO->cbImage;
[2952]1763}
1764
1765
1766/** @copydoc kLdrModGetBits */
1767static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1768{
1769 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1770 uint32_t i;
1771 int rc;
1772
1773 /*
1774 * Zero the entire buffer first to simplify things.
1775 */
[2956]1776 kLdrHlpMemSet(pvBits, 0, (size_t)pModMachO->cbImage);
[2952]1777
1778 /*
[2956]1779 * When possible use the segment table to load the data.
1780 * If not iterate the load commands and execute the segment / section loads.
[2952]1781 */
[2956]1782 if (!pModMachO->fMapUsingLoadCommandSections)
[2952]1783 {
[2956]1784 for (i = 0; i < pMod->cSegments; i++)
1785 {
1786 /* skip it? */
1787 if ( pMod->aSegments[i].cbFile == -1
1788 || pMod->aSegments[i].offFile == -1
1789 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
1790 || !pMod->aSegments[i].Alignment)
1791 continue;
1792 rc = kLdrRdrRead(pMod->pRdr,
1793 (uint8_t *)pvBits + (pMod->aSegments[i].LinkAddress - pModMachO->LinkAddress),
1794 pMod->aSegments[i].cbFile,
1795 pMod->aSegments[i].offFile);
1796 if (rc)
1797 return rc;
1798 }
[2952]1799 }
[2956]1800 else
1801 {
1802 /** @todo implement this */
1803 return KLDR_ERR_TODO;
1804 }
[2952]1805
1806 /*
1807 * Perform relocations.
1808 */
[2956]1809 return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
[2952]1810}
1811
1812
1813/** @copydoc kLdrModRelocateBits */
1814static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
[2954]1815 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
[2952]1816{
1817 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1818 int rc;
1819
1820 /*
1821 * Call workers to do the jobs.
1822 */
1823 rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress);
[2956]1824 if (pModMachO->Hdr.filetype != MH_OBJECT)
[2952]1825 rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
1826
1827 return rc;
1828}
1829
1830
1831/**
[2954]1832 * The Mach-O module interpreter method table.
[2952]1833 */
[2954]1834KLDRMODOPS g_kLdrModMachOOps =
[2952]1835{
[2954]1836 "Mach-O",
[2952]1837 NULL,
1838 kldrModMachOCreate,
1839 kldrModMachODestroy,
1840 kldrModMachOQuerySymbol,
1841 kldrModMachOEnumSymbols,
1842 kldrModMachOGetImport,
1843 kldrModMachONumberOfImports,
1844 NULL /* can execute one is optional */,
1845 kldrModMachOGetStackInfo,
1846 kldrModMachOQueryMainEntrypoint,
1847 NULL,
1848 NULL,
1849 kldrModMachOEnumDbgInfo,
1850 kldrModMachOHasDbgInfo,
1851 kldrModMachOMap,
1852 kldrModMachOUnmap,
1853 kldrModMachOAllocTLS,
1854 kldrModMachOFreeTLS,
1855 kldrModMachOReload,
1856 kldrModMachOFixupMapping,
1857 kldrModMachOCallInit,
1858 kldrModMachOCallTerm,
1859 kldrModMachOCallThread,
1860 kldrModMachOSize,
1861 kldrModMachOGetBits,
1862 kldrModMachORelocateBits,
1863 NULL, /** @todo mostly done */
1864 42 /* the end */
1865};
1866
Note: See TracBrowser for help on using the repository browser.