source: trunk/kLdr/kLdrModMachO.c@ 2954

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

implemented kldrModMachOPreParseLoadCommands

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