source: trunk/kLdr/kLdrModMachO.c@ 4

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

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

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