source: trunk/kLdr/kLdrModMachO.c@ 22

Last change on this file since 22 was 22, checked in by bird, 17 years ago

kLdrModMachO.c: Initial 64-bit support (MH_OBJECT).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 123.1 KB
RevLine 
[2]1/* $Id: kLdrModMachO.c 22 2009-01-30 06:29:43Z bird $ */
2/** @file
3 * kLdr - The Module Interpreter for the MACH-O format.
4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
8 *
9 * This file is part of kStuff.
10 *
11 * kStuff is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * In addition to the permissions in the GNU Lesser General Public
17 * License, you are granted unlimited permission to link the compiled
18 * version of this file into combinations with other programs, and to
19 * distribute those combinations without any restriction coming from
20 * the use of this file.
21 *
22 * kStuff is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with kStuff; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 * 02110-1301, USA
31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#include <k/kLdr.h>
37#include "kLdrInternal.h"
38#include <k/kLdrFmts/mach-o.h>
39
40
41/*******************************************************************************
42* Defined Constants And Macros *
43*******************************************************************************/
44/** @def KLDRMODMACHO_STRICT
45 * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */
46#define KLDRMODMACHO_STRICT 1
47
48/** @def KLDRMODMACHO_ASSERT
49 * Assert that an expression is true when KLDR_STRICT is defined.
50 */
51#ifdef KLDRMODMACHO_STRICT
52# define KLDRMODMACHO_ASSERT(expr) kHlpAssert(expr)
53#else
54# define KLDRMODMACHO_ASSERT(expr) do {} while (0)
55#endif
56
[22]57/** @def KLDRMODMACHO_CHECK_RETURN
58 * Checks that an expression is true and return if it isn't.
59 * This is a debug aid.
60 */
61#ifdef KLDRMODMACHO_STRICT2
62# define KLDRMODMACHO_CHECK_RETURN(expr, rc) kHlpAssertReturn(expr, rc)
63#else
64# define KLDRMODMACHO_CHECK_RETURN(expr, rc) do { if (!(expr)) { return (rc); } } while (0)
65#endif
[2]66
[22]67
[2]68/*******************************************************************************
69* Structures and Typedefs *
70*******************************************************************************/
71/**
72 * Mach-O section details.
73 */
74typedef struct KLDRMODMACHOSECT
75{
76 /** The size of the section (in bytes). */
77 KLDRSIZE cb;
78 /** The link address of this section. */
79 KLDRADDR LinkAddress;
80 /** The RVA of this section. */
81 KLDRADDR RVA;
82 /** The file offset of this section.
83 * This is -1 if the section doesn't have a file backing. */
84 KLDRFOFF offFile;
85 /** The number of fixups. */
86 KU32 cFixups;
87 /** The array of fixups. (lazy loaded) */
88 macho_relocation_info_t *paFixups;
89 /** The file offset of the fixups for this section.
90 * This is -1 if the section doesn't have any fixups. */
91 KLDRFOFF offFixups;
92 /** Mach-O section flags. */
93 KU32 fFlags;
94 /** kLdr segment index. */
95 KU32 iSegment;
96 /** Pointer to the Mach-O section structure. */
97 void *pvMachoSection;
98} KLDRMODMACHOSECT, *PKLDRMODMACHOSECT;
99
100/**
101 * Extra per-segment info.
102 *
103 * This is corresponds to a kLdr segment, not a Mach-O segment!
104 */
105typedef struct KLDRMODMACHOSEG
106{
107 /** The number of sections in the segment. */
108 KU32 cSections;
109 /** Pointer to the sections belonging to this segment.
110 * The array resides in the big memory chunk allocated for
111 * the module handle, so it doesn't need freeing. */
112 PKLDRMODMACHOSECT paSections;
113
114} KLDRMODMACHOSEG, *PKLDRMODMACHOSEG;
115
116/**
117 * Instance data for the Mach-O MH_OBJECT module interpreter.
118 * @todo interpret the other MH_* formats.
119 */
120typedef struct KLDRMODMACHO
121{
122 /** Pointer to the module. (Follows the section table.) */
123 PKLDRMOD pMod;
124 /** Pointer to the RDR file mapping of the raw file bits. NULL if not mapped. */
125 const void *pvBits;
126 /** Pointer to the user mapping. */
127 void *pvMapping;
128
129 /** The link address. */
130 KLDRADDR LinkAddress;
131 /** The size of the mapped image. */
132 KLDRADDR cbImage;
[22]133 /** The RVA of the Global Offset Table. */
134 KLDRADDR GotRVA;
135 /** Whether we're creating a global offset table segment.
136 * This dependes on the cputype and image type. */
137 KBOOL fMakeGot;
[2]138 /** When set the sections in the load command segments must be used when
139 * mapping or loading the image. */
[22]140 KBOOL fMapUsingLoadCommandSections;
[2]141 /** Pointer to the load commands. (endian converted) */
142 KU8 *pbLoadCommands;
143 /** The Mach-O header. (endian converted)
144 * @remark The reserved field is only valid for real 64-bit headers. */
145 mach_header_64_t Hdr;
146
147 /** The offset of the symbol table. */
148 KLDRFOFF offSymbols;
149 /** The number of symbols. */
150 KU32 cSymbols;
151 /** The pointer to the loaded symbol table. */
152 void *pvaSymbols;
153 /** The offset of the string table. */
154 KLDRFOFF offStrings;
155 /** The size of the of the string table. */
156 KU32 cchStrings;
157 /** Pointer to the loaded string table. */
158 char *pchStrings;
159
160 /** The number of sections. */
161 KU32 cSections;
162 /** Pointer to the section array running in parallel to the Mach-O one. */
163 PKLDRMODMACHOSECT paSections;
164
165 /** Array of segments parallel to the one in KLDRMOD. */
166 KLDRMODMACHOSEG aSegments[1];
167} KLDRMODMACHO, *PKLDRMODMACHO;
168
169
170
171/*******************************************************************************
172* Internal Functions *
173*******************************************************************************/
174#if 0
175static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits);
176#endif
177static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
178 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
179
180static int kldrModMachODoCreate(PKRDR pRdr, PKLDRMODMACHO *ppMod);
181static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr,
182 KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool);
183static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool);
184static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress);
185
186/*static int kldrModMachOLoadLoadCommands(PKLDRMODMACHO pModMachO);*/
187static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO);
188static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups);
189static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO);
190
191static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings,
192 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol,
193 KSIZE cchSymbol, PKLDRADDR puValue, KU32 *pfKind);
[22]194static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings,
195 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol,
196 KSIZE cchSymbol, PKLDRADDR puValue, KU32 *pfKind);
[2]197static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
198 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
199 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
[22]200static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms,
201 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
202 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
[2]203static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
204static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress);
205static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
206 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress);
[22]207static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
208 macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress);
[2]209
[22]210static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress);
211
[2]212/*static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
213static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);*/
214
215
216/**
217 * Create a loader module instance interpreting the executable image found
218 * in the specified file provider instance.
219 *
220 * @returns 0 on success and *ppMod pointing to a module instance.
221 * On failure, a non-zero OS specific error code is returned.
222 * @param pOps Pointer to the registered method table.
223 * @param pRdr The file provider instance to use.
224 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
225 * @param ppMod Where to store the module instance pointer.
226 */
227static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
228{
229 PKLDRMODMACHO pModMachO;
230 int rc;
231
232 /*
233 * Create the instance data and do a minimal header validation.
234 */
235 rc = kldrModMachODoCreate(pRdr, &pModMachO);
236 if (!rc)
237 {
238 pModMachO->pMod->pOps = pOps;
239 pModMachO->pMod->u32Magic = KLDRMOD_MAGIC;
240 *ppMod = pModMachO->pMod;
241 return 0;
242 }
243 if (pModMachO)
244 {
245 kHlpFree(pModMachO->pbLoadCommands);
246 kHlpFree(pModMachO);
247 }
248 return rc;
249}
250
251
252/**
[22]253 * Separate function for reading creating the Mach-O module instance to
[2]254 * simplify cleanup on failure.
255 */
256static int kldrModMachODoCreate(PKRDR pRdr, PKLDRMODMACHO *ppModMachO)
257{
258 union
259 {
260 mach_header_32_t Hdr32;
261 mach_header_64_t Hdr64;
262 } s;
263 PKLDRMODMACHO pModMachO;
264 PKLDRMOD pMod;
265 KU8 *pbLoadCommands;
266 KU32 cSegments;
267 KU32 cSections;
268 KU32 cbStringPool;
269 KSIZE cchFilename;
270 KSIZE cb;
[22]271 KBOOL fMakeGot;
[2]272 int rc;
273 *ppModMachO = NULL;
274
[22]275 kHlpAssert(&s.Hdr32.magic == &s.Hdr64.magic);
276 kHlpAssert(&s.Hdr32.flags == &s.Hdr64.flags);
277
[2]278 /*
279 * Read the Mach-O header.
280 */
281 rc = kRdrRead(pRdr, &s, sizeof(s), 0);
282 if (rc)
283 return rc;
[22]284 if ( s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE
285 && s.Hdr32.magic != IMAGE_MACHO64_SIGNATURE
286 )
[2]287 {
288 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
289 || s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE)
290 return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED;
291 return KLDR_ERR_UNKNOWN_FORMAT;
292 }
293
294 /* sanity checks. */
295 if ( s.Hdr32.sizeofcmds > kRdrSize(pRdr) - sizeof(mach_header_32_t)
296 || s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds
297 || (s.Hdr32.flags & ~MH_VALID_FLAGS))
298 return KLDR_ERR_MACHO_BAD_HEADER;
299 switch (s.Hdr32.cputype)
300 {
301 case CPU_TYPE_X86:
[22]302 fMakeGot = K_FALSE;
303 break;
[2]304 case CPU_TYPE_X86_64:
[22]305 fMakeGot = s.Hdr32.filetype == MH_OBJECT;
[2]306 break;
307 default:
308 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
309 }
310 if (s.Hdr32.filetype != MH_OBJECT)
311 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
312
313 /*
314 * Read and pre-parse the load commands to figure out how many segments we'll be needing.
315 */
316 pbLoadCommands = kHlpAlloc(s.Hdr32.sizeofcmds);
317 if (!pbLoadCommands)
318 return KERR_NO_MEMORY;
319 rc = kRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds,
320 s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
321 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
322 ? sizeof(mach_header_32_t) : sizeof(mach_header_64_t));
323 if (!rc)
324 rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, &cSegments, &cSections, &cbStringPool);
325 if (rc)
326 {
327 kHlpFree(pbLoadCommands);
328 return rc;
329 }
[22]330 cSegments += fMakeGot;
[2]331
332
333 /*
334 * Calc the instance size, allocate and initialize it.
335 */
336 cchFilename = kHlpStrLen(kRdrName(pRdr));
337 cb = K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
338 + sizeof(KLDRMODMACHOSECT) * cSections, 16)
339 + K_OFFSETOF(KLDRMOD, aSegments[cSegments])
340 + cchFilename + 1
341 + cbStringPool;
342 pModMachO = (PKLDRMODMACHO)kHlpAlloc(cb);
343 if (!pModMachO)
344 return KERR_NO_MEMORY;
345 *ppModMachO = pModMachO;
346 pModMachO->pbLoadCommands = pbLoadCommands;
347
348 /* KLDRMOD */
349 pMod = (PKLDRMOD)((KU8 *)pModMachO + K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
350 + sizeof(KLDRMODMACHOSECT) * cSections, 16));
351 pMod->pvData = pModMachO;
352 pMod->pRdr = pRdr;
353 pMod->pOps = NULL; /* set upon success. */
354 pMod->cSegments = cSegments;
355 pMod->cchFilename = cchFilename;
356 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
357 kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1);
358 pMod->pszName = kHlpGetFilename(pMod->pszFilename);
359 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
360 switch (s.Hdr32.cputype)
361 {
362 case CPU_TYPE_X86:
363 pMod->enmArch = KCPUARCH_X86_32;
364 pMod->enmEndian = KLDRENDIAN_LITTLE;
365 switch (s.Hdr32.cpusubtype)
366 {
367 case CPU_SUBTYPE_I386_ALL: pMod->enmCpu = KCPU_X86_32_BLEND; break;
368 /*case CPU_SUBTYPE_386: ^^ pMod->enmCpu = KCPU_I386; break;*/
369 case CPU_SUBTYPE_486: pMod->enmCpu = KCPU_I486; break;
370 case CPU_SUBTYPE_486SX: pMod->enmCpu = KCPU_I486SX; break;
371 /*case CPU_SUBTYPE_586: vv */
372 case CPU_SUBTYPE_PENT: pMod->enmCpu = KCPU_I586; break;
373 case CPU_SUBTYPE_PENTPRO:
374 case CPU_SUBTYPE_PENTII_M3:
375 case CPU_SUBTYPE_PENTII_M5:
376 case CPU_SUBTYPE_CELERON:
377 case CPU_SUBTYPE_CELERON_MOBILE:
378 case CPU_SUBTYPE_PENTIUM_3:
379 case CPU_SUBTYPE_PENTIUM_3_M:
380 case CPU_SUBTYPE_PENTIUM_3_XEON: pMod->enmCpu = KCPU_I686; break;
381 case CPU_SUBTYPE_PENTIUM_M:
382 case CPU_SUBTYPE_PENTIUM_4:
383 case CPU_SUBTYPE_PENTIUM_4_M:
384 case CPU_SUBTYPE_XEON:
385 case CPU_SUBTYPE_XEON_MP: pMod->enmCpu = KCPU_P4; break;
386 break;
387 default:
388 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
389 }
390 break;
391
392 case CPU_TYPE_X86_64:
393 pMod->enmArch = KCPUARCH_AMD64;
394 pMod->enmEndian = KLDRENDIAN_LITTLE;
[22]395 switch (s.Hdr32.cpusubtype & ~CPU_SUBTYPE_MASK)
[2]396 {
397 case CPU_SUBTYPE_X86_64_ALL: pMod->enmCpu = KCPU_AMD64_BLEND; break;
398 default:
399 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
400 }
401 break;
402
403 default:
404 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
405 }
406
407 pMod->enmFmt = KLDRFMT_MACHO;
408 switch (s.Hdr32.filetype)
409 {
410 case MH_OBJECT:
411 pMod->enmType = KLDRTYPE_OBJECT;
412 break;
413 default:
414 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
415 }
416 pMod->u32Magic = 0; /* set upon success. */
417
418 /* KLDRMODMACHO */
419 pModMachO->pMod = pMod;
420 pModMachO->pvBits = NULL;
421 pModMachO->pvMapping = NULL;
422 pModMachO->Hdr = s.Hdr64;
423 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
424 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE)
425 pModMachO->Hdr.reserved = 0;
426 pModMachO->LinkAddress = 0;
427 pModMachO->cbImage = 0;
[22]428 pModMachO->GotRVA = NIL_KLDRADDR;
429 pModMachO->fMakeGot = fMakeGot;
430 pModMachO->fMapUsingLoadCommandSections = K_FALSE;
[2]431 pModMachO->offSymbols = 0;
432 pModMachO->cSymbols = 0;
433 pModMachO->pvaSymbols = NULL;
434 pModMachO->offStrings = 0;
435 pModMachO->cchStrings = 0;
436 pModMachO->pchStrings = NULL;
437 pModMachO->cSections = cSections;
438 pModMachO->paSections = (PKLDRMODMACHOSECT)&pModMachO->aSegments[pModMachO->pMod->cSegments];
439
440 /*
441 * Setup the KLDRMOD segment array.
442 */
443 rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool);
444 if (rc)
445 return rc;
446
447 /*
448 * We're done.
449 */
450 return 0;
451}
452
453
454/**
455 * Converts, validates and preparses the load commands before we carve
456 * out the module instance.
457 *
458 * The conversion that's preformed is format endian to host endian.
459 * The preparsing has to do with segment counting, section counting and string pool sizing.
460 *
461 * @returns 0 on success.
462 * @returns KLDR_ERR_MACHO_* on failure.
463 * @param pbLoadCommands The load commands to parse.
464 * @param pHdr The header.
465 * @param pRdr The file reader.
466 * @param pcSegments Where to store the segment count.
467 * @param pcSegments Where to store the section count.
468 * @param pcbStringPool Where to store the string pool size.
469 */
470static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr,
471 KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool)
472{
473 union
474 {
475 KU8 *pb;
476 load_command_t *pLoadCmd;
477 segment_command_32_t *pSeg32;
478 segment_command_64_t *pSeg64;
479 thread_command_t *pThread;
480 symtab_command_t *pSymTab;
481 uuid_command_t *pUuid;
482 } u;
483 const KU64 cbFile = kRdrSize(pRdr);
484 KU32 cSegments = 0;
485 KU32 cSections = 0;
486 KU32 cbStringPool = 0;
487 KU32 cLeft = pHdr->ncmds;
488 KU32 cbLeft = pHdr->sizeofcmds;
489 KU8 *pb = pbLoadCommands;
490 int cSegmentCommands = 0;
491 int cSymbolTabs = 0;
492 int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
493 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
494
495 *pcSegments = 0;
496 *pcSections = 0;
497 *pcbStringPool = 0;
498
499 while (cLeft-- > 0)
500 {
501 u.pb = pb;
502
503 /*
504 * Convert and validate command header.
505 */
506 if (cbLeft < sizeof(load_command_t))
507 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
508 if (fConvertEndian)
509 {
510 u.pLoadCmd->cmd = K_E2E_U32(u.pLoadCmd->cmd);
511 u.pLoadCmd->cmdsize = K_E2E_U32(u.pLoadCmd->cmdsize);
512 }
513 if (u.pLoadCmd->cmdsize > cbLeft)
514 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
515 cbLeft -= u.pLoadCmd->cmdsize;
516 pb += u.pLoadCmd->cmdsize;
517
518 /*
519 * Convert endian if needed, parse and validate the command.
520 */
521 switch (u.pLoadCmd->cmd)
522 {
523 case LC_SEGMENT_32:
524 {
525 section_32_t *pSect;
526 section_32_t *pFirstSect;
527 KU32 cSectionsLeft;
528
529 /* convert and verify*/
530 if (u.pLoadCmd->cmdsize < sizeof(segment_command_32_t))
531 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
532 if ( pHdr->magic != IMAGE_MACHO32_SIGNATURE_OE
533 && pHdr->magic != IMAGE_MACHO32_SIGNATURE)
534 return KLDR_ERR_MACHO_BIT_MIX;
535 if (fConvertEndian)
536 {
537 u.pSeg32->vmaddr = K_E2E_U32(u.pSeg32->vmaddr);
538 u.pSeg32->vmsize = K_E2E_U32(u.pSeg32->vmsize);
539 u.pSeg32->fileoff = K_E2E_U32(u.pSeg32->fileoff);
540 u.pSeg32->filesize = K_E2E_U32(u.pSeg32->filesize);
541 u.pSeg32->maxprot = K_E2E_U32(u.pSeg32->maxprot);
542 u.pSeg32->initprot = K_E2E_U32(u.pSeg32->initprot);
543 u.pSeg32->nsects = K_E2E_U32(u.pSeg32->nsects);
544 u.pSeg32->flags = K_E2E_U32(u.pSeg32->flags);
545 }
546
547 if ( u.pSeg32->filesize
548 && ( u.pSeg32->fileoff > cbFile
549 || (KU64)u.pSeg32->fileoff + u.pSeg32->filesize > cbFile))
550 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
551 if (!u.pSeg32->filesize && u.pSeg32->fileoff)
552 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
553 if (u.pSeg32->vmsize < u.pSeg32->filesize)
554 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
555 if ((u.pSeg32->maxprot & u.pSeg32->initprot) != u.pSeg32->initprot)
556 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
557 if (u.pSeg32->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
558 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
559 if (u.pSeg32->nsects * sizeof(section_32_t) > u.pLoadCmd->cmdsize - sizeof(segment_command_32_t))
560 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
561 if ( pHdr->filetype == MH_OBJECT
562 && cSegmentCommands > 0)
563 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
564 cSegmentCommands++;
565
566 /*
567 * convert, validate and parse the sections.
568 */
569 cSectionsLeft = u.pSeg32->nsects;
570 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
571 while (cSectionsLeft-- > 0)
572 {
573 int fFileBits;
574
575 if (fConvertEndian)
576 {
577 pSect->addr = K_E2E_U32(pSect->addr);
578 pSect->size = K_E2E_U32(pSect->size);
579 pSect->offset = K_E2E_U32(pSect->offset);
580 pSect->align = K_E2E_U32(pSect->align);
581 pSect->reloff = K_E2E_U32(pSect->reloff);
582 pSect->nreloc = K_E2E_U32(pSect->nreloc);
583 pSect->flags = K_E2E_U32(pSect->flags);
584 pSect->reserved1 = K_E2E_U32(pSect->reserved1);
585 pSect->reserved2 = K_E2E_U32(pSect->reserved2);
586 }
587
588 /* validate */
589 switch (pSect->flags & SECTION_TYPE)
590 {
591 case S_ZEROFILL:
592 if (pSect->reserved1 || pSect->reserved2)
593 return KLDR_ERR_MACHO_BAD_SECTION;
594 fFileBits = 0;
595 break;
596 case S_REGULAR:
597 case S_CSTRING_LITERALS:
598 case S_COALESCED:
599 case S_4BYTE_LITERALS:
600 case S_8BYTE_LITERALS:
601 case S_16BYTE_LITERALS:
602 if (pSect->reserved1 || pSect->reserved2)
603 return KLDR_ERR_MACHO_BAD_SECTION;
604 fFileBits = 1;
605 break;
606
607 case S_LITERAL_POINTERS:
608 case S_INTERPOSING:
609 case S_GB_ZEROFILL:
610 case S_NON_LAZY_SYMBOL_POINTERS:
611 case S_LAZY_SYMBOL_POINTERS:
612 case S_SYMBOL_STUBS:
[22]613 return KLDR_ERR_MACHO_UNSUPPORTED_SECTION;
[2]614 case S_MOD_INIT_FUNC_POINTERS:
[22]615 return KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION;
[2]616 case S_MOD_TERM_FUNC_POINTERS:
[22]617 return KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION;
[2]618
619 default:
620 return KLDR_ERR_MACHO_UNKNOWN_SECTION;
621 }
622 if (pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS
623 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE
624 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC
625 | S_ATTR_LOC_RELOC | SECTION_TYPE))
626 return KLDR_ERR_MACHO_BAD_SECTION;
627 if ( pSect->addr - u.pSeg32->vmaddr > u.pSeg32->vmsize
628 || pSect->addr - u.pSeg32->vmaddr + pSect->size > u.pSeg32->vmsize)
629 return KLDR_ERR_MACHO_BAD_SECTION;
630 if ( pSect->align >= 31
631 || (((1 << pSect->align) - 1) & pSect->addr)
632 || (((1 << pSect->align) - 1) & u.pSeg32->vmaddr))
633 return KLDR_ERR_MACHO_BAD_SECTION;
634 if ( fFileBits
635 && ( pSect->offset > cbFile
636 || (KU64)pSect->offset + pSect->size > cbFile))
637 return KLDR_ERR_MACHO_BAD_SECTION;
638 if (!fFileBits && pSect->offset)
639 return KLDR_ERR_MACHO_BAD_SECTION;
640 if (!pSect->nreloc && pSect->reloff)
641 return KLDR_ERR_MACHO_BAD_SECTION;
642 if ( pSect->nreloc
643 && ( pSect->reloff > cbFile
644 || (KU64)pSect->reloff + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t)) > cbFile)
645 return KLDR_ERR_MACHO_BAD_SECTION;
646
647
648 /* count segments and strings */
649 switch (pHdr->filetype)
650 {
651 case MH_OBJECT:
652 {
653 cSections++;
654
655 /* Don't load debug symbols. (test this) */
656 if (pSect->flags & S_ATTR_DEBUG)
657 break;
658
659 /* a new segment? */
660 if ( !cSegments
661 || kHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
662 {
[22]663#if 0 /** @todo This doesn't work because of BSS. */
[2]664 /* verify that the linker/assembler has ordered sections correctly. */
665 section_32_t *pCur = (pSect - 2);
666 while ((KUPTR)pCur >= (KUPTR)pFirstSect)
667 {
668 if (!kHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
669 return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
670 pCur--;
671 }
672#endif
673
674 /* ok. count it and the string. */
675 cSegments++;
676 cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1;
677 }
678 break;
679 }
680
681 default:
682 return KERR_INVALID_PARAMETER;
683 }
684
685 /* next */
686 pSect++;
687 }
688 break;
689 }
690
[22]691 case LC_SEGMENT_64:
692 {
693 section_64_t *pSect;
694 section_64_t *pFirstSect;
695 KU32 cSectionsLeft;
696
697 /* convert and verify*/
698 if (u.pLoadCmd->cmdsize < sizeof(segment_command_64_t))
699 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
700 if ( pHdr->magic != IMAGE_MACHO64_SIGNATURE_OE
701 && pHdr->magic != IMAGE_MACHO64_SIGNATURE)
702 return KLDR_ERR_MACHO_BIT_MIX;
703 if (fConvertEndian)
704 {
705 u.pSeg64->vmaddr = K_E2E_U64(u.pSeg64->vmaddr);
706 u.pSeg64->vmsize = K_E2E_U64(u.pSeg64->vmsize);
707 u.pSeg64->fileoff = K_E2E_U64(u.pSeg64->fileoff);
708 u.pSeg64->filesize = K_E2E_U64(u.pSeg64->filesize);
709 u.pSeg64->maxprot = K_E2E_U32(u.pSeg64->maxprot);
710 u.pSeg64->initprot = K_E2E_U32(u.pSeg64->initprot);
711 u.pSeg64->nsects = K_E2E_U32(u.pSeg64->nsects);
712 u.pSeg64->flags = K_E2E_U32(u.pSeg64->flags);
713 }
714
715 if ( u.pSeg64->filesize
716 && ( u.pSeg64->fileoff > cbFile
717 || u.pSeg64->fileoff + u.pSeg64->filesize > cbFile))
718 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
719 if (!u.pSeg64->filesize && u.pSeg64->fileoff)
720 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
721 if (u.pSeg64->vmsize < u.pSeg64->filesize)
722 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
723 if ((u.pSeg64->maxprot & u.pSeg64->initprot) != u.pSeg64->initprot)
724 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
725 if (u.pSeg64->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
726 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
727 if (u.pSeg64->nsects * sizeof(section_64_t) > u.pLoadCmd->cmdsize - sizeof(segment_command_64_t))
728 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
729 if ( pHdr->filetype == MH_OBJECT
730 && cSegmentCommands > 0)
731 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
732 cSegmentCommands++;
733
734 /*
735 * convert, validate and parse the sections.
736 */
737 cSectionsLeft = u.pSeg64->nsects;
738 pFirstSect = pSect = (section_64_t *)(u.pSeg64 + 1);
739 while (cSectionsLeft-- > 0)
740 {
741 int fFileBits;
742
743 if (fConvertEndian)
744 {
745 pSect->addr = K_E2E_U64(pSect->addr);
746 pSect->size = K_E2E_U64(pSect->size);
747 pSect->offset = K_E2E_U32(pSect->offset);
748 pSect->align = K_E2E_U32(pSect->align);
749 pSect->reloff = K_E2E_U32(pSect->reloff);
750 pSect->nreloc = K_E2E_U32(pSect->nreloc);
751 pSect->flags = K_E2E_U32(pSect->flags);
752 pSect->reserved1 = K_E2E_U32(pSect->reserved1);
753 pSect->reserved2 = K_E2E_U32(pSect->reserved2);
754 }
755
756 /* validate */
757 switch (pSect->flags & SECTION_TYPE)
758 {
759 case S_ZEROFILL:
760 if (pSect->reserved1 || pSect->reserved2)
761 return KLDR_ERR_MACHO_BAD_SECTION;
762 fFileBits = 0;
763 break;
764 case S_REGULAR:
765 case S_CSTRING_LITERALS:
766 case S_COALESCED:
767 case S_4BYTE_LITERALS:
768 case S_8BYTE_LITERALS:
769 case S_16BYTE_LITERALS:
770 if (pSect->reserved1 || pSect->reserved2)
771 return KLDR_ERR_MACHO_BAD_SECTION;
772 fFileBits = 1;
773 break;
774
775 case S_LITERAL_POINTERS:
776 case S_INTERPOSING:
777 case S_GB_ZEROFILL:
778 case S_NON_LAZY_SYMBOL_POINTERS:
779 case S_LAZY_SYMBOL_POINTERS:
780 case S_SYMBOL_STUBS:
781 return KLDR_ERR_MACHO_UNSUPPORTED_SECTION;
782#if 1 /** @todo this requires a query API or flag... */
783 case S_MOD_INIT_FUNC_POINTERS:
784 return KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION;
785 case S_MOD_TERM_FUNC_POINTERS:
786 return KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION;
787#else
788 case S_MOD_INIT_FUNC_POINTERS:
789 case S_MOD_TERM_FUNC_POINTERS:
790 fFileBits = 1;
791 break; /* ignored */
792#endif
793
794 default:
795 return KLDR_ERR_MACHO_UNKNOWN_SECTION;
796 }
797 if (pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS
798 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE
799 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC
800 | S_ATTR_LOC_RELOC | SECTION_TYPE))
801 return KLDR_ERR_MACHO_BAD_SECTION;
802 if ( pSect->addr - u.pSeg64->vmaddr > u.pSeg64->vmsize
803 || pSect->addr - u.pSeg64->vmaddr + pSect->size > u.pSeg64->vmsize)
804 return KLDR_ERR_MACHO_BAD_SECTION;
805 if ( pSect->align >= 31
806 || (((1 << pSect->align) - 1) & pSect->addr)
807 || (((1 << pSect->align) - 1) & u.pSeg64->vmaddr))
808 return KLDR_ERR_MACHO_BAD_SECTION;
809 if ( fFileBits
810 && ( pSect->offset > cbFile
811 || (KU64)pSect->offset + pSect->size > cbFile))
812 return KLDR_ERR_MACHO_BAD_SECTION;
813 if (!fFileBits && pSect->offset)
814 return KLDR_ERR_MACHO_BAD_SECTION;
815 if (!pSect->nreloc && pSect->reloff)
816 return KLDR_ERR_MACHO_BAD_SECTION;
817 if ( pSect->nreloc
818 && ( pSect->reloff > cbFile
819 || (KU64)pSect->reloff + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t)) > cbFile)
820 return KLDR_ERR_MACHO_BAD_SECTION;
821
822
823 /* count segments and strings */
824 switch (pHdr->filetype)
825 {
826 case MH_OBJECT:
827 {
828 cSections++;
829
830 /* Don't load debug symbols. (test this) */
831 if (pSect->flags & S_ATTR_DEBUG)
832 break;
833
834 /* a new segment? */
835 if ( !cSegments
836 || kHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
837 {
838#if 0 /** @todo This doesn't work because of BSS. */
839 /* verify that the linker/assembler has ordered sections correctly. */
840 section_64_t *pCur = (pSect - 2);
841 while ((KUPTR)pCur >= (KUPTR)pFirstSect)
842 {
843 if (!kHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
844 return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
845 pCur--;
846 }
847#endif
848
849 /* ok. count it and the string. */
850 cSegments++;
851 cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1;
852 }
853 break;
854 }
855
856 default:
857 return KERR_INVALID_PARAMETER;
858 }
859
860 /* next */
861 pSect++;
862 }
[2]863 break;
[22]864 } /* LC_SEGMENT_64 */
[2]865
[22]866
[2]867 case LC_SYMTAB:
868 {
869 KSIZE cbSym;
870 if (fConvertEndian)
871 {
872 u.pSymTab->symoff = K_E2E_U32(u.pSymTab->symoff);
873 u.pSymTab->nsyms = K_E2E_U32(u.pSymTab->nsyms);
874 u.pSymTab->stroff = K_E2E_U32(u.pSymTab->stroff);
875 u.pSymTab->strsize = K_E2E_U32(u.pSymTab->strsize);
876 }
877
878 /* verify */
879 cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE
880 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
881 ? sizeof(macho_nlist_32_t)
882 : sizeof(macho_nlist_64_t);
883 if ( u.pSymTab->symoff >= cbFile
884 || (KU64)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > cbFile)
885 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
886 if ( u.pSymTab->stroff >= cbFile
887 || (KU64)u.pSymTab->stroff + u.pSymTab->strsize > cbFile)
888 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
889
890 /* only one string in objects, please. */
891 cSymbolTabs++;
892 if ( pHdr->filetype == MH_OBJECT
893 && cSymbolTabs != 1)
894 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
895 break;
896 }
897
898 case LC_DYSYMTAB:
899 /** @todo deal with this! */
900 break;
901
902 case LC_THREAD:
903 case LC_UNIXTHREAD:
904 {
905 KU32 *pu32 = (KU32 *)(u.pb + sizeof(load_command_t));
906 KU32 cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(KU32);
907 while (cItemsLeft)
908 {
909 /* convert & verify header items ([0] == flavor, [1] == KU32 count). */
910 if (cItemsLeft < 2)
911 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
912 if (fConvertEndian)
913 {
914 pu32[0] = K_E2E_U32(pu32[0]);
915 pu32[1] = K_E2E_U32(pu32[1]);
916 }
917 if (pu32[1] + 2 > cItemsLeft)
918 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
919
920 /* convert & verify according to flavor. */
921 switch (pu32[0])
922 {
923 /** @todo */
924 default:
925 break;
926 }
927
928 /* next */
929 cItemsLeft -= pu32[1] + 2;
930 pu32 += pu32[1] + 2;
931 }
932 break;
933 }
934
935 case LC_UUID:
936 if (u.pUuid->cmdsize != sizeof(uuid_command_t))
937 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
938 /** @todo Check anything here need converting? */
939 break;
940
941 case LC_LOADFVMLIB:
942 case LC_IDFVMLIB:
943 case LC_IDENT:
944 case LC_FVMFILE:
945 case LC_PREPAGE:
946 case LC_LOAD_DYLIB:
947 case LC_ID_DYLIB:
948 case LC_LOAD_DYLINKER:
949 case LC_ID_DYLINKER:
950 case LC_PREBOUND_DYLIB:
951 case LC_ROUTINES:
952 case LC_ROUTINES_64:
953 case LC_SUB_FRAMEWORK:
954 case LC_SUB_UMBRELLA:
955 case LC_SUB_CLIENT:
956 case LC_SUB_LIBRARY:
957 case LC_TWOLEVEL_HINTS:
958 case LC_PREBIND_CKSUM:
959 case LC_LOAD_WEAK_DYLIB:
960 case LC_SYMSEG:
961 return KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND;
962
963 default:
964 return KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND;
965 }
966 }
967
968 /* be strict. */
969 if (cbLeft)
970 return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
971
972 switch (pHdr->filetype)
973 {
974 case MH_OBJECT:
975 if (!cSegments)
976 return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
977 break;
978 }
979
980 *pcSegments = cSegments;
981 *pcSections = cSections;
982 *pcbStringPool = cbStringPool;
983
984 return 0;
985}
986
987
988/**
989 * Parses the load commands after we've carved out the module instance.
990 *
991 * This fills in the segment table and perhaps some other properties.
992 *
993 * @returns 0 on success.
994 * @returns KLDR_ERR_MACHO_* on failure.
995 * @param pModMachO The module.
996 * @param pbStringPool The string pool
997 * @param cbStringPool The size of the string pool.
998 */
999static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool)
1000{
1001 union
1002 {
1003 const KU8 *pb;
1004 const load_command_t *pLoadCmd;
1005 const segment_command_32_t *pSeg32;
1006 const segment_command_64_t *pSeg64;
1007 const symtab_command_t *pSymTab;
1008 } u;
1009 KU32 cLeft = pModMachO->Hdr.ncmds;
1010 KU32 cbLeft = pModMachO->Hdr.sizeofcmds;
1011 const KU8 *pb = pModMachO->pbLoadCommands;
1012 int fFirstSegment = 1;
1013 PKLDRSEG pSeg = &pModMachO->pMod->aSegments[0];
1014 PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0];
1015 PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections;
1016 const KU32 cSegments = pModMachO->pMod->cSegments;
1017 KU32 i;
1018
1019 while (cLeft-- > 0)
1020 {
1021 u.pb = pb;
1022 cbLeft -= u.pLoadCmd->cmdsize;
1023 pb += u.pLoadCmd->cmdsize;
1024
1025 /*
1026 * Convert endian if needed, parse and validate the command.
1027 */
1028 switch (u.pLoadCmd->cmd)
1029 {
1030 case LC_SEGMENT_32:
1031 {
1032 section_32_t *pSect;
1033 section_32_t *pFirstSect;
1034 KU32 cSectionsLeft;
1035
1036 pModMachO->LinkAddress = u.pSeg32->vmaddr;
1037
1038 /*
1039 * convert, validate and parse the sections.
1040 */
1041 cSectionsLeft = u.pSeg32->nsects;
1042 pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
1043 while (cSectionsLeft-- > 0)
1044 {
1045 switch (pModMachO->Hdr.filetype)
1046 {
1047 case MH_OBJECT:
1048 {
1049 /* Section data extract. */
1050 pSectExtra->cb = pSect->size;
1051 pSectExtra->RVA = pSect->addr;
1052 pSectExtra->LinkAddress = pSect->addr;
1053 pSectExtra->offFile = pSect->offset ? pSect->offset : -1;
1054 pSectExtra->cFixups = pSect->nreloc;
1055 pSectExtra->paFixups = NULL;
1056 pSectExtra->offFixups = pSect->nreloc ? pSect->reloff : -1;
1057 pSectExtra->fFlags = pSect->flags;
1058 pSectExtra->iSegment = pSegExtra - &pModMachO->aSegments[0];
1059 pSectExtra->pvMachoSection = pSect;
1060
1061 /* Don't load debug symbols. (test this!) */
1062 if (pSect->flags & S_ATTR_DEBUG)
1063 {
1064 pSectExtra++;
1065 /** @todo */
1066 break;
1067 }
1068
1069 if ( fFirstSegment
1070 || kHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
1071 {
1072 /* close the previous segment */
1073 if (pSegExtra != &pModMachO->aSegments[0])
1074 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
1075
1076 /* new segment. */
1077 pSeg->pvUser = NULL;
1078 pSeg->pchName = pbStringPool;
1079 pSeg->cchName = (KU32)kHlpStrNLen(&pSect->segname[0], sizeof(pSect->sectname));
1080 kHlpMemCopy(pbStringPool, &pSect->segname[0], pSeg->cchName);
1081 pbStringPool += pSeg->cchName;
1082 *pbStringPool++ = '\0';
1083 pSeg->SelFlat = 0;
1084 pSeg->Sel16bit = 0;
1085 pSeg->fFlags = 0;
1086 pSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */
1087 pSeg->cb = pSect->size;
1088 pSeg->Alignment = (1 << pSect->align);
1089 pSeg->LinkAddress = pSect->addr;
1090 pSeg->offFile = pSect->offset ? pSect->offset : -1;
1091 pSeg->cbFile = pSect->offset ? pSect->size : -1;
1092 pSeg->RVA = pSect->addr - pModMachO->LinkAddress;
1093 pSeg->cbMapped = 0;
1094 pSeg->MapAddress = 0;
1095
1096 pSegExtra->cSections = 0;
1097 pSegExtra->paSections = pSectExtra;
1098
1099 pSeg++;
1100 pSegExtra++;
1101 fFirstSegment = 0;
1102 }
1103 else
1104 {
1105 /* update exiting segment */
1106 if (pSeg[-1].Alignment < (1 << pSect->align))
1107 pSeg[-1].Alignment = (1 << pSect->align);
1108 if (pSect->addr < pSeg[-1].LinkAddress)
1109 return KLDR_ERR_MACHO_BAD_SECTION; /** @todo move up! */
1110
1111 /* If there are file bits, ensure they are in the current flow.
1112 (yes, we are very very careful here, I know.) */
1113 if ( pSect->offset
1114 && pSeg[-1].cbFile == pSeg[-1].cb)
1115 {
1116 int fOk = pSeg[-1].offFile + (pSect->addr - pSeg[-1].LinkAddress) == pSect->offset
1117 && pSect[-1].offset
1118 && pSeg[-1].offFile + pSeg[-1].cbFile == pSect[-1].offset + pSect[-1].size;
1119 /* more checks? */
1120 if (fOk)
1121 pSeg[-1].cbFile = (KLDRFOFF)(pSect->addr - pSeg[-1].LinkAddress) + pSect->size;
1122 else
1123 {
1124
1125 pSeg[-1].cbFile = pSeg[-1].offFile = -1;
[22]1126 pModMachO->fMapUsingLoadCommandSections = K_TRUE;
[2]1127 }
1128 }
1129 pSeg[-1].cb = pSect->addr - pSeg[-1].LinkAddress + pSect->size;
1130
1131 /** @todo update the protection... */
1132 }
1133 pSectExtra++;
1134 break;
1135 }
1136
1137 default:
1138 return KERR_INVALID_PARAMETER;
1139 }
1140
1141 /* next */
1142 pSect++;
1143 }
1144 break;
1145 }
1146
[22]1147 case LC_SEGMENT_64:
1148 {
1149 section_64_t *pSect;
1150 section_64_t *pFirstSect;
1151 KU32 cSectionsLeft;
1152
1153 pModMachO->LinkAddress = u.pSeg64->vmaddr;
1154
1155 /*
1156 * convert, validate and parse the sections.
1157 */
1158 cSectionsLeft = u.pSeg64->nsects;
1159 pFirstSect = pSect = (section_64_t *)(u.pSeg64 + 1);
1160 while (cSectionsLeft-- > 0)
1161 {
1162 switch (pModMachO->Hdr.filetype)
1163 {
1164 case MH_OBJECT:
1165 {
1166 /* Section data extract. */
1167 pSectExtra->cb = pSect->size;
1168 pSectExtra->RVA = pSect->addr;
1169 pSectExtra->LinkAddress = pSect->addr;
1170 pSectExtra->offFile = pSect->offset ? pSect->offset : -1;
1171 pSectExtra->cFixups = pSect->nreloc;
1172 pSectExtra->paFixups = NULL;
1173 pSectExtra->offFixups = pSect->nreloc ? pSect->reloff : -1;
1174 pSectExtra->fFlags = pSect->flags;
1175 pSectExtra->iSegment = pSegExtra - &pModMachO->aSegments[0];
1176 pSectExtra->pvMachoSection = pSect;
1177
1178 /* Don't load debug symbols. (test this!) */
1179 if (pSect->flags & S_ATTR_DEBUG)
1180 {
1181 pSectExtra++;
1182 /** @todo */
1183 break;
1184 }
1185
1186 if ( fFirstSegment
1187 || kHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
1188 {
1189 /* close the previous segment */
1190 if (pSegExtra != &pModMachO->aSegments[0])
1191 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
1192
1193 /* new segment. */
1194 pSeg->pvUser = NULL;
1195 pSeg->pchName = pbStringPool;
1196 pSeg->cchName = (KU32)kHlpStrNLen(&pSect->segname[0], sizeof(pSect->sectname));
1197 kHlpMemCopy(pbStringPool, &pSect->segname[0], pSeg->cchName);
1198 pbStringPool += pSeg->cchName;
1199 *pbStringPool++ = '\0';
1200 pSeg->SelFlat = 0;
1201 pSeg->Sel16bit = 0;
1202 pSeg->fFlags = 0;
1203 pSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */
1204 pSeg->cb = pSect->size;
1205 pSeg->Alignment = (1 << pSect->align);
1206 pSeg->LinkAddress = pSect->addr;
1207 pSeg->offFile = pSect->offset ? pSect->offset : -1;
1208 pSeg->cbFile = pSect->offset ? pSect->size : -1;
1209 pSeg->RVA = pSect->addr - pModMachO->LinkAddress;
1210 pSeg->cbMapped = 0;
1211 pSeg->MapAddress = 0;
1212
1213 pSegExtra->cSections = 0;
1214 pSegExtra->paSections = pSectExtra;
1215
1216 pSeg++;
1217 pSegExtra++;
1218 fFirstSegment = 0;
1219 }
1220 else
1221 {
1222 /* update exiting segment */
1223 if (pSeg[-1].Alignment < (1 << pSect->align))
1224 pSeg[-1].Alignment = (1 << pSect->align);
1225 if (pSect->addr < pSeg[-1].LinkAddress)
1226 return KLDR_ERR_MACHO_BAD_SECTION; /** @todo move up! */
1227
1228 /* If there are file bits, ensure they are in the current flow.
1229 (yes, we are very very careful here, I know.) */
1230 if ( pSect->offset
1231 && pSeg[-1].cbFile == pSeg[-1].cb)
1232 {
1233 int fOk = pSeg[-1].offFile + (pSect->addr - pSeg[-1].LinkAddress) == pSect->offset
1234 && pSect[-1].offset
1235 && pSeg[-1].offFile + pSeg[-1].cbFile == pSect[-1].offset + pSect[-1].size;
1236 /* more checks? */
1237 if (fOk)
1238 pSeg[-1].cbFile = (KLDRFOFF)(pSect->addr - pSeg[-1].LinkAddress) + pSect->size;
1239 else
1240 {
1241
1242 pSeg[-1].cbFile = pSeg[-1].offFile = -1;
1243 pModMachO->fMapUsingLoadCommandSections = K_TRUE;
1244 }
1245 }
1246 pSeg[-1].cb = pSect->addr - pSeg[-1].LinkAddress + pSect->size;
1247
1248 /** @todo update the protection... */
1249 }
1250 pSectExtra++;
1251 break;
1252 }
1253
1254 default:
1255 return KERR_INVALID_PARAMETER;
1256 }
1257
1258 /* next */
1259 pSect++;
1260 }
1261 break;
1262 }
1263
[2]1264 case LC_SYMTAB:
1265 switch (pModMachO->Hdr.filetype)
1266 {
1267 case MH_OBJECT:
1268 pModMachO->offSymbols = u.pSymTab->symoff;
1269 pModMachO->cSymbols = u.pSymTab->nsyms;
1270 pModMachO->offStrings = u.pSymTab->stroff;
1271 pModMachO->cchStrings = u.pSymTab->strsize;
1272 break;
1273 }
1274 break;
1275
1276 default:
1277 break;
1278 } /* command switch */
1279 } /* while more commands */
1280
1281 /*
1282 * Close the last segment (if any).
1283 */
1284 if (pSegExtra != &pModMachO->aSegments[0])
1285 pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
1286
1287 /*
[22]1288 * Make the GOT segment if necessary.
1289 */
1290 if (pModMachO->fMakeGot)
1291 {
1292 KSIZE cbPtr = ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1293 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1294 ? sizeof(KU32)
1295 : sizeof(KU64);
1296
1297 if (pSeg != &pModMachO->pMod->aSegments[0])
1298 pModMachO->GotRVA = pSeg[-1].RVA + KLDR_ALIGN_ADDR(pSeg[-1].cb, pSeg[-1].Alignment);
1299 else
1300 pModMachO->GotRVA = 0;
1301
1302 pSeg->pvUser = NULL;
1303 pSeg->pchName = "GOT";
1304 pSeg->cchName = 3;
1305 pSeg->SelFlat = 0;
1306 pSeg->Sel16bit = 0;
1307 pSeg->fFlags = 0;
1308 pSeg->enmProt = KPROT_READONLY;
1309 pSeg->cb = cbPtr * pModMachO->cSymbols;
1310 pSeg->Alignment = 64;
1311 pSeg->LinkAddress = pModMachO->LinkAddress + pModMachO->GotRVA;
1312 pSeg->offFile = -1;
1313 pSeg->cbFile = -1;
1314 pSeg->RVA = pModMachO->GotRVA;
1315 pSeg->cbMapped = 0;
1316 pSeg->MapAddress = 0;
1317
1318 pSegExtra->cSections = 0;
1319 pSegExtra->paSections = NULL;
1320 }
1321
1322 /*
[2]1323 * Adjust mapping addresses calculating the image size.
1324 */
1325 pSeg = &pModMachO->pMod->aSegments[0];
1326 switch (pModMachO->Hdr.filetype)
1327 {
1328 case MH_OBJECT:
1329 {
1330 KLDRADDR cb1;
1331 KSIZE cb2;
1332
1333 for (i = 0; i < cSegments - 1; i++)
1334 {
1335 cb1 = pSeg[i + 1].LinkAddress - pSeg[i].LinkAddress;
1336 cb2 = (KSIZE)cb1;
1337 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(KSIZE)0;
1338 }
1339 cb1 = KLDR_ALIGN_ADDR(pSeg[i].cb, pSeg[i].Alignment);
1340 cb2 = (KSIZE)cb1;
1341 pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(KSIZE)0;
1342
1343 pModMachO->cbImage = pSeg[i].RVA + cb1;
1344 break;
1345 }
1346 }
1347
[22]1348
[2]1349 return 0;
1350}
1351
1352
1353/** @copydoc KLDRMODOPS::pfnDestroy */
1354static int kldrModMachODestroy(PKLDRMOD pMod)
1355{
1356 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1357 int rc = 0;
1358 KU32 i, j;
1359 KLDRMODMACHO_ASSERT(!pModMachO->pvMapping);
1360
1361 i = pMod->cSegments;
1362 while (i-- > 0)
1363 {
1364 j = pModMachO->aSegments[i].cSections;
1365 while (j-- > 0)
1366 {
1367 kHlpFree(pModMachO->aSegments[i].paSections[j].paFixups);
1368 pModMachO->aSegments[i].paSections[j].paFixups = NULL;
1369 }
1370 }
1371
1372 if (pMod->pRdr)
1373 {
1374 rc = kRdrClose(pMod->pRdr);
1375 pMod->pRdr = NULL;
1376 }
1377 pMod->u32Magic = 0;
1378 pMod->pOps = NULL;
1379 kHlpFree(pModMachO->pbLoadCommands);
1380 pModMachO->pbLoadCommands = NULL;
1381 kHlpFree(pModMachO->pchStrings);
1382 pModMachO->pchStrings = NULL;
1383 kHlpFree(pModMachO->pvaSymbols);
1384 pModMachO->pvaSymbols = NULL;
1385 kHlpFree(pModMachO);
1386 return rc;
1387}
1388
1389
1390/**
1391 * Gets the right base address.
1392 *
1393 * @returns 0 on success.
1394 * @returns A non-zero status code if the BaseAddress isn't right.
1395 * @param pModMachO The interpreter module instance
1396 * @param pBaseAddress The base address, IN & OUT. Optional.
1397 */
1398static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress)
1399{
1400 /*
1401 * Adjust the base address.
1402 */
1403 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
1404 *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress;
1405 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
1406 *pBaseAddress = pModMachO->LinkAddress;
1407
1408 return 0;
1409}
1410
1411
1412
1413/** @copydoc kLdrModQuerySymbol */
1414static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
1415 const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
1416 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
1417{
1418 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1419 int rc;
1420
1421 /*
1422 * Resolve defaults.
1423 */
1424 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
1425 if (rc)
1426 return rc;
1427
1428 /*
1429 * Refuse segmented requests for now.
1430 */
[22]1431 KLDRMODMACHO_CHECK_RETURN( !pfKind
1432 || (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) == KLDRSYMKIND_REQ_FLAT,
1433 KLDR_ERR_TODO);
[2]1434
1435 /*
1436 * Take action according to file type.
1437 */
1438 if (pModMachO->Hdr.filetype == MH_OBJECT)
1439 {
1440 rc = kldrModMachOLoadObjSymTab(pModMachO);
1441 if (!rc)
1442 {
1443 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1444 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1445 rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1446 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
1447 cchSymbol, puValue, pfKind);
1448 else
[22]1449 rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
[2]1450 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
[22]1451 cchSymbol, puValue, pfKind);
[2]1452 }
1453 }
1454 else
1455 rc = KLDR_ERR_TODO;
1456
1457 return rc;
1458}
1459
1460
1461/**
1462 * Lookup a symbol in a 32-bit symbol table.
1463 *
1464 * @returns See kLdrModQuerySymbol.
1465 * @param pModMachO
1466 * @param paSyms Pointer to the symbol table.
1467 * @param cSyms Number of symbols in the table.
1468 * @param pchStrings Pointer to the string table.
1469 * @param cchStrings Size of the string table.
1470 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
1471 * @param iSymbol See kLdrModQuerySymbol.
1472 * @param pchSymbol See kLdrModQuerySymbol.
1473 * @param cchSymbol See kLdrModQuerySymbol.
1474 * @param puValue See kLdrModQuerySymbol.
1475 * @param pfKind See kLdrModQuerySymbol.
1476 */
1477static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings,
1478 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
1479 PKLDRADDR puValue, KU32 *pfKind)
1480{
1481 /*
1482 * Find a valid symbol matching the search criteria.
1483 */
1484 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
1485 {
1486 /* simplify validation. */
1487 if (cchStrings <= cchSymbol)
1488 return KLDR_ERR_SYMBOL_NOT_FOUND;
1489 cchStrings -= cchSymbol;
1490
1491 /* external symbols are usually at the end, so search the other way. */
1492 for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
1493 {
1494 const char *psz;
1495
1496 /* Skip irrellevant and non-public symbols. */
1497 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1498 continue;
1499 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1500 continue;
1501 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1502 continue;
1503 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1504 continue;
1505
1506 /* get name */
1507 if (!paSyms[iSymbol].n_un.n_strx)
1508 continue;
1509 if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1510 continue;
1511 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1512 if (psz[cchSymbol])
1513 continue;
1514 if (kHlpMemComp(psz, pchSymbol, cchSymbol))
1515 continue;
1516
1517 /* match! */
1518 break;
1519 }
1520 if (iSymbol == KU32_MAX)
1521 return KLDR_ERR_SYMBOL_NOT_FOUND;
1522 }
1523 else
1524 {
1525 if (iSymbol >= cSyms)
1526 return KLDR_ERR_SYMBOL_NOT_FOUND;
1527 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1528 return KLDR_ERR_SYMBOL_NOT_FOUND;
1529 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1530 return KLDR_ERR_SYMBOL_NOT_FOUND;
1531 }
1532
1533 /*
1534 * Calc the return values.
1535 */
1536 if (pfKind)
1537 {
1538 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1539 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1540 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
1541 else
1542 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1543 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1544 *pfKind |= KLDRSYMKIND_WEAK;
1545 }
1546
1547 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1548 {
1549 case MACHO_N_SECT:
1550 {
1551 PKLDRMODMACHOSECT pSect;
1552 KLDRADDR RVA;
1553 if ((KU32)(paSyms[iSymbol].n_sect - 1) >= pModMachO->cSections)
1554 return KLDR_ERR_MACHO_BAD_SYMBOL;
1555 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1556
1557 RVA = paSyms[iSymbol].n_value - pModMachO->LinkAddress;
1558 if (RVA - pSect->RVA >= pSect->cb)
1559 return KLDR_ERR_MACHO_BAD_SYMBOL;
1560 if (puValue)
1561 *puValue = RVA + BaseAddress;
1562
1563 if ( pfKind
1564 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1565 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1566 break;
1567 }
1568
1569 case MACHO_N_ABS:
1570 if (puValue)
1571 *puValue = paSyms[iSymbol].n_value;
1572 /*if (pfKind)
1573 pfKind |= KLDRSYMKIND_ABS;*/
1574 break;
1575
1576 case MACHO_N_PBUD:
1577 case MACHO_N_INDR:
1578 /** @todo implement indirect and prebound symbols. */
1579 default:
[22]1580 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]1581 }
1582
1583 return 0;
1584}
1585
1586
[22]1587/**
1588 * Lookup a symbol in a 64-bit symbol table.
1589 *
1590 * @returns See kLdrModQuerySymbol.
1591 * @param pModMachO
1592 * @param paSyms Pointer to the symbol table.
1593 * @param cSyms Number of symbols in the table.
1594 * @param pchStrings Pointer to the string table.
1595 * @param cchStrings Size of the string table.
1596 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
1597 * @param iSymbol See kLdrModQuerySymbol.
1598 * @param pchSymbol See kLdrModQuerySymbol.
1599 * @param cchSymbol See kLdrModQuerySymbol.
1600 * @param puValue See kLdrModQuerySymbol.
1601 * @param pfKind See kLdrModQuerySymbol.
1602 */
1603static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings,
1604 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
1605 PKLDRADDR puValue, KU32 *pfKind)
1606{
1607 /*
1608 * Find a valid symbol matching the search criteria.
1609 */
1610 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
1611 {
1612 /* simplify validation. */
1613 if (cchStrings <= cchSymbol)
1614 return KLDR_ERR_SYMBOL_NOT_FOUND;
1615 cchStrings -= cchSymbol;
1616
1617 /* external symbols are usually at the end, so search the other way. */
1618 for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
1619 {
1620 const char *psz;
1621
1622 /* Skip irrellevant and non-public symbols. */
1623 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1624 continue;
1625 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1626 continue;
1627 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1628 continue;
1629 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1630 continue;
1631
1632 /* get name */
1633 if (!paSyms[iSymbol].n_un.n_strx)
1634 continue;
1635 if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1636 continue;
1637 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1638 if (psz[cchSymbol])
1639 continue;
1640 if (kHlpMemComp(psz, pchSymbol, cchSymbol))
1641 continue;
1642
1643 /* match! */
1644 break;
1645 }
1646 if (iSymbol == KU32_MAX)
1647 return KLDR_ERR_SYMBOL_NOT_FOUND;
1648 }
1649 else
1650 {
1651 if (iSymbol >= cSyms)
1652 return KLDR_ERR_SYMBOL_NOT_FOUND;
1653 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1654 return KLDR_ERR_SYMBOL_NOT_FOUND;
1655 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1656 return KLDR_ERR_SYMBOL_NOT_FOUND;
1657 }
1658
1659 /*
1660 * Calc the return values.
1661 */
1662 if (pfKind)
1663 {
1664 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1665 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1666 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
1667 else
1668 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1669 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1670 *pfKind |= KLDRSYMKIND_WEAK;
1671 }
1672
1673 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1674 {
1675 case MACHO_N_SECT:
1676 {
1677 PKLDRMODMACHOSECT pSect;
1678 KLDRADDR RVA;
1679 if ((KU32)(paSyms[iSymbol].n_sect - 1) >= pModMachO->cSections)
1680 return KLDR_ERR_MACHO_BAD_SYMBOL;
1681 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1682
1683 RVA = paSyms[iSymbol].n_value - pModMachO->LinkAddress;
1684 if (RVA - pSect->RVA >= pSect->cb)
1685 return KLDR_ERR_MACHO_BAD_SYMBOL;
1686 if (puValue)
1687 *puValue = RVA + BaseAddress;
1688
1689 if ( pfKind
1690 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1691 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1692 break;
1693 }
1694
1695 case MACHO_N_ABS:
1696 if (puValue)
1697 *puValue = paSyms[iSymbol].n_value;
1698 /*if (pfKind)
1699 pfKind |= KLDRSYMKIND_ABS;*/
1700 break;
1701
1702 case MACHO_N_PBUD:
1703 case MACHO_N_INDR:
1704 /** @todo implement indirect and prebound symbols. */
1705 default:
1706 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
1707 }
1708
1709 return 0;
1710}
1711
1712
[2]1713/** @copydoc kLdrModEnumSymbols */
1714static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
1715 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
1716{
1717 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1718 int rc;
1719
1720 /*
1721 * Resolve defaults.
1722 */
1723 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
1724 if (rc)
1725 return rc;
1726
1727 /*
1728 * Take action according to file type.
1729 */
1730 if (pModMachO->Hdr.filetype == MH_OBJECT)
1731 {
1732 rc = kldrModMachOLoadObjSymTab(pModMachO);
1733 if (!rc)
1734 {
1735 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1736 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1737 rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1738 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
1739 fFlags, pfnCallback, pvUser);
1740 else
[22]1741 rc = kldrModMachODoEnumSymbols64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1742 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
1743 fFlags, pfnCallback, pvUser);
[2]1744 }
1745 }
1746 else
[22]1747 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]1748
1749 return rc;
1750}
1751
1752
1753/**
1754 * Enum a 32-bit symbol table.
1755 *
1756 * @returns See kLdrModQuerySymbol.
1757 * @param pModMachO
1758 * @param paSyms Pointer to the symbol table.
1759 * @param cSyms Number of symbols in the table.
1760 * @param pchStrings Pointer to the string table.
1761 * @param cchStrings Size of the string table.
1762 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
1763 * @param fFlags See kLdrModEnumSymbols.
1764 * @param pfnCallback See kLdrModEnumSymbols.
1765 * @param pvUser See kLdrModEnumSymbols.
1766 */
1767static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
1768 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
1769 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
1770{
[22]1771 const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1772 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
1773 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT;
[2]1774 KU32 iSym;
1775 int rc;
1776
1777 /*
1778 * Iterate the symbol table.
1779 */
1780 for (iSym = 0; iSym < cSyms; iSym++)
1781 {
1782 KU32 fKind;
1783 KLDRADDR uValue;
1784 const char *psz;
1785 KSIZE cch;
1786
1787 /* Skip debug symbols and undefined symbols. */
1788 if (paSyms[iSym].n_type & MACHO_N_STAB)
1789 continue;
1790 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1791 continue;
1792
1793 /* Skip non-public symbols unless they are requested explicitly. */
1794 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
1795 {
1796 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
1797 continue;
1798 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
1799 continue;
1800 if (!paSyms[iSym].n_un.n_strx)
1801 continue;
1802 }
1803
1804 /*
1805 * Gather symbol info
1806 */
1807
1808 /* name */
1809 if ((KU32)paSyms[iSym].n_un.n_strx >= cchStrings)
1810 return KLDR_ERR_MACHO_BAD_SYMBOL;
1811 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
1812 cch = kHlpStrLen(psz);
1813 if (!cch)
1814 psz = NULL;
1815
1816 /* kind & value */
1817 fKind = fKindBase;
1818 if (paSyms[iSym].n_desc & N_WEAK_DEF)
1819 fKind |= KLDRSYMKIND_WEAK;
1820 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
1821 {
1822 case MACHO_N_SECT:
1823 {
1824 PKLDRMODMACHOSECT pSect;
1825 if ((KU32)(paSyms[iSym].n_sect - 1) >= pModMachO->cSections)
1826 return KLDR_ERR_MACHO_BAD_SYMBOL;
1827 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
1828
1829 uValue = paSyms[iSym].n_value - pModMachO->LinkAddress;
1830 if (uValue - pSect->RVA >= pSect->cb)
1831 return KLDR_ERR_MACHO_BAD_SYMBOL;
1832 uValue += BaseAddress;
1833
1834 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
1835 fKind |= KLDRSYMKIND_CODE;
1836 else
1837 fKind |= KLDRSYMKIND_NO_TYPE;
1838 break;
1839 }
1840
1841 case MACHO_N_ABS:
1842 uValue = paSyms[iSym].n_value;
1843 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
1844 break;
1845
1846 case MACHO_N_PBUD:
1847 case MACHO_N_INDR:
1848 /** @todo implement indirect and prebound symbols. */
1849 default:
[22]1850 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]1851 }
1852
1853 /*
1854 * Do callback.
1855 */
1856 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
1857 if (rc)
1858 return rc;
1859 }
1860 return 0;
1861}
1862
1863
[22]1864/**
1865 * Enum a 64-bit symbol table.
1866 *
1867 * @returns See kLdrModQuerySymbol.
1868 * @param pModMachO
1869 * @param paSyms Pointer to the symbol table.
1870 * @param cSyms Number of symbols in the table.
1871 * @param pchStrings Pointer to the string table.
1872 * @param cchStrings Size of the string table.
1873 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
1874 * @param fFlags See kLdrModEnumSymbols.
1875 * @param pfnCallback See kLdrModEnumSymbols.
1876 * @param pvUser See kLdrModEnumSymbols.
1877 */
1878static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms,
1879 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
1880 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
1881{
1882 const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE
1883 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE
1884 ? KLDRSYMKIND_64BIT : KLDRSYMKIND_32BIT;
1885 KU32 iSym;
1886 int rc;
1887
1888 /*
1889 * Iterate the symbol table.
1890 */
1891 for (iSym = 0; iSym < cSyms; iSym++)
1892 {
1893 KU32 fKind;
1894 KLDRADDR uValue;
1895 const char *psz;
1896 KSIZE cch;
1897
1898 /* Skip debug symbols and undefined symbols. */
1899 if (paSyms[iSym].n_type & MACHO_N_STAB)
1900 continue;
1901 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1902 continue;
1903
1904 /* Skip non-public symbols unless they are requested explicitly. */
1905 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
1906 {
1907 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
1908 continue;
1909 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
1910 continue;
1911 if (!paSyms[iSym].n_un.n_strx)
1912 continue;
1913 }
1914
1915 /*
1916 * Gather symbol info
1917 */
1918
1919 /* name */
1920 if ((KU32)paSyms[iSym].n_un.n_strx >= cchStrings)
1921 return KLDR_ERR_MACHO_BAD_SYMBOL;
1922 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
1923 cch = kHlpStrLen(psz);
1924 if (!cch)
1925 psz = NULL;
1926
1927 /* kind & value */
1928 fKind = fKindBase;
1929 if (paSyms[iSym].n_desc & N_WEAK_DEF)
1930 fKind |= KLDRSYMKIND_WEAK;
1931 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
1932 {
1933 case MACHO_N_SECT:
1934 {
1935 PKLDRMODMACHOSECT pSect;
1936 if ((KU32)(paSyms[iSym].n_sect - 1) >= pModMachO->cSections)
1937 return KLDR_ERR_MACHO_BAD_SYMBOL;
1938 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
1939
1940 uValue = paSyms[iSym].n_value - pModMachO->LinkAddress;
1941 if (uValue - pSect->RVA >= pSect->cb)
1942 return KLDR_ERR_MACHO_BAD_SYMBOL;
1943 uValue += BaseAddress;
1944
1945 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
1946 fKind |= KLDRSYMKIND_CODE;
1947 else
1948 fKind |= KLDRSYMKIND_NO_TYPE;
1949 break;
1950 }
1951
1952 case MACHO_N_ABS:
1953 uValue = paSyms[iSym].n_value;
1954 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
1955 break;
1956
1957 case MACHO_N_PBUD:
1958 case MACHO_N_INDR:
1959 /** @todo implement indirect and prebound symbols. */
1960 default:
1961 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
1962 }
1963
1964 /*
1965 * Do callback.
1966 */
1967 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
1968 if (rc)
1969 return rc;
1970 }
1971 return 0;
1972}
1973
1974
[2]1975/** @copydoc kLdrModGetImport */
1976static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
1977{
1978 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1979 if (pModMachO->Hdr.filetype == MH_OBJECT)
1980 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1981
1982 /* later */
1983 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1984}
1985
1986
1987/** @copydoc kLdrModNumberOfImports */
1988static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits)
1989{
1990 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1991 if (pModMachO->Hdr.filetype == MH_OBJECT)
1992 return 0;
1993
1994 /* later */
1995 return 0;
1996}
1997
1998
1999/** @copydoc kLdrModGetStackInfo */
2000static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
2001{
2002 /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
2003
2004 pStackInfo->Address = NIL_KLDRADDR;
2005 pStackInfo->LinkAddress = NIL_KLDRADDR;
2006 pStackInfo->cbStack = pStackInfo->cbStackThread = 0;
2007 /* later */
2008
2009 return 0;
2010}
2011
2012
2013/** @copydoc kLdrModQueryMainEntrypoint */
2014static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
2015{
2016#if 0
2017 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2018 int rc;
2019
2020 /*
2021 * Resolve base address alias if any.
2022 */
2023 rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress);
2024 if (rc)
2025 return rc;
2026
2027 /*
2028 * Convert the address from the header.
2029 */
2030 *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
2031 ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
2032 : NIL_KLDRADDR;
2033#else
2034 *pMainEPAddress = NIL_KLDRADDR;
2035#endif
2036 return 0;
2037}
2038
2039
2040/** @copydoc kLdrModEnumDbgInfo */
2041static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
2042{
2043#if 0
2044 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2045 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
2046 KU32 iDbgInfo;
2047 KU32 cb;
2048 int rc;
2049
2050 /*
2051 * Check that there is a debug directory first.
2052 */
2053 cb = pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
2054 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
2055 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
2056 return 0;
2057
2058 /*
2059 * Make sure we've got mapped bits.
2060 */
2061 rc = kldrModMachOBitsAndBaseAddress(pModMachO, &pvBits, NULL);
2062 if (rc)
2063 return rc;
2064
2065 /*
2066 * Enumerate the debug directory.
2067 */
2068 pDbgDir = KLDRMODMACHO_RVA2TYPE(pvBits,
2069 pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
2070 const IMAGE_DEBUG_DIRECTORY *);
2071 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
2072 {
2073 KLDRDBGINFOTYPE enmDbgInfoType;
2074
2075 /* convert the type. */
2076 switch (pDbgDir->Type)
2077 {
2078 case IMAGE_DEBUG_TYPE_UNKNOWN:
2079 case IMAGE_DEBUG_TYPE_FPO:
2080 case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
2081 case IMAGE_DEBUG_TYPE_MISC:
2082 case IMAGE_DEBUG_TYPE_EXCEPTION:
2083 case IMAGE_DEBUG_TYPE_FIXUP:
2084 case IMAGE_DEBUG_TYPE_BORLAND:
2085 default:
2086 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
2087 break;
2088 case IMAGE_DEBUG_TYPE_CODEVIEW:
2089 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
2090 break;
2091 }
2092
2093 rc = pfnCallback(pMod, iDbgInfo,
2094 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
2095 pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
2096 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
2097 pDbgDir->SizeOfData,
2098 NULL,
2099 pvUser);
2100 if (rc)
2101 break;
2102
2103 /* next */
2104 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
2105 break;
2106 }
2107
2108 return rc;
2109#else
2110 return 0;
2111#endif
2112}
2113
2114
2115/** @copydoc kLdrModHasDbgInfo */
2116static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
2117{
2118 /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
2119
2120#if 0
2121 /*
2122 * Base this entirely on the presence of a debug directory.
2123 */
2124 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
2125 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
2126 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
2127 return KLDR_ERR_NO_DEBUG_INFO;
2128 return 0;
2129#else
2130 return KLDR_ERR_NO_DEBUG_INFO;
2131#endif
2132}
2133
2134
2135/** @copydoc kLdrModMap */
2136static int kldrModMachOMap(PKLDRMOD pMod)
2137{
2138 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2139 unsigned fFixed;
2140 KU32 i;
2141 void *pvBase;
2142 int rc;
2143
2144 /*
2145 * Already mapped?
2146 */
2147 if (pModMachO->pvMapping)
2148 return KLDR_ERR_ALREADY_MAPPED;
2149
2150 /*
2151 * Map it.
2152 */
2153 /* fixed image? */
2154 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
2155 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
2156 if (!fFixed)
2157 pvBase = NULL;
2158 else
2159 {
2160 pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
2161 if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
2162 return KLDR_ERR_ADDRESS_OVERFLOW;
2163 }
2164
2165 /* try do the prepare */
2166 if (pModMachO->fMapUsingLoadCommandSections)
[22]2167 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO); /* deal with this if it ever occurs. */
[2]2168 else
2169 {
2170 rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
2171 if (rc)
2172 return rc;
2173 }
2174
2175 /*
2176 * Update the segments with their map addresses.
2177 */
2178 for (i = 0; i < pMod->cSegments; i++)
2179 {
2180 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
2181 pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
2182 }
2183 pModMachO->pvMapping = pvBase;
2184
2185 return 0;
2186}
2187
2188
2189/** @copydoc kLdrModUnmap */
2190static int kldrModMachOUnmap(PKLDRMOD pMod)
2191{
2192 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2193 KU32 i;
2194 int rc;
2195
2196 /*
2197 * Mapped?
2198 */
2199 if (!pModMachO->pvMapping)
2200 return KLDR_ERR_NOT_MAPPED;
2201
2202 /*
2203 * Try unmap the image.
2204 */
2205 if (pModMachO->fMapUsingLoadCommandSections)
[22]2206 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO); /* deal with this if it ever occurs. */
[2]2207 else
2208 {
2209 rc = kRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
2210 if (rc)
2211 return rc;
2212 }
2213
2214 /*
2215 * Update the segments to reflect that they aren't mapped any longer.
2216 */
2217 pModMachO->pvMapping = NULL;
2218 for (i = 0; i < pMod->cSegments; i++)
2219 pMod->aSegments[i].MapAddress = 0;
2220
2221 return 0;
2222}
2223
2224
2225/** @copydoc kLdrModAllocTLS */
2226static int kldrModMachOAllocTLS(PKLDRMOD pMod)
2227{
2228 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2229
2230 /*
2231 * Mapped?
2232 */
2233 if (!pModMachO->pvMapping)
2234 return KLDR_ERR_NOT_MAPPED;
2235 return 0;
2236}
2237
2238
2239/** @copydoc kLdrModFreeTLS */
2240static void kldrModMachOFreeTLS(PKLDRMOD pMod)
2241{
2242}
2243
2244
2245/** @copydoc kLdrModReload */
2246static int kldrModMachOReload(PKLDRMOD pMod)
2247{
2248 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2249
2250 /*
2251 * Mapped?
2252 */
2253 if (!pModMachO->pvMapping)
2254 return KLDR_ERR_NOT_MAPPED;
2255
2256 /* the file provider does it all */
2257 return kRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
2258}
2259
2260
2261/** @copydoc kLdrModFixupMapping */
2262static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2263{
2264 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2265 int rc, rc2;
2266
2267 /*
2268 * Mapped?
2269 */
2270 if (!pModMachO->pvMapping)
2271 return KLDR_ERR_NOT_MAPPED;
2272
2273 /*
2274 * Before doing anything we'll have to make all pages writable.
2275 */
2276 if (pModMachO->fMapUsingLoadCommandSections)
[22]2277 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO); /* deal with this if it ever occurs. */
[2]2278 else
2279 {
2280 rc = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
2281 if (rc)
2282 return rc;
2283 }
2284
2285 /*
2286 * Resolve imports and apply base relocations.
2287 */
2288 rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (KUPTR)pModMachO->pvMapping, pModMachO->LinkAddress,
2289 pfnGetImport, pvUser);
2290
2291 /*
2292 * Restore protection.
2293 */
2294 if (pModMachO->fMapUsingLoadCommandSections)
2295 rc2 = KLDR_ERR_TODO; /* deal with this if it ever occurs. */
2296 else
2297 rc2 = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
2298 if (!rc && rc2)
2299 rc = rc2;
2300 return rc;
2301}
2302
2303
2304/**
2305 * MH_OBJECT: Resolves undefined symbols (imports).
2306 *
2307 * @returns 0 on success, non-zero kLdr status code on failure.
2308 * @param pModMachO The Mach-O module interpreter instance.
2309 * @param pfnGetImport The callback for resolving an imported symbol.
2310 * @param pvUser User argument to the callback.
2311 */
2312static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2313{
2314 const KU32 cSyms = pModMachO->cSymbols;
2315 KU32 iSym;
2316 int rc;
2317
2318 /*
2319 * Ensure that we've got the symbol table and section fixups handy.
2320 */
2321 rc = kldrModMachOLoadObjSymTab(pModMachO);
2322 if (rc)
2323 return rc;
2324
2325 /*
2326 * Iterate the symbol table and resolve undefined symbols.
2327 * We currently ignore REFERENCE_TYPE.
2328 */
2329 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2330 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2331 {
2332 macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols;
2333 for (iSym = 0; iSym < cSyms; iSym++)
2334 {
2335 /* skip stabs */
2336 if (paSyms[iSym].n_type & MACHO_N_STAB)
2337 continue;
2338
2339 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2340 {
2341 const char *pszSymbol;
2342 KSIZE cchSymbol;
2343 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
2344 KLDRADDR Value;
2345
2346 /** @todo Implement N_REF_TO_WEAK. */
[22]2347 KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO);
[2]2348
2349 /* Get the symbol name and try resolve it. */
2350 if ((KU32)paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
2351 return KLDR_ERR_MACHO_BAD_SYMBOL;
2352 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
2353 cchSymbol = kHlpStrLen(pszSymbol);
2354 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
2355 &Value, &fKind, pvUser);
2356 if (rc)
2357 {
2358 /* weak reference? */
2359 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
2360 break;
2361 Value = 0;
2362 }
2363
2364 /* Update the symbol. */
2365 paSyms[iSym].n_value = (KU32)Value;
2366 if (paSyms[iSym].n_value != Value)
2367 {
2368 rc = KLDR_ERR_ADDRESS_OVERFLOW;
2369 break;
2370 }
2371 }
2372 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
2373 {
2374 /** @todo implement weak symbols. */
2375 /*return KLDR_ERR_TODO; - ignored for now. */
2376 }
2377 }
2378 }
2379 else
2380 {
2381 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
2382 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols;
2383 for (iSym = 0; iSym < cSyms; iSym++)
2384 {
2385 /* skip stabs */
2386 if (paSyms[iSym].n_type & MACHO_N_STAB)
2387 continue;
2388
2389 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2390 {
2391 const char *pszSymbol;
2392 KSIZE cchSymbol;
2393 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
2394 KLDRADDR Value;
2395
2396 /** @todo Implement N_REF_TO_WEAK. */
[22]2397 KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO);
[2]2398
[22]2399 /* Get the symbol name and try resolve it. */
[2]2400 if (paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
2401 return KLDR_ERR_MACHO_BAD_SYMBOL;
2402 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
2403 cchSymbol = kHlpStrLen(pszSymbol);
2404 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
2405 &Value, &fKind, pvUser);
2406 if (rc)
2407 {
2408 /* weak reference? */
2409 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
2410 break;
2411 Value = 0;
2412 }
2413
2414 /* Update the symbol. */
2415 paSyms[iSym].n_value = Value;
2416 if (paSyms[iSym].n_value != Value)
2417 {
2418 rc = KLDR_ERR_ADDRESS_OVERFLOW;
2419 break;
2420 }
2421 }
2422 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
2423 {
2424 /** @todo implement weak symbols. */
2425 /*return KLDR_ERR_TODO; - ignored for now. */
2426 }
2427 }
2428 }
2429
2430 return rc;
2431}
2432
2433
2434/**
2435 * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
2436 *
2437 * @returns 0 on success, non-zero kLdr status code on failure.
2438 * @param pModMachO The Mach-O module interpreter instance.
2439 * @param pvMapping The mapping to fixup.
2440 * @param NewBaseAddress The address to fixup the mapping to.
2441 * @param OldBaseAddress The address the mapping is currently fixed up to.
2442 */
2443static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress)
2444{
2445 KU32 iSeg;
2446 int rc;
2447
2448
2449 /*
2450 * Ensure that we've got the symbol table and section fixups handy.
2451 */
2452 rc = kldrModMachOLoadObjSymTab(pModMachO);
2453 if (rc)
2454 return rc;
2455
2456 /*
2457 * Iterate over the segments and their sections and apply fixups.
2458 */
2459 for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++)
2460 {
2461 PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg];
2462 KU32 iSect;
2463
2464 for (iSect = 0; iSect < pSeg->cSections; iSect++)
2465 {
2466 PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect];
2467 KU8 *pbSectBits;
2468
2469 /* skip sections without fixups. */
2470 if (!pSect->cFixups)
2471 continue;
2472
2473 /* lazy load (and endian convert) the fixups. */
2474 if (!pSect->paFixups)
2475 {
2476 rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
2477 if (rc)
2478 break;
2479 }
2480
2481 /*
2482 * Apply the fixups.
2483 */
2484 pbSectBits = (KU8 *)pvMapping + (KUPTR)pSect->RVA;
2485 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
2486 rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect,
2487 (macho_nlist_32_t *)pModMachO->pvaSymbols,
2488 pModMachO->cSymbols, NewBaseAddress);
[22]2489 else if ( pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE
2490 && pModMachO->Hdr.cputype == CPU_TYPE_X86_64)
2491 rc = kldrModMachOFixupSectionAMD64(pModMachO, pbSectBits, pSect,
2492 (macho_nlist_64_t *)pModMachO->pvaSymbols,
2493 pModMachO->cSymbols, NewBaseAddress);
[2]2494 else
[22]2495 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2496 if (rc)
2497 break;
2498 }
2499 }
2500
2501 return rc;
2502}
2503
2504
2505/**
2506 * Applies generic fixups to a section in an image of the same endian-ness
2507 * as the host CPU.
2508 *
2509 * @returns 0 on success, non-zero kLdr status code on failure.
2510 * @param pModMachO The Mach-O module interpreter instance.
2511 * @param pbSectBits Pointer to the section bits.
2512 * @param pFixupSect The section being fixed up.
2513 * @param NewBaseAddress The new base image address.
2514 */
2515static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
2516 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
2517{
2518 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
2519 const KU32 cFixups = pFixupSect->cFixups;
2520 KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
2521 const KU8 *pbSectVirginBits;
2522 KU32 iFixup;
2523 KLDRPU uFixVirgin;
2524 KLDRPU uFix;
2525 KLDRADDR SymAddr;
2526 int rc;
2527
2528 /*
2529 * Find the virgin bits.
2530 */
2531 if (pFixupSect->offFile != -1)
2532 {
2533 rc = kldrModMachOMapVirginBits(pModMachO);
2534 if (rc)
2535 return rc;
2536 pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
2537 }
2538 else
2539 pbSectVirginBits = NULL;
2540
2541 /*
2542 * Iterate the fixups and apply them.
2543 */
2544 for (iFixup = 0; iFixup < cFixups; iFixup++)
2545 {
2546 union
2547 {
2548 macho_relocation_info_t r;
2549 scattered_relocation_info_t s;
2550 } Fixup;
2551 Fixup.r = paFixups[iFixup];
2552
2553 if (!(Fixup.r.r_address & R_SCATTERED))
2554 {
2555 /* sanity */
2556 if ((KU32)Fixup.r.r_address >= cbSectBits)
2557 return KLDR_ERR_BAD_FIXUP;
2558
2559 /* calc fixup addresses. */
2560 uFix.pv = pbSectBits + Fixup.r.r_address;
2561 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
2562
2563 /*
2564 * Calc the symbol value.
2565 */
2566 /* Calc the linked symbol address / addend. */
2567 switch (Fixup.r.r_length)
2568 {
2569 /** @todo Deal with unaligned accesses on non x86 platforms. */
2570 case 0: SymAddr = *uFixVirgin.pi8; break;
2571 case 1: SymAddr = *uFixVirgin.pi16; break;
2572 case 2: SymAddr = *uFixVirgin.pi32; break;
2573 case 3: SymAddr = *uFixVirgin.pi64; break;
2574 }
2575 if (Fixup.r.r_pcrel)
2576 SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress;
2577
2578 /* Add symbol / section address. */
2579 if (Fixup.r.r_extern)
2580 {
2581 const macho_nlist_32_t *pSym;
2582 if (Fixup.r.r_symbolnum >= cSyms)
2583 return KLDR_ERR_BAD_FIXUP;
2584 pSym = &paSyms[Fixup.r.r_symbolnum];
2585
2586 if (pSym->n_type & MACHO_N_STAB)
2587 return KLDR_ERR_BAD_FIXUP;
2588
2589 switch (pSym->n_type & MACHO_N_TYPE)
2590 {
2591 case MACHO_N_SECT:
2592 {
2593 PKLDRMODMACHOSECT pSymSect;
2594 if ((KU32)pSym->n_sect - 1 > pModMachO->cSections)
2595 return KLDR_ERR_MACHO_BAD_SYMBOL;
2596 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
2597
2598 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2599 break;
2600 }
2601
2602 case MACHO_N_UNDF:
2603 case MACHO_N_ABS:
2604 SymAddr += pSym->n_value;
2605 break;
2606
2607 case MACHO_N_INDR:
2608 case MACHO_N_PBUD:
[22]2609 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
[2]2610 default:
[22]2611 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
[2]2612 }
2613 }
2614 else if (Fixup.r.r_symbolnum != R_ABS)
2615 {
2616 PKLDRMODMACHOSECT pSymSect;
2617 if (Fixup.r.r_symbolnum > pModMachO->cSections)
2618 return KLDR_ERR_BAD_FIXUP;
2619 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
2620
2621 SymAddr -= pSymSect->LinkAddress;
2622 SymAddr += pSymSect->RVA + NewBaseAddress;
2623 }
2624
2625 /* adjust for PC relative */
2626 if (Fixup.r.r_pcrel)
2627 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
2628 }
2629 else
2630 {
2631 PKLDRMODMACHOSECT pSymSect;
2632 KU32 iSymSect;
2633 KLDRADDR Value;
2634
2635 /* sanity */
2636 KLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
2637 if ((KU32)Fixup.s.r_address >= cbSectBits)
2638 return KLDR_ERR_BAD_FIXUP;
2639
2640 /* calc fixup addresses. */
2641 uFix.pv = pbSectBits + Fixup.s.r_address;
2642 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.s.r_address : 0;
2643
2644 /*
2645 * Calc the symbol value.
2646 */
2647 /* The addend is stored in the code. */
2648 switch (Fixup.s.r_length)
2649 {
2650 case 0: SymAddr = *uFixVirgin.pi8; break;
2651 case 1: SymAddr = *uFixVirgin.pi16; break;
2652 case 2: SymAddr = *uFixVirgin.pi32; break;
2653 case 3: SymAddr = *uFixVirgin.pi64; break;
2654 }
2655 if (Fixup.s.r_pcrel)
2656 SymAddr += Fixup.s.r_address;
2657 Value = Fixup.s.r_value;
2658 SymAddr -= Value; /* (-> addend only) */
2659
2660 /* Find the section number from the r_value. */
2661 pSymSect = NULL;
2662 for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++)
2663 {
2664 KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress;
2665 if (off < pModMachO->paSections[iSymSect].cb)
2666 {
2667 pSymSect = &pModMachO->paSections[iSymSect];
2668 break;
2669 }
2670 else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */
2671 pSymSect = &pModMachO->paSections[iSymSect];
2672 }
2673 if (!pSymSect)
2674 return KLDR_ERR_BAD_FIXUP;
2675
2676 /* Calc the symbol address. */
2677 SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2678 if (Fixup.s.r_pcrel)
2679 SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
2680
2681 Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
2682 Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type;
2683 }
2684
2685 /*
2686 * Write back the fixed up value.
2687 */
2688 if (Fixup.r.r_type == GENERIC_RELOC_VANILLA)
2689 {
2690 switch (Fixup.r.r_length)
2691 {
2692 case 0: *uFix.pu8 = (KU8)SymAddr; break;
2693 case 1: *uFix.pu16 = (KU16)SymAddr; break;
2694 case 2: *uFix.pu32 = (KU32)SymAddr; break;
2695 case 3: *uFix.pu64 = (KU64)SymAddr; break;
2696 }
2697 }
2698 else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF)
2699 return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE;
2700 else
2701 return KLDR_ERR_BAD_FIXUP;
2702 }
2703
2704 return 0;
2705}
2706
2707
2708/**
[22]2709 * Applies AMD64 fixups to a section.
2710 *
2711 * @returns 0 on success, non-zero kLdr status code on failure.
2712 * @param pModMachO The Mach-O module interpreter instance.
2713 * @param pbSectBits Pointer to the section bits.
2714 * @param pFixupSect The section being fixed up.
2715 * @param NewBaseAddress The new base image address.
2716 */
2717static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
2718 macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
2719{
2720 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
2721 const KU32 cFixups = pFixupSect->cFixups;
2722 KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
2723 const KU8 *pbSectVirginBits;
2724 KU32 iFixup;
2725 KLDRPU uFixVirgin;
2726 KLDRPU uFix;
2727 KLDRADDR SymAddr;
2728 int rc;
2729
2730 /*
2731 * Find the virgin bits.
2732 */
2733 if (pFixupSect->offFile != -1)
2734 {
2735 rc = kldrModMachOMapVirginBits(pModMachO);
2736 if (rc)
2737 return rc;
2738 pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
2739 }
2740 else
2741 pbSectVirginBits = NULL;
2742
2743 /*
2744 * Iterate the fixups and apply them.
2745 */
2746 for (iFixup = 0; iFixup < cFixups; iFixup++)
2747 {
2748 union
2749 {
2750 macho_relocation_info_t r;
2751 scattered_relocation_info_t s;
2752 } Fixup;
2753 Fixup.r = paFixups[iFixup];
2754
2755 /* AMD64 doesn't use scattered fixups. */
2756 KLDRMODMACHO_CHECK_RETURN(!(Fixup.r.r_address & R_SCATTERED), KLDR_ERR_BAD_FIXUP);
2757
2758 /* sanity */
2759 KLDRMODMACHO_CHECK_RETURN((KU32)Fixup.r.r_address < cbSectBits, KLDR_ERR_BAD_FIXUP);
2760
2761 /* calc fixup addresses. */
2762 uFix.pv = pbSectBits + Fixup.r.r_address;
2763 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
2764
2765 /*
2766 * Calc the symbol value.
2767 */
2768 /* Calc the linked symbol address / addend. */
2769 switch (Fixup.r.r_length)
2770 {
2771 /** @todo Deal with unaligned accesses on non x86 platforms. */
2772 case 2: SymAddr = *uFixVirgin.pi32; break;
2773 case 3: SymAddr = *uFixVirgin.pi64; break;
2774 default:
2775 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
2776 }
2777 if (Fixup.r.r_pcrel)
2778 SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress;
2779
2780 /* Add symbol / section address. */
2781 if (Fixup.r.r_extern)
2782 {
2783 const macho_nlist_64_t *pSym;
2784
2785 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP);
2786 pSym = &paSyms[Fixup.r.r_symbolnum];
2787 KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP);
2788
2789 switch (Fixup.r.r_type)
2790 {
2791 /* GOT references just needs to have their symbol verified.
2792 Later, we'll optimize GOT building here using a parallel sym->got array. */
2793 case X86_64_RELOC_GOT_LOAD:
2794 case X86_64_RELOC_GOT:
2795 switch (pSym->n_type & MACHO_N_TYPE)
2796 {
2797 case MACHO_N_SECT:
2798 case MACHO_N_UNDF:
2799 case MACHO_N_ABS:
2800 break;
2801 case MACHO_N_INDR:
2802 case MACHO_N_PBUD:
2803 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
2804 default:
2805 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
2806 }
2807 SymAddr = sizeof(KU64) * Fixup.r.r_symbolnum + pModMachO->GotRVA + NewBaseAddress;
2808 break;
2809
2810 /* Verify the r_pcrel field for signed fixups on the way into the default case. */
2811 case X86_64_RELOC_BRANCH:
2812 case X86_64_RELOC_SIGNED:
2813 case X86_64_RELOC_SIGNED_1:
2814 case X86_64_RELOC_SIGNED_2:
2815 case X86_64_RELOC_SIGNED_4:
2816 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
2817 default:
2818 {
2819 /* Adjust with fixup specific addend and vierfy unsigned/r_pcrel. */
2820 switch (Fixup.r.r_type)
2821 {
2822 case X86_64_RELOC_UNSIGNED:
2823 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
2824 break;
2825 case X86_64_RELOC_SIGNED:
2826 break;
2827 case X86_64_RELOC_BRANCH:
2828 switch (Fixup.r.r_length)
2829 {
2830 case 0: SymAddr -= 1; break;
2831 case 1: SymAddr -= 2; break;
2832 case 2: SymAddr -= 4; break;
2833 case 3: SymAddr -= 8; break;
2834 }
2835 break;
2836 case X86_64_RELOC_SIGNED_1: SymAddr -= 1; break;
2837 case X86_64_RELOC_SIGNED_2: SymAddr -= 2; break;
2838 case X86_64_RELOC_SIGNED_4: SymAddr -= 4; break;
2839 default:
2840 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
2841 }
2842
2843 switch (pSym->n_type & MACHO_N_TYPE)
2844 {
2845 case MACHO_N_SECT:
2846 {
2847 PKLDRMODMACHOSECT pSymSect;
2848 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
2849 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
2850 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2851 break;
2852 }
2853
2854 case MACHO_N_UNDF:
2855 case MACHO_N_ABS:
2856 SymAddr += pSym->n_value;
2857 break;
2858
2859 case MACHO_N_INDR:
2860 case MACHO_N_PBUD:
2861 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
2862 default:
2863 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
2864 }
2865 break;
2866 }
2867
2868 /*
2869 * This is a weird customer, it will always be follows by an UNSIGNED fixup.
2870 */
2871 case X86_64_RELOC_SUBTRACTOR:
2872 {
2873 macho_relocation_info_t Fixup2;
2874
2875 /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */
2876 switch (pSym->n_type & MACHO_N_TYPE)
2877 {
2878 case MACHO_N_SECT:
2879 {
2880 PKLDRMODMACHOSECT pSymSect;
2881 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
2882 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
2883 SymAddr -= pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2884 break;
2885 }
2886
2887 case MACHO_N_UNDF:
2888 case MACHO_N_ABS:
2889 SymAddr -= pSym->n_value;
2890 break;
2891
2892 case MACHO_N_INDR:
2893 case MACHO_N_PBUD:
2894 KLDRMODMACHO_CHECK_RETURN(0,KLDR_ERR_TODO);
2895 default:
2896 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
2897 }
2898
2899 /* Load the 2nd fixup, check sanity. */
2900 iFixup++;
2901 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, KLDR_ERR_BAD_FIXUP);
2902 Fixup2 = paFixups[iFixup];
2903 KLDRMODMACHO_CHECK_RETURN( Fixup2.r_address == Fixup.r.r_address
2904 && Fixup2.r_length == Fixup.r.r_length
2905 && Fixup2.r_type == X86_64_RELOC_UNSIGNED
2906 && !Fixup2.r_pcrel
2907 && Fixup2.r_extern /*??*/
2908 && Fixup2.r_symbolnum < cSyms,
2909 KLDR_ERR_BAD_FIXUP);
2910
2911 pSym = &paSyms[Fixup.r.r_symbolnum];
2912 KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP);
2913
2914 /* Add it's value to SymAddr. */
2915 switch (pSym->n_type & MACHO_N_TYPE)
2916 {
2917 case MACHO_N_SECT:
2918 {
2919 PKLDRMODMACHOSECT pSymSect;
2920 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
2921 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
2922 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2923 break;
2924 }
2925
2926 case MACHO_N_UNDF:
2927 case MACHO_N_ABS:
2928 SymAddr += pSym->n_value;
2929 break;
2930
2931 case MACHO_N_INDR:
2932 case MACHO_N_PBUD:
2933 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO);
2934 default:
2935 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_MACHO_BAD_SYMBOL);
2936 }
2937 }
2938 break;
2939 }
2940 }
2941 else
2942 {
2943 /* verify against fixup type */
2944 switch (Fixup.r.r_type)
2945 {
2946 case X86_64_RELOC_UNSIGNED:
2947 case X86_64_RELOC_SIGNED:
2948 case X86_64_RELOC_BRANCH:
2949 /*case X86_64_RELOC_GOT_LOAD:*/
2950 /*case X86_64_RELOC_GOT: */
2951 /*case X86_64_RELOC_SUBTRACTOR: - ???*/
2952 case X86_64_RELOC_SIGNED_1:
2953 case X86_64_RELOC_SIGNED_2:
2954 case X86_64_RELOC_SIGNED_4:
2955 break;
2956 default:
2957 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
2958 }
2959 if (Fixup.r.r_symbolnum != R_ABS)
2960 {
2961 PKLDRMODMACHOSECT pSymSect;
2962 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP);
2963 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
2964
2965 SymAddr -= pSymSect->LinkAddress;
2966 SymAddr += pSymSect->RVA + NewBaseAddress;
2967 }
2968 }
2969
2970 /* adjust for PC relative */
2971 if (Fixup.r.r_pcrel)
2972 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
2973
2974 /*
2975 * Write back the fixed up value.
2976 */
2977 switch (Fixup.r.r_length)
2978 {
2979 case 3:
2980 *uFix.pu64 = (KU64)SymAddr;
2981 break;
2982 case 2:
2983 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel || Fixup.r.r_type == X86_64_RELOC_SUBTRACTOR, KLDR_ERR_BAD_FIXUP);
2984 KLDRMODMACHO_CHECK_RETURN((KI32)SymAddr == (KI64)SymAddr, KLDR_ERR_ADDRESS_OVERFLOW);
2985 *uFix.pu32 = (KU32)SymAddr;
2986 break;
2987 default:
2988 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_BAD_FIXUP);
2989 }
2990 }
2991
2992 return 0;
2993}
2994
2995
2996/**
[2]2997 * Loads the symbol table for a MH_OBJECT file.
2998 *
2999 * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols.
3000 *
3001 * @returns 0 on success, non-zero kLdr status code on failure.
3002 * @param pModMachO The Mach-O module interpreter instance.
3003 */
3004static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO)
3005{
3006 int rc = 0;
3007
3008 if ( !pModMachO->pvaSymbols
3009 && pModMachO->cSymbols)
3010 {
3011 KSIZE cbSyms;
3012 KSIZE cbSym;
3013 void *pvSyms;
3014 void *pvStrings;
3015
3016 /* sanity */
[22]3017 KLDRMODMACHO_CHECK_RETURN( pModMachO->offSymbols
3018 && (!pModMachO->cchStrings || pModMachO->offStrings),
3019 KLDR_ERR_MACHO_BAD_OBJECT_FILE);
[2]3020
3021 /* allocate */
3022 cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
3023 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
3024 ? sizeof(macho_nlist_32_t)
3025 : sizeof(macho_nlist_64_t);
3026 cbSyms = pModMachO->cSymbols * cbSym;
[22]3027 KLDRMODMACHO_CHECK_RETURN(cbSyms / cbSym == pModMachO->cSymbols, KLDR_ERR_SIZE_OVERFLOW);
[2]3028 rc = KERR_NO_MEMORY;
3029 pvSyms = kHlpAlloc(cbSyms);
3030 if (pvSyms)
3031 {
3032 if (pModMachO->cchStrings)
3033 pvStrings = kHlpAlloc(pModMachO->cchStrings);
3034 else
3035 pvStrings = kHlpAllocZ(4);
3036 if (pvStrings)
3037 {
3038 /* read */
3039 rc = kRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols);
3040 if (!rc && pModMachO->cchStrings)
3041 rc = kRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings);
3042 if (!rc)
3043 {
3044 pModMachO->pvaSymbols = pvSyms;
3045 pModMachO->pchStrings = (char *)pvStrings;
3046
3047 /* perform endian conversion? */
3048 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
3049 {
3050 KU32 cLeft = pModMachO->cSymbols;
3051 macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms;
3052 while (cLeft-- > 0)
3053 {
3054 pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
3055 pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
3056 pSym->n_value = K_E2E_U32(pSym->n_value);
3057 pSym++;
3058 }
3059 }
3060 else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
3061 {
3062 KU32 cLeft = pModMachO->cSymbols;
3063 macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms;
3064 while (cLeft-- > 0)
3065 {
3066 pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
3067 pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
3068 pSym->n_value = K_E2E_U64(pSym->n_value);
3069 pSym++;
3070 }
3071 }
3072
3073 return 0;
3074 }
3075 kHlpFree(pvStrings);
3076 }
3077 kHlpFree(pvSyms);
3078 }
3079 }
3080 else
3081 KLDRMODMACHO_ASSERT(pModMachO->pchStrings);
3082
3083 return rc;
3084}
3085
3086
3087/**
3088 * Loads the fixups at the given address and performs endian
3089 * conversion if necessary.
3090 *
3091 * @returns 0 on success, non-zero kLdr status code on failure.
3092 * @param pModMachO The Mach-O module interpreter instance.
3093 * @param offFixups The file offset of the fixups.
3094 * @param cFixups The number of fixups to load.
3095 * @param ppaFixups Where to put the pointer to the allocated fixup array.
3096 */
3097static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups)
3098{
3099 macho_relocation_info_t *paFixups;
3100 KSIZE cbFixups;
3101 int rc;
3102
3103 /* allocate the memory. */
3104 cbFixups = cFixups * sizeof(*paFixups);
[22]3105 KLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, KLDR_ERR_SIZE_OVERFLOW);
[2]3106 paFixups = (macho_relocation_info_t *)kHlpAlloc(cbFixups);
3107 if (!paFixups)
3108 return KERR_NO_MEMORY;
3109
3110 /* read the fixups. */
3111 rc = kRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups);
3112 if (!rc)
3113 {
3114 *ppaFixups = paFixups;
3115
3116 /* do endian conversion if necessary. */
3117 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
3118 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
3119 {
3120 KU32 iFixup;
3121 for (iFixup = 0; iFixup < cFixups; iFixup++)
3122 {
3123 KU32 *pu32 = (KU32 *)&paFixups[iFixup];
3124 pu32[0] = K_E2E_U32(pu32[0]);
3125 pu32[1] = K_E2E_U32(pu32[1]);
3126 }
3127 }
3128 }
3129 else
3130 kHlpFree(paFixups);
3131 return rc;
3132}
3133
3134
3135/**
3136 * Maps the virgin file bits into memory if not already done.
3137 *
3138 * @returns 0 on success, non-zero kLdr status code on failure.
3139 * @param pModMachO The Mach-O module interpreter instance.
3140 */
3141static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO)
3142{
3143 int rc = 0;
3144 if (!pModMachO->pvBits)
3145 rc = kRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits);
3146 return rc;
3147}
3148
3149
3150/** @copydoc kLdrModCallInit */
3151static int kldrModMachOCallInit(PKLDRMOD pMod, KUPTR uHandle)
3152{
3153 /* later */
3154 return 0;
3155}
3156
3157
3158/** @copydoc kLdrModCallTerm */
3159static int kldrModMachOCallTerm(PKLDRMOD pMod, KUPTR uHandle)
3160{
3161 /* later */
3162 return 0;
3163}
3164
3165
3166/** @copydoc kLdrModCallThread */
3167static int kldrModMachOCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
3168{
3169 /* Relevant for Mach-O? */
3170 return 0;
3171}
3172
3173
3174/** @copydoc kLdrModSize */
3175static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
3176{
3177 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3178 return pModMachO->cbImage;
3179}
3180
3181
3182/** @copydoc kLdrModGetBits */
3183static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
3184{
3185 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3186 KU32 i;
3187 int rc;
3188
3189 /*
3190 * Zero the entire buffer first to simplify things.
3191 */
3192 kHlpMemSet(pvBits, 0, (KSIZE)pModMachO->cbImage);
3193
3194 /*
3195 * When possible use the segment table to load the data.
3196 * If not iterate the load commands and execute the segment / section loads.
3197 */
3198 if (pModMachO->fMapUsingLoadCommandSections)
[22]3199 KLDRMODMACHO_CHECK_RETURN(0, KLDR_ERR_TODO); /* deal with this if it ever occurs. */
[2]3200 else
3201 {
3202 for (i = 0; i < pMod->cSegments; i++)
3203 {
3204 /* skip it? */
3205 if ( pMod->aSegments[i].cbFile == -1
3206 || pMod->aSegments[i].offFile == -1
3207 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
3208 || !pMod->aSegments[i].Alignment)
3209 continue;
3210 rc = kRdrRead(pMod->pRdr,
[22]3211 (KU8 *)pvBits + (pMod->aSegments[i].LinkAddress - pModMachO->LinkAddress),
3212 pMod->aSegments[i].cbFile,
3213 pMod->aSegments[i].offFile);
[2]3214 if (rc)
3215 return rc;
3216 }
3217 }
3218
3219 /*
3220 * Perform relocations.
3221 */
[22]3222 rc = kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
3223 if (rc)
3224 return rc;
3225
3226 /*
3227 * Construct the global offset table if necessary, it's always the last
3228 * segment when present.
3229 */
3230 if (pModMachO->fMakeGot)
3231 rc = kldrModMachOMakeGOT(pModMachO, pvBits, BaseAddress);
3232 return rc;
[2]3233}
3234
3235
[22]3236/**
3237 * Builds the GOT.
3238 *
3239 * Assumes the symbol table has all external symbols resolved correctly and that
3240 * the bits has been cleared up front.
3241 */
3242static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress)
3243{
3244 KU32 iSym = pModMachO->cSymbols;
3245 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
3246 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
3247 {
3248 macho_nlist_32_t const *paSyms = (macho_nlist_32_t const *)pModMachO->pvaSymbols;
3249 KU32 *paGOT = (KU32 *)((KU8 *)pvBits + pModMachO->GotRVA);
3250 while (iSym-- > 0)
3251 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
3252 {
3253 case MACHO_N_SECT:
3254 {
3255 PKLDRMODMACHOSECT pSymSect;
3256 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3257 pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
3258 paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3259 break;
3260 }
3261
3262 case MACHO_N_UNDF:
3263 case MACHO_N_ABS:
3264 paGOT[iSym] = paSyms[iSym].n_value;
3265 break;
3266 }
3267 }
3268 else
3269 {
3270 macho_nlist_64_t const *paSyms = (macho_nlist_64_t const *)pModMachO->pvaSymbols;
3271 KU64 *paGOT = (KU64 *)((KU8 *)pvBits + pModMachO->GotRVA);
3272 while (iSym-- > 0)
3273 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
3274 {
3275 case MACHO_N_SECT:
3276 {
3277 PKLDRMODMACHOSECT pSymSect;
3278 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3279 pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
3280 paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3281 break;
3282 }
3283
3284 case MACHO_N_UNDF:
3285 case MACHO_N_ABS:
3286 paGOT[iSym] = paSyms[iSym].n_value;
3287 break;
3288 }
3289 }
3290 return 0;
3291}
3292
3293
[2]3294/** @copydoc kLdrModRelocateBits */
3295static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
3296 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
3297{
3298 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3299 int rc;
3300
3301 /*
3302 * Call workers to do the jobs.
3303 */
3304 if (pModMachO->Hdr.filetype == MH_OBJECT)
3305 {
3306 rc = kldrModMachOObjDoImports(pModMachO, pfnGetImport, pvUser);
3307 if (!rc)
3308 rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress);
3309
3310 }
3311 else
3312 rc = KLDR_ERR_TODO;
3313 /*{
3314 rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
3315 if (!rc)
3316 rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
3317 }*/
3318
3319 return rc;
3320}
3321
3322
3323/**
3324 * The Mach-O module interpreter method table.
3325 */
3326KLDRMODOPS g_kLdrModMachOOps =
3327{
3328 "Mach-O",
3329 NULL,
3330 kldrModMachOCreate,
3331 kldrModMachODestroy,
3332 kldrModMachOQuerySymbol,
3333 kldrModMachOEnumSymbols,
3334 kldrModMachOGetImport,
3335 kldrModMachONumberOfImports,
3336 NULL /* can execute one is optional */,
3337 kldrModMachOGetStackInfo,
3338 kldrModMachOQueryMainEntrypoint,
3339 NULL,
3340 NULL,
3341 kldrModMachOEnumDbgInfo,
3342 kldrModMachOHasDbgInfo,
3343 kldrModMachOMap,
3344 kldrModMachOUnmap,
3345 kldrModMachOAllocTLS,
3346 kldrModMachOFreeTLS,
3347 kldrModMachOReload,
3348 kldrModMachOFixupMapping,
3349 kldrModMachOCallInit,
3350 kldrModMachOCallTerm,
3351 kldrModMachOCallThread,
3352 kldrModMachOSize,
3353 kldrModMachOGetBits,
3354 kldrModMachORelocateBits,
3355 NULL, /** @todo mostly done */
3356 42 /* the end */
3357};
3358
Note: See TracBrowser for help on using the repository browser.