source: trunk/kLdr/kLdrModMachO.c@ 2976

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

More fixup bugs.

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