source: trunk/kLdr/kLdrModMachO.c@ 2955

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

Completed kldrModMachOParseLoadCommands and kldrModMachOSize. Added an kLdrErrStr API.

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