source: trunk/kLdr/kLdrModMachO.c@ 2961

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

Some more work in the GetBits and Relocate area.

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