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