source: trunk/kLdr/kLdrModMachO.c@ 3525

Last change on this file since 3525 was 3525, checked in by bird, 18 years ago

made the format headers usable externally.

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