2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (C) 2006 Graham Dennis. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #import <Cocoa/Cocoa.h>
31 #include <mach-o/dyld.h>
33 #include <mach-o/loader.h>
34 #include <mach-o/nlist.h>
37 static void cleanUpAfterOurselves(void) __attribute__ ((constructor));
38 static void *symbol_lookup(char *symbol);
40 static bool extensionBundlesWereLoaded = NO;
41 static NSSet *extensionPaths = nil;
43 static void myBundleDidLoad(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
45 // Break out early if we have already detected an extension
46 if (extensionBundlesWereLoaded)
49 NSBundle *bundle = (NSBundle *)object;
50 NSString *bundlePath = [[bundle bundlePath] stringByAbbreviatingWithTildeInPath];
51 NSString *bundleFileName = [bundlePath lastPathComponent];
53 // Explicitly ignore SIMBL.bundle, as its only purpose is to load extensions
54 // on a per-application basis. It's presence indicates a user has application
55 // extensions, but not that any will be loaded into Safari
56 if ([bundleFileName isEqualToString:@"SIMBL.bundle"])
59 // If the bundle lives inside a known extension path, flag it as an extension
60 NSEnumerator *e = [extensionPaths objectEnumerator];
62 while (path = [e nextObject]) {
63 if ([bundlePath length] < [path length])
66 if ([[bundlePath substringToIndex:[path length]] isEqualToString:path]) {
67 extensionBundlesWereLoaded = YES;
73 static void myApplicationWillFinishLaunching(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
75 CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), &myApplicationWillFinishLaunching, NULL, NULL);
76 CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), &myBundleDidLoad, NULL, NULL);
77 [extensionPaths release];
80 if (extensionBundlesWereLoaded)
81 NSRunInformationalAlertPanel(@"Safari extensions detected",
82 @"Safari extensions were detected on your system. They are incompatible with nightly builds of WebKit, and may cause crashes or incorrect behavior. Please disable them if you experience such behavior.", @"Continue", nil, nil);
85 void cleanUpAfterOurselves(void)
87 char **args = *(char***)_NSGetArgv();
88 char **procPath = symbol_lookup("___CFProcessPath");
89 char *procPathBackup = *procPath;
91 CFBundleGetMainBundle();
92 *procPath = procPathBackup;
93 unsetenv("DYLD_INSERT_LIBRARIES");
94 unsetenv("CFProcessPath");
96 extensionPaths = [[NSSet alloc] initWithObjects:@"~/Library/InputManagers/", @"/Library/InputManagers/",
97 @"~/Library/Application Support/SIMBL/Plugins/", @"/Library/Application Support/SIMBL/Plugins/",
98 @"~/Library/Application Enhancers/", @"/Library/Application Enhancers/",
101 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), &myBundleDidLoad,
102 myBundleDidLoad, (CFStringRef) NSBundleDidLoadNotification,
103 NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
104 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), &myApplicationWillFinishLaunching,
105 myApplicationWillFinishLaunching, (CFStringRef) NSApplicationWillFinishLaunchingNotification,
106 NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
110 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
111 #define macho_header mach_header_64
112 #define macho_segment_command segment_command_64
113 #define macho_section section_64
114 #define getsectdatafromheader getsectdatafromheader_64
115 #define macho_nlist nlist_64
117 #define LC_SEGMENT_COMMAND LC_SEGMENT
118 #define macho_header mach_header
119 #define macho_segment_command segment_command
120 #define macho_section section
121 #define macho_nlist nlist
124 void *GDSymbolLookup(const struct macho_header *header, const char *symbol);
126 void *symbol_lookup(char *symbol)
129 for(i=0;i<_dyld_image_count();i++)
131 void *symbolResult = GDSymbolLookup((const struct macho_header*)_dyld_get_image_header(i), symbol);
138 void *GDSymbolLookup(const struct macho_header *header, const char *symbol)
140 if (!header || !symbol)
142 if ((header->magic != MH_MAGIC) && (header->magic != MH_MAGIC_64))
145 uint32_t currCommand;
146 const struct load_command *loadCommand = (const struct load_command *)( ((void *)header) + sizeof(struct macho_header));
147 const struct macho_segment_command *segCommand;
149 const struct symtab_command *symtabCommand = NULL;
150 const struct dysymtab_command *dysymtabCommand = NULL;
151 const struct macho_segment_command *textSegment = NULL;
152 const struct macho_segment_command *linkEditSegment = NULL;
154 for (currCommand = 0; currCommand < header->ncmds; currCommand++)
156 switch (loadCommand->cmd)
158 case LC_SEGMENT_COMMAND:
159 segCommand = (const struct macho_segment_command *)loadCommand;
160 if (strcmp(segCommand->segname, "__TEXT")==0)
161 textSegment = segCommand;
162 else if (strcmp(segCommand->segname, "__LINKEDIT")==0)
163 linkEditSegment = segCommand;
167 symtabCommand = (const struct symtab_command *)loadCommand;
171 dysymtabCommand = (const struct dysymtab_command *)loadCommand;
175 loadCommand = (const struct load_command *)(((void*)loadCommand) + loadCommand->cmdsize);
177 if (textSegment==NULL || linkEditSegment==NULL || symtabCommand==NULL || dysymtabCommand==NULL) {
181 typedef enum { Start = 0, LocalSymbols, ExternalSymbols, Done } SymbolSearchState;
182 uint32_t currentSymbolIndex;
183 uint32_t maximumSymbolIndex;
184 SymbolSearchState state;
186 for (state = Start + 1; state < Done; state++)
190 currentSymbolIndex = dysymtabCommand->ilocalsym;
191 maximumSymbolIndex = dysymtabCommand->ilocalsym + dysymtabCommand->nlocalsym;
194 case ExternalSymbols:
195 currentSymbolIndex = dysymtabCommand->iextdefsym;
196 maximumSymbolIndex = dysymtabCommand->nextdefsym;
202 for (; currentSymbolIndex < maximumSymbolIndex; currentSymbolIndex++)
204 const struct macho_nlist *symbolTableEntry;
205 symbolTableEntry = (const struct macho_nlist *)(currentSymbolIndex*sizeof(struct macho_nlist)
206 + (ptrdiff_t)header + symtabCommand->symoff
207 + linkEditSegment->vmaddr - linkEditSegment->fileoff
208 - textSegment->vmaddr);
209 int32_t stringTableIndex = symbolTableEntry->n_un.n_strx;
210 if (stringTableIndex<0)
212 const char *stringTableEntry = (const char*)(stringTableIndex + (ptrdiff_t)header + symtabCommand->stroff
213 + linkEditSegment->vmaddr - linkEditSegment->fileoff
214 - textSegment->vmaddr);
215 if (strcmp(symbol, stringTableEntry)==0) {
216 return ((void*)header) - textSegment->vmaddr + symbolTableEntry->n_value;