source: trunk/kLdr/kLdrModMachO.c@ 2962

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

Symbol enum and querying works.

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