source: trunk/kStuff/kLdr/kLdrModMachO.c@ 3579

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

error code cleanup.

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