source: trunk/kLdr/kLdrModMachO.c@ 2968

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

Made tst-3 load.

File size: 86.1 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. */
70 off_t offFile;
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. */
77 off_t 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. */
130 off_t offSymbols;
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. */
136 off_t offStrings;
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);
[2961]170static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, off_t offFixups, uint32_t cFixups, void **pvFixups);
[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 */
199static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
200{
201 PKLDRMODMACHO pModMachO;
202 int rc;
203
204 /*
205 * Create the instance data and do a minimal header validation.
206 */
207 rc = kldrModMachODoCreate(pRdr, &pModMachO);
208 if (!rc)
209 {
210 pModMachO->pMod->pOps = pOps;
211 pModMachO->pMod->u32Magic = KLDRMOD_MAGIC;
212 *ppMod = pModMachO->pMod;
213 return 0;
214 }
215 if (pModMachO)
216 {
217 kldrHlpFree(pModMachO->pbLoadCommands);
218 kldrHlpFree(pModMachO);
219 }
220 return rc;
221}
222
223
224/**
225 * Separate function for reading creating the PE module instance to
226 * simplify cleanup on failure.
227 */
228static int kldrModMachODoCreate(PKLDRRDR pRdr, PKLDRMODMACHO *ppModMachO)
229{
230 union
231 {
232 mach_header_32_t Hdr32;
233 mach_header_64_t Hdr64;
234 } s;
235 PKLDRMODMACHO pModMachO;
236 PKLDRMOD pMod;
237 uint8_t *pbLoadCommands;
238 uint32_t cSegments;
[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
[2961]604 || (uint64_t)pSect->reloff + (off_t)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 {
621 /* verify that the linker/assembler has ordered sections correctly. */
622 section_32_t *pCur = (pSect - 2);
623 while ((uintptr_t)pCur >= (uintptr_t)pFirstSect)
624 {
625 if (!kLdrHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
626 return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
627 pCur--;
628 }
629
630 /* ok. count it and the string. */
631 cSegments++;
[2955]632 cbStringPool += kLdrHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1;
[2954]633 }
[2961]634 cSections++;
[2954]635 break;
636 }
637
638 default:
639 return KLDR_ERR_INVALID_PARAMETER;
640 }
641
642 /* next */
643 pSect++;
644 }
645 break;
646 }
647
[2955]648 /*case LC_SEGMENT_64:
[2963]649 copy 32-bit code
[2954]650 break;
[2955]651 */
[2954]652
653 case LC_SYMTAB:
[2961]654 {
655 size_t cbSym;
[2954]656 if (fConvertEndian)
657 {
658 u.pSymTab->symoff = KLDRHLP_E2E_U32(u.pSymTab->symoff);
659 u.pSymTab->nsyms = KLDRHLP_E2E_U32(u.pSymTab->nsyms);
660 u.pSymTab->stroff = KLDRHLP_E2E_U32(u.pSymTab->stroff);
661 u.pSymTab->strsize = KLDRHLP_E2E_U32(u.pSymTab->strsize);
662 }
663
664 /* verify */
[2961]665 cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE
666 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
[2963]667 ? sizeof(macho_nlist_32_t)
[2961]668 : sizeof(macho_nlist_64_t);
[2954]669 if ( u.pSymTab->symoff >= cbFile
[2961]670 || (uint64_t)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > kLdrRdrSize(pRdr))
[2954]671 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
672 if ( u.pSymTab->stroff >= cbFile
673 || (uint64_t)u.pSymTab->stroff + u.pSymTab->strsize > cbFile)
674 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
[2956]675
676 /* only one string in objects, please. */
677 cSymbolTabs++;
678 if ( pHdr->filetype == MH_OBJECT
679 && cSymbolTabs != 1)
680 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
[2954]681 break;
[2961]682 }
[2954]683
[2963]684 case LC_DYSYMTAB:
685 /** @todo deal with this! */
686 break;
687
[2954]688 case LC_THREAD:
689 case LC_UNIXTHREAD:
690 {
691 uint32_t *pu32 = (uint32_t *)(u.pb + sizeof(load_command_t));
692 uint32_t cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(uint32_t);
693 while (cItemsLeft)
694 {
695 /* convert & verify header items ([0] == flavor, [1] == uint32_t count). */
696 if (cItemsLeft < 2)
697 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
698 if (fConvertEndian)
699 {
700 pu32[0] = KLDRHLP_E2E_U32(pu32[0]);
701 pu32[1] = KLDRHLP_E2E_U32(pu32[1]);
702 }
703 if (pu32[1] + 2 > cItemsLeft)
704 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
705
706 /* convert & verify according to flavor. */
707 switch (pu32[0])
708 {
709 /** @todo */
710 default:
711 break;
712 }
713
714 /* next */
715 cItemsLeft -= pu32[1] + 2;
716 pu32 += pu32[1] + 2;
717 }
718 break;
719 }
720
721 case LC_UUID:
722 if (u.pUuid->cmdsize != sizeof(uuid_command_t))
723 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
724 /** @todo Check anything here need converting? */
725 break;
726
[2955]727 case LC_SEGMENT_64:
[2954]728 case LC_LOADFVMLIB:
729 case LC_IDFVMLIB:
730 case LC_IDENT:
731 case LC_FVMFILE:
732 case LC_PREPAGE:
733 case LC_LOAD_DYLIB:
734 case LC_ID_DYLIB:
735 case LC_LOAD_DYLINKER:
736 case LC_ID_DYLINKER:
737 case LC_PREBOUND_DYLIB:
738 case LC_ROUTINES:
739 case LC_ROUTINES_64:
740 case LC_SUB_FRAMEWORK:
741 case LC_SUB_UMBRELLA:
742 case LC_SUB_CLIENT:
743 case LC_SUB_LIBRARY:
744 case LC_TWOLEVEL_HINTS:
745 case LC_PREBIND_CKSUM:
746 case LC_LOAD_WEAK_DYLIB:
747 case LC_SYMSEG:
748 return KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND;
749
750 default:
751 return KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND;
752 }
753 }
754
[2955]755 /* be strict. */
[2954]756 if (cbLeft)
757 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
758
[2955]759 switch (pHdr->filetype)
760 {
761 case MH_OBJECT:
762 if (!cSegments)
763 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
764 break;
765 }
766
[2954]767 *pcSegments = cSegments;
[2961]768 *pcSections = cSections;
[2955]769 *pcbStringPool = cbStringPool;
[2954]770
[2952]771 return 0;
772}
773
774
775/**
776 * Parses the load commands after we've carved out the module instance.
777 *
778 * This fills in the segment table and perhaps some other properties.
779 *
780 * @returns 0 on success.
781 * @returns KLDR_ERR_MACHO_* on failure.
782 * @param pModMachO The module.
783 * @param pbStringPool The string pool
784 * @param cbStringPool The size of the string pool.
785 */
786static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, uint32_t cbStringPool)
787{
[2955]788 union
789 {
790 const uint8_t *pb;
791 const load_command_t *pLoadCmd;
792 const segment_command_32_t *pSeg32;
793 const segment_command_64_t *pSeg64;
794 const symtab_command_t *pSymTab;
795 } u;
796 uint32_t cLeft = pModMachO->Hdr.ncmds;
797 uint32_t cbLeft = pModMachO->Hdr.sizeofcmds;
798 const uint8_t *pb = pModMachO->pbLoadCommands;
799 int fFirstSegment = 1;
800 PKLDRSEG pSeg = &pModMachO->pMod->aSegments[0];
[2961]801 PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0];
[2962]802 PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections;
[2955]803 const uint32_t cSegments = pModMachO->pMod->cSegments;
804 uint32_t i;
805
806 while (cLeft-- > 0)
807 {
808 u.pb = pb;
809 cbLeft -= u.pLoadCmd->cmdsize;
810 pb += u.pLoadCmd->cmdsize;
811
812 /*
813 * Convert endian if needed, parse and validate the command.
814 */
815 switch (u.pLoadCmd->cmd)
816 {
817 case LC_SEGMENT_32:
818 {
819 section_32_t *pSect;
820 section_32_t *pFirstSect;
821 uint32_t cSectionsLeft;
822
823 pModMachO->LinkAddress = u.pSeg32->vmaddr;
824
[2963]825 /*
826 * convert, validate and parse the sections.
[2955]827 */
828 cSectionsLeft = u.pSeg32->nsects;
829 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
830 while (cSectionsLeft-- > 0)
831 {
832 switch (pModMachO->Hdr.filetype)
833 {
834 case MH_OBJECT:
835 {
[2962]836 /* Section data extract. */
837 pSectExtra->cb = pSect->size;
838 pSectExtra->RVA = pSect->addr;
[2968]839 pSectExtra->LinkAddress = pSect->addr;
[2962]840 pSectExtra->offFile = pSect->offset ? pSect->offset : -1;
841 pSectExtra->cFixups = pSect->nreloc;
842 pSectExtra->paFixups = NULL;
843 pSectExtra->offFixups = pSect->nreloc ? pSect->reloff : -1;
844 pSectExtra->fFlags = pSect->flags;
845 pSectExtra->iSegment = pSegExtra - &pModMachO->aSegments[0];
846 pSectExtra->pvMachoSection = pSect;
847
848 /* Don't load debug symbols. (test this!) */
[2955]849 if (pSect->flags & S_ATTR_DEBUG)
850 break;
851
852 if ( fFirstSegment
853 || kLdrHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
854 {
[2961]855 /* close the previous segment */
[2962]856 if (pSegExtra != &pModMachO->aSegments[0])
[2961]857 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
858
[2955]859 /* new segment. */
860 pSeg->pvUser = NULL;
861 pSeg->pchName = pbStringPool;
862 pSeg->cchName = (uint32_t)kLdrHlpStrNLen(&pSect->segname[0], sizeof(pSect->sectname));
863 kLdrHlpMemCopy(pbStringPool, &pSect->segname[0], pSeg->cchName);
864 pbStringPool += pSeg->cchName;
865 *pbStringPool++ = '\0';
866 pSeg->SelFlat = 0;
867 pSeg->Sel16bit = 0;
868 pSeg->fFlags = 0;
869 pSeg->enmProt = KLDRPROT_EXECUTE_WRITECOPY; /** @todo fixme! */
870 pSeg->cb = pSect->size;
871 pSeg->Alignment = (1 << pSect->align);
872 pSeg->LinkAddress = pSect->addr;
873 pSeg->offFile = pSect->offset ? pSect->offset : -1;
874 pSeg->cbFile = pSect->offset ? pSect->size : -1;
875 pSeg->RVA = pSect->addr - pModMachO->LinkAddress;
876 pSeg->cbMapped = 0;
877 pSeg->MapAddress = 0;
878
[2961]879 pSegExtra->cSections = 0;
880 pSegExtra->paSections = pSectExtra;
881
[2955]882 pSeg++;
[2961]883 pSegExtra++;
[2955]884 fFirstSegment = 0;
885 }
[2961]886 else
[2955]887 {
888 /* update exiting segment */
889 if (pSeg[-1].Alignment < (1 << pSect->align))
890 pSeg[-1].Alignment = (1 << pSect->align);
891 if (pSect->addr < pSeg[-1].LinkAddress)
892 return KLDR_ERR_MACHO_BAD_SECTION; /** @todo move up! */
893
[2963]894 /* If there are file bits, ensure they are in the current flow.
[2956]895 (yes, we are very very careful here, I know.) */
[2963]896 if ( pSect->offset
[2955]897 && pSeg[-1].cbFile == pSeg[-1].cb)
898 {
[2956]899 int fOk = pSeg[-1].offFile + (pSect->addr - pSeg[-1].LinkAddress) == pSect->offset
900 && pSect[-1].offset
901 && pSeg[-1].offFile + pSeg[-1].cbFile == pSect[-1].offset + pSect[-1].size;
902 /* more checks? */
903 if (fOk)
[2955]904 pSeg[-1].cbFile = (off_t)(pSect->addr - pSeg[-1].LinkAddress) + pSect->size;
[2963]905 else
[2955]906 {
[2963]907
[2955]908 pSeg[-1].cbFile = pSeg[-1].offFile = -1;
[2956]909 pModMachO->fMapUsingLoadCommandSections = 1;
[2955]910 }
911 }
912 pSeg[-1].cb = pSect->addr - pSeg[-1].LinkAddress + pSect->size;
913
914 /** @todo update the protection... */
915 }
[2961]916 pSectExtra++;
[2955]917 break;
918 }
919
920 default:
921 return KLDR_ERR_INVALID_PARAMETER;
922 }
923
924 /* next */
925 pSect++;
926 }
927 break;
928 }
929
[2956]930 case LC_SYMTAB:
931 switch (pModMachO->Hdr.filetype)
932 {
933 case MH_OBJECT:
934 pModMachO->offSymbols = u.pSymTab->symoff;
935 pModMachO->cSymbols = u.pSymTab->nsyms;
936 pModMachO->offStrings = u.pSymTab->stroff;
[2962]937 pModMachO->cchStrings = u.pSymTab->strsize;
[2956]938 break;
939 }
940 break;
941
[2955]942 default:
943 break;
[2956]944 } /* command switch */
945 } /* while more commands */
[2955]946
[2961]947 /*
948 * Close the last segment (if any).
949 */
950 if (pSegExtra != &pModMachO->aSegments[1])
951 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
952
[2963]953 /*
[2955]954 * Adjust mapping addresses calculating the image size.
955 */
956 pSeg = &pModMachO->pMod->aSegments[0];
957 switch (pModMachO->Hdr.filetype)
958 {
959 case MH_OBJECT:
960 {
961 KLDRADDR cb1;
962 size_t cb2;
963
964 for (i = 0; i < cSegments - 1; i++)
965 {
966 cb1 = pSeg[i + 1].LinkAddress - pSeg[i].LinkAddress;
967 cb2 = (size_t)cb1;
968 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(size_t)0;
969 }
970 cb1 = KLDR_ALIGN_ADDR(pSeg[i].cb, pSeg[i].Alignment);
971 cb2 = (size_t)cb1;
972 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(size_t)0;
973
974 pModMachO->cbImage = pSeg[i].RVA + cb1;
975 break;
976 }
977 }
978
[2952]979 return 0;
980}
981
982
983/** @copydoc KLDRMODOPS::pfnDestroy */
984static int kldrModMachODestroy(PKLDRMOD pMod)
985{
986 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
987 int rc = 0;
[2961]988 uint32_t i, j;
[2952]989 KLDRMODMACHO_ASSERT(!pModMachO->pvMapping);
990
[2961]991 i = pMod->cSegments;
992 while (i-- > 0)
993 {
994 j = pModMachO->aSegments[i].cSections;
995 while (j-- > 0)
996 {
997 kldrHlpFree(pModMachO->aSegments[i].paSections[j].paFixups);
998 pModMachO->aSegments[i].paSections[j].paFixups = NULL;
999 }
1000 }
1001
[2952]1002 if (pMod->pRdr)
1003 {
1004 rc = kLdrRdrClose(pMod->pRdr);
1005 pMod->pRdr = NULL;
1006 }
1007 pMod->u32Magic = 0;
1008 pMod->pOps = NULL;
1009 kldrHlpFree(pModMachO->pbLoadCommands);
1010 pModMachO->pbLoadCommands = NULL;
[2961]1011 kldrHlpFree(pModMachO->pchStrings);
1012 pModMachO->pchStrings = NULL;
1013 kldrHlpFree(pModMachO->pvaSymbols);
1014 pModMachO->pvaSymbols = NULL;
[2952]1015 kldrHlpFree(pModMachO);
1016 return rc;
1017}
1018
1019
1020/**
[2962]1021 * Gets the right base address.
[2952]1022 *
[2962]1023 * @returns 0 on success.
1024 * @returns A non-zero status code if the BaseAddress isn't right.
1025 * @param pModMachO The interpreter module instance
1026 * @param pBaseAddress The base address, IN & OUT. Optional.
[2952]1027 */
[2962]1028static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress)
[2952]1029{
1030 /*
[2962]1031 * Adjust the base address.
[2952]1032 */
[2962]1033 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
1034 *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress;
1035 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
1036 *pBaseAddress = pModMachO->LinkAddress;
[2952]1037
1038 return 0;
1039}
1040
1041
[2962]1042
1043/** @copydoc kLdrModQuerySymbol */
1044static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
1045 const char *pchSymbol, size_t cchSymbol, const char *pszVersion,
1046 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
[2952]1047{
[2962]1048 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1049 int rc;
[2952]1050
1051 /*
[2962]1052 * Resolve defaults.
[2952]1053 */
[2962]1054 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
[2952]1055 if (rc)
1056 return rc;
1057
1058 /*
[2962]1059 * Refuse segmented requests for now.
[2952]1060 */
[2963]1061 if ( pfKind
[2962]1062 && (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) != KLDRSYMKIND_REQ_FLAT)
1063 return KLDR_ERR_TODO;
1064
1065 /*
1066 * Take action according to file type.
1067 */
1068 if (pModMachO->Hdr.filetype == MH_OBJECT)
[2952]1069 {
[2962]1070 rc = kldrModMachOLoadObjSymTab(pModMachO);
1071 if (!rc)
1072 {
1073 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1074 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
[2963]1075 rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1076 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
[2962]1077 cchSymbol, puValue, pfKind);
1078 else
1079 rc = KLDR_ERR_TODO; /** @todo duplicate kldrModMachOQuerySymbol32 for parsing 64-bit symbols when everything is working. */
[2963]1080 /*rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1081 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
[2962]1082 cchSymbol, puValue, pfKind);*/
1083
1084 }
[2952]1085 }
[2962]1086 else
1087 rc = KLDR_ERR_TODO;
[2952]1088
[2962]1089 return rc;
[2952]1090}
1091
1092
[2962]1093
[2952]1094/**
[2962]1095 * Lookup a symbol in a 32-bit symbol table.
[2963]1096 *
[2962]1097 * @returns See kLdrModQuerySymbol.
[2963]1098 * @param pModMachO
[2962]1099 * @param paSyms Pointer to the symbol table.
1100 * @param cSyms Number of symbols in the table.
1101 * @param pchStrings Pointer to the string table.
1102 * @param cchStrings Size of the string table.
[2963]1103 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
[2962]1104 * @param iSymbol See kLdrModQuerySymbol.
1105 * @param pchSymbol See kLdrModQuerySymbol.
1106 * @param cchSymbol See kLdrModQuerySymbol.
1107 * @param puValue See kLdrModQuerySymbol.
1108 * @param pfKind See kLdrModQuerySymbol.
[2952]1109 */
[2962]1110static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, uint32_t cSyms, const char *pchStrings,
1111 uint32_t cchStrings, KLDRADDR BaseAddress, uint32_t iSymbol, const char *pchSymbol, size_t cchSymbol,
1112 PKLDRADDR puValue, uint32_t *pfKind)
[2952]1113{
1114 /*
[2962]1115 * Find a valid symbol matching the search criteria.
[2952]1116 */
[2962]1117 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
[2952]1118 {
[2962]1119 /* simplify validation. */
1120 if (cchStrings <= cchSymbol)
1121 return KLDR_ERR_SYMBOL_NOT_FOUND;
1122 cchStrings -= cchSymbol;
1123
[2963]1124 /* external symbols are usually at the end, so search the other way. */
1125 for (iSymbol = cSyms - 1; iSymbol != UINT32_MAX; iSymbol--)
[2962]1126 {
1127 const char *psz;
1128
1129 /* Skip irrellevant and non-public symbols. */
1130 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1131 continue;
1132 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1133 continue;
1134 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1135 continue;
1136 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1137 continue;
[2963]1138
[2962]1139 /* get name */
[2963]1140 if (!paSyms[iSymbol].n_un.n_strx)
[2962]1141 continue;
1142 if ((uint32_t)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1143 continue;
1144 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1145 if (psz[cchSymbol])
1146 continue;
1147 if (kLdrHlpMemComp(psz, pchSymbol, cchSymbol))
1148 continue;
1149
1150 /* match! */
1151 break;
1152 }
[2963]1153 if (iSymbol == UINT32_MAX)
[2962]1154 return KLDR_ERR_SYMBOL_NOT_FOUND;
[2952]1155 }
[2962]1156 else
1157 {
1158 if (iSymbol >= cSyms)
1159 return KLDR_ERR_SYMBOL_NOT_FOUND;
1160 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1161 return KLDR_ERR_SYMBOL_NOT_FOUND;
1162 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1163 return KLDR_ERR_SYMBOL_NOT_FOUND;
1164 }
[2952]1165
[2963]1166 /*
[2962]1167 * Calc the return values.
[2952]1168 */
[2962]1169 if (pfKind)
[2952]1170 {
[2963]1171 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
[2962]1172 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1173 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
[2952]1174 else
[2962]1175 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1176 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1177 *pfKind |= KLDRSYMKIND_WEAK;
1178 }
1179
1180 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1181 {
1182 case MACHO_N_SECT:
[2952]1183 {
[2962]1184 PKLDRMODMACHOSECT pSect;
1185 KLDRADDR RVA;
1186 if ((uint32_t)(paSyms[iSymbol].n_sect - 1) >= pModMachO->cSections)
1187 return KLDR_ERR_MACHO_BAD_SYMBOL;
1188 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1189
1190 RVA = paSyms[iSymbol].n_value - pModMachO->LinkAddress;
1191 if (RVA - pSect->RVA >= pSect->cb)
1192 return KLDR_ERR_MACHO_BAD_SYMBOL;
1193 if (puValue)
1194 *puValue = RVA + BaseAddress;
1195
[2963]1196 if ( pfKind
[2962]1197 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1198 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1199 break;
[2952]1200 }
[2962]1201
1202 case MACHO_N_ABS:
1203 if (puValue)
1204 *puValue = paSyms[iSymbol].n_value;
1205 /*if (pfKind)
1206 pfKind |= KLDRSYMKIND_ABS;*/
1207 break;
1208
1209 case MACHO_N_PBUD:
1210 case MACHO_N_INDR:
1211 /** @todo implement indirect and prebound symbols. */
1212 default:
1213 KLDRMODMACHO_ASSERT(0);
1214 return KLDR_ERR_TODO;
[2952]1215 }
1216
1217 return 0;
1218}
1219
1220
[2962]1221/** @copydoc kLdrModEnumSymbols */
1222static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
1223 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
[2952]1224{
[2962]1225 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1226 int rc;
[2952]1227
1228 /*
[2962]1229 * Resolve defaults.
[2952]1230 */
[2962]1231 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
[2952]1232 if (rc)
1233 return rc;
1234
[2962]1235 /*
1236 * Take action according to file type.
1237 */
1238 if (pModMachO->Hdr.filetype == MH_OBJECT)
[2952]1239 {
[2962]1240 rc = kldrModMachOLoadObjSymTab(pModMachO);
1241 if (!rc)
[2952]1242 {
[2962]1243 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1244 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
[2963]1245 rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1246 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
[2962]1247 fFlags, pfnCallback, pvUser);
[2952]1248 else
[2962]1249 rc = KLDR_ERR_TODO; /** @todo duplicate kldrModMachOQuerySymbol32 for parsing 64-bit symbols when everything is working. */
[2963]1250 /*rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
[2962]1251 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, pfnCallback, pvUser);*/
[2952]1252 }
1253 }
[2962]1254 else
1255 rc = KLDR_ERR_TODO;
[2952]1256
[2962]1257 return rc;
[2952]1258}
1259
1260
[2962]1261/**
1262 * Enum a 32-bit symbol table.
[2963]1263 *
[2962]1264 * @returns See kLdrModQuerySymbol.
[2963]1265 * @param pModMachO
[2962]1266 * @param paSyms Pointer to the symbol table.
1267 * @param cSyms Number of symbols in the table.
1268 * @param pchStrings Pointer to the string table.
1269 * @param cchStrings Size of the string table.
[2963]1270 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
[2962]1271 * @param fFlags See kLdrModEnumSymbols.
1272 * @param pfnCallback See kLdrModEnumSymbols.
1273 * @param pvUser See kLdrModEnumSymbols.
1274 */
[2963]1275static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, uint32_t cSyms,
[2962]1276 const char *pchStrings, uint32_t cchStrings, KLDRADDR BaseAddress,
1277 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
[2952]1278{
[2962]1279 const uint32_t fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1280 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
1281 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT;
1282 uint32_t iSym;
1283 int rc;
[2952]1284
1285 /*
[2962]1286 * Iterate the symbol table.
[2952]1287 */
[2962]1288 for (iSym = 0; iSym < cSyms; iSym++)
1289 {
1290 uint32_t fKind;
1291 KLDRADDR uValue;
1292 const char *psz;
1293 size_t cch;
[2952]1294
[2962]1295 /* Skip debug symbols and undefined symbols. */
1296 if (paSyms[iSym].n_type & MACHO_N_STAB)
1297 continue;
1298 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1299 continue;
[2952]1300
[2962]1301 /* Skip non-public symbols unless they are requested explicitly. */
1302 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
1303 {
1304 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
1305 continue;
1306 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
1307 continue;
[2963]1308 if (!paSyms[iSym].n_un.n_strx)
[2962]1309 continue;
1310 }
[2952]1311
[2963]1312 /*
1313 * Gather symbol info
[2962]1314 */
[2952]1315
[2962]1316 /* name */
1317 if ((uint32_t)paSyms[iSym].n_un.n_strx >= cchStrings)
1318 return KLDR_ERR_MACHO_BAD_SYMBOL;
1319 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
1320 cch = kLdrHlpStrLen(psz);
1321 if (!cch)
1322 psz = NULL;
1323
1324 /* kind & value */
1325 fKind = fKindBase;
1326 if (paSyms[iSym].n_desc & N_WEAK_DEF)
1327 fKind |= KLDRSYMKIND_WEAK;
1328 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
[2952]1329 {
[2962]1330 case MACHO_N_SECT:
1331 {
1332 PKLDRMODMACHOSECT pSect;
1333 if ((uint32_t)(paSyms[iSym].n_sect - 1) >= pModMachO->cSections)
1334 return KLDR_ERR_MACHO_BAD_SYMBOL;
1335 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
1336
1337 uValue = paSyms[iSym].n_value - pModMachO->LinkAddress;
1338 if (uValue - pSect->RVA >= pSect->cb)
1339 return KLDR_ERR_MACHO_BAD_SYMBOL;
1340 uValue += BaseAddress;
1341
1342 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
1343 fKind |= KLDRSYMKIND_CODE;
1344 else
1345 fKind |= KLDRSYMKIND_NO_TYPE;
1346 break;
1347 }
1348
1349 case MACHO_N_ABS:
1350 uValue = paSyms[iSym].n_value;
1351 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
1352 break;
1353
1354 case MACHO_N_PBUD:
1355 case MACHO_N_INDR:
1356 /** @todo implement indirect and prebound symbols. */
1357 default:
1358 KLDRMODMACHO_ASSERT(0);
1359 return KLDR_ERR_TODO;
[2952]1360 }
1361
1362 /*
[2962]1363 * Do callback.
[2952]1364 */
[2962]1365 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
1366 if (rc)
1367 return rc;
[2952]1368 }
1369 return 0;
1370}
1371
1372
1373/** @copydoc kLdrModGetImport */
1374static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
1375{
[2956]1376 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1377 if (pModMachO->Hdr.filetype == MH_OBJECT)
[2952]1378 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1379
[2956]1380 /* later */
1381 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
[2952]1382}
1383
1384
1385/** @copydoc kLdrModNumberOfImports */
1386static int32_t kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits)
1387{
1388 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2956]1389 if (pModMachO->Hdr.filetype == MH_OBJECT)
1390 return 0;
[2952]1391
[2956]1392 /* later */
[2952]1393 return 0;
1394}
1395
1396
1397/** @copydoc kLdrModGetStackInfo */
1398static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1399{
1400 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1401
1402 pStackInfo->Address = NIL_KLDRADDR;
1403 pStackInfo->LinkAddress = NIL_KLDRADDR;
[2956]1404 pStackInfo->cbStack = pStackInfo->cbStackThread = 0;
1405 /* later */
[2952]1406
1407 return 0;
1408}
1409
1410
1411/** @copydoc kLdrModQueryMainEntrypoint */
1412static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1413{
1414#if 0
1415 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1416 int rc;
1417
1418 /*
1419 * Resolve base address alias if any.
1420 */
1421 rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress);
1422 if (rc)
1423 return rc;
1424
1425 /*
1426 * Convert the address from the header.
1427 */
1428 *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
1429 ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
1430 : NIL_KLDRADDR;
1431#else
1432 *pMainEPAddress = NIL_KLDRADDR;
1433#endif
1434 return 0;
1435}
1436
1437
1438/** @copydoc kLdrModEnumDbgInfo */
1439static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1440{
1441#if 0
1442 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1443 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
1444 uint32_t iDbgInfo;
1445 uint32_t cb;
1446 int rc;
1447
1448 /*
1449 * Check that there is a debug directory first.
1450 */
1451 cb = pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
1452 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1453 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1454 return 0;
1455
1456 /*
1457 * Make sure we've got mapped bits.
1458 */
1459 rc = kldrModMachOBitsAndBaseAddress(pModMachO, &pvBits, NULL);
1460 if (rc)
1461 return rc;
1462
1463 /*
1464 * Enumerate the debug directory.
1465 */
1466 pDbgDir = KLDRMODMACHO_RVA2TYPE(pvBits,
1467 pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
1468 const IMAGE_DEBUG_DIRECTORY *);
1469 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
1470 {
1471 KLDRDBGINFOTYPE enmDbgInfoType;
1472
1473 /* convert the type. */
1474 switch (pDbgDir->Type)
1475 {
1476 case IMAGE_DEBUG_TYPE_UNKNOWN:
1477 case IMAGE_DEBUG_TYPE_FPO:
1478 case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
1479 case IMAGE_DEBUG_TYPE_MISC:
1480 case IMAGE_DEBUG_TYPE_EXCEPTION:
1481 case IMAGE_DEBUG_TYPE_FIXUP:
1482 case IMAGE_DEBUG_TYPE_BORLAND:
1483 default:
1484 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
1485 break;
1486 case IMAGE_DEBUG_TYPE_CODEVIEW:
1487 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
1488 break;
1489 }
1490
1491 rc = pfnCallback(pMod, iDbgInfo,
1492 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
1493 pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
1494 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
1495 pDbgDir->SizeOfData,
1496 NULL,
1497 pvUser);
1498 if (rc)
1499 break;
1500
1501 /* next */
1502 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
1503 break;
1504 }
1505
1506 return rc;
1507#else
1508 return 0;
1509#endif
1510}
1511
1512
1513/** @copydoc kLdrModHasDbgInfo */
1514static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1515{
1516 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1517
1518#if 0
1519 /*
1520 * Base this entirely on the presence of a debug directory.
1521 */
1522 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
1523 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1524 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1525 return KLDR_ERR_NO_DEBUG_INFO;
1526 return 0;
1527#else
1528 return KLDR_ERR_NO_DEBUG_INFO;
1529#endif
1530}
1531
1532
1533/** @copydoc kLdrModMap */
1534static int kldrModMachOMap(PKLDRMOD pMod)
1535{
[2962]1536 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1537 unsigned fFixed;
1538 uint32_t i;
1539 void *pvBase;
1540 int rc;
[2952]1541
1542 /*
1543 * Already mapped?
1544 */
1545 if (pModMachO->pvMapping)
1546 return KLDR_ERR_ALREADY_MAPPED;
1547
1548 /*
[2962]1549 * Map it.
[2952]1550 */
[2962]1551 /* fixed image? */
1552 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
1553 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1554 if (!fFixed)
1555 pvBase = NULL;
1556 else
1557 {
1558 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
1559 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
1560 return KLDR_ERR_ADDRESS_OVERFLOW;
1561 }
1562
1563 /* try do the prepare */
1564 if (pModMachO->fMapUsingLoadCommandSections)
1565 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
1566 else
1567 {
1568 rc = kLdrRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
1569 if (rc)
1570 return rc;
1571 }
1572
1573 /*
1574 * Update the segments with their map addresses.
1575 */
1576 for (i = 0; i < pMod->cSegments; i++)
1577 {
1578 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
1579 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
1580 }
1581 pModMachO->pvMapping = pvBase;
1582
[2952]1583 return 0;
1584}
1585
1586
1587/** @copydoc kLdrModUnmap */
1588static int kldrModMachOUnmap(PKLDRMOD pMod)
1589{
[2962]1590 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1591 uint32_t i;
1592 int rc;
[2952]1593
1594 /*
1595 * Mapped?
1596 */
1597 if (!pModMachO->pvMapping)
1598 return KLDR_ERR_NOT_MAPPED;
1599
1600 /*
[2962]1601 * Try unmap the image.
[2952]1602 */
[2962]1603 if (pModMachO->fMapUsingLoadCommandSections)
1604 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
1605 else
1606 {
1607 rc = kLdrRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
1608 if (rc)
1609 return rc;
1610 }
1611
1612 /*
1613 * Update the segments to reflect that they aren't mapped any longer.
1614 */
1615 pModMachO->pvMapping = NULL;
1616 for (i = 0; i < pMod->cSegments; i++)
1617 pMod->aSegments[i].MapAddress = 0;
1618
[2952]1619 return 0;
1620}
1621
1622
1623/** @copydoc kLdrModAllocTLS */
1624static int kldrModMachOAllocTLS(PKLDRMOD pMod)
1625{
[2962]1626 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2952]1627
1628 /*
1629 * Mapped?
1630 */
1631 if (!pModMachO->pvMapping)
1632 return KLDR_ERR_NOT_MAPPED;
1633 return 0;
1634}
1635
1636
1637/** @copydoc kLdrModFreeTLS */
1638static void kldrModMachOFreeTLS(PKLDRMOD pMod)
1639{
1640}
1641
1642
1643/** @copydoc kLdrModReload */
1644static int kldrModMachOReload(PKLDRMOD pMod)
1645{
1646 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1647
1648 /*
1649 * Mapped?
1650 */
1651 if (!pModMachO->pvMapping)
1652 return KLDR_ERR_NOT_MAPPED;
1653
1654 /* the file provider does it all */
[2962]1655 return kLdrRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
[2952]1656}
1657
1658
1659/** @copydoc kLdrModFixupMapping */
1660static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1661{
1662 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1663 int rc, rc2;
1664
1665 /*
1666 * Mapped?
1667 */
1668 if (!pModMachO->pvMapping)
1669 return KLDR_ERR_NOT_MAPPED;
1670
1671 /*
1672 * Before doing anything we'll have to make all pages writable.
1673 */
[2962]1674 if (pModMachO->fMapUsingLoadCommandSections)
1675 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
1676 else
1677 {
1678 rc = kLdrRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
1679 if (rc)
1680 return rc;
1681 }
[2952]1682
1683 /*
[2962]1684 * Resolve imports and apply base relocations.
[2952]1685 */
[2963]1686 rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (uintptr_t)pModMachO->pvMapping, pModMachO->LinkAddress,
[2962]1687 pfnGetImport, pvUser);
[2952]1688
1689 /*
1690 * Restore protection.
1691 */
[2962]1692 if (pModMachO->fMapUsingLoadCommandSections)
1693 rc2 = KLDR_ERR_TODO; /* deal with this if it ever occurs. */
1694 else
1695 rc2 = kLdrRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
[2952]1696 if (!rc && rc2)
1697 rc = rc2;
1698 return rc;
1699}
1700
1701
1702/**
[2961]1703 * MH_OBJECT: Resolves undefined symbols (imports).
[2952]1704 *
1705 * @returns 0 on success, non-zero kLdr status code on failure.
[2961]1706 * @param pModMachO The Mach-O module interpreter instance.
1707 * @param pfnGetImport The callback for resolving an imported symbol.
1708 * @param pvUser User argument to the callback.
[2952]1709 */
[2961]1710static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
[2952]1711{
[2961]1712 const uint32_t cSyms = pModMachO->cSymbols;
1713 uint32_t iSym;
1714 int rc;
[2952]1715
1716 /*
[2961]1717 * Ensure that we've got the symbol table and section fixups handy.
[2952]1718 */
[2961]1719 rc = kldrModMachOLoadObjSymTab(pModMachO);
1720 if (rc)
1721 return rc;
[2952]1722
1723 /*
[2961]1724 * Iterate the symbol table and resolve undefined symbols.
1725 * We currently ignore REFERENCE_TYPE.
[2952]1726 */
[2963]1727 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
[2961]1728 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
[2952]1729 {
[2961]1730 macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols;
1731 for (iSym = 0; iSym < cSyms; iSym++)
[2952]1732 {
[2961]1733 /* skip stabs */
1734 if (paSyms[iSym].n_type & MACHO_N_STAB)
1735 continue;
[2952]1736
[2961]1737 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
[2952]1738 {
[2961]1739 const char *pszSymbol;
1740 size_t cchSymbol;
1741 uint32_t fKind = KLDRSYMKIND_REQ_FLAT;
[2963]1742 KLDRADDR Value;
[2952]1743
[2961]1744 /** @todo Implement N_REF_TO_WEAK. */
1745 if (paSyms[iSym].n_desc & N_REF_TO_WEAK)
1746 return KLDR_ERR_TODO;
[2952]1747
[2961]1748 /* Get the symbol name and try resolve it. */
[2962]1749 if ((uint32_t)paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
[2961]1750 return KLDR_ERR_MACHO_BAD_SYMBOL;
1751 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
1752 cchSymbol = kLdrHlpStrLen(pszSymbol);
1753 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
1754 &Value, &fKind, pvUser);
1755 if (rc)
1756 {
1757 /* weak reference? */
1758 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
1759 break;
1760 Value = 0;
1761 }
[2952]1762
[2961]1763 /* Update the symbol. */
1764 paSyms[iSym].n_value = (uint32_t)Value;
1765 if (paSyms[iSym].n_value != Value)
1766 {
1767 rc = KLDR_ERR_ADDRESS_OVERFLOW;
[2952]1768 break;
[2961]1769 }
1770 }
1771 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
[2964]1772 {
1773 /** @todo implement weak symbols. */
1774 /*return KLDR_ERR_TODO; - ignored for now. */
1775 }
[2961]1776 }
1777 }
1778 else
1779 {
1780 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
1781 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols;
1782 for (iSym = 0; iSym < cSyms; iSym++)
1783 {
1784 /* skip stabs */
1785 if (paSyms[iSym].n_type & MACHO_N_STAB)
1786 continue;
[2952]1787
[2961]1788 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1789 {
1790 const char *pszSymbol;
1791 size_t cchSymbol;
1792 uint32_t fKind = KLDRSYMKIND_REQ_FLAT;
[2963]1793 KLDRADDR Value;
[2961]1794
1795 /** @todo Implement N_REF_TO_WEAK. */
1796 if (paSyms[iSym].n_desc & N_REF_TO_WEAK)
1797 return KLDR_ERR_TODO;
1798
1799 /* Get the symbol name and try resolve it. */
[2962]1800 if (paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
[2961]1801 return KLDR_ERR_MACHO_BAD_SYMBOL;
1802 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
1803 cchSymbol = kLdrHlpStrLen(pszSymbol);
1804 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
1805 &Value, &fKind, pvUser);
1806 if (rc)
[2952]1807 {
[2961]1808 /* weak reference? */
1809 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
1810 break;
1811 Value = 0;
1812 }
[2952]1813
[2961]1814 /* Update the symbol. */
1815 paSyms[iSym].n_value = Value;
1816 if (paSyms[iSym].n_value != Value)
1817 {
1818 rc = KLDR_ERR_ADDRESS_OVERFLOW;
[2952]1819 break;
1820 }
[2961]1821 }
1822 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
[2964]1823 {
1824 /** @todo implement weak symbols. */
1825 /*return KLDR_ERR_TODO; - ignored for now. */
1826 }
[2961]1827 }
1828 }
[2952]1829
[2961]1830 return rc;
1831}
[2952]1832
1833
[2961]1834/**
1835 * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
1836 *
1837 * @returns 0 on success, non-zero kLdr status code on failure.
1838 * @param pModMachO The Mach-O module interpreter instance.
1839 * @param pvMapping The mapping to fixup.
1840 * @param NewBaseAddress The address to fixup the mapping to.
1841 * @param OldBaseAddress The address the mapping is currently fixed up to.
1842 */
1843static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress)
1844{
1845 uint32_t iSeg;
1846 int rc;
[2952]1847
1848
[2961]1849 /*
1850 * Ensure that we've got the symbol table and section fixups handy.
1851 */
1852 rc = kldrModMachOLoadObjSymTab(pModMachO);
1853 if (rc)
1854 return rc;
[2952]1855
[2961]1856 /*
1857 * Iterate over the segments and their sections and apply fixups.
1858 */
1859 for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++)
1860 {
1861 PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg];
1862 uint32_t iSect;
1863
1864 for (iSect = 0; iSect < pSeg->cSections; iSect++)
1865 {
1866 PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect];
1867 uint8_t *pbSectBits;
1868
1869 /* skip sections without fixups. */
1870 if (!pSect->cFixups)
1871 continue;
1872
1873 /* lazy load (and endian convert) the fixups. */
1874 if (!pSect->paFixups)
1875 {
1876 rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
1877 if (rc)
[2952]1878 break;
[2961]1879 }
[2952]1880
[2961]1881 /*
1882 * Apply the fixups.
1883 */
1884 pbSectBits = (uint8_t *)pvMapping + (uintptr_t)pSect->RVA;
[2963]1885 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
1886 rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect,
1887 (macho_nlist_32_t *)pModMachO->pvaSymbols,
1888 pModMachO->cSymbols, NewBaseAddress);
1889 else
1890 rc = KLDR_ERR_TODO; /* save space for now. */
[2961]1891 if (rc)
1892 break;
[2952]1893 }
[2961]1894 }
[2952]1895
[2961]1896 return rc;
1897}
[2952]1898
1899
[2963]1900/**
1901 * Applies generic fixups to a section in an image of the same endian-ness
1902 * as the host CPU.
1903 *
1904 * @returns 0 on success, non-zero kLdr status code on failure.
1905 * @param pModMachO The Mach-O module interpreter instance.
1906 * @param pbSectBits Pointer to the section bits.
1907 * @param pFixupSect The section being fixed up.
1908 * @param NewBaseAddress The new base image address.
1909 */
1910static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, uint8_t *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
1911 macho_nlist_32_t *paSyms, uint32_t cSyms, KLDRADDR NewBaseAddress)
[2961]1912{
[2963]1913 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
1914 const uint32_t cFixups = pFixupSect->cFixups;
1915 size_t cbSectBits = (size_t)pFixupSect->cb;
1916 const uint8_t *pbSectVirginBits;
1917 uint32_t iFixup;
1918 KLDRPU uFixVirgin;
1919 KLDRPU uFix;
1920 KLDRADDR SymAddr;
1921 int rc;
[2961]1922
[2963]1923 /*
1924 * Find the virgin bits.
1925 */
1926 if (pFixupSect->offFile != -1)
1927 {
1928 rc = kldrModMachOMapVirginBits(pModMachO);
1929 if (rc)
1930 return rc;
1931 pbSectVirginBits = (const uint8_t *)pModMachO->pvBits + pFixupSect->offFile;
1932 }
1933 else
1934 pbSectVirginBits = NULL;
1935
1936 /*
1937 * Iterate the fixups and apply them.
1938 */
1939 for (iFixup = 0; iFixup < cFixups; iFixup++)
1940 {
1941 union
1942 {
1943 macho_relocation_info_t r;
1944 scattered_relocation_info_t s;
1945 } Fixup;
1946 Fixup.r = paFixups[iFixup];
1947
1948 if (!(Fixup.r.r_address & R_SCATTERED))
1949 {
1950 /* sanity */
1951 if ((uint32_t)Fixup.r.r_address >= cbSectBits)
1952 return KLDR_ERR_BAD_FIXUP;
1953
1954 /* calc fixup addresses. */
1955 uFix.pv = pbSectBits + Fixup.r.r_address;
1956 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.r.r_address : 0;
1957
1958 /*
1959 * Calc the symbol value.
1960 */
1961 /* The addend is stored in the code. */
1962 /** @todo Deal with unaligned accesses on non x86 platforms. */
1963 switch (Fixup.r.r_length)
1964 {
1965 case 0: SymAddr = *uFixVirgin.pi8; break;
1966 case 1: SymAddr = *uFixVirgin.pi16; break;
1967 case 2: SymAddr = *uFixVirgin.pi32; break;
1968 case 3: SymAddr = *uFixVirgin.pi64; break;
1969 }
[2968]1970 if (Fixup.r.r_pcrel)
1971 SymAddr += Fixup.r.r_address;
[2963]1972
1973 /* Add symbol / section address. */
1974 if (Fixup.r.r_extern)
1975 {
1976 const macho_nlist_32_t *pSym;
1977 if (Fixup.r.r_symbolnum >= cSyms)
1978 return KLDR_ERR_BAD_FIXUP;
1979 pSym = &paSyms[Fixup.r.r_symbolnum];
1980
1981 if (pSym->n_type & MACHO_N_STAB)
1982 return KLDR_ERR_BAD_FIXUP;
1983
1984 switch (pSym->n_type & MACHO_N_TYPE)
1985 {
1986 case MACHO_N_SECT:
1987 {
1988 PKLDRMODMACHOSECT pSymSect;
1989 if ((uint32_t)pSym->n_sect - 1 > pModMachO->cSections)
1990 return KLDR_ERR_MACHO_BAD_SYMBOL;
1991 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
1992
1993 SymAddr += pSym->n_value - pModMachO->LinkAddress + pSymSect->RVA;
1994 break;
1995 }
1996
1997 case MACHO_N_UNDF:
1998 case MACHO_N_ABS:
1999 SymAddr += pSym->n_value;
2000 break;
2001
2002 case MACHO_N_INDR:
2003 case MACHO_N_PBUD:
2004 return KLDR_ERR_TODO;
2005 default:
2006 return KLDR_ERR_MACHO_BAD_SYMBOL;
2007 }
2008 }
2009 else if (Fixup.r.r_symbolnum != R_ABS)
2010 {
2011 PKLDRMODMACHOSECT pSymSect;
2012 if (Fixup.r.r_symbolnum > pModMachO->cSections)
2013 return KLDR_ERR_BAD_FIXUP;
2014 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
[2968]2015
2016 SymAddr -= pSymSect->LinkAddress;
[2963]2017 SymAddr += NewBaseAddress + pSymSect->RVA;
2018 }
2019
2020 /* adjust for PC relative */
2021 if (Fixup.r.r_pcrel)
2022 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
2023 }
2024 else
2025 {
2026 PKLDRMODMACHOSECT pSymSect;
2027 uint32_t iSymSect;
2028 KLDRADDR Value;
2029
2030 /* sanity */
2031 KLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
2032 if ((uint32_t)Fixup.s.r_address >= cbSectBits)
2033 return KLDR_ERR_BAD_FIXUP;
2034
2035 /* calc fixup addresses. */
2036 uFix.pv = pbSectBits + Fixup.s.r_address;
2037 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.s.r_address : 0;
2038
2039 /*
2040 * Calc the symbol value.
2041 */
2042 /* The addend is stored in the code. */
2043 switch (Fixup.s.r_length)
2044 {
2045 case 0: SymAddr = *uFixVirgin.pi8; break;
2046 case 1: SymAddr = *uFixVirgin.pi16; break;
2047 case 2: SymAddr = *uFixVirgin.pi32; break;
2048 case 3: SymAddr = *uFixVirgin.pi64; break;
2049 }
[2968]2050 if (Fixup.s.r_pcrel)
2051 Value += Fixup.s.r_address;
[2963]2052
2053 /* Calc the section number from the r_value and adjust the value. */
2054 pSymSect = NULL;
[2968]2055 Value = Fixup.s.r_value;
[2963]2056 for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++)
2057 {
[2968]2058 KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress;
[2963]2059 if (off < pModMachO->paSections[iSymSect].cb)
2060 {
2061 pSymSect = &pModMachO->paSections[iSymSect];
2062 break;
2063 }
2064 else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */
2065 pSymSect = &pModMachO->paSections[iSymSect];
2066 }
2067 if (!pSymSect)
2068 return KLDR_ERR_BAD_FIXUP;
[2968]2069 Value -= pSymSect->LinkAddress;
[2963]2070
[2968]2071 /* Calc the symbol address. */
2072 SymAddr += NewBaseAddress + pSymSect->RVA + Value;
[2963]2073 if (Fixup.s.r_pcrel)
2074 SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
2075
2076 Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
2077 Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type;
2078 }
2079
2080 /*
2081 * Write back the fixed up value.
2082 */
2083 if (Fixup.r.r_type == GENERIC_RELOC_VANILLA)
2084 {
2085 switch (Fixup.r.r_length)
2086 {
2087 case 0: *uFix.pu8 = (uint8_t)SymAddr; break;
2088 case 1: *uFix.pu16 = (uint16_t)SymAddr; break;
2089 case 2: *uFix.pu32 = (uint32_t)SymAddr; break;
2090 case 3: *uFix.pu64 = (uint64_t)SymAddr; break;
2091 }
2092 }
2093 else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF)
[2964]2094 return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE;
[2963]2095 else
2096 return KLDR_ERR_BAD_FIXUP;
2097 }
2098
[2952]2099 return 0;
2100}
2101
2102
[2961]2103/**
2104 * Loads the symbol table for a MH_OBJECT file.
[2963]2105 *
[2961]2106 * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols.
[2963]2107 *
[2961]2108 * @returns 0 on success, non-zero kLdr status code on failure.
[2963]2109 * @param pModMachO The Mach-O module interpreter instance.
[2961]2110 */
2111static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO)
2112{
2113 int rc = 0;
[2952]2114
[2963]2115 if ( !pModMachO->pvaSymbols
[2961]2116 && pModMachO->cSymbols)
2117 {
2118 size_t cbSyms;
2119 size_t cbSym;
2120 void *pvSyms;
2121 void *pvStrings;
2122
2123 /* sanity */
2124 if ( !pModMachO->offSymbols
[2962]2125 || (pModMachO->cchStrings && !pModMachO->offStrings))
[2961]2126 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
2127
2128 /* allocate */
2129 cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2130 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
2131 ? sizeof(macho_nlist_32_t)
2132 : sizeof(macho_nlist_64_t);
2133 cbSyms = pModMachO->cSymbols * cbSym;
2134 if (cbSyms / cbSym != pModMachO->cSymbols)
2135 return KLDR_ERR_SIZE_OVERFLOW;
2136 rc = KLDR_ERR_NO_MEMORY;
2137 pvSyms = kldrHlpAlloc(cbSyms);
2138 if (pvSyms)
2139 {
[2962]2140 if (pModMachO->cchStrings)
2141 pvStrings = kldrHlpAlloc(pModMachO->cchStrings);
[2961]2142 else
2143 pvStrings = kldrHlpAllocZ(4);
2144 if (pvStrings)
2145 {
2146 /* read */
2147 rc = kLdrRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols);
[2962]2148 if (!rc && pModMachO->cchStrings)
2149 rc = kLdrRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings);
[2961]2150 if (!rc)
2151 {
2152 pModMachO->pvaSymbols = pvSyms;
2153 pModMachO->pchStrings = (char *)pvStrings;
[2963]2154
[2961]2155 /* perform endian conversion? */
2156 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2157 {
2158 uint32_t cLeft = pModMachO->cSymbols;
2159 macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms;
2160 while (cLeft-- > 0)
2161 {
2162 pSym->n_un.n_strx = KLDRHLP_E2E_U32(pSym->n_un.n_strx);
2163 pSym->n_desc = (int16_t)KLDRHLP_E2E_U16(pSym->n_desc);
2164 pSym->n_value = KLDRHLP_E2E_U32(pSym->n_value);
2165 pSym++;
2166 }
[2963]2167 }
[2961]2168 else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
2169 {
2170 uint32_t cLeft = pModMachO->cSymbols;
2171 macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms;
2172 while (cLeft-- > 0)
2173 {
2174 pSym->n_un.n_strx = KLDRHLP_E2E_U32(pSym->n_un.n_strx);
2175 pSym->n_desc = (int16_t)KLDRHLP_E2E_U16(pSym->n_desc);
2176 pSym->n_value = KLDRHLP_E2E_U64(pSym->n_value);
2177 pSym++;
2178 }
2179 }
2180
2181 return 0;
2182 }
2183 kldrHlpFree(pvStrings);
2184 }
2185 kldrHlpFree(pvSyms);
2186 }
2187 }
2188 else
2189 KLDRMODMACHO_ASSERT(pModMachO->pchStrings);
2190
2191 return rc;
2192}
2193
2194
[2952]2195/**
[2963]2196 * Loads the fixups at the given address and performs endian
[2961]2197 * conversion if necessary.
[2963]2198 *
[2952]2199 * @returns 0 on success, non-zero kLdr status code on failure.
[2963]2200 * @param pModMachO The Mach-O module interpreter instance.
[2961]2201 * @param offFixups The file offset of the fixups.
2202 * @param cFixups The number of fixups to load.
2203 * @param ppaFixups Where to put the pointer to the allocated fixup array.
[2952]2204 */
[2961]2205static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, off_t offFixups, uint32_t cFixups, macho_relocation_info_t **ppaFixups)
[2952]2206{
[2961]2207 macho_relocation_info_t *paFixups;
2208 size_t cbFixups;
2209 int rc;
2210
2211 /* allocate the memory. */
2212 cbFixups = cFixups * sizeof(*paFixups);
2213 if (cbFixups / sizeof(*paFixups) != cFixups)
2214 return KLDR_ERR_SIZE_OVERFLOW;
2215 paFixups = (macho_relocation_info_t *)kldrHlpAlloc(cbFixups);
2216 if (!paFixups)
2217 return KLDR_ERR_NO_MEMORY;
2218
2219 /* read the fixups. */
2220 rc = kLdrRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups);
2221 if (!rc)
2222 {
2223 *ppaFixups = paFixups;
2224
2225 /* do endian conversion if necessary. */
[2963]2226 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
[2961]2227 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
2228 {
2229 uint32_t iFixup;
2230 for (iFixup = 0; iFixup < cFixups; iFixup++)
2231 {
2232 uint32_t *pu32 = (uint32_t *)&paFixups[iFixup];
2233 pu32[0] = KLDRHLP_E2E_U32(pu32[0]);
2234 pu32[1] = KLDRHLP_E2E_U32(pu32[1]);
2235 }
2236 }
2237 }
2238 else
2239 kldrHlpFree(paFixups);
2240 return rc;
[2952]2241}
2242
2243
[2963]2244/**
2245 * Maps the virgin file bits into memory if not already done.
2246 *
2247 * @returns 0 on success, non-zero kLdr status code on failure.
2248 * @param pModMachO The Mach-O module interpreter instance.
2249 */
2250static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO)
2251{
2252 int rc = 0;
2253 if (!pModMachO->pvBits)
2254 rc = kLdrRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits);
2255 return rc;
2256}
2257
2258
[2952]2259/** @copydoc kLdrModCallInit */
2260static int kldrModMachOCallInit(PKLDRMOD pMod, uintptr_t uHandle)
2261{
[2956]2262 /* later */
[2952]2263 return 0;
2264}
2265
2266
2267/** @copydoc kLdrModCallTerm */
2268static int kldrModMachOCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
2269{
[2956]2270 /* later */
[2952]2271 return 0;
2272}
2273
2274
2275/** @copydoc kLdrModCallThread */
2276static int kldrModMachOCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
2277{
[2956]2278 /* Relevant for Mach-O? */
[2952]2279 return 0;
2280}
2281
2282
2283/** @copydoc kLdrModSize */
2284static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
2285{
2286 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
[2955]2287 return pModMachO->cbImage;
[2952]2288}
2289
2290
2291/** @copydoc kLdrModGetBits */
2292static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2293{
2294 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2295 uint32_t i;
2296 int rc;
2297
2298 /*
2299 * Zero the entire buffer first to simplify things.
2300 */
[2956]2301 kLdrHlpMemSet(pvBits, 0, (size_t)pModMachO->cbImage);
[2952]2302
2303 /*
[2956]2304 * When possible use the segment table to load the data.
2305 * If not iterate the load commands and execute the segment / section loads.
[2952]2306 */
[2962]2307 if (pModMachO->fMapUsingLoadCommandSections)
2308 return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
2309 else
[2952]2310 {
[2956]2311 for (i = 0; i < pMod->cSegments; i++)
2312 {
2313 /* skip it? */
2314 if ( pMod->aSegments[i].cbFile == -1
2315 || pMod->aSegments[i].offFile == -1
2316 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
2317 || !pMod->aSegments[i].Alignment)
2318 continue;
2319 rc = kLdrRdrRead(pMod->pRdr,
2320 (uint8_t *)pvBits + (pMod->aSegments[i].LinkAddress - pModMachO->LinkAddress),
2321 pMod->aSegments[i].cbFile,
2322 pMod->aSegments[i].offFile);
2323 if (rc)
2324 return rc;
2325 }
[2952]2326 }
2327
2328 /*
2329 * Perform relocations.
2330 */
[2956]2331 return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
[2952]2332}
2333
2334
2335/** @copydoc kLdrModRelocateBits */
2336static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
[2954]2337 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
[2952]2338{
2339 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2340 int rc;
2341
2342 /*
2343 * Call workers to do the jobs.
2344 */
[2961]2345 if (pModMachO->Hdr.filetype == MH_OBJECT)
2346 {
2347 rc = kldrModMachOObjDoImports(pModMachO, pfnGetImport, pvUser);
2348 if (!rc)
2349 rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress);
[2952]2350
[2961]2351 }
2352 else
2353 rc = KLDR_ERR_TODO;
2354 /*{
2355 rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
2356 if (!rc)
2357 rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
2358 }*/
2359
[2952]2360 return rc;
2361}
2362
2363
2364/**
[2954]2365 * The Mach-O module interpreter method table.
[2952]2366 */
[2954]2367KLDRMODOPS g_kLdrModMachOOps =
[2952]2368{
[2954]2369 "Mach-O",
[2952]2370 NULL,
2371 kldrModMachOCreate,
2372 kldrModMachODestroy,
2373 kldrModMachOQuerySymbol,
2374 kldrModMachOEnumSymbols,
2375 kldrModMachOGetImport,
2376 kldrModMachONumberOfImports,
2377 NULL /* can execute one is optional */,
2378 kldrModMachOGetStackInfo,
2379 kldrModMachOQueryMainEntrypoint,
2380 NULL,
2381 NULL,
2382 kldrModMachOEnumDbgInfo,
2383 kldrModMachOHasDbgInfo,
2384 kldrModMachOMap,
2385 kldrModMachOUnmap,
2386 kldrModMachOAllocTLS,
2387 kldrModMachOFreeTLS,
2388 kldrModMachOReload,
2389 kldrModMachOFixupMapping,
2390 kldrModMachOCallInit,
2391 kldrModMachOCallTerm,
2392 kldrModMachOCallThread,
2393 kldrModMachOSize,
2394 kldrModMachOGetBits,
2395 kldrModMachORelocateBits,
2396 NULL, /** @todo mostly done */
2397 42 /* the end */
2398};
2399
Note: See TracBrowser for help on using the repository browser.