]> git.saurik.com Git - apple/xnu.git/blame - libsa/kld_patch.c
xnu-517.7.21.tar.gz
[apple/xnu.git] / libsa / kld_patch.c
CommitLineData
0b4e3aa0
A
1/*
2 * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
0b4e3aa0
A
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
0b4e3aa0
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * History:
26 * 2001-05-30 gvdl Initial implementation of the vtable patcher.
27 */
28// 45678901234567890123456789012345678901234567890123456789012345678901234567890
29
30#include <mach-o/fat.h>
31#include <mach-o/loader.h>
32#include <mach-o/nlist.h>
33#include <mach-o/reloc.h>
55e303ae
A
34#if !KERNEL
35#include <mach-o/swap.h>
36#endif
0b4e3aa0
A
37
38#if KERNEL
39
40#include <stdarg.h>
41#include <string.h>
42
43#include <sys/systm.h>
44
45#include <libkern/OSTypes.h>
46
47#include <libsa/stdlib.h>
48#include <libsa/mach/mach.h>
49
50#include "mach_loader.h"
51
52#include <vm/vm_kern.h>
53
54enum { false = 0, true = 1 };
55
56#define vm_page_size page_size
57
58extern load_return_t fatfile_getarch(
59 void * vp, // normally a (struct vnode *)
60 vm_offset_t data_ptr,
61 struct fat_arch * archret);
62
9bccf70c
A
63__private_extern__ char *strstr(const char *in, const char *str);
64
0b4e3aa0 65#else /* !KERNEL */
9bccf70c 66
0b4e3aa0
A
67#include <unistd.h>
68
69#include <stdio.h>
70#include <stdlib.h>
71#include <string.h>
72
73#include <sys/errno.h>
74#include <sys/fcntl.h>
75#include <sys/stat.h>
76#include <sys/mman.h>
9bccf70c 77#include <sys/vm.h>
0b4e3aa0
A
78
79#include <mach/mach.h>
80#include <mach/mach_error.h>
81
82#include <mach-o/arch.h>
83
84#include <CoreFoundation/CoreFoundation.h>
9bccf70c
A
85
86#define PAGE_SIZE vm_page_size
87#define PAGE_MASK (PAGE_SIZE - 1)
88
0b4e3aa0
A
89#endif /* KERNEL */
90
91#include "kld_patch.h"
9bccf70c 92#include "c++rem3.h"
0b4e3aa0
A
93
94#if 0
9bccf70c
A
95#define DIE() do { for (;;) ; } while(0)
96
97#if KERNEL
98# define LOG_DELAY() /* IODelay(200000) */
99# define DEBUG_LOG(x) do { IOLog x; LOG_DELAY(); } while(0)
100#else
101# define LOG_DELAY()
102# define DEBUG_LOG(x) do { printf x; } while(0)
103#endif
0b4e3aa0 104
0b4e3aa0
A
105#else
106
107#define DIE()
108#define LOG_DELAY()
109#define DEBUG_LOG(x)
110
111#endif
112
113// OSObject symbol prefixes and suffixes
9bccf70c
A
114#define kCPPSymbolPrefix "_Z"
115#define kVTablePrefix "_" kCPPSymbolPrefix "TV"
116#define kOSObjPrefix "_" kCPPSymbolPrefix "N"
117#define kReservedNamePrefix "_RESERVED"
118#define k29SuperClassSuffix "superClass"
119#define k31SuperClassSuffix "10superClassE"
120#define kGMetaSuffix "10gMetaClassE"
0b4e3aa0
A
121#define kLinkEditSegName SEG_LINKEDIT
122
123// GCC 2.95 drops 2 leading constants in the vtable
124#define kVTablePreambleLen 2
125
126// Last address that I'm willing to try find vm in
127#define kTopAddr ((unsigned char *) (1024 * 1024 * 1024))
128
129// Size in bytes that Data Ref object's get increased in size
130// Must be a power of 2
131#define kDataCapacityIncrement 128
132
133// My usual set of helper macros. I personally find these macros
134// easier to read in the code rather than an explicit error condition
135// check. If I don't make it easy then I may get lazy ond not check
136// everything. I'm sorry if you find this code harder to read.
137
138// break_if will evaluate the expression and if it is true
139// then it will print the msg, which is enclosed in parens
140// and then break. Usually used in loops are do { } while (0)
141#define break_if(expr, msg) \
142 if (expr) { \
143 errprintf msg; \
144 break; \
145 }
146
147// return_if will evaluate expr and if true it will log the
148// msg, which is enclosed in parens, and then it will return
149// with the return code of ret.
150#define return_if(expr, ret, msg) do { \
151 if (expr) { \
152 errprintf msg; \
153 return ret; \
154 } \
155} while (0)
156
157#ifndef MIN
158#define MIN(a,b) (((a)<(b))?(a):(b))
159#endif /* MIN */
160#ifndef MAX
161#define MAX(a,b) (((a)>(b))?(a):(b))
162#endif /* MAX */
163
164typedef struct Data {
165 unsigned long fLength, fCapacity;
166 unsigned char *fData;
167} Data, *DataRef;
168
169struct sectionRecord {
170 const struct section *fSection;
171 DataRef fRelocCache;
172};
173
174enum patchState {
175 kSymbolIdentical,
176 kSymbolLocal,
177 kSymbolPadUpdate,
178 kSymbolSuperUpdate,
179 kSymbolMismatch
180};
181
182struct patchRecord {
183 struct nlist *fSymbol;
55e303ae 184 const struct fileRecord *fFile;
0b4e3aa0
A
185 enum patchState fType;
186};
187
188struct relocRecord {
189 void *fValue;
190 const struct nlist *fSymbol;
191 struct relocation_info *fRInfo;
192 void *reserved;
193};
194
195struct metaClassRecord {
196 char *fSuperName;
197 struct fileRecord *fFile;
198 const struct nlist *fVTableSym;
199 struct patchRecord *fPatchedVTable;
200 char fClassName[1];
201};
202
203struct fileRecord {
204 size_t fMapSize, fMachOSize;
0b4e3aa0
A
205 unsigned char *fMap, *fMachO, *fPadEnd;
206 DataRef fClassList;
207 DataRef fSectData;
9bccf70c
A
208 DataRef fNewSymbols, fNewStringBlocks;
209 DataRef fSym2Strings;
0b4e3aa0
A
210 struct symtab_command *fSymtab;
211 struct sectionRecord *fSections;
55e303ae 212 vm_offset_t fVMAddr, fVMEnd;
9bccf70c
A
213 struct segment_command *fLinkEditSeg;
214 const char **fSymbToStringTable;
0b4e3aa0
A
215 char *fStringBase;
216 struct nlist *fSymbolBase;
217 const struct nlist *fLocalSyms;
218 unsigned int fNSects;
219 int fNLocal;
55e303ae 220 Boolean fIsKernel, fIsReloc, fIsIncrLink, fNoKernelExecutable, fIsKmem;
0b4e3aa0 221 Boolean fImageDirty, fSymbolsDirty;
9bccf70c
A
222 Boolean fRemangled, fFoundOSObject;
223 Boolean fIgnoreFile;
55e303ae
A
224#if !KERNEL
225 Boolean fSwapped;
226#endif
9bccf70c 227 const char fPath[1];
0b4e3aa0
A
228};
229
230static DataRef sFilesTable;
231static struct fileRecord *sKernelFile;
232
55e303ae
A
233static DataRef sMergedFiles;
234static DataRef sMergeMetaClasses;
235static Boolean sMergedKernel;
236#if !KERNEL
237static const NXArchInfo * sPreferArchInfo;
238#endif
239static const struct nlist *
240findSymbolByName(struct fileRecord *file, const char *symname);
0b4e3aa0
A
241
242static void errprintf(const char *fmt, ...)
243{
244 extern void kld_error_vprintf(const char *format, va_list ap);
245
246 va_list ap;
247
248 va_start(ap, fmt);
249 kld_error_vprintf(fmt, ap);
250 va_end(ap);
251
252DIE();
253}
254
255static __inline__ unsigned long DataGetLength(DataRef data)
256{
257 return data->fLength;
258}
259
260static __inline__ unsigned char *DataGetPtr(DataRef data)
261{
262 return data->fData;
263}
264
9bccf70c
A
265static __inline__ unsigned char *DataGetEndPtr(DataRef data)
266{
267 return data->fData + data->fLength;
268}
269
270static __inline__ unsigned long DataRemaining(DataRef data)
271{
272 return data->fCapacity - data->fLength;
273}
0b4e3aa0
A
274
275static __inline__ Boolean DataContainsAddr(DataRef data, void *vAddr)
276{
9bccf70c
A
277 vm_offset_t offset = (vm_address_t) vAddr;
278
279 if (!data)
280 return false;
281
282 offset = (vm_address_t) vAddr - (vm_address_t) data->fData;
283 return (offset < data->fLength);
284}
285
286static Boolean DataEnsureCapacity(DataRef data, unsigned long capacity)
287{
288 // Don't bother to ever shrink a data object.
289 if (capacity > data->fCapacity) {
290 unsigned char *newData;
291
292 capacity += kDataCapacityIncrement - 1;
293 capacity &= ~(kDataCapacityIncrement - 1);
294 newData = (unsigned char *) realloc(data->fData, capacity);
295 if (!newData)
296 return false;
297
298 bzero(newData + data->fCapacity, capacity - data->fCapacity);
299 data->fData = newData;
300 data->fCapacity = capacity;
301 }
302
303 return true;
304}
0b4e3aa0 305
9bccf70c
A
306static __inline__ Boolean DataSetLength(DataRef data, unsigned long length)
307{
308 if (DataEnsureCapacity(data, length)) {
309 data->fLength = length;
310 return true;
311 }
312 else
313 return false;
0b4e3aa0
A
314}
315
316static __inline__ Boolean DataAddLength(DataRef data, unsigned long length)
317{
0b4e3aa0
A
318 return DataSetLength(data, data->fLength + length);
319}
320
321static __inline__ Boolean
322DataAppendBytes(DataRef data, const void *addr, unsigned int len)
323{
324 unsigned long size = DataGetLength(data);
325
326 if (!DataAddLength(data, len))
327 return false;
328
329 bcopy(addr, DataGetPtr(data) + size, len);
330 return true;
331}
332
333static __inline__ Boolean DataAppendData(DataRef dst, DataRef src)
334{
335 return DataAppendBytes(dst, DataGetPtr(src), DataGetLength(src));
336}
337
9bccf70c 338static DataRef DataCreate(unsigned long capacity)
0b4e3aa0
A
339{
340 DataRef data = (DataRef) malloc(sizeof(Data));
341
342 if (data) {
9bccf70c 343 if (!capacity)
0b4e3aa0
A
344 data->fCapacity = kDataCapacityIncrement;
345 else {
9bccf70c 346 data->fCapacity = capacity + kDataCapacityIncrement - 1;
0b4e3aa0
A
347 data->fCapacity &= ~(kDataCapacityIncrement - 1);
348 }
349
350 data->fData = (unsigned char *) malloc(data->fCapacity);
351 if (!data->fData) {
352 free(data);
353 return NULL;
354 }
355
356 bzero(data->fData, data->fCapacity);
9bccf70c 357 data->fLength = 0;
0b4e3aa0
A
358 }
359 return data;
360}
361
362static void DataRelease(DataRef data)
363{
364 if (data) {
365 if (data->fData)
366 free(data->fData);
367 data->fData = 0;
368 free(data);
369 }
370}
371
9bccf70c
A
372static __inline__ const char *
373symNameByIndex(const struct fileRecord *file, unsigned int symInd)
374{
375 return file->fSymbToStringTable[symInd];
376}
377
378static __inline__ const char *
0b4e3aa0
A
379symbolname(const struct fileRecord *file, const struct nlist *sym)
380{
9bccf70c 381 unsigned int index;
0b4e3aa0 382
9bccf70c
A
383 index = sym - file->fSymbolBase;
384 if (index < file->fSymtab->nsyms)
385 return symNameByIndex(file, index);
0b4e3aa0 386
9bccf70c
A
387 if (-1 == sym->n_un.n_strx)
388 return (const char *) sym->n_value;
0b4e3aa0 389
9bccf70c
A
390 // If the preceding tests fail then we have a getNewSymbol patch and
391 // the file it refers to has already been patched as the n_strx is set
392 // to -1 temporarily while we are still processing a file.
393 // Once we have finished with a file then we repair the 'strx' offset
394 // to be valid for the repaired file's string table.
395 return file->fStringBase + sym->n_un.n_strx;
0b4e3aa0
A
396}
397
9bccf70c
A
398static struct fileRecord *
399getFile(const char *path)
0b4e3aa0
A
400{
401 if (sFilesTable) {
402 int i, nfiles;
403 struct fileRecord **files;
404
405 // Check to see if we have already merged this file
406 nfiles = DataGetLength(sFilesTable) / sizeof(struct fileRecord *);
407 files = (struct fileRecord **) DataGetPtr(sFilesTable);
408 for (i = 0; i < nfiles; i++) {
409 if (!strcmp(path, files[i]->fPath))
410 return files[i];
411 }
412 }
413
414 return NULL;
415}
416
9bccf70c
A
417static struct fileRecord *
418addFile(struct fileRecord *file, const char *path)
0b4e3aa0
A
419{
420 struct fileRecord *newFile;
421
422 if (!sFilesTable) {
423 sFilesTable = DataCreate(0);
424 if (!sFilesTable)
425 return NULL;
426 }
427
9bccf70c
A
428 newFile = (struct fileRecord *)
429 malloc(sizeof(struct fileRecord) + strlen(path));
0b4e3aa0
A
430 if (!newFile)
431 return NULL;
432
433 if (!DataAppendBytes(sFilesTable, &newFile, sizeof(newFile))) {
434 free(newFile);
435 return NULL;
436 }
437
9bccf70c
A
438 bcopy(file, newFile, sizeof(struct fileRecord) - 1);
439 strcpy((char *) newFile->fPath, path);
440
0b4e3aa0
A
441 return newFile;
442}
443
444// @@@ gvdl: need to clean up the sMergeMetaClasses
445// @@@ gvdl: I had better fix the object file up again
9bccf70c 446static void unmapFile(struct fileRecord *file)
0b4e3aa0 447{
0b4e3aa0
A
448 if (file->fSectData) {
449 struct sectionRecord *section;
450 unsigned int i, nsect;
451
452 nsect = file->fNSects;
453 section = file->fSections;
454 for (i = 0; i < nsect; i++, section++) {
455 if (section->fRelocCache) {
456 DataRelease(section->fRelocCache);
457 section->fRelocCache = 0;
458 }
459 }
460
461 DataRelease(file->fSectData);
462 file->fSectData = 0;
463 file->fSections = 0;
464 file->fNSects = 0;
465 }
466
9bccf70c
A
467 if (file->fSym2Strings) {
468 DataRelease(file->fSym2Strings);
469 file->fSym2Strings = 0;
470 }
471
0b4e3aa0
A
472 if (file->fMap) {
473#if KERNEL
474 if (file->fIsKmem)
475 kmem_free(kernel_map, (vm_address_t) file->fMap, file->fMapSize);
476#else /* !KERNEL */
477 if (file->fPadEnd) {
478 vm_address_t padVM;
479 vm_size_t padSize;
480
481 padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
482 padSize = (vm_size_t) ((vm_address_t) file->fPadEnd - padVM);
483 (void) vm_deallocate(mach_task_self(), padVM, padSize);
484 file->fPadEnd = 0;
485 }
486
487 (void) munmap((caddr_t) file->fMap, file->fMapSize);
488#endif /* !KERNEL */
489 file->fMap = 0;
490 }
9bccf70c
A
491}
492
493static void removeFile(struct fileRecord *file)
494{
495 if (file->fClassList) {
496 DataRelease(file->fClassList);
497 file->fClassList = 0;
498 }
0b4e3aa0 499
9bccf70c
A
500 unmapFile(file);
501
502 free(file);
0b4e3aa0
A
503}
504
505#if !KERNEL
506static Boolean
9bccf70c 507mapObjectFile(struct fileRecord *file, const char *pathName)
0b4e3aa0
A
508{
509 Boolean result = false;
9bccf70c 510 static unsigned char *sFileMapBaseAddr = 0;
0b4e3aa0
A
511
512 int fd = 0;
513
514 if (!sFileMapBaseAddr) {
515 kern_return_t ret;
516 vm_address_t probeAddr;
517
518 // If we don't already have a base addr find any random chunk
519 // of 32 meg of VM and to use the 16 meg boundrary as a base.
520 ret = vm_allocate(mach_task_self(), &probeAddr,
521 32 * 1024 * 1024, VM_FLAGS_ANYWHERE);
522 return_if(KERN_SUCCESS != ret, false,
523 ("Unable to allocate base memory %s\n", mach_error_string(ret)));
524 (void) vm_deallocate(mach_task_self(), probeAddr, 32 * 1024 * 1024);
525
526 // Now round to the next 16 Meg boundrary
527 probeAddr = (probeAddr + (16 * 1024 * 1024 - 1))
528 & ~(16 * 1024 * 1024 - 1);
529 sFileMapBaseAddr = (unsigned char *) probeAddr;
530 }
531
9bccf70c 532 fd = open(pathName, O_RDONLY, 0);
0b4e3aa0 533 return_if(fd == -1, false, ("Can't open %s for reading - %s\n",
9bccf70c 534 pathName, strerror(errno)));
0b4e3aa0
A
535
536 do {
537 kern_return_t ret;
538 struct stat sb;
539 int retaddr = -1;
540
541 break_if(fstat(fd, &sb) == -1,
542 ("Can't stat %s - %s\n", file->fPath, strerror(errno)));
543
544 file->fMapSize = sb.st_size;
545 file->fMap = sFileMapBaseAddr;
546 ret = KERN_SUCCESS;
547 while (file->fMap < kTopAddr) {
548 vm_address_t padVM;
549 vm_address_t padVMEnd;
550 vm_size_t padSize;
551
552 padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
553 retaddr = (int) mmap(file->fMap, file->fMapSize,
554 PROT_READ|PROT_WRITE,
555 MAP_FIXED|MAP_FILE|MAP_PRIVATE,
556 fd, 0);
557 if (-1 == retaddr) {
558 break_if(ENOMEM != errno,
559 ("mmap failed %d - %s\n", errno, strerror(errno)));
560
561 file->fMap = (unsigned char *) padVM;
562 continue;
563 }
564
565
566 // Round up padVM to the next page after the file and assign at
567 // least another fMapSize more room rounded up to the next page
568 // boundary.
569 padVMEnd = round_page(padVM + file->fMapSize);
570 padSize = padVMEnd - padVM;
571 ret = vm_allocate(
572 mach_task_self(), &padVM, padSize, VM_FLAGS_FIXED);
573 if (KERN_SUCCESS == ret) {
574 file->fPadEnd = (unsigned char *) padVMEnd;
575 break;
576 }
577 else {
578 munmap(file->fMap, file->fMapSize);
579 break_if(KERN_INVALID_ADDRESS != ret,
580 ("Unable to allocate pad vm for %s - %s\n",
9bccf70c 581 pathName, mach_error_string(ret)));
0b4e3aa0
A
582
583 file->fMap = (unsigned char *) padVMEnd;
584 continue; // try again wherever the vm system wants
585 }
586 }
587
588 if (-1 == retaddr || KERN_SUCCESS != ret)
589 break;
590
591 break_if(file->fMap >= kTopAddr,
592 ("Unable to map memory %s\n", file->fPath));
593
594 sFileMapBaseAddr = file->fPadEnd;
595 result = true;
596 } while(0);
597
598 close(fd);
599 return result;
600}
55e303ae
A
601
602void
603kld_set_architecture(const NXArchInfo * arch)
604{
605 sPreferArchInfo = arch;
606}
607
608Boolean
609kld_macho_swap(struct mach_header * mh)
610{
611 struct segment_command * seg;
612 struct section * section;
613 CFIndex ncmds, cmd, sect;
614 enum NXByteOrder hostOrder = NXHostByteOrder();
615
616 if (MH_CIGAM != mh->magic)
617 return (false);
618
619 swap_mach_header(mh, hostOrder);
620
621 ncmds = mh->ncmds;
622 seg = (struct segment_command *)(mh + 1);
623 for (cmd = 0;
624 cmd < ncmds;
625 cmd++, seg = (struct segment_command *)(((vm_offset_t)seg) + seg->cmdsize))
626 {
627 if (NXSwapLong(LC_SYMTAB) == seg->cmd) {
628 swap_symtab_command((struct symtab_command *) seg, hostOrder);
629 swap_nlist((struct nlist *) (((vm_offset_t) mh) + ((struct symtab_command *) seg)->symoff),
630 ((struct symtab_command *) seg)->nsyms, hostOrder);
631 continue;
632 }
633 if (NXSwapLong(LC_SEGMENT) != seg->cmd) {
634 swap_load_command((struct load_command *) seg, hostOrder);
635 continue;
636 }
637 swap_segment_command(seg, hostOrder);
638 swap_section((struct section *) (seg + 1), seg->nsects, hostOrder);
639
640 section = (struct section *) (seg + 1);
641 for (sect = 0; sect < seg->nsects; sect++, section++) {
642 if (section->nreloc)
643 swap_relocation_info((struct relocation_info *) (((vm_offset_t) mh) + section->reloff),
644 section->nreloc, hostOrder);
645 }
646 }
647
648 return (true);
649}
650
651void
652kld_macho_unswap(struct mach_header * mh, Boolean didSwap, int symbols)
653{
654 // symbols == 0 => everything
655 // symbols == 1 => just nlists
656 // symbols == -1 => everything but nlists
657
658 struct segment_command * seg;
659 struct section * section;
660 unsigned long cmdsize;
661 CFIndex ncmds, cmd, sect;
662 enum NXByteOrder hostOrder = (NXHostByteOrder() == NX_LittleEndian)
663 ? NX_BigEndian : NX_LittleEndian;
664 if (!didSwap)
665 return;
666
667 ncmds = mh->ncmds;
668 seg = (struct segment_command *)(mh + 1);
669 for (cmd = 0;
670 cmd < ncmds;
671 cmd++, seg = (struct segment_command *)(((vm_offset_t)seg) + cmdsize))
672 {
673 cmdsize = seg->cmdsize;
674 if (LC_SYMTAB == seg->cmd) {
675 if (symbols >= 0)
676 swap_nlist((struct nlist *) (((vm_offset_t) mh) + ((struct symtab_command *) seg)->symoff),
677 ((struct symtab_command *) seg)->nsyms, hostOrder);
678 if (symbols > 0)
679 break;
680 swap_symtab_command((struct symtab_command *) seg, hostOrder);
681 continue;
682 }
683 if (symbols > 0)
684 continue;
685 if (LC_SEGMENT != seg->cmd) {
686 swap_load_command((struct load_command *) seg, hostOrder);
687 continue;
688 }
689
690 section = (struct section *) (seg + 1);
691 for (sect = 0; sect < seg->nsects; sect++, section++) {
692 if (section->nreloc)
693 swap_relocation_info((struct relocation_info *) (((vm_offset_t) mh) + section->reloff),
694 section->nreloc, hostOrder);
695 }
696 swap_section((struct section *) (seg + 1), seg->nsects, hostOrder);
697 swap_segment_command(seg, hostOrder);
698 }
699 if (symbols <= 0)
700 swap_mach_header(mh, hostOrder);
701}
702
0b4e3aa0
A
703#endif /* !KERNEL */
704
9bccf70c 705static Boolean findBestArch(struct fileRecord *file, const char *pathName)
0b4e3aa0
A
706{
707 unsigned long magic;
708 struct fat_header *fat;
709
710
711 file->fMachOSize = file->fMapSize;
712 file->fMachO = file->fMap;
713 magic = ((const struct mach_header *) file->fMachO)->magic;
714 fat = (struct fat_header *) file->fMachO;
715
716 // Try to figure out what type of file this is
717 return_if(file->fMapSize < sizeof(unsigned long), false,
9bccf70c 718 ("%s isn't a valid object file - no magic\n", pathName));
0b4e3aa0
A
719
720#if KERNEL
721
722 // CIGAM is byte-swapped MAGIC
723 if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
724
725 load_return_t load_return;
726 struct fat_arch fatinfo;
727
728 load_return = fatfile_getarch(NULL, (vm_address_t) fat, &fatinfo);
729 return_if(load_return != LOAD_SUCCESS, false,
9bccf70c 730 ("Extension \"%s\": has no code for this computer\n", pathName));
0b4e3aa0
A
731
732 file->fMachO = file->fMap + fatinfo.offset;
733 file->fMachOSize = fatinfo.size;
734 magic = ((const struct mach_header *) file->fMachO)->magic;
735 }
736
737#else /* !KERNEL */
738
739 // Do we need to in-place swap the endianness of the fat header?
740 if (magic == FAT_CIGAM) {
741 unsigned long i;
742 struct fat_arch *arch;
743
744 fat->nfat_arch = NXSwapBigLongToHost(fat->nfat_arch);
745 return_if(file->fMapSize < sizeof(struct fat_header)
746 + fat->nfat_arch * sizeof(struct fat_arch),
747 false, ("%s is too fat\n", file->fPath));
748
749 arch = (struct fat_arch *) &fat[1];
750 for (i = 0; i < fat->nfat_arch; i++) {
751 arch[i].cputype = NXSwapBigLongToHost(arch[i].cputype);
752 arch[i].cpusubtype = NXSwapBigLongToHost(arch[i].cpusubtype);
753 arch[i].offset = NXSwapBigLongToHost(arch[i].offset);
754 arch[i].size = NXSwapBigLongToHost(arch[i].size);
755 arch[i].align = NXSwapBigLongToHost(arch[i].align);
756 }
757
758 magic = NXSwapBigLongToHost(fat->magic);
759 }
760
761 // Now see if we can find any valid architectures
762 if (magic == FAT_MAGIC) {
763 const NXArchInfo *myArch;
764 unsigned long fatsize;
765 struct fat_arch *arch;
766
767 fatsize = sizeof(struct fat_header)
768 + fat->nfat_arch * sizeof(struct fat_arch);
769 return_if(file->fMapSize < fatsize,
9bccf70c 770 false, ("%s isn't a valid fat file\n", pathName));
0b4e3aa0 771
55e303ae
A
772 if (sPreferArchInfo)
773 myArch = sPreferArchInfo;
774 else
775 myArch = NXGetLocalArchInfo();
776
0b4e3aa0
A
777 arch = NXFindBestFatArch(myArch->cputype, myArch->cpusubtype,
778 (struct fat_arch *) &fat[1], fat->nfat_arch);
779 return_if(!arch,
9bccf70c 780 false, ("%s hasn't got arch for %s\n", pathName, myArch->name));
0b4e3aa0 781 return_if(arch->offset + arch->size > file->fMapSize,
9bccf70c 782 false, ("%s's %s arch is incomplete\n", pathName, myArch->name));
0b4e3aa0
A
783 file->fMachO = file->fMap + arch->offset;
784 file->fMachOSize = arch->size;
785 magic = ((const struct mach_header *) file->fMachO)->magic;
786 }
787
55e303ae
A
788 file->fSwapped = kld_macho_swap((struct mach_header *) file->fMachO);
789 if (file->fSwapped)
790 magic = ((const struct mach_header *) file->fMachO)->magic;
791
0b4e3aa0
A
792#endif /* KERNEL */
793
794 return_if(magic != MH_MAGIC,
9bccf70c 795 false, ("%s isn't a valid mach-o\n", pathName));
0b4e3aa0
A
796
797 return true;
798}
799
800static Boolean
801parseSegments(struct fileRecord *file, struct segment_command *seg)
802{
803 struct sectionRecord *sections;
804 int i, nsects = seg->nsects;
805 const struct segmentMap {
806 struct segment_command seg;
807 const struct section sect[1];
808 } *segMap;
809
0b4e3aa0
A
810 if (!file->fSectData) {
811 file->fSectData = DataCreate(0);
812 if (!file->fSectData)
813 return false;
814 }
815
816 // Increase length of section DataRef and cache data pointer
817 if (!DataAddLength(file->fSectData, nsects * sizeof(struct sectionRecord)))
818 return false;
819 file->fSections = (struct sectionRecord *) DataGetPtr(file->fSectData);
820
821 // Initialise the new sections
822 sections = &file->fSections[file->fNSects];
823 file->fNSects += nsects;
824 for (i = 0, segMap = (struct segmentMap *) seg; i < nsects; i++)
55e303ae 825 {
0b4e3aa0 826 sections[i].fSection = &segMap->sect[i];
55e303ae
A
827 file->fIsReloc |= (0 != segMap->sect[i].nreloc);
828 }
0b4e3aa0
A
829
830 return true;
831}
832
9bccf70c
A
833static Boolean
834remangleExternSymbols(struct fileRecord *file, const char *pathName)
835{
836 const struct nlist *sym;
837 int i, nsyms, len;
838 DataRef strings = NULL;
839
840 DEBUG_LOG(("Remangling %s\n", pathName));
841
842 file->fNewStringBlocks = DataCreate(0);
843 return_if(!file->fNewStringBlocks, false,
844 ("Unable to allocate new string table for %s\n", pathName));
845
846 nsyms = file->fSymtab->nsyms;
847 for (i = 0, sym = file->fSymbolBase; i < nsyms; i++, sym++) {
848 Rem3Return ret;
849 const char *symname;
850 char *newname;
851 unsigned char n_type = sym->n_type;
852
853 // Not an external symbol or it is a stab in any case don't bother
854 if ((n_type ^ N_EXT) & (N_STAB | N_EXT))
855 continue;
856
857 symname = symNameByIndex(file, i);
858
859tryRemangleAgain:
860 if (!strings) {
861 strings = DataCreate(16 * 1024); // Arbitrary block size
862 return_if(!strings, false,
863 ("Unable to allocate new string block for %s\n", pathName));
864 }
865
866 len = DataRemaining(strings);
867 newname = DataGetEndPtr(strings);
868 ret = rem3_remangle_name(newname, &len, symname);
869 switch (ret) {
870 case kR3InternalNotRemangled:
871 errprintf("Remangler fails on %s in %s\n", symname, pathName);
872 /* No break */
873 case kR3NotRemangled:
874 break;
875
876 case kR3Remangled:
877 file->fSymbToStringTable[i] = newname;
878 file->fRemangled = file->fSymbolsDirty = true;
879 DataAddLength(strings, len + 1); // returns strlen
880 break;
881
882 case kR3BufferTooSmallRemangled:
883 return_if(!DataAppendBytes
884 (file->fNewStringBlocks, &strings, sizeof(strings)),
885 false, ("Unable to allocate string table for %s\n", pathName));
886 strings = NULL;
887 goto tryRemangleAgain;
888
889 case kR3BadArgument:
890 default:
891 return_if(true, false,
892 ("Internal error - remangle of %s\n", pathName));
893 }
894 }
895
896 if (strings) {
897 return_if(!DataAppendBytes
898 (file->fNewStringBlocks, &strings, sizeof(strings)),
899 false, ("Unable to allocate string table for %s\n", pathName));
900 }
901
902 return true;
903}
904
905static Boolean parseSymtab(struct fileRecord *file, const char *pathName)
906{
907 const struct nlist *sym;
908 unsigned int i, firstlocal, nsyms;
909 unsigned long strsize;
910 const char *strbase;
55e303ae 911 Boolean foundOSObject, found295CPP, havelocal;
9bccf70c
A
912
913 // we found a link edit segment so recompute the bases
914 if (file->fLinkEditSeg) {
915 struct segment_command *link = file->fLinkEditSeg;
916
917 file->fSymbolBase = (struct nlist *)
918 (link->vmaddr + (file->fSymtab->symoff - link->fileoff));
919 file->fStringBase = (char *)
920 (link->vmaddr + (file->fSymtab->stroff - link->fileoff));
921 return_if( ( (caddr_t) file->fStringBase + file->fSymtab->strsize
922 > (caddr_t) link->vmaddr + link->vmsize ), false,
923 ("%s isn't a valid mach-o le, bad symbols\n", pathName));
924 }
925 else {
926 file->fSymbolBase = (struct nlist *)
927 (file->fMachO + file->fSymtab->symoff);
928 file->fStringBase = (char *)
929 (file->fMachO + file->fSymtab->stroff);
930 return_if( ( file->fSymtab->stroff + file->fSymtab->strsize
931 > file->fMachOSize ), false,
932 ("%s isn't a valid mach-o, bad symbols\n", pathName));
933 }
934
935 nsyms = file->fSymtab->nsyms;
936
937 // If this file the kernel and do we have an executable image
938 file->fNoKernelExecutable = (vm_page_size == file->fSymtab->symoff)
939 && (file->fSections[0].fSection->size == 0);
940
941 // Generate a table of pointers to strings indexed by the symbol number
942
943 file->fSym2Strings = DataCreate(nsyms * sizeof(const char *));
944 DataSetLength(file->fSym2Strings, nsyms * sizeof(const char *));
945 return_if(!file->fSym2Strings, false,
946 ("Unable to allocate memory - symbol string trans\n", pathName));
947 file->fSymbToStringTable = (const char **) DataGetPtr(file->fSym2Strings);
948
949 // Search for the first non-stab symbol in table
950 strsize = file->fSymtab->strsize;
951 strbase = file->fStringBase;
952 firstlocal = 0;
55e303ae 953 havelocal = false;
9bccf70c
A
954 found295CPP = foundOSObject = false;
955 for (i = 0, sym = file->fSymbolBase; i < nsyms; i++, sym++) {
956 long strx = sym->n_un.n_strx;
957 const char *symname = strbase + strx;
958 unsigned char n_type;
959
960 return_if(((unsigned long) strx > strsize), false,
961 ("%s has an illegal string offset in symbol %d\n", pathName, i));
55e303ae
A
962#if 0
963 // Make all syms abs
964 if (file->fIsIncrLink) {
965 if ( (sym->n_type & N_TYPE) == N_SECT) {
966 sym->n_sect = NO_SECT;
967 sym->n_type = (sym->n_type & ~N_TYPE) | N_ABS;
968 }
969 }
970#endif
971
972 if (file->fIsIncrLink && !file->fNSects)
973 {
974 // symbol set
975 struct nlist *patchsym = (struct nlist *) sym;
976 const char * lookname;
977 const struct nlist * realsym;
978
979 if ( (patchsym->n_type & N_TYPE) == N_INDR)
980 lookname = strbase + patchsym->n_value;
981 else
982 lookname = symname;
983 realsym = findSymbolByName(sKernelFile, lookname);
984
985 patchsym->n_sect = NO_SECT;
986 if (realsym)
987 {
988 patchsym->n_type = realsym->n_type;
989 patchsym->n_desc = realsym->n_desc;
990 patchsym->n_value = realsym->n_value;
991 if ((patchsym->n_type & N_TYPE) == N_SECT)
992 patchsym->n_type = (patchsym->n_type & ~N_TYPE) | N_ABS;
993 }
994 else
995 {
996 errprintf("%s: Undefined in symbol set: %s\n", pathName, symname);
997 patchsym->n_type = N_ABS;
998 patchsym->n_desc = 0;
999 patchsym->n_value = 0;
1000 patchsym->n_un.n_strx = 0;
1001 }
1002
1003 if (!havelocal && (patchsym->n_type & N_EXT)) {
1004 firstlocal = i;
1005 havelocal = true;
1006 file->fLocalSyms = patchsym;
1007 }
1008 continue;
1009 } /* symbol set */
9bccf70c
A
1010
1011 // Load up lookup symbol look table with sym names
1012 file->fSymbToStringTable[i] = symname;
1013
1014 n_type = sym->n_type & (N_TYPE | N_EXT);
1015
1016 // Find the first exported symbol
1017 if ( !firstlocal && (n_type & N_EXT) ) {
1018 firstlocal = i;
55e303ae 1019 havelocal = true;
9bccf70c
A
1020 file->fLocalSyms = sym;
1021 }
1022
1023 // Find the a OSObject based subclass by searching for symbols
1024 // that have a suffix of '10superClassE'
1025 symname++; // Skip leading '_'
1026
1027 if (!foundOSObject
1028 && (n_type == (N_SECT | N_EXT) || n_type == (N_ABS | N_EXT))
1029 && strx) {
1030 const char *suffix, *endSym;
1031
1032 endSym = symname + strlen(symname);
1033
1034 // Find out if this symbol has the superclass suffix.
1035 if (symname[0] == kCPPSymbolPrefix[0]
1036 && symname[1] == kCPPSymbolPrefix[1]) {
1037
1038 suffix = endSym - sizeof(k31SuperClassSuffix) + 1;
1039
1040 // Check for a gcc3 OSObject subclass
1041 if (suffix > symname
1042 && !strcmp(suffix, k31SuperClassSuffix))
1043 foundOSObject = true;
1044 }
1045 else {
1046 suffix = endSym - sizeof(k29SuperClassSuffix);
1047
1048 // Check for a gcc295 OSObject subclass
1049 if (suffix > symname
1050 && ('.' == *suffix || '$' == *suffix)
1051 && !strcmp(suffix+1, k29SuperClassSuffix)) {
1052 found295CPP = foundOSObject = true;
1053 }
1054 else if (!found295CPP) {
1055 // Finally just check if we need to remangle
1056 symname++; // skip leading '__'
1057 while (*symname) {
55e303ae 1058 if ('_' == symname[0] && '_' == symname[1]) {
9bccf70c
A
1059 found295CPP = true;
1060 break;
1061 }
55e303ae 1062 symname++;
9bccf70c
A
1063 }
1064 }
1065 }
1066 }
1067 else if (sym->n_type == (N_EXT | N_UNDF)) {
1068 if ( !file->fNLocal) // Find the last local symbol
1069 file->fNLocal = i - firstlocal;
1070 if (!found295CPP) {
1071 symname++; // Skip possible second '_' at start.
1072 while (*symname) {
55e303ae 1073 if ('_' == symname[0] && '_' == symname[1]) {
9bccf70c
A
1074 found295CPP = true;
1075 break;
1076 }
55e303ae 1077 symname++;
9bccf70c
A
1078 }
1079 }
1080 }
1081 // Note symname is trashed at this point
1082 }
1083 return_if(i < nsyms, false,
1084 ("%s isn't a valid mach-o, bad symbol strings\n", pathName));
1085
1086 return_if(!file->fLocalSyms, false, ("%s has no symbols?\n", pathName));
1087
1088 // If we don't have any undefined symbols then all symbols
1089 // must be local so just compute it now if necessary.
1090 if ( !file->fNLocal )
1091 file->fNLocal = i - firstlocal;
1092
1093 file->fFoundOSObject = foundOSObject;
1094
1095 if (found295CPP && !remangleExternSymbols(file, pathName))
1096 return false;
1097
1098 return true;
1099}
1100
0b4e3aa0
A
1101// @@@ gvdl: These functions need to be hashed they are
1102// going to be way too slow for production code.
1103static const struct nlist *
1104findSymbolByAddress(const struct fileRecord *file, void *entry)
1105{
1106 // not quite so dumb linear search of all symbols
1107 const struct nlist *sym;
1108 int i, nsyms;
1109
1110 // First try to find the symbol in the most likely place which is the
1111 // extern symbols
1112 sym = file->fLocalSyms;
1113 for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
1114 if (sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
1115 return sym;
1116 }
1117
1118 // Didn't find it in the external symbols so try to local symbols before
1119 // giving up.
1120 sym = file->fSymbolBase;
1121 for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
1122 if ( (sym->n_type & N_EXT) )
1123 return NULL;
1124 if ( sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
1125 return sym;
1126 }
1127
1128 return NULL;
1129}
1130
55e303ae
A
1131static const struct nlist *
1132findSymbolByAddressInAllFiles(const struct fileRecord * fromFile,
1133 void *entry, const struct fileRecord **resultFile)
1134{
1135 int i, nfiles = 0;
1136 struct fileRecord **files;
1137
1138 if (sFilesTable) {
1139
1140 // Check to see if we have already merged this file
1141 nfiles = DataGetLength(sFilesTable) / sizeof(struct fileRecord *);
1142 files = (struct fileRecord **) DataGetPtr(sFilesTable);
1143 for (i = 0; i < nfiles; i++) {
1144 if ((((vm_offset_t)entry) >= files[i]->fVMAddr)
1145 && (((vm_offset_t)entry) < files[i]->fVMEnd))
1146 {
1147 const struct nlist * result;
1148 if (resultFile)
1149 *resultFile = files[i];
1150 result = findSymbolByAddress(files[i], entry);
1151 return result;
1152 }
1153 }
1154 }
1155
1156 return NULL;
1157}
1158
0b4e3aa0
A
1159struct searchContext {
1160 const char *fSymname;
9bccf70c 1161 const struct fileRecord *fFile;
0b4e3aa0
A
1162};
1163
1164static int symbolSearch(const void *vKey, const void *vSym)
1165{
1166 const struct searchContext *key = (const struct searchContext *) vKey;
1167 const struct nlist *sym = (const struct nlist *) vSym;
1168
55e303ae 1169 return strcmp(key->fSymname, symbolname(key->fFile, sym));
0b4e3aa0
A
1170}
1171
1172static const struct nlist *
1173findSymbolByName(struct fileRecord *file, const char *symname)
1174{
9bccf70c
A
1175 if (file->fRemangled) {
1176 // @@@ gvdl: Performance problem
1177 // Linear search as we don't sort after remangling
1178 const struct nlist *sym;
1179 int i = file->fLocalSyms - file->fSymbolBase;
1180 int nLocal = file->fNLocal + i;
1181
1182 for (sym = file->fLocalSyms; i < nLocal; i++, sym++)
55e303ae 1183 if (!strcmp(symNameByIndex(file, i), symname))
9bccf70c
A
1184 return sym;
1185 return NULL;
1186 }
1187 else {
1188 struct searchContext context;
1189
1190 context.fSymname = symname;
1191 context.fFile = file;
1192 return (struct nlist *)
1193 bsearch(&context,
1194 file->fLocalSyms, file->fNLocal, sizeof(struct nlist),
1195 symbolSearch);
1196 }
0b4e3aa0
A
1197}
1198
1199static Boolean
1200relocateSection(const struct fileRecord *file, struct sectionRecord *sectionRec)
1201{
1202 const struct nlist *symbol;
1203 const struct section *section;
1204 struct relocRecord *rec;
1205 struct relocation_info *rinfo;
1206 unsigned long i;
1207 unsigned long r_address, r_symbolnum, r_length;
1208 enum reloc_type_generic r_type;
1209 UInt8 *sectionBase;
1210 void **entry;
1211
1212 sectionRec->fRelocCache = DataCreate(
1213 sectionRec->fSection->nreloc * sizeof(struct relocRecord));
1214 if (!sectionRec->fRelocCache)
1215 return false;
1216
1217 section = sectionRec->fSection;
1218 sectionBase = file->fMachO + section->offset;
1219
1220 rec = (struct relocRecord *) DataGetPtr(sectionRec->fRelocCache);
1221 rinfo = (struct relocation_info *) (file->fMachO + section->reloff);
1222 for (i = 0; i < section->nreloc; i++, rec++, rinfo++) {
1223
1224 // Totally uninterested in scattered relocation entries
1225 if ( (rinfo->r_address & R_SCATTERED) )
1226 continue;
1227
1228 r_address = rinfo->r_address;
1229 entry = (void **) (sectionBase + r_address);
1230
1231 /*
1232 * The r_address field is really an offset into the contents of the
1233 * section and must reference something inside the section (Note
1234 * that this is not the case for PPC_RELOC_PAIR entries but this
1235 * can't be one with the above checks).
1236 */
1237 return_if(r_address >= section->size, false,
1238 ("Invalid relocation entry in %s - not in section\n", file->fPath));
1239
1240 // If we don't have a VANILLA entry or the Vanilla entry isn't
1241 // a 'long' then ignore the entry and try the next.
1242 r_type = (enum reloc_type_generic) rinfo->r_type;
1243 r_length = rinfo->r_length;
1244 if (r_type != GENERIC_RELOC_VANILLA || r_length != 2)
1245 continue;
1246
1247 r_symbolnum = rinfo->r_symbolnum;
1248
1249 /*
1250 * If rinfo->r_extern is set this relocation entry is an external entry
1251 * else it is a local entry.
1252 */
1253 if (rinfo->r_extern) {
1254 /*
1255 * This is an external relocation entry.
1256 * r_symbolnum is an index into the input file's symbol table
1257 * of the symbol being refered to. The symbol must be
1258 * undefined to be used in an external relocation entry.
1259 */
1260 return_if(r_symbolnum >= file->fSymtab->nsyms, false,
1261 ("Invalid relocation entry in %s - no symbol\n", file->fPath));
1262
1263 /*
1264 * If this is an indirect symbol resolve indirection (all chains
1265 * of indirect symbols have been resolved so that they point at
1266 * a symbol that is not an indirect symbol).
1267 */
1268 symbol = file->fSymbolBase;
1269 if ((symbol[r_symbolnum].n_type & N_TYPE) == N_INDR)
1270 r_symbolnum = symbol[r_symbolnum].n_value;
1271 symbol = &symbol[r_symbolnum];
1272
1273 return_if(symbol->n_type != (N_EXT | N_UNDF), false,
1274 ("Invalid relocation entry in %s - extern\n", file->fPath));
1275 }
1276 else {
1277 /*
1278 * If the symbol is not in any section then it can't be a
1279 * pointer to a local segment and I don't care about it.
1280 */
1281 if (r_symbolnum == R_ABS)
1282 continue;
1283
1284 // Note segment references are offset by 1 from 0.
1285 return_if(r_symbolnum > file->fNSects, false,
1286 ("Invalid relocation entry in %s - local\n", file->fPath));
1287
1288 // Find the symbol, if any, that backs this entry
55e303ae
A
1289 void * addr = *entry;
1290#if !KERNEL
1291 if (file->fSwapped)
1292 addr = (void *) NXSwapLong((long) addr);
1293#endif
1294 symbol = findSymbolByAddress(file, addr);
0b4e3aa0
A
1295 }
1296
1297 rec->fValue = *entry; // Save the previous value
1298 rec->fRInfo = rinfo; // Save a pointer to the reloc
1299 rec->fSymbol = symbol; // Record the current symbol
1300
1301 *entry = (void *) rec; // Save pointer to record in object image
1302 }
1303
9bccf70c 1304 DataSetLength(sectionRec->fRelocCache, i * sizeof(struct relocRecord));
0b4e3aa0
A
1305 ((struct fileRecord *) file)->fImageDirty = true;
1306
1307 return true;
1308}
1309
1310static const struct nlist *
1311findSymbolRefAtLocation(const struct fileRecord *file,
55e303ae 1312 struct sectionRecord *sctn, void **loc, const struct fileRecord **foundInFile)
0b4e3aa0 1313{
55e303ae
A
1314 const struct nlist * result;
1315
1316 *foundInFile = file;
1317
1318 if (!file->fIsReloc) {
1319 if (*loc) {
1320 void * addr = *loc;
1321#if !KERNEL
1322 if (file->fSwapped)
1323 addr = (void *) NXSwapLong((long) addr);
1324#endif
1325 result = findSymbolByAddress(file, addr);
1326 if (!result)
1327 result = findSymbolByAddressInAllFiles(file, addr, foundInFile);
1328 return result;
1329 }
0b4e3aa0
A
1330 }
1331 else if (sctn->fRelocCache || relocateSection(file, sctn)) {
1332 struct relocRecord *reloc = (struct relocRecord *) *loc;
1333
1334 if (DataContainsAddr(sctn->fRelocCache, reloc))
1335 return reloc->fSymbol;
1336 }
1337
1338 return NULL;
1339}
1340
1341static Boolean
1342addClass(struct fileRecord *file,
1343 struct metaClassRecord *inClass,
1344 const char *cname)
1345{
9bccf70c 1346 Boolean result = false;
0b4e3aa0
A
1347 struct metaClassRecord *newClass = NULL;
1348 struct metaClassRecord **fileClasses = NULL;
1349 int len;
1350
0b4e3aa0
A
1351 if (!file->fClassList) {
1352 file->fClassList = DataCreate(0);
1353 if (!file->fClassList)
1354 return false;
1355 }
1356
1357 do {
1358 // Attempt to allocate all necessary resource first
1359 len = strlen(cname) + 1
1360 + (int) (&((struct metaClassRecord *) 0)->fClassName);
1361 newClass = (struct metaClassRecord *) malloc(len);
1362 if (!newClass)
1363 break;
1364
1365 if (!DataAddLength(file->fClassList, sizeof(struct metaClassRecord *)))
1366 break;
1367 fileClasses = (struct metaClassRecord **)
1368 (DataGetPtr(file->fClassList) + DataGetLength(file->fClassList));
1369
9bccf70c
A
1370 // Copy the meta Class structure and string name into newClass and
1371 // insert object at end of the file->fClassList and sMergeMetaClasses
0b4e3aa0
A
1372 *newClass = *inClass;
1373 strcpy(newClass->fClassName, cname);
9bccf70c 1374 fileClasses[-1] = newClass;
0b4e3aa0
A
1375
1376 return true;
1377 } while (0);
1378
1379 if (fileClasses)
1380 DataAddLength(file->fClassList, -sizeof(struct metaClassRecord *));
1381
1382 if (newClass)
1383 free(newClass);
1384
9bccf70c 1385 return result;
0b4e3aa0
A
1386}
1387
1388static struct metaClassRecord *getClass(DataRef classList, const char *cname)
1389{
1390 if (classList) {
1391 int i, nclass;
1392 struct metaClassRecord **classes, *thisClass;
1393
1394 nclass = DataGetLength(classList) / sizeof(struct metaClassRecord *);
1395 classes = (struct metaClassRecord **) DataGetPtr(classList);
1396 for (i = 0; i < nclass; i++) {
1397 thisClass = classes[i];
1398 if (!strcmp(thisClass->fClassName, cname))
1399 return thisClass;
1400 }
1401 }
1402
1403 return NULL;
1404}
1405
1406// Add the class 'cname' to the list of known OSObject based classes
9bccf70c 1407// Note 'sym' is the <cname>10superClassE symbol.
0b4e3aa0
A
1408static Boolean
1409recordClass(struct fileRecord *file, const char *cname, const struct nlist *sym)
1410{
9bccf70c 1411 Boolean result = false;
0b4e3aa0
A
1412 char *supername = NULL;
1413 const char *classname = NULL;
1414 struct metaClassRecord newClass;
1415 char strbuffer[1024];
1416
9bccf70c 1417 // Only do the work to find the super class if we are
55e303ae 1418 // not currently working on the kernel. The kernel is the end
9bccf70c 1419 // of all superclass chains by definition as the kernel must be binary
0b4e3aa0 1420 // compatible with itself.
55e303ae 1421 if (file->fIsReloc) {
9bccf70c 1422 const char *suffix;
55e303ae 1423 const struct fileRecord *superfile;
0b4e3aa0
A
1424 const struct nlist *supersym;
1425 const struct section *section;
1426 struct sectionRecord *sectionRec;
1427 unsigned char sectind = sym->n_sect;
1428 const char *superstr;
1429 void **location;
9bccf70c 1430 int snamelen;
0b4e3aa0
A
1431
1432 // We can't resolve anything that isn't in a real section
1433 // Note that the sectind is starts at one to make room for the
1434 // NO_SECT flag but the fNSects field isn't offset so we have a
1435 // '>' test. Which means this isn't an OSObject based class
9bccf70c
A
1436 if (sectind == NO_SECT || sectind > file->fNSects) {
1437 result = true;
1438 goto finish;
1439 }
0b4e3aa0
A
1440 sectionRec = file->fSections + sectind - 1;
1441 section = sectionRec->fSection;
1442 location = (void **) ( file->fMachO + section->offset
1443 + sym->n_value - section->addr );
55e303ae
A
1444
1445 supersym = findSymbolRefAtLocation(file, sectionRec, location, &superfile);
9bccf70c
A
1446 if (!supersym) {
1447 result = true; // No superclass symbol then it isn't an OSObject.
1448 goto finish;
1449 }
0b4e3aa0 1450
9bccf70c 1451 // Find string in file and skip leading '_' and then find the suffix
55e303ae 1452 superstr = symbolname(superfile, supersym) + 1;
9bccf70c
A
1453 suffix = superstr + strlen(superstr) - sizeof(kGMetaSuffix) + 1;
1454 if (suffix <= superstr || strcmp(suffix, kGMetaSuffix)) {
1455 result = true; // Not an OSObject superclass so ignore it..
1456 goto finish;
1457 }
0b4e3aa0 1458
9bccf70c
A
1459 // Got a candidate so hand it over for class processing.
1460 snamelen = suffix - superstr - sizeof(kOSObjPrefix) + 2;
1461 supername = (char *) malloc(snamelen + 1);
1462 bcopy(superstr + sizeof(kOSObjPrefix) - 2, supername, snamelen);
1463 supername[snamelen] = '\0';
0b4e3aa0
A
1464 }
1465
1466 do {
1467 break_if(getClass(file->fClassList, cname),
1468 ("Duplicate class %s in %s\n", cname, file->fPath));
9bccf70c 1469
0b4e3aa0
A
1470 snprintf(strbuffer, sizeof(strbuffer), "%s%s", kVTablePrefix, cname);
1471 newClass.fVTableSym = findSymbolByName(file, strbuffer);
1472 break_if(!newClass.fVTableSym,
1473 ("Can't find vtable %s in %s\n", cname, file->fPath));
1474
1475 newClass.fFile = file;
1476 newClass.fSuperName = supername;
1477 newClass.fPatchedVTable = NULL;
1478
1479 // Can't use cname as it may be a stack variable
1480 // However the vtable's string has the class name as a suffix
1481 // so why don't we use that rather than mallocing a string.
1482 classname = symbolname(file, newClass.fVTableSym)
1483 + sizeof(kVTablePrefix) - 1;
9bccf70c 1484 break_if(!addClass(file, &newClass, classname),
0b4e3aa0
A
1485 ("recordClass - no memory?\n"));
1486
9bccf70c
A
1487 supername = NULL;
1488 result = true;
0b4e3aa0 1489 } while (0);
9bccf70c
A
1490
1491finish:
0b4e3aa0
A
1492 if (supername)
1493 free(supername);
1494
9bccf70c 1495 return result;
0b4e3aa0
A
1496}
1497
9bccf70c 1498
0b4e3aa0
A
1499static Boolean getMetaClassGraph(struct fileRecord *file)
1500{
1501 const struct nlist *sym;
0b4e3aa0
A
1502 int i, nsyms;
1503
1504 // Search the symbol table for the local symbols that are generated
1505 // by the metaclass system. There are three metaclass variables
1506 // that are relevant.
1507 //
1508 // <ClassName>.metaClass A pointer to the meta class structure.
1509 // <ClassName>.superClass A pointer to the super class's meta class.
1510 // <ClassName>.gMetaClass The meta class structure itself.
1511 // ___vt<ClassName> The VTable for the class <ClassName>.
1512 //
1513 // In this code I'm going to search for any symbols that
9bccf70c 1514 // ends in k31SuperClassSuffix as this indicates this class is a conforming
0b4e3aa0
A
1515 // OSObject subclass and will need to be patched, and it also
1516 // contains a pointer to the super class's meta class structure.
0b4e3aa0
A
1517 sym = file->fLocalSyms;
1518 for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
1519 const char *symname;
9bccf70c 1520 const char *suffix;
0b4e3aa0
A
1521 char classname[1024];
1522 unsigned char n_type = sym->n_type & (N_TYPE | N_EXT);
9bccf70c 1523 int cnamelen;
0b4e3aa0
A
1524
1525 // Check that the symbols is a global and that it has a name.
1526 if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)
1527 || !sym->n_un.n_strx)
1528 continue;
1529
9bccf70c 1530 // Only search from the last *sep* in the symbol.
0b4e3aa0 1531 // but skip the leading '_' in all symbols first.
9bccf70c
A
1532 symname = symbolname(file, sym) + 1;
1533 if (symname[0] != kCPPSymbolPrefix[0]
1534 || symname[1] != kCPPSymbolPrefix[1])
1535 continue;
1536
1537 suffix = symname + strlen(symname) - sizeof(k31SuperClassSuffix) + 1;
1538 if (suffix <= symname || strcmp(suffix, k31SuperClassSuffix))
0b4e3aa0
A
1539 continue;
1540
1541 // Got a candidate so hand it over for class processing.
9bccf70c
A
1542 cnamelen = suffix - symname - sizeof(kOSObjPrefix) + 2;
1543 return_if(cnamelen + 1 >= (int) sizeof(classname),
1544 false, ("Symbol %s is too long", symname));
0b4e3aa0 1545
9bccf70c
A
1546 bcopy(symname + sizeof(kOSObjPrefix) - 2, classname, cnamelen);
1547 classname[cnamelen] = '\0';
0b4e3aa0
A
1548 if (!recordClass(file, classname, sym))
1549 return false;
1550 }
1551
1552 return_if(!file->fClassList, false, ("Internal error, "
1553 "getMetaClassGraph(%s) found no classes", file->fPath));
1554
9bccf70c 1555 DEBUG_LOG(("Found %ld classes in %p for %s\n",
0b4e3aa0
A
1556 DataGetLength(file->fClassList)/sizeof(void*),
1557 file->fClassList, file->fPath));
1558
1559 return true;
1560}
1561
1562static Boolean mergeOSObjectsForFile(const struct fileRecord *file)
1563{
1564 int i, nmerged;
1565 Boolean foundDuplicates = false;
1566
9bccf70c 1567 DEBUG_LOG(("Merging file %s\n", file->fPath)); // @@@ gvdl:
0b4e3aa0
A
1568
1569 if (!file->fClassList)
1570 return true;
1571
1572 if (!sMergedFiles) {
1573 sMergedFiles = DataCreate(0);
1574 return_if(!sMergedFiles, false,
1575 ("Unable to allocate memory metaclass list\n", file->fPath));
1576 }
1577
1578 // Check to see if we have already merged this file
1579 nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
1580 for (i = 0; i < nmerged; i++) {
1581 if (file == ((void **) DataGetPtr(sMergedFiles))[i])
1582 return true;
1583 }
1584
1585 if (!sMergeMetaClasses) {
1586 sMergeMetaClasses = DataCreate(0);
1587 return_if(!sMergeMetaClasses, false,
1588 ("Unable to allocate memory metaclass list\n", file->fPath));
1589 }
1590 else { /* perform a duplicate check */
1591 int i, j, cnt1, cnt2;
1592 struct metaClassRecord **list1, **list2;
1593
1594 list1 = (struct metaClassRecord **) DataGetPtr(file->fClassList);
1595 cnt1 = DataGetLength(file->fClassList) / sizeof(*list1);
1596 list2 = (struct metaClassRecord **) DataGetPtr(sMergeMetaClasses);
1597 cnt2 = DataGetLength(sMergeMetaClasses) / sizeof(*list2);
1598
1599 for (i = 0; i < cnt1; i++) {
1600 for (j = 0; j < cnt2; j++) {
1601 if (!strcmp(list1[i]->fClassName, list2[j]->fClassName)) {
1602 errprintf("duplicate class %s in %s & %s\n",
1603 list1[i]->fClassName,
1604 file->fPath, list2[j]->fFile->fPath);
1605 }
1606 }
1607 }
1608 }
1609 if (foundDuplicates)
1610 return false;
1611
1612 return_if(!DataAppendBytes(sMergedFiles, &file, sizeof(file)), false,
1613 ("Unable to allocate memory to merge %s\n", file->fPath));
1614
1615 return_if(!DataAppendData(sMergeMetaClasses, file->fClassList), false,
1616 ("Unable to allocate memory to merge %s\n", file->fPath));
1617
1618 if (file == sKernelFile)
1619 sMergedKernel = true;
1620
1621 return true;
1622}
1623
1624// Returns a pointer to the base of the section offset by the sections
1625// base address. The offset is so that we can add nlist::n_values directly
1626// to this address and get a valid pointer in our memory.
1627static unsigned char *
1628getSectionForSymbol(const struct fileRecord *file, const struct nlist *symb,
1629 void ***endP)
1630{
1631 const struct section *section;
1632 unsigned char sectind;
1633 unsigned char *base;
1634
1635 sectind = symb->n_sect; // Default to symbols section
55e303ae 1636 if ((symb->n_type & N_TYPE) == N_ABS && !file->fIsReloc) {
0b4e3aa0
A
1637 // Absolute symbol so we have to iterate over our sections
1638 for (sectind = 1; sectind <= file->fNSects; sectind++) {
1639 unsigned long start, end;
1640
1641 section = file->fSections[sectind - 1].fSection;
1642 start = section->addr;
1643 end = start + section->size;
1644 if (start <= symb->n_value && symb->n_value < end) {
1645 // Found the relevant section
1646 break;
1647 }
1648 }
1649 }
1650
1651 // Is the vtable in a valid section?
1652 return_if(sectind == NO_SECT || sectind > file->fNSects,
1653 (unsigned char *) -1,
1654 ("%s isn't a valid kext, bad section reference\n", file->fPath));
1655
1656 section = file->fSections[sectind - 1].fSection;
1657
1658 // for when we start walking the vtable so compute offset's now.
1659 base = file->fMachO + section->offset;
1660 *endP = (void **) (base + section->size);
1661
1662 return base - section->addr; // return with addr offset
1663}
1664
1665static Boolean resolveKernelVTable(struct metaClassRecord *metaClass)
1666{
1667 const struct fileRecord *file;
1668 struct patchRecord *patchedVTable;
1669 void **curEntry, **vtableEntries, **endSection;
1670 unsigned char *sectionBase;
1671 struct patchRecord *curPatch;
1672 int classSize;
1673
1674 // Should never occur but it doesn't cost us anything to check.
1675 if (metaClass->fPatchedVTable)
1676 return true;
1677
9bccf70c 1678 DEBUG_LOG(("Kernel vtable %s\n", metaClass->fClassName)); // @@@ gvdl:
0b4e3aa0
A
1679
1680 // Do we have a valid vtable to patch?
1681 return_if(!metaClass->fVTableSym,
1682 false, ("Internal error - no class vtable symbol?\n"));
1683
1684 file = metaClass->fFile;
1685
1686 // If the metaClass we are being to ask is in the kernel then we
1687 // need to do a quick scan to grab the fPatchList in a reliable format
1688 // however we don't need to check the superclass in the kernel
1689 // as the kernel vtables are always correct wrt themselves.
1690 // Note this ends the superclass chain recursion.
55e303ae
A
1691 return_if(file->fIsReloc,
1692 false, ("Internal error - resolveKernelVTable is relocateable\n"));
0b4e3aa0
A
1693
1694 if (file->fNoKernelExecutable) {
1695 // Oh dear attempt to map the kernel's VM into my memory space
1696 return_if(file->fNoKernelExecutable, false,
1697 ("Internal error - fNoKernelExecutable not implemented yet\n"));
1698 }
1699
1700 // We are going to need the base and the end
1701 sectionBase = getSectionForSymbol(file, metaClass->fVTableSym, &endSection);
1702 if (-1 == (long) sectionBase)
1703 return false;
1704
1705 vtableEntries = (void **) (sectionBase + metaClass->fVTableSym->n_value);
1706 curEntry = vtableEntries + kVTablePreambleLen;
1707 for (classSize = 0; curEntry < endSection && *curEntry; classSize++)
1708 curEntry++;
1709
1710 return_if(*curEntry, false, ("Bad kernel image, short section\n"));
1711
1712 patchedVTable = (struct patchRecord *)
1713 malloc((classSize + 1) * sizeof(struct patchRecord));
1714 return_if(!patchedVTable, false, ("resolveKernelVTable - no memory\n"));
1715
1716 // Copy the vtable of this class into the patch table
1717 curPatch = patchedVTable;
1718 curEntry = vtableEntries + kVTablePreambleLen;
1719 for (; *curEntry; curEntry++, curPatch++) {
55e303ae
A
1720 void * addr = *curEntry;
1721#if !KERNEL
1722 if (file->fSwapped)
1723 addr = (void *) NXSwapLong((long) addr);
1724#endif
0b4e3aa0 1725 curPatch->fSymbol = (struct nlist *)
55e303ae
A
1726 findSymbolByAddress(file, addr);
1727 if (curPatch->fSymbol)
1728 {
1729 curPatch->fType = kSymbolLocal;
1730 curPatch->fFile = file;
1731 }
1732 else
1733 {
1734 curPatch->fSymbol = (struct nlist *)
1735 findSymbolByAddressInAllFiles(file, addr, &curPatch->fFile);
1736 if (!curPatch->fSymbol) {
1737 errprintf("%s: !findSymbolByAddressInAllFiles(%p)\n",
1738 file->fPath, addr);
1739 return false;
1740 }
1741 curPatch->fType = kSymbolLocal;
1742 }
0b4e3aa0
A
1743 }
1744
1745 // Tag the end of the patch vtable
1746 curPatch->fSymbol = NULL;
1747 metaClass->fPatchedVTable = patchedVTable;
1748
1749 return true;
1750}
1751
9bccf70c
A
1752static const char *addNewString(struct fileRecord *file,
1753 const char *strname, int namelen)
1754{
1755 DataRef strings = 0;
1756 const char *newStr;
1757
1758 namelen++; // Include terminating '\0';
1759
1760 // Make sure we have a string table as well for this symbol
1761 if (file->fNewStringBlocks) {
1762 DataRef *blockTable = (DataRef *) DataGetPtr(file->fNewStringBlocks);
1763 int index = DataGetLength(file->fNewStringBlocks) / sizeof(DataRef*);
1764 strings = blockTable[index - 1];
1765 if (DataRemaining(strings) < namelen)
1766 strings = 0;
1767 }
1768 else
1769 {
1770 file->fNewStringBlocks = DataCreate(0);
1771 return_if(!file->fNewStringBlocks, NULL,
1772 ("Unable to allocate new string table %s\n", file->fPath));
1773 }
1774
1775 if (!strings) {
1776 int size = (namelen + 1023) & ~1023;
1777 if (size < 16 * 1024)
1778 size = 16 * 1024;
1779 strings = DataCreate(size);
1780 return_if(!strings, NULL,
1781 ("Unable to allocate new string block %s\n", file->fPath));
1782 return_if(
1783 !DataAppendBytes(file->fNewStringBlocks, &strings, sizeof(strings)),
1784 false, ("Unable to allocate string table for %s\n", file->fPath));
1785 }
1786
1787 newStr = DataGetEndPtr(strings);
1788 DataAppendBytes(strings, strname, namelen);
1789 return newStr;
1790}
1791
1792// reloc->fPatch must contain a valid pointer
0b4e3aa0
A
1793static struct nlist *
1794getNewSymbol(struct fileRecord *file,
1795 const struct relocRecord *reloc, const char *supername)
1796{
9bccf70c 1797 unsigned int size, i;
0b4e3aa0
A
1798 struct nlist **sym;
1799 struct nlist *msym;
0b4e3aa0 1800 struct relocation_info *rinfo;
9bccf70c 1801 const char *newStr;
0b4e3aa0
A
1802
1803 if (!file->fNewSymbols) {
1804 file->fNewSymbols = DataCreate(0);
1805 return_if(!file->fNewSymbols, NULL,
1806 ("Unable to allocate new symbol table for %s\n", file->fPath));
1807 }
1808
0b4e3aa0
A
1809 rinfo = (struct relocation_info *) reloc->fRInfo;
1810 size = DataGetLength(file->fNewSymbols) / sizeof(struct nlist *);
9bccf70c 1811 sym = (struct nlist **) DataGetPtr(file->fNewSymbols);
0b4e3aa0 1812 for (i = 0; i < size; i++, sym++) {
9bccf70c
A
1813 int symnum = i + file->fSymtab->nsyms;
1814 newStr = symNameByIndex(file, symnum);
1815 if (!strcmp(newStr, supername)) {
1816 rinfo->r_symbolnum = symnum;
0b4e3aa0
A
1817 file->fSymbolsDirty = true;
1818 return *sym;
1819 }
1820 }
1821
55e303ae
A
1822 if (reloc->fSymbol->n_un.n_strx >= 0) {
1823 // This symbol has not been previously processed, so assert that it
1824 // is a valid non-local symbol. I need this condition to be true for
1825 // the later code to set to -1. Now, being the first time through,
1826 // I'd better make sure that n_sect is NO_SECT.
1827
1828 return_if(reloc->fSymbol->n_sect != NO_SECT, NULL,
1829 ("Undefined symbol entry with non-zero section %s:%s\n",
1830 file->fPath, symbolname(file, reloc->fSymbol)));
1831
1832 // Mark the original symbol entry as having been processed.
1833 // This means that we wont attempt to create the symbol again
1834 // in the future if we come through a different path.
1835 ((struct nlist *) reloc->fSymbol)->n_un.n_strx =
1836 -reloc->fSymbol->n_un.n_strx;
1837
1838 // Mark the old symbol as being potentially deletable I can use the
1839 // n_sect field as the input symbol must be of type N_UNDF which means
1840 // that the n_sect field must be set to NO_SECT otherwise it is an
1841 // invalid input file.
1842 ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1;
1843 }
0b4e3aa0 1844
9bccf70c 1845 // If we are here we didn't find the symbol so create a new one now
0b4e3aa0
A
1846 msym = (struct nlist *) malloc(sizeof(struct nlist));
1847 return_if(!msym,
9bccf70c
A
1848 NULL, ("Unable to create symbol table entry for %s", file->fPath));
1849 return_if(!DataAppendBytes(file->fNewSymbols, &msym, sizeof(msym)),
0b4e3aa0 1850 NULL, ("Unable to grow symbol table for %s\n", file->fPath));
0b4e3aa0 1851
9bccf70c
A
1852 newStr = addNewString(file, supername, strlen(supername));
1853 if (!newStr)
1854 return NULL;
55e303ae 1855
9bccf70c
A
1856 // If we are here we didn't find the symbol so create a new one now
1857 return_if(!DataAppendBytes(file->fSym2Strings, &newStr, sizeof(newStr)),
1858 NULL, ("Unable to grow symbol table for %s\n", file->fPath));
1859 file->fSymbToStringTable = (const char **) DataGetPtr(file->fSym2Strings);
0b4e3aa0
A
1860
1861 // Offset the string index by the original string table size
1862 // and negate the address to indicate that this is a 'new' symbol
9bccf70c 1863 msym->n_un.n_strx = -1;
0b4e3aa0
A
1864 msym->n_type = (N_EXT | N_UNDF);
1865 msym->n_sect = NO_SECT;
1866 msym->n_desc = 0;
9bccf70c 1867 msym->n_value = (unsigned long) newStr;
0b4e3aa0 1868
0b4e3aa0
A
1869 rinfo->r_symbolnum = i + file->fSymtab->nsyms;
1870 file->fSymbolsDirty = true;
1871 return msym;
1872}
1873
1874static struct nlist *
1875fixOldSymbol(struct fileRecord *file,
1876 const struct relocRecord *reloc, const char *supername)
1877{
1878 unsigned int namelen;
1879 struct nlist *sym = (struct nlist *) reloc->fSymbol;
1880 const char *oldname = symbolname(file, sym);
1881
1882 // assert(sym->n_un.n_strx >= 0);
1883
1884 namelen = strlen(supername);
9bccf70c
A
1885
1886 sym->n_un.n_strx = -sym->n_un.n_strx;
1887 if (oldname && namelen < strlen(oldname))
1888 {
0b4e3aa0
A
1889 // Overwrite old string in string table
1890 strcpy((char *) oldname, supername);
9bccf70c
A
1891 file->fSymbolsDirty = true;
1892 return sym;
0b4e3aa0 1893 }
0b4e3aa0 1894
9bccf70c
A
1895 oldname = addNewString(file, supername, namelen);
1896 if (!oldname)
1897 return NULL;
0b4e3aa0 1898
9bccf70c 1899 file->fSymbToStringTable[sym - file->fSymbolBase] = oldname;
0b4e3aa0
A
1900 file->fSymbolsDirty = true;
1901 return sym;
1902}
1903
1904static enum patchState
1905symbolCompare(const struct fileRecord *file,
1906 const struct nlist *classsym,
1907 const char *supername)
1908{
1909 const char *classname;
1910
1911
1912 // Check to see if the target function is locally defined
1913 // if it is then we can assume this is a local vtable override
1914 if ((classsym->n_type & N_TYPE) != N_UNDF)
1915 return kSymbolLocal;
1916
1917 // Check to see if both symbols point to the same symbol name
1918 // if so then we are still identical.
1919 classname = symbolname(file, classsym);
1920 if (!strcmp(classname, supername))
1921 return kSymbolIdentical;
1922
9bccf70c 1923 // We know that the target's vtable entry is different from the
0b4e3aa0
A
1924 // superclass' vtable entry. This means that we will have to apply a
1925 // patch to the current entry, however before returning lets check to
1926 // see if we have a _RESERVEDnnn field 'cause we can use this as a
1927 // registration point that must align between vtables.
9bccf70c 1928 if (strstr(supername, kReservedNamePrefix))
0b4e3aa0
A
1929 return kSymbolMismatch;
1930
1931 // OK, we have a superclass difference where the superclass doesn't
1932 // reference a pad function so assume that the superclass is correct.
9bccf70c 1933 if (strstr(classname, kReservedNamePrefix))
0b4e3aa0
A
1934 return kSymbolPadUpdate;
1935 else
1936 return kSymbolSuperUpdate;
1937}
1938
1939static Boolean patchVTable(struct metaClassRecord *metaClass)
1940{
1941 struct metaClassRecord *super = NULL;
1942 struct fileRecord *file;
1943 struct patchRecord *patchedVTable;
1944 struct relocRecord **curReloc, **vtableRelocs, **endSection;
1945 unsigned char *sectionBase;
1946 int classSize;
1947
1948 // Should never occur but it doesn't cost us anything to check.
1949 if (metaClass->fPatchedVTable)
1950 return true;
1951
1952 // Do we have a valid vtable to patch?
1953 return_if(!metaClass->fVTableSym,
1954 false, ("Internal error - no class vtable symbol?\n"));
1955
1956 file = metaClass->fFile;
1957
55e303ae
A
1958 if (!file->fIsReloc)
1959 {
1960 // If the metaClass we are being to ask is already relocated then we
1961 // need to do a quick scan to grab the fPatchList in a reliable format
1962 // however we don't need to check the superclass in the already linked
1963 // modules as the vtables are always correct wrt themselves.
1964 // Note this ends the superclass chain recursion.
1965 Boolean res;
1966 res = resolveKernelVTable(metaClass);
1967 return res;
1968 }
0b4e3aa0
A
1969
1970 if (!metaClass->fSuperName)
1971 return false;
1972
1973 // The class isn't in the kernel so make sure that the super class
1974 // is patched before patching ouselves.
1975 super = getClass(sMergeMetaClasses, metaClass->fSuperName);
9bccf70c 1976 return_if(!super, false, ("Can't find superclass for %s : %s\n",
0b4e3aa0
A
1977 metaClass->fClassName, metaClass->fSuperName));
1978
1979 // Superclass recursion if necessary
1980 if (!super->fPatchedVTable) {
1981 Boolean res;
55e303ae 1982 res = patchVTable(super);
0b4e3aa0
A
1983 if (!res)
1984 return false;
1985 }
1986
9bccf70c 1987 DEBUG_LOG(("Patching %s\n", metaClass->fClassName)); // @@@ gvdl:
0b4e3aa0
A
1988
1989 // We are going to need the base and the end
1990
1991 sectionBase = getSectionForSymbol(file,
1992 metaClass->fVTableSym, (void ***) &endSection);
1993 if (-1 == (long) sectionBase)
1994 return false;
1995
1996 vtableRelocs = (struct relocRecord **)
1997 (sectionBase + metaClass->fVTableSym->n_value);
1998 curReloc = vtableRelocs + kVTablePreambleLen;
1999 for (classSize = 0; curReloc < endSection && *curReloc; classSize++)
2000 curReloc++;
2001
2002 return_if(*curReloc, false,
2003 ("%s isn't a valid kext, short section\n", file->fPath));
2004
2005 patchedVTable = (struct patchRecord *)
2006 malloc((classSize + 1) * sizeof(struct patchRecord));
2007 return_if(!patchedVTable, false, ("patchedVTable - no memory\n"));
2008
2009 do {
2010 struct patchRecord *curPatch;
2011 struct nlist *symbol;
2012
2013 curPatch = patchedVTable;
2014 curReloc = vtableRelocs + kVTablePreambleLen;
2015
2016 // Grab the super table patches if necessary
2017 // Can't be patching a kernel table as we don't walk super
2018 // class chains in the kernel symbol space.
2019 if (super && super->fPatchedVTable) {
2020 const struct patchRecord *spp;
2021
2022 spp = super->fPatchedVTable;
2023
2024 for ( ; spp->fSymbol; curReloc++, spp++, curPatch++) {
2025 const char *supername =
55e303ae 2026 symbolname(spp->fFile, spp->fSymbol);
0b4e3aa0
A
2027
2028 symbol = (struct nlist *) (*curReloc)->fSymbol;
2029
2030 curPatch->fType = symbolCompare(file, symbol, supername);
2031 switch (curPatch->fType) {
2032 case kSymbolIdentical:
2033 case kSymbolLocal:
2034 break;
2035
2036 case kSymbolSuperUpdate:
2037 symbol = getNewSymbol(file, (*curReloc), supername);
2038 break;
2039
2040 case kSymbolPadUpdate:
2041 symbol = fixOldSymbol(file, (*curReloc), supername);
2042 break;
2043
2044 case kSymbolMismatch:
9bccf70c
A
2045 errprintf("%s is not compatible with its superclass, "
2046 "%s superclass changed?\n",
0b4e3aa0
A
2047 metaClass->fClassName, super->fClassName);
2048 goto abortPatch;
2049
2050 default:
2051 errprintf("Internal error - unknown patch type\n");
2052 goto abortPatch;
2053 }
2054 if (symbol) {
2055 curPatch->fSymbol = symbol;
2056 (*curReloc)->fSymbol = symbol;
55e303ae 2057 curPatch->fFile = file;
0b4e3aa0
A
2058 }
2059 else
2060 goto abortPatch;
2061 }
2062 }
2063
2064 // Copy the remainder of this class' vtable into the patch table
2065 for (; *curReloc; curReloc++, curPatch++) {
2066 // Local reloc symbols
2067 curPatch->fType = kSymbolLocal;
2068 curPatch->fSymbol = (struct nlist *) (*curReloc)->fSymbol;
55e303ae 2069 curPatch->fFile = file;
0b4e3aa0
A
2070 }
2071
2072 // Tag the end of the patch vtable
2073 curPatch->fSymbol = NULL;
2074
2075 metaClass->fPatchedVTable = patchedVTable;
2076 return true;
2077 } while(0);
2078
2079abortPatch:
2080 if (patchedVTable)
2081 free(patchedVTable);
2082
2083 return false;
2084}
2085
2086static Boolean growImage(struct fileRecord *file, vm_size_t delta)
2087{
2088#if !KERNEL
2089 file->fMachOSize += delta;
2090 return (file->fMachO + file->fMachOSize <= file->fPadEnd);
2091#else /* KERNEL */
2092 vm_address_t startMachO, endMachO, endMap;
2093 vm_offset_t newMachO;
2094 vm_size_t newsize;
9bccf70c 2095 unsigned long i, last = 0;
0b4e3aa0
A
2096 struct metaClassRecord **classes = NULL;
2097 struct sectionRecord *section;
2098 kern_return_t ret;
2099
2100 startMachO = (vm_address_t) file->fMachO;
2101 endMachO = startMachO + file->fMachOSize + delta;
2102 endMap = (vm_address_t) file->fMap + file->fMapSize;
2103
2104 // Do we have room in the current mapped image
55e303ae 2105 if (endMachO < round_page_32(endMap)) {
0b4e3aa0
A
2106 file->fMachOSize += delta;
2107 return true;
2108 }
2109
2110 newsize = endMachO - startMachO;
55e303ae 2111 if (newsize < round_page_32(file->fMapSize)) {
9bccf70c
A
2112 DEBUG_LOG(("Growing image %s by moving\n", file->fPath));
2113
0b4e3aa0
A
2114 // We have room in the map if we shift the macho image within the
2115 // current map. We will have to patch up pointers into the object.
2116 newMachO = (vm_offset_t) file->fMap;
2117 bcopy((char *) startMachO, (char *) newMachO, file->fMachOSize);
2118 }
2119 else if (file->fIsKmem) {
2120 // kmem_alloced mapping so we can try a kmem_realloc
2121 ret = kmem_realloc(kernel_map,
2122 (vm_address_t) file->fMap,
2123 (vm_size_t) file->fMapSize,
2124 &newMachO,
2125 newsize);
2126 if (KERN_SUCCESS != ret)
2127 return false;
2128
2129 // If the mapping didn't move then just return
2130 if ((vm_address_t) file->fMap == newMachO) {
2131 file->fMachOSize = file->fMapSize = newsize;
2132 return true;
2133 }
2134
9bccf70c 2135 DEBUG_LOG(("Growing image %s by reallocing\n", file->fPath));
0b4e3aa0
A
2136 // We have relocated the kmem image so we are going to have to
2137 // move all of the pointers into the image around.
2138 }
2139 else {
9bccf70c 2140 DEBUG_LOG(("Growing image %s by allocating\n", file->fPath));
0b4e3aa0
A
2141 // The image doesn't have room for us and I can't kmem_realloc
2142 // then I just have to bite the bullet and copy the object code
2143 // into a bigger memory segment
2144 ret = kmem_alloc(kernel_map, &newMachO, newsize);
2145
2146 if (KERN_SUCCESS != ret)
2147 return false;
2148 bcopy((char *) startMachO, (void *) newMachO, file->fMachOSize);
2149 file->fIsKmem = true;
2150 }
2151
2152
2153 file->fMap = file->fMachO = (unsigned char *) newMachO;
2154 file->fMapSize = newsize;
2155 file->fMachOSize += delta; // Increment the image size
2156
2157 // If we are here then we have shifted the object image in memory
2158 // I really should change all of my pointers into the image to machO offsets
2159 // but I have run out of time. So I'm going to very quickly go over the
2160 // cached data structures and add adjustments to the addresses that are
2161 // affected. I wonder how long it will take me to get them all.
2162 //
2163 // For every pointer into the MachO I need to add an adjustment satisfying
2164 // the following simultanous equations
2165 // addr_old = macho_old + fixed_offset
2166 // addr_new = macho_new + fixed_offset therefore:
2167 // addr_new = addr_old + (macho_new - macho_old)
2168#define REBASE(addr, delta) ( ((vm_address_t) (addr)) += (delta) )
2169 delta = newMachO - startMachO;
2170
9bccf70c 2171 // Rebase the cached-in object 'struct symtab_command' pointer
0b4e3aa0
A
2172 REBASE(file->fSymtab, delta);
2173
9bccf70c 2174 // Rebase the cached-in object 'struct nlist' pointer for all symbols
0b4e3aa0
A
2175 REBASE(file->fSymbolBase, delta);
2176
9bccf70c 2177 // Rebase the cached-in object 'struct nlist' pointer for local symbols
0b4e3aa0
A
2178 REBASE(file->fLocalSyms, delta);
2179
9bccf70c 2180 // Rebase the cached-in object 'char' pointer for the string table
0b4e3aa0
A
2181 REBASE(file->fStringBase, delta);
2182
2183 // Ok now we have to go over all of the relocs one last time
2184 // to clean up the pad updates which had their string index negated
2185 // to indicate that we have finished with them.
2186 section = file->fSections;
9bccf70c 2187 for (i = 0, last = file->fNSects; i < last; i++, section++)
0b4e3aa0
A
2188 REBASE(section->fSection, delta);
2189
2190 // We only ever grow images that contain class lists so dont bother
2191 // the check if file->fClassList is non-zero 'cause it can't be
2192 // assert(file->fClassList);
9bccf70c 2193 last = DataGetLength(file->fClassList)
0b4e3aa0
A
2194 / sizeof(struct metaClassRecord *);
2195 classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
9bccf70c 2196 for (i = 0; i < last; i++) {
0b4e3aa0
A
2197 struct patchRecord *patch;
2198
2199 for (patch = classes[i]->fPatchedVTable; patch->fSymbol; patch++) {
2200 vm_address_t symAddr = (vm_address_t) patch->fSymbol;
9bccf70c
A
2201
2202 // Only need to rebase if the symbol is part of the image
2203 // If this is a new symbol then it was independantly allocated
0b4e3aa0
A
2204 if (symAddr >= startMachO && symAddr < endMachO)
2205 REBASE(patch->fSymbol, delta);
2206 }
2207 }
2208
9bccf70c
A
2209 // Finally rebase all of the string table pointers
2210 last = file->fSymtab->nsyms;
2211 for (i = 0; i < last; i++)
2212 REBASE(file->fSymbToStringTable[i], delta);
0b4e3aa0
A
2213
2214#undef REBASE
2215
2216 return true;
2217
2218#endif /* KERNEL */
2219}
2220
2221static Boolean
2222prepareFileForLink(struct fileRecord *file)
2223{
2224 unsigned long i, last, numnewsyms, newsymsize, newstrsize;
2225 struct sectionRecord *section;
2226 struct nlist **symp, *sym;
9bccf70c 2227 DataRef newStrings, *stringBlocks;
0b4e3aa0
A
2228
2229 // If we didn't even do a pseudo 'relocate' and dirty the image
2230 // then we can just return now.
55e303ae
A
2231 if (!file->fImageDirty) {
2232#if !KERNEL
2233 if (file->fSwapped) {
2234 kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
2235 file->fSwapped = false;
2236 }
2237#endif
0b4e3aa0 2238 return true;
55e303ae 2239 }
0b4e3aa0
A
2240
2241DEBUG_LOG(("Linking 2 %s\n", file->fPath)); // @@@ gvdl:
2242
2243 // We have to go over all of the relocs to repair the damage
2244 // that we have done to the image when we did our 'relocation'
2245 section = file->fSections;
2246 for (i = 0, last = file->fNSects; i < last; i++, section++) {
2247 unsigned char *sectionBase;
2248 struct relocRecord *rec;
2249 unsigned long j, nreloc;
2250
2251 if (section->fRelocCache) {
2252 sectionBase = file->fMachO + section->fSection->offset;
2253 nreloc = section->fSection->nreloc;
2254 rec = (struct relocRecord *) DataGetPtr(section->fRelocCache);
2255
2256 // We will need to repair the reloc list
2257 for (j = 0; j < nreloc; j++, rec++) {
2258 void **entry;
2259 struct nlist *sym;
2260
2261 // Repair Damage to object image
2262 entry = (void **) (sectionBase + rec->fRInfo->r_address);
2263 *entry = rec->fValue;
2264
2265 // Check if the symbol that this relocation entry points
2266 // to is marked as erasable
2267 sym = (struct nlist *) rec->fSymbol;
2268 if (sym && sym->n_type == (N_EXT | N_UNDF)
2269 && sym->n_sect == (unsigned char) -1) {
9bccf70c 2270 // It is in use so we better clear the mark
0b4e3aa0
A
2271 sym->n_un.n_strx = -sym->n_un.n_strx;
2272 sym->n_sect = NO_SECT;
2273 }
2274 }
2275
2276 // Clean up the fRelocCache we don't need it any more.
2277 DataRelease(section->fRelocCache);
2278 section->fRelocCache = 0;
2279 }
2280 }
2281 file->fImageDirty = false; // Image is clean
2282
2283 // If we didn't dirty the symbol table then just return
55e303ae
A
2284 if (!file->fSymbolsDirty) {
2285#if !KERNEL
2286 if (file->fSwapped) {
2287 kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
2288 file->fSwapped = false;
2289 }
2290#endif
0b4e3aa0 2291 return true;
55e303ae 2292 }
0b4e3aa0
A
2293
2294 // calculate total file size increase and check against padding
9bccf70c
A
2295 if (file->fNewSymbols) {
2296 numnewsyms = DataGetLength(file->fNewSymbols);
2297 symp = (struct nlist **) DataGetPtr(file->fNewSymbols);
2298 }
2299 else {
2300 numnewsyms = 0;
2301 symp = 0;
2302 }
0b4e3aa0 2303 numnewsyms /= sizeof(struct nlist *);
9bccf70c
A
2304 file->fSymtab->nsyms += numnewsyms;
2305
2306 // old sting size + 30% rounded up to nearest page
2307 newstrsize = file->fSymtab->strsize * 21 / 16;
2308 newstrsize = (newstrsize + PAGE_MASK) & ~PAGE_MASK;
2309 newStrings = DataCreate(newstrsize);
2310 return_if(!newStrings, false,
2311 ("Unable to allocate a copy aside buffer, no memory\n"));
2312
0b4e3aa0 2313 newsymsize = numnewsyms * sizeof(struct nlist);
9bccf70c
A
2314 file->fStringBase += newsymsize;
2315 file->fSymtab->stroff += newsymsize;
2316
2317 last = file->fSymtab->nsyms - numnewsyms;
2318 newstrsize = 0;
2319 DataAppendBytes(newStrings, &newstrsize, 4); // Leading nuls
2320 sym = file->fSymbolBase;
2321
2322 // Pre-compute an already offset new symbol pointer. The offset is the
2323 // orignal symbol table.
2324 symp -= last;
2325 for (i = 0; i < file->fSymtab->nsyms; i++, sym++) {
2326 const char *str = symNameByIndex(file, i);
2327 int len = strlen(str) + 1;
2328 unsigned int strx;
2329
2330 // Rebase sym in the new symbol region
2331 if (i >= last)
2332 sym = symp[i];
2333
2334 if (sym->n_un.n_strx < 0 && sym->n_type == (N_EXT | N_UNDF)
2335 && (unsigned char) -1 == sym->n_sect) {
2336 // after patching we find that this symbol is no longer in
2337 // use. So invalidate it by converting it into an N_ABS
2338 // symbol, remove the external bit and null out the name.
2339 bzero(sym, sizeof(*sym));
2340 sym->n_type = N_ABS;
2341 }
2342 else {
2343 // Repair the symbol for the getNewSymbol case.
2344 if (-1 == sym->n_un.n_strx)
2345 sym->n_value = 0;
2346
2347 // Record the offset of the string in the new table
2348 strx = DataGetLength(newStrings);
2349 return_if(!DataAppendBytes(newStrings, str, len), false,
2350 ("Unable to append string, no memory\n"));
2351
2352 sym->n_un.n_strx = strx;
2353 file->fSymbToStringTable[i] = file->fStringBase + strx;
2354 }
2355 }
2356
2357 // Don't need the new strings any more
55e303ae
A
2358 if (file->fNewStringBlocks){
2359 last = DataGetLength(file->fNewStringBlocks) / sizeof(DataRef);
2360 stringBlocks = (DataRef *) DataGetPtr(file->fNewStringBlocks);
2361 }
2362 else{
2363 last =0;
2364 stringBlocks=0;
2365 }
9bccf70c
A
2366 for (i = 0; i < last; i++)
2367 DataRelease(stringBlocks[i]);
2368
2369 DataRelease(file->fNewStringBlocks);
2370 file->fNewStringBlocks = 0;
2371
2372 newstrsize = DataGetLength(newStrings);
0b4e3aa0 2373 newstrsize = (newstrsize + 3) & ~3; // Round to nearest word
9bccf70c
A
2374 return_if(
2375 !growImage(file, newsymsize + newstrsize - file->fSymtab->strsize),
0b4e3aa0
A
2376 false, ("Unable to patch the extension, no memory\n", file->fPath));
2377
2378 // Push out the new symbol table if necessary
2379 if (numnewsyms) {
2380 caddr_t base;
2381
9bccf70c 2382 // Append the new symbols to the original symbol table.
0b4e3aa0 2383 base = (caddr_t) file->fSymbolBase
9bccf70c 2384 + (file->fSymtab->nsyms - numnewsyms) * sizeof(struct nlist);
0b4e3aa0
A
2385 symp = (struct nlist **) DataGetPtr(file->fNewSymbols);
2386 for (i = 0; i < numnewsyms; i++, base += sizeof(struct nlist), symp++)
2387 bcopy(*symp, base, sizeof(struct nlist));
0b4e3aa0
A
2388
2389 DataRelease(file->fNewSymbols);
2390 file->fNewSymbols = 0;
2391 }
2392
2393 // Push out the new string table if necessary
9bccf70c
A
2394 if (newStrings) {
2395 unsigned long *base = (unsigned long *) file->fStringBase;
2396 unsigned long actuallen = DataGetLength(newStrings);
0b4e3aa0
A
2397
2398 // Set the last word in string table to zero before copying data
9bccf70c 2399 base[(newstrsize / sizeof(unsigned long)) - 1] = 0;
0b4e3aa0 2400
9bccf70c
A
2401 // Now copy the new strings back to the end of the file
2402 bcopy((caddr_t) DataGetPtr(newStrings), file->fStringBase, actuallen);
0b4e3aa0 2403
9bccf70c 2404 file->fSymtab->strsize = newstrsize;
0b4e3aa0 2405
9bccf70c 2406 DataRelease(newStrings);
0b4e3aa0
A
2407 }
2408
0b4e3aa0 2409 file->fSymbolsDirty = false;
55e303ae
A
2410#if !KERNEL
2411 if (file->fSwapped) {
2412 kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
2413 file->fSwapped = false;
2414 }
2415#endif
0b4e3aa0
A
2416 return true;
2417}
2418
2419Boolean
2420#if KERNEL
2421kld_file_map(const char *pathName,
2422 unsigned char *map,
2423 size_t mapSize,
2424 Boolean isKmem)
2425#else
2426kld_file_map(const char *pathName)
2427#endif /* KERNEL */
2428{
2429 struct fileRecord file, *fp = 0;
2430
2431 // Already done no need to repeat
2432 fp = getFile(pathName);
2433 if (fp)
2434 return true;
2435
2436 bzero(&file, sizeof(file));
0b4e3aa0
A
2437
2438#if KERNEL
2439 file.fMap = map;
2440 file.fMapSize = mapSize;
2441 file.fIsKmem = isKmem;
2442#else
9bccf70c 2443 if (!mapObjectFile(&file, pathName))
0b4e3aa0
A
2444 return false;
2445#endif /* KERNEL */
2446
2447 do {
2448 const struct machOMapping {
2449 struct mach_header h;
2450 struct load_command c[1];
2451 } *machO;
2452 const struct load_command *cmd;
55e303ae 2453 boolean_t lookVMRange;
9bccf70c 2454 int i;
0b4e3aa0 2455
9bccf70c 2456 if (!findBestArch(&file, pathName))
0b4e3aa0 2457 break;
9bccf70c 2458
0b4e3aa0
A
2459 machO = (const struct machOMapping *) file.fMachO;
2460 if (file.fMachOSize < machO->h.sizeofcmds)
2461 break;
2462
2463 // If the file type is MH_EXECUTE then this must be a kernel
2464 // as all Kernel extensions must be of type MH_OBJECT
55e303ae
A
2465 file.fIsKernel = (MH_EXECUTE == machO->h.filetype);
2466
2467 for (i = 0, cmd = &machO->c[0], lookVMRange = true; i < machO->h.ncmds; i++) {
9bccf70c 2468 if (cmd->cmd == LC_SYMTAB)
0b4e3aa0 2469 file.fSymtab = (struct symtab_command *) cmd;
9bccf70c
A
2470 else if (cmd->cmd == LC_SEGMENT) {
2471 struct segment_command *seg = (struct segment_command *) cmd;
2472 int nsects = seg->nsects;
2473
55e303ae
A
2474 if (lookVMRange) {
2475 if (!strcmp("__PRELINK", seg->segname))
2476 // segments following __PRELINK are going to move, so ignore them
2477 lookVMRange = false;
2478 else if (!file.fVMAddr && !file.fVMEnd) {
2479 file.fVMAddr = seg->vmaddr;
2480 file.fVMEnd = seg->vmaddr + seg->vmsize;
2481 } else {
2482 if (seg->vmaddr < file.fVMAddr)
2483 file.fVMAddr = seg->vmaddr;
2484 if ((seg->vmaddr + seg->vmsize) > file.fVMEnd)
2485 file.fVMEnd = seg->vmaddr + seg->vmsize;
2486 }
2487 }
2488
9bccf70c
A
2489 if (nsects)
2490 return_if(!parseSegments(&file, seg),
2491 false, ("%s isn't a valid mach-o, bad segment",
2492 pathName));
55e303ae
A
2493
2494 if (file.fIsKernel) {
9bccf70c
A
2495#if KERNEL
2496 // We don't need to look for the LinkEdit segment unless
2497 // we are running in the kernel environment.
2498 if (!strcmp(kLinkEditSegName, seg->segname))
2499 file.fLinkEditSeg = seg;
2500#endif
2501 }
2502 }
0b4e3aa0
A
2503 cmd = (struct load_command *) ((UInt8 *) cmd + cmd->cmdsize);
2504 }
2505 break_if(!file.fSymtab,
9bccf70c 2506 ("%s isn't a valid mach-o, no symbols\n", pathName));
0b4e3aa0 2507
55e303ae
A
2508 if (machO->h.flags & MH_INCRLINK) {
2509
2510 file.fIsIncrLink = true;
2511 ((struct machOMapping *) machO)->h.flags &= ~MH_INCRLINK;
2512
2513#if !KERNEL
2514 // the symtab fileoffset is the end of seg0's vmsize,
2515 // which can be (rarely) unaligned.
2516 unsigned int
2517 align = file.fSymtab->symoff % sizeof(long);
2518 if (align != 0) {
2519 align = sizeof(long) - align;
2520 growImage(&file, align);
2521 bcopy(file.fMachO + file.fSymtab->symoff,
2522 file.fMachO + file.fSymtab->symoff + align,
2523 file.fSymtab->stroff + file.fSymtab->strsize - file.fSymtab->symoff);
2524 file.fSymtab->symoff += align;
2525 file.fSymtab->stroff += align;
2526 }
2527#endif
2528 }
2529
9bccf70c
A
2530 if (!parseSymtab(&file, pathName))
2531 break;
0b4e3aa0 2532
9bccf70c 2533 fp = addFile(&file, pathName);
0b4e3aa0
A
2534 if (!fp)
2535 break;
2536
9bccf70c 2537 if (file.fFoundOSObject && !getMetaClassGraph(fp))
0b4e3aa0
A
2538 break;
2539
2540 if (file.fIsKernel)
2541 sKernelFile = fp;
9bccf70c 2542
0b4e3aa0 2543#if KERNEL
9bccf70c
A
2544 // Automatically load the kernel's link edit segment if we are
2545 // attempting to load a driver.
0b4e3aa0
A
2546 if (!sKernelFile) {
2547 extern struct mach_header _mh_execute_header;
2548 extern struct segment_command *getsegbyname(char *seg_name);
2549
2550 struct segment_command *sg;
2551 size_t kernelSize;
2552 Boolean ret;
2553
2554 sg = (struct segment_command *) getsegbyname(kLinkEditSegName);
2555 break_if(!sg, ("Can't find kernel link edit segment\n"));
2556
2557 kernelSize = sg->vmaddr + sg->vmsize - (size_t) &_mh_execute_header;
2558 ret = kld_file_map(kld_basefile_name,
2559 (unsigned char *) &_mh_execute_header, kernelSize,
2560 /* isKmem */ false);
2561 break_if(!ret, ("kld can't map kernel file"));
2562 }
2563#endif /* KERNEL */
2564
2565 return true;
2566 } while(0);
2567
9bccf70c
A
2568 // Failure path, then clean up
2569 if (fp)
2570 // @@@ gvdl: for the time being leak the file ref in the file table
2571 removeFile(fp);
2572 else
2573 unmapFile(&file);
0b4e3aa0
A
2574
2575 return false;
2576}
2577
2578void *kld_file_getaddr(const char *pathName, long *size)
2579{
2580 struct fileRecord *file = getFile(pathName);
2581
2582 if (!file)
2583 return 0;
2584
2585 if (size)
2586 *size = file->fMachOSize;
2587
2588 return file->fMachO;
2589}
2590
2591void *kld_file_lookupsymbol(const char *pathName, const char *symname)
2592{
2593 struct fileRecord *file = getFile(pathName);
2594 const struct nlist *sym;
2595 const struct section *section;
2596 unsigned char *sectionBase;
2597 unsigned char sectind;
2598
2599 return_if(!file,
2600 NULL, ("Unknown file %s\n", pathName));
2601
2602 sym = findSymbolByName(file, symname);
2603
2604 // May be a non-extern symbol so look for it there
2605 if (!sym) {
0b4e3aa0
A
2606 unsigned int i, nsyms;
2607
2608 sym = file->fSymbolBase;
0b4e3aa0
A
2609 for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
2610 if ( (sym->n_type & N_EXT) ) {
2611 sym = 0;
2612 break; // Terminate search when we hit an extern
2613 }
2614 if ( (sym->n_type & N_STAB) )
2615 continue;
9bccf70c 2616 if ( !strcmp(symname, symNameByIndex(file, i)) )
0b4e3aa0
A
2617 break;
2618 }
2619 }
2620
2621 return_if(!sym,
2622 NULL, ("Unknown symbol %s in %s\n", symname, pathName));
2623
2624 // Is the vtable in a valid section?
2625 sectind = sym->n_sect;
2626 return_if(sectind == NO_SECT || sectind > file->fNSects, NULL,
2627 ("Malformed object file, invalid section reference for %s in %s\n",
2628 symname, pathName));
2629
2630 section = file->fSections[sectind - 1].fSection;
2631 sectionBase = file->fMachO + section->offset - section->addr;
2632
2633 return (void *) (sectionBase + sym->n_value);
2634}
2635
2636Boolean kld_file_merge_OSObjects(const char *pathName)
2637{
2638 struct fileRecord *file = getFile(pathName);
2639
2640 return_if(!file,
2641 false, ("Internal error - unable to find file %s\n", pathName));
2642
2643 return mergeOSObjectsForFile(file);
2644}
2645
2646Boolean kld_file_patch_OSObjects(const char *pathName)
2647{
2648 struct fileRecord *file = getFile(pathName);
2649 struct metaClassRecord **classes;
2650 unsigned long i, last;
2651
2652 return_if(!file,
2653 false, ("Internal error - unable to find file %s\n", pathName));
2654
9bccf70c 2655 DEBUG_LOG(("Patch file %s\n", pathName)); // @@@ gvdl:
0b4e3aa0
A
2656
2657 // If we don't have any classes we can return now.
2658 if (!file->fClassList)
2659 return true;
2660
2661 // If we haven't alread merged the kernel then do it now
2662 if (!sMergedKernel && sKernelFile)
2663 mergeOSObjectsForFile(sKernelFile);
2664 return_if(!sMergedKernel, false, ("Internal error no kernel?\n"));
2665
2666 if (!mergeOSObjectsForFile(file))
2667 return false;
2668
2669 // Patch all of the classes in this executable
2670 last = DataGetLength(file->fClassList) / sizeof(void *);
2671 classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
2672 for (i = 0; i < last; i++) {
9bccf70c
A
2673 if (!patchVTable(classes[i])) {
2674 // RY: Set a flag in the file list to invalidate this data.
2675 // I would remove the file from the list, but that seems to be
2676 // not worth the effort.
2677 file->fIgnoreFile = TRUE;
2678
2679 return false;
2680 }
0b4e3aa0
A
2681 }
2682
2683 return true;
2684}
2685
2686Boolean kld_file_prepare_for_link()
2687{
2688 if (sMergedFiles) {
2689 unsigned long i, nmerged = 0;
2690 struct fileRecord **files;
2691
2692 // Check to see if we have already merged this file
2693 nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
2694 files = (struct fileRecord **) DataGetPtr(sMergedFiles);
9bccf70c
A
2695 for (i = 0; i < nmerged; i++) {
2696 if (!files[i]->fIgnoreFile && !prepareFileForLink(files[i]))
0b4e3aa0
A
2697 return false;
2698 }
2699 }
2700
2701 // Clear down the meta class table and merged file lists
2702 DataRelease(sMergeMetaClasses);
2703 DataRelease(sMergedFiles);
2704 sMergedFiles = sMergeMetaClasses = NULL;
2705 sMergedKernel = false;
2706
2707 return true;
2708}
2709
2710void kld_file_cleanup_all_resources()
2711{
2712 unsigned long i, nfiles;
2713
2714#if KERNEL // @@@ gvdl:
2715 // Debugger("kld_file_cleanup_all_resources");
2716#endif
2717
2718 if (!sFilesTable || !(nfiles = DataGetLength(sFilesTable)))
2719 return; // Nothing to do just return now
2720
2721 nfiles /= sizeof(struct fileRecord *);
2722 for (i = 0; i < nfiles; i++)
2723 removeFile(((void **) DataGetPtr(sFilesTable))[i]);
2724
9bccf70c
A
2725 DataRelease(sFilesTable);
2726 sFilesTable = NULL;
2727
0b4e3aa0
A
2728 // Don't really have to clean up anything more as the whole
2729 // malloc engine is going to be released and I couldn't be bothered.
2730}
2731
9bccf70c 2732
0b4e3aa0 2733#if !KERNEL
9bccf70c
A
2734#if 0
2735static const struct fileRecord *sortFile;
2736static int symCompare(const void *vSym1, const void *vSym2)
2737{
2738 const struct nlist *sym1 = vSym1;
2739 const struct nlist *sym2 = vSym2;
2740
2741 {
2742 unsigned int ind1, ind2;
2743
2744 ind1 = sym1->n_type & N_TYPE;
2745 ind2 = sym2->n_type & N_TYPE;
2746 if (ind1 != ind2) {
2747 // if sym1 is undefined then sym1 must come later than sym2
2748 if (ind1 == N_UNDF)
2749 return 1;
2750 // if sym2 is undefined then sym1 must come earlier than sym2
2751 if (ind2 == N_UNDF)
2752 return -1;
2753 /* drop out if neither are undefined */
2754 }
2755 }
2756
2757 {
2758 const struct fileRecord *file = sortFile;
2759 const char *name1, *name2;
2760
2761 name1 = file->fStringBase + sym1->n_un.n_strx;
2762 name2 = file->fStringBase + sym2->n_un.n_strx;
2763 return strcmp(name1, name2);
2764 }
2765}
2766#endif /* 0 */
2767
0b4e3aa0
A
2768Boolean kld_file_debug_dump(const char *pathName, const char *outName)
2769{
2770 const struct fileRecord *file = getFile(pathName);
2771 int fd;
2772 Boolean ret = false;
2773
2774 return_if(!file, false, ("Unknown file %s for dumping\n", pathName));
2775
2776 fd = open(outName, O_WRONLY|O_CREAT|O_TRUNC, 0666);
2777 return_if(-1 == fd, false, ("Can't create output file %s - %s(%d)\n",
2778 outName, strerror(errno), errno));
2779
2780 do {
9bccf70c
A
2781#if 0
2782 // Sorting doesn't work until I fix the relocs too?
2783
2784 // sort the symbol table appropriately
2785 unsigned int nsyms = file->fSymtab->nsyms
2786 - (file->fLocalSyms - file->fSymbolBase);
2787 sortFile = file;
2788 heapsort((void *) file->fLocalSyms, nsyms, sizeof(struct nlist),
2789 symCompare);
2790#endif
2791
0b4e3aa0
A
2792 break_if(-1 == write(fd, file->fMachO, file->fMachOSize),
2793 ("Can't dump output file %s - %s(%d)\n",
2794 outName, strerror(errno), errno));
2795 ret = true;
2796 } while(0);
2797
2798 close(fd);
2799
2800 return ret;
2801}
9bccf70c 2802
0b4e3aa0
A
2803#endif /* !KERNEL */
2804