this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dyld refactoring complete

+1667 -3109
+5 -5
etc/dylib.conf
··· 4 4 /usr/lib/libintl.8.dylib=libc.so.6 5 5 /usr/lib/libz.1.dylib=libz.so.1 6 6 /usr/lib/libstdc++.6.dylib=libstdc++darwin.so 7 - /usr/lib/libc++.1.dylib=/dev/null 8 - /usr/lib/libc++abi.dylib=/dev/null 7 + /usr/lib/libc++.1.dylib=libstdc++darwin.so 8 + /usr/lib/libc++abi.dylib=libstdc++darwin.so 9 9 /usr/lib/libcrypto.0.9.8.dylib=libcrypto.so 10 10 /usr/lib/libcrypto.0.9.7.dylib=libcrypto.so 11 - /usr/lib/libgcc_s.1.dylib=/dev/null 11 + /usr/lib/libgcc_s.1.dylib=libgcc_s.so.1 12 12 /usr/lib/libbz2.1.0.dylib=libbz2.so.1 13 13 /usr/lib/libiconv.2.dylib=libc.so.6 14 - /usr/lib/libauto.dylib=/dev/null 14 + /usr/lib/libauto.dylib=libauto.so 15 15 /usr/lib/libsqlite3.dylib=libsqlite3.so 16 16 /usr/lib/libncurses.5.4.dylib=libncurses.5.4.dylib.so 17 17 /usr/lib/libltdl.7.dylib=libc.so.6 ··· 59 59 A=libCoreSecurity.so 60 60 61 61 [ApplicationServices.framework] 62 - A=/dev/null 62 + A=libCoreServices.so 63 63 64 64 [LDAP.framework] 65 65 A=libldap_r-2.4.so.2
+6
src/CoreFoundation/AppleCFString.h
··· 25 25 - (unichar)characterAtIndex:(NSUInteger)index; 26 26 - (void)getCharacters:(unichar *)buffer range:(NSRange)aRange; 27 27 - (const char *)UTF8String; 28 + 29 + - (NSUInteger) retainCount; 30 + - (id) retain; 31 + - (void) release; 32 + - (id) autorelease; 33 + - (NSZone*) zone; 28 34 @end 29 35 #pragma pack() 30 36
+25
src/CoreFoundation/AppleCFString.mm
··· 47 47 else 48 48 return _data._asciiData; 49 49 } 50 + 51 + - (NSUInteger) retainCount 52 + { 53 + return UINT_MAX; 54 + } 55 + 56 + - (id) retain 57 + { 58 + return self; 59 + } 60 + 61 + - (void) release 62 + { 63 + } 64 + 65 + - (id) autorelease 66 + { 67 + return self; 68 + } 69 + 70 + - (NSZone*) zone 71 + { 72 + return NSDefaultMallocZone(); 73 + } 74 + 50 75 @end 51 76
+69
src/CoreFoundation/CFPreferences.h
··· 1 + #ifndef CFPREFERENCES_H 2 + #define CFPREFERENCES_H 3 + 4 + #include <CoreFoundation/CFBase.h> 5 + #include <CoreFoundation/CFArray.h> 6 + #include <CoreFoundation/CFString.h> 7 + 8 + CF_EXTERN_C_BEGIN 9 + 10 + CF_EXPORT 11 + const CFStringRef kCFPreferencesAnyApplication; 12 + CF_EXPORT 13 + const CFStringRef kCFPreferencesCurrentApplication; 14 + CF_EXPORT 15 + const CFStringRef kCFPreferencesAnyHost; 16 + CF_EXPORT 17 + const CFStringRef kCFPreferencesCurrentHost; 18 + CF_EXPORT 19 + const CFStringRef kCFPreferencesAnyUser; 20 + CF_EXPORT 21 + const CFStringRef kCFPreferencesCurrentUser; 22 + 23 + CF_EXPORT 24 + CFPropertyListRef CFPreferencesCopyAppValue(CFStringRef key, CFStringRef applicationID); 25 + 26 + CF_EXPORT 27 + Boolean CFPreferencesGetAppBooleanValue(CFStringRef key, CFStringRef applicationID, Boolean *keyExistsAndHasValidFormat); 28 + 29 + CF_EXPORT 30 + CFIndex CFPreferencesGetAppIntegerValue(CFStringRef key, CFStringRef applicationID, Boolean *keyExistsAndHasValidFormat); 31 + 32 + CF_EXPORT 33 + void CFPreferencesSetAppValue(CFStringRef key, CFPropertyListRef value, CFStringRef applicationID); 34 + 35 + CF_EXPORT 36 + void CFPreferencesAddSuitePreferencesToApp(CFStringRef applicationID, CFStringRef suiteID); 37 + 38 + CF_EXPORT 39 + void CFPreferencesRemoveSuitePreferencesFromApp(CFStringRef applicationID, CFStringRef suiteID); 40 + 41 + CF_EXPORT 42 + Boolean CFPreferencesAppSynchronize(CFStringRef applicationID); 43 + 44 + CF_EXPORT 45 + CFPropertyListRef CFPreferencesCopyValue(CFStringRef key, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName); 46 + 47 + CF_EXPORT 48 + CFDictionaryRef CFPreferencesCopyMultiple(CFArrayRef keysToFetch, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName); 49 + 50 + CF_EXPORT 51 + void CFPreferencesSetValue(CFStringRef key, CFPropertyListRef value, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName); 52 + 53 + CF_EXPORT 54 + void CFPreferencesSetMultiple(CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName); 55 + 56 + CF_EXPORT 57 + Boolean CFPreferencesSynchronize(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName); 58 + 59 + CF_EXPORT 60 + CFArrayRef CFPreferencesCopyApplicationList(CFStringRef userName, CFStringRef hostName); 61 + 62 + CF_EXPORT 63 + CFArrayRef CFPreferencesCopyKeyList(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName); 64 + 65 + 66 + CF_EXTERN_C_END 67 + 68 + #endif 69 +
+107
src/CoreFoundation/CFPreferences.mm
··· 1 + #include "CFPreferences.h" 2 + #include <util/debug.h> 3 + #import <Foundation/NSUserDefaults.h> 4 + 5 + #ifndef CONST_STRING_DECL 6 + # define CONST_STRING_DECL(name, value) const CFStringRef name = CFSTR(value); 7 + #endif 8 + 9 + CONST_STRING_DECL(kCFPreferencesAnyApplication, 10 + "kCFPreferencesAnyApplication"); 11 + CONST_STRING_DECL(kCFPreferencesCurrentApplication, 12 + "kCFPreferencesCurrentApplication"); 13 + CONST_STRING_DECL(kCFPreferencesAnyHost, 14 + "kCFPreferencesAnyHost"); 15 + CONST_STRING_DECL(kCFPreferencesCurrentHost, 16 + "kCFPreferencesCurrentHost"); 17 + CONST_STRING_DECL(kCFPreferencesAnyUser, 18 + "kCFPreferencesAnyUser"); 19 + CONST_STRING_DECL(kCFPreferencesCurrentUser, 20 + "kCFPreferencesCurrentUser"); 21 + 22 + CFPropertyListRef CFPreferencesCopyAppValue(CFStringRef key, CFStringRef applicationID) 23 + { 24 + if (applicationID == kCFPreferencesCurrentApplication) 25 + { 26 + return [[NSUserDefaults standardUserDefaults] objectForKey: (NSString*) key]; 27 + } 28 + else 29 + { 30 + STUB(); 31 + return NULL; 32 + } 33 + } 34 + 35 + Boolean CFPreferencesGetAppBooleanValue(CFStringRef key, CFStringRef applicationID, Boolean *keyExistsAndHasValidFormat) 36 + { 37 + STUB(); 38 + return 0; 39 + } 40 + 41 + CFIndex CFPreferencesGetAppIntegerValue(CFStringRef key, CFStringRef applicationID, Boolean *keyExistsAndHasValidFormat) 42 + { 43 + STUB(); 44 + return -1; 45 + } 46 + 47 + void CFPreferencesSetAppValue(CFStringRef key, CFPropertyListRef value, CFStringRef applicationID) 48 + { 49 + STUB(); 50 + } 51 + 52 + void CFPreferencesAddSuitePreferencesToApp(CFStringRef applicationID, CFStringRef suiteID) 53 + { 54 + STUB(); 55 + } 56 + 57 + void CFPreferencesRemoveSuitePreferencesFromApp(CFStringRef applicationID, CFStringRef suiteID) 58 + { 59 + STUB(); 60 + } 61 + 62 + Boolean CFPreferencesAppSynchronize(CFStringRef applicationID) 63 + { 64 + STUB(); 65 + return 0; 66 + } 67 + 68 + CFPropertyListRef CFPreferencesCopyValue(CFStringRef key, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName) 69 + { 70 + STUB(); 71 + return NULL; 72 + } 73 + 74 + CFDictionaryRef CFPreferencesCopyMultiple(CFArrayRef keysToFetch, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName) 75 + { 76 + STUB(); 77 + return NULL; 78 + } 79 + 80 + void CFPreferencesSetValue(CFStringRef key, CFPropertyListRef value, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName) 81 + { 82 + STUB(); 83 + } 84 + 85 + void CFPreferencesSetMultiple(CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName) 86 + { 87 + STUB(); 88 + } 89 + 90 + Boolean CFPreferencesSynchronize(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName) 91 + { 92 + STUB(); 93 + return 0; 94 + } 95 + 96 + CFArrayRef CFPreferencesCopyApplicationList(CFStringRef userName, CFStringRef hostName) 97 + { 98 + STUB(); 99 + return NULL; 100 + } 101 + 102 + CFArrayRef CFPreferencesCopyKeyList(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName) 103 + { 104 + STUB(); 105 + return NULL; 106 + } 107 +
+1 -1
src/CoreFoundation/CMakeLists.txt
··· 19 19 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../util) 20 20 21 21 set(CoreFoundation_SRCS 22 - #NameTranslate.cpp 22 + CFPreferences.mm 23 23 AppleCFString.mm 24 24 CFUtilities.cpp 25 25 )
+5 -5
src/CoreServices/CoreEndian.cpp
··· 22 22 #include <stdint.h> 23 23 #include <map> 24 24 #include "MacErrors.h" 25 - #include "util/mutex.h" 25 + #include <mutex> 26 26 27 27 static std::map< 28 28 std::pair<uint32_t,uint32_t>, 29 29 std::pair<CEFlipper,void*> 30 30 > g_flippers; 31 - static Darling::Mutex g_flippersMutex; 31 + static std::mutex g_flippersMutex; 32 32 33 33 template <typename T> T bswap(T value); 34 34 ··· 288 288 289 289 OSStatus CoreEndianFlipData(uint32_t dataDomain, uint32_t dataType, int16_t id, void* data, unsigned long length, Boolean isNative) 290 290 { 291 - Darling::MutexLock l(g_flippersMutex); 291 + std::lock_guard<std::mutex> l(g_flippersMutex); 292 292 auto it = g_flippers.find(std::make_pair(dataDomain, dataType)); 293 293 294 294 if (it == g_flippers.end()) ··· 299 299 300 300 OSStatus CoreEndianInstallFlipper(uint32_t dataDomain, uint32_t dataType, CEFlipper flipper, void* opaque) 301 301 { 302 - Darling::MutexLock l(g_flippersMutex); 302 + std::lock_guard<std::mutex> l(g_flippersMutex); 303 303 g_flippers[std::make_pair(dataDomain, dataType)] = std::make_pair(flipper, opaque); 304 304 return noErr; 305 305 } 306 306 307 307 OSStatus CoreEndianGetFlipper(uint32_t dataDomain, uint32_t dataType, CEFlipper* flipper, void** opaque) 308 308 { 309 - Darling::MutexLock l(g_flippersMutex); 309 + std::lock_guard<std::mutex> l(g_flippersMutex); 310 310 auto it = g_flippers.find(std::make_pair(dataDomain, dataType)); 311 311 312 312 *opaque = nullptr;
+5 -4
src/Foundation/NSDarwinBundle.mm
··· 4 4 #include <string> 5 5 #include <algorithm> 6 6 #include <unistd.h> 7 - #include "../util/log.h" 8 - #include "../dyld/ld.h" 7 + #include <util/debug.h> 8 + #include <dyld/MachOMgr.h> 9 + #include <dyld/MachOObject.h> 10 + #include <dyld/dl_public.h> 9 11 10 - extern char g_darwin_executable_path[PATH_MAX]; 11 12 extern int g_argc asm("NXArgc"); 12 13 extern char** g_argv asm("NXArgv"); 13 14 static NSBundle* _mainBundle = 0; ··· 60 61 LOG << "x_mainBundle() called\n"; 61 62 if (!_mainBundle) 62 63 { 63 - std::string path = g_darwin_executable_path; 64 + std::string path = Darling::MachOMgr::instance()->mainModule()->path(); 64 65 size_t pos; 65 66 66 67 //size_t pos = path.find_last_of('/');
+2 -4
src/dyld/CMakeLists.txt
··· 13 13 eh/BufWriter.cpp 14 14 eh/BufReader.cpp 15 15 eh/EHSection.cpp 16 - FileMap.cpp 17 - MachOLoader.cpp 18 16 Trampoline.cpp 19 17 trampoline_helper.nasm 20 18 dyld_stub_binder.nasm 21 19 tls_helper.nasm 22 - ld.cpp 23 20 dyld.cpp 24 - public.cpp 21 + dyld_public.cpp 22 + dl_public.cpp 25 23 binfmt_misc.cpp 26 24 TLS.cpp 27 25
+106 -3
src/dyld/DylibSearch.cpp
··· 4 4 #include <iostream> 5 5 #include "MachOObject.h" 6 6 #include "MachOMgr.h" 7 + #include <regex.h> 8 + #include <unistd.h> 9 + #include <util/stlutils.h> 10 + #include <cassert> 11 + 12 + namespace Darling { 7 13 8 14 DylibSearch::DylibSearch() 9 15 { 10 16 try 11 17 { 18 + int rv = regcomp(&m_reFrameworkPath, "/System/Library/Frameworks/([a-zA-Z0-9\\.]+)/Versions/([a-zA-Z0-9\\.]+)/.*", REG_EXTENDED); 19 + assert(rv == 0); 20 + 12 21 m_config = new IniConfig(ETC_DARLING_PATH "/dylib.conf"); 13 22 } 14 23 catch (const std::exception& e) ··· 25 34 26 35 std::string DylibSearch::resolve(std::string dylib, MachOObject* requester) 27 36 { 37 + if (dylib.empty()) 38 + return std::string(); 39 + 28 40 // expand @rpath, @executable_path and @loader_path 29 41 if (requester != nullptr && dylib[0] == '@') 30 42 { ··· 48 60 } 49 61 50 62 // Search in configuration 63 + if (const char* aliasTarget = resolveAlias(dylib)) 64 + return aliasTarget; 51 65 52 66 // Search in DYLD_LIBRARY_PATH 67 + std::string ldpath = resolveInLdPath(dylib); 68 + if (!ldpath.empty()) 69 + return ldpath; 70 + 71 + // Try the path as is 72 + if (::access(dylib.c_str(), F_OK) == 0) 73 + return dylib; 53 74 54 - // Search in sysroot 55 - 56 - 75 + // If absolute, search in sysroot 76 + if (dylib[0] == '/' && !MachOMgr::instance()->sysRoot().empty()) 77 + { 78 + std::string path = MachOMgr::instance()->sysRoot(); 79 + path += '/'; 80 + path += dylib; 81 + 82 + if (::access(path.c_str(), F_OK) == 0) 83 + return path; 84 + } 85 + 86 + return std::string(); 87 + } 88 + 89 + std::string DylibSearch::resolveInLdPath(std::string name) 90 + { 91 + std::string ldpath = MachOMgr::instance()->libraryPath(); 92 + std::vector<std::string> elems; 93 + 94 + if (ldpath.empty()) 95 + return std::string(); 96 + 97 + elems = string_explode(name, ':'); 98 + 99 + for (const std::string& e : elems) 100 + { 101 + std::string path = e + "/" + name; 102 + 103 + if (::access(path.c_str(), F_OK) == 0) 104 + return path; 105 + } 106 + 107 + return std::string(); 108 + } 109 + 110 + const char* DylibSearch::resolveAlias(const std::string& library) 111 + { 112 + if (!m_config) 113 + return nullptr; 114 + 115 + if (m_config->hasSection("dylibs")) 116 + { 117 + const IniConfig::ValueMap* m = m_config->getSection("dylibs"); 118 + auto it = m->find(library); 119 + if (it != m->end()) 120 + return it->second.c_str(); 121 + } 122 + if (library.compare(0, 27, "/System/Library/Frameworks/", 27) == 0) 123 + { 124 + regmatch_t match[3]; 125 + if (regexec(&m_reFrameworkPath, library.c_str(), sizeof(match)/sizeof(match[0]), match, 0) != REG_NOMATCH) 126 + { 127 + std::string name, version; 128 + 129 + name = library.substr(match[1].rm_so, match[1].rm_eo - match[1].rm_so); 130 + version = library.substr(match[2].rm_so, match[2].rm_eo - match[2].rm_so); 131 + 132 + if (m_config->hasSection(name)) 133 + { 134 + const IniConfig::ValueMap* m = m_config->getSection(name); 135 + auto it = m->find(version); 136 + 137 + if (it != m->end()) 138 + return it->second.c_str(); 139 + } 140 + } 141 + } 142 + return nullptr; 57 143 } 58 144 59 145 std::string DylibSearch::filenameFromPath(const std::string& path) ··· 67 153 68 154 std::string DylibSearch::resolveViaRpath(std::string name, MachOObject* requester) 69 155 { 156 + bool print = MachOMgr::instance()->printRpathExpansion(); 157 + 70 158 for (const char* rpath : requester->runPaths()) 71 159 { 72 160 std::string expanded = name; 73 161 std::string result; 74 162 75 163 expanded.replace(0, 6, rpath); 164 + 165 + if (print) 166 + std::cerr << "dyld: Expanding \"" << name << "\" -> \"" << expanded << "\"\n"; 167 + 76 168 result = resolve(expanded, requester); 77 169 78 170 if (!result.empty()) 171 + { 172 + if (print) 173 + std::cerr << "dyld: @rpath expansion successful\n"; 79 174 return result; 175 + } 176 + else 177 + { 178 + if (print) 179 + std::cerr << "dyld: @rpath expansion not successful\n"; 180 + } 80 181 } 81 182 82 183 return std::string(); 83 184 } 185 + 186 + } // namespace Darling
+8
src/dyld/DylibSearch.h
··· 2 2 #define DYLIBSEARCH_H 3 3 #include <util/IniConfig.h> 4 4 #include <string> 5 + #include <regex.h> 6 + 7 + namespace Darling { 5 8 6 9 class MachOObject; 7 10 ··· 15 18 std::string resolve(std::string name, MachOObject* requester); 16 19 private: 17 20 std::string resolveViaRpath(std::string name, MachOObject* requester); 21 + std::string resolveInLdPath(std::string name); 22 + const char* resolveAlias(const std::string& library); 18 23 static std::string filenameFromPath(const std::string& path); 19 24 private: 20 25 IniConfig* m_config; 26 + regex_t m_reFrameworkPath; 21 27 }; 28 + 29 + } 22 30 23 31 #endif
-200
src/dyld/FileMap.cpp
··· 1 - /* 2 - This file is part of Darling. 3 - 4 - Copyright (C) 2012 Lubos Dolezel 5 - Copyright (C) 2011 Shinichiro Hamaji 6 - 7 - Darling is free software: you can redistribute it and/or modify 8 - it under the terms of the GNU General Public License as published by 9 - the Free Software Foundation, either version 3 of the License, or 10 - (at your option) any later version. 11 - 12 - Darling is distributed in the hope that it will be useful, 13 - but WITHOUT ANY WARRANTY; without even the implied warranty of 14 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 - GNU General Public License for more details. 16 - 17 - You should have received a copy of the GNU General Public License 18 - along with Darling. If not, see <http://www.gnu.org/licenses/>. 19 - */ 20 - 21 - #include "FileMap.h" 22 - #include <cassert> 23 - #include <cstring> 24 - #include <cstdio> 25 - #include <iostream> 26 - #include <stdexcept> 27 - #include <sstream> 28 - 29 - FileMap::~FileMap() 30 - { 31 - for (auto m : m_maps) 32 - { 33 - if (m.second) 34 - delete m.second->header; 35 - delete m.second; 36 - } 37 - } 38 - 39 - const FileMap::ImageMap* FileMap::add(const MachO& mach, uintptr_t slide, uintptr_t base, bool bindLazy) 40 - { 41 - ImageMap* symbol_map = new ImageMap; 42 - 43 - symbol_map->filename = mach.filename(); 44 - symbol_map->base = base; 45 - symbol_map->slide = slide; 46 - 47 - // This needs to be allocated dynamically, because its memory location must be permanent. 48 - // It is used in certain silly APIs as a handle. 49 - symbol_map->header = new mach_header; 50 - *symbol_map->header = mach.header(); 51 - 52 - symbol_map->eh_frame = mach.get_eh_frame(); 53 - symbol_map->unwind_info = mach.get_unwind_info(); 54 - symbol_map->sections = mach.sections(); 55 - 56 - if (!bindLazy) 57 - { 58 - for (auto* b : mach.binds()) 59 - { 60 - if (!b->is_lazy) 61 - continue; 62 - symbol_map->lazy_binds.push_back(*b); 63 - } 64 - } 65 - 66 - if (!m_maps.insert(std::make_pair(base, symbol_map)).second) 67 - { 68 - std::stringstream ss; 69 - ss << "dupicated base addr: " << (void*) base << " in " << mach.filename(); 70 - throw std::runtime_error(ss.str()); 71 - } 72 - 73 - m_maps_vec.push_back(symbol_map); 74 - m_maps_mach[symbol_map->header] = symbol_map; 75 - 76 - for (MachO::Symbol sym : mach.symbols()) 77 - { 78 - if (sym.name.empty() || sym.name[0] != '_') 79 - continue; 80 - sym.addr += slide; 81 - if (sym.addr < base) 82 - continue; 83 - symbol_map->symbols.insert(std::make_pair(sym.addr, sym.name.substr(1))); 84 - } 85 - for (const char* rpath : mach.rpaths()) 86 - symbol_map->rpaths.push_back(rpath); 87 - 88 - return symbol_map; 89 - } 90 - 91 - void FileMap::addWatchDog(uintptr_t addr) 92 - { 93 - bool r = m_maps.insert(std::make_pair(addr, (ImageMap*)NULL)).second; 94 - assert(r); 95 - } 96 - 97 - const char* FileMap::gdbInfoForAddr(const void* p) const 98 - { 99 - Dl_info i; 100 - 101 - if (!findSymbolInfo(p, &i)) 102 - return 0; 103 - 104 - if (i.dli_fbase) 105 - { 106 - #ifdef __i386__ 107 - const char* fmt_string = "0x%08lx in %s+%x () from %s"; 108 - #else 109 - const char* fmt_string = "0x%016lx in %s%x () from %s"; 110 - #endif 111 - 112 - ptrdiff_t func_offset = uintptr_t(p) - uintptr_t(i.dli_saddr); 113 - snprintf(m_dumped_stack_frame_buf, sizeof(m_dumped_stack_frame_buf)-1, fmt_string, p, i.dli_sname, func_offset, i.dli_fname); 114 - } 115 - else 116 - { 117 - #ifdef __i386__ 118 - const char* fmt_string = "0x%08lx in ?? () from %s"; 119 - #else 120 - const char* fmt_string = "0x%016lx in ?? () from %s"; 121 - #endif 122 - snprintf(m_dumped_stack_frame_buf, sizeof(m_dumped_stack_frame_buf)-1, fmt_string, p, i.dli_fname); 123 - } 124 - 125 - return m_dumped_stack_frame_buf; 126 - } 127 - 128 - const FileMap::ImageMap* FileMap::mainExecutable() const 129 - { 130 - assert(!m_maps_vec.empty()); 131 - return m_maps_vec[0]; 132 - } 133 - 134 - const char* FileMap::fileNameForAddr(const void* p) const 135 - { 136 - const ImageMap* map = imageMapForAddr(p); 137 - if (!map) 138 - return 0; 139 - return map->filename.c_str(); 140 - } 141 - 142 - const FileMap::ImageMap* FileMap::imageMapForAddr(const void* p) const 143 - { 144 - uintptr_t addr = reinterpret_cast<uintptr_t>(p); 145 - const ImageMap* symbol_map; 146 - 147 - std::map<uintptr_t, ImageMap*>::const_iterator found = m_maps.upper_bound(addr); 148 - if (found == m_maps.begin() || found == m_maps.end()) 149 - return 0; 150 - 151 - --found; 152 - return found->second; 153 - } 154 - 155 - const FileMap::ImageMap* FileMap::imageMapForHeader(const mach_header* p) const 156 - { 157 - auto it = m_maps_mach.find(const_cast<mach_header*>(p)); 158 - if (it == m_maps_mach.end()) 159 - return nullptr; 160 - else 161 - return it->second; 162 - } 163 - 164 - /* 165 - const FileMap::ImageMap* FileMap::imageMapForName(const std::string& name) const 166 - { 167 - auto it = m_maps.find(name); 168 - if (it == m_maps.end()) 169 - return nullptr; 170 - else 171 - return it->second; 172 - } 173 - */ 174 - 175 - bool FileMap::findSymbolInfo(const void* p, Dl_info* info) const 176 - { 177 - uintptr_t addr = reinterpret_cast<uintptr_t>(p); 178 - const ImageMap* symbol_map; 179 - 180 - std::map<uintptr_t, ImageMap*>::const_iterator found = m_maps.upper_bound(addr); 181 - if (found == m_maps.begin() || found == m_maps.end()) 182 - return false; 183 - 184 - --found; 185 - symbol_map = found->second; 186 - 187 - std::map<uintptr_t, std::string>::const_iterator sfound = symbol_map->symbols.lower_bound(addr); 188 - if (sfound != symbol_map->symbols.begin()) 189 - { 190 - // found in lib and in symbols 191 - info->dli_sname = sfound->second.c_str(); 192 - info->dli_saddr = reinterpret_cast<void*>(sfound->first); 193 - } 194 - 195 - info->dli_fname = symbol_map->filename.c_str(); 196 - info->dli_fbase = reinterpret_cast<void*>(symbol_map->base); 197 - 198 - return true; 199 - } 200 -
-76
src/dyld/FileMap.h
··· 1 - /* 2 - This file is part of Darling. 3 - 4 - Copyright (C) 2012 Lubos Dolezel 5 - Copyright (C) 2011 Shinichiro Hamaji 6 - 7 - Darling is free software: you can redistribute it and/or modify 8 - it under the terms of the GNU General Public License as published by 9 - the Free Software Foundation, either version 3 of the License, or 10 - (at your option) any later version. 11 - 12 - Darling is distributed in the hope that it will be useful, 13 - but WITHOUT ANY WARRANTY; without even the implied warranty of 14 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 - GNU General Public License for more details. 16 - 17 - You should have received a copy of the GNU General Public License 18 - along with Darling. If not, see <http://www.gnu.org/licenses/>. 19 - */ 20 - 21 - #ifndef FILEMAP_H 22 - #define FILEMAP_H 23 - #include <stdint.h> 24 - #include <string> 25 - #include <map> 26 - #include <list> 27 - #include <libmach-o/MachO.h> 28 - #include <dlfcn.h> 29 - #include "../util/mutex.h" 30 - 31 - class FileMap 32 - { 33 - public: 34 - ~FileMap(); 35 - 36 - struct ImageMap; 37 - 38 - const ImageMap* add(const MachO& mach, uintptr_t slide, uintptr_t base, bool bindLazy); 39 - 40 - void addWatchDog(uintptr_t addr); 41 - 42 - struct ImageMap 43 - { 44 - std::string filename; 45 - std::map<uintptr_t, std::string> symbols; 46 - uintptr_t base, slide; 47 - mach_header* header; 48 - std::pair<uint64_t,uint64_t> eh_frame; 49 - std::pair<uint64_t,uint64_t> unwind_info; 50 - std::vector<MachO::Section> sections; 51 - std::vector<std::string> rpaths; 52 - 53 - std::list<MachO::Bind> lazy_binds; 54 - mutable Darling::Mutex mutex_lazy_binds; 55 - }; 56 - 57 - const ImageMap* imageMapForAddr(const void* p) const; 58 - const ImageMap* imageMapForHeader(const mach_header* p) const; 59 - // const ImageMap* imageMapForName(const std::string& name) const; 60 - const char* fileNameForAddr(const void* p) const; 61 - const char* gdbInfoForAddr(const void* p) const; 62 - bool findSymbolInfo(const void* addr, Dl_info* p) const; // used by __darwin_dladdr 63 - 64 - const std::vector<ImageMap*>& images() const { return m_maps_vec; } 65 - const ImageMap* mainExecutable() const; 66 - 67 - private: 68 - 69 - std::map<uintptr_t, ImageMap*> m_maps; 70 - std::map<mach_header*, ImageMap*> m_maps_mach; 71 - std::vector<ImageMap*> m_maps_vec; // for easier access 72 - mutable char m_dumped_stack_frame_buf[4096]; 73 - }; 74 - 75 - 76 - #endif
+12 -3
src/dyld/LoadableObject.cpp
··· 4 4 #include "NativeObject.h" 5 5 #include "arch.h" 6 6 7 + namespace Darling { 8 + 9 + LoadableObject::LoadableObject() 10 + { 11 + m_refs = 1; 12 + } 13 + 7 14 int LoadableObject::addRef() 8 15 { 9 - return __sync_add_and_fetch(&m_refs, 1); 16 + return ++m_refs; 10 17 } 11 18 12 19 int LoadableObject::delRef() 13 20 { 14 - int refs = __sync_add_and_fetch(&m_refs, -1); 15 - if (!refs) 21 + int refs = --m_refs; 22 + if (!refs && !m_noDelete) 16 23 { 17 24 unload(); 18 25 delete this; ··· 34 41 return new NativeObject(path); 35 42 } 36 43 } 44 + 45 + } // namespace Darling
+27 -11
src/dyld/LoadableObject.h
··· 2 2 #define LOADABLEOBJECT_H 3 3 #include <dlfcn.h> 4 4 #include <string> 5 + #include <atomic> 6 + 7 + namespace Darling { 5 8 6 9 class MachOObject; 7 10 8 11 class LoadableObject 9 12 { 10 13 protected: 14 + LoadableObject(); 11 15 virtual ~LoadableObject() {} 12 16 public: 13 - inline void setLoadAttributes(int attribs) { m_attribs = attribs; } 14 - 15 17 virtual void load() = 0; 16 18 virtual void unload() = 0; 19 + virtual bool isLoaded() const = 0; 17 20 18 21 virtual void* getExportedSymbol(const std::string& symbolName, bool nonWeakOnly = false) const = 0; 19 22 virtual bool findSymbolInfo(const void* addr, Dl_info* p) const = 0; 23 + 24 + // This must return const char* because of a couple of NS* functions 25 + virtual const char* name() const = 0; 26 + 27 + // Absolute path to this object 28 + virtual const std::string& path() const = 0; 20 29 21 30 int addRef(); 22 31 int delRef(); 32 + 33 + // Whether exports of this object should be available for symbol resolution of subsequently loaded libraries (RTLD_GLOBAL) 34 + inline void setGlobalExports(bool global) { m_globalExports = global; } 35 + bool globalExports() const { return m_globalExports; } 36 + 37 + // Whether all lazy references should be bound upon loading. 38 + // Setting this to true is equivatent to using RTLD_NOW. 39 + inline void setBindAllAtLoad(bool bindAll) { m_bindAllAtLoad = bindAll; } 40 + inline bool bindAllAtLoad() const { return m_bindAllAtLoad; } 41 + 42 + inline void setNoDelete(bool noDelete) { m_noDelete = noDelete; } 43 + inline bool noDelete() const { return m_noDelete; } 23 44 protected: 24 45 static LoadableObject* instantiateForPath(const std::string& path, MachOObject* requester); 25 46 protected: 26 - int m_refs = 1; 27 - int m_attribs = 0; 47 + std::atomic<int> m_refs; 48 + bool m_globalExports = true; 49 + bool m_bindAllAtLoad = false, m_noDelete = false; 28 50 }; 29 51 30 - #define DARWIN_RTLD_LAZY 0x1 31 - #define DARWIN_RTLD_NOW 0x2 32 - #define DARWIN_RTLD_LOCAL 0x4 33 - #define DARWIN_RTLD_GLOBAL 0x8 34 - #define DARWIN_RTLD_NOLOAD 0x10 35 - #define DARWIN_RTLD_NODELETE 0x80 36 - #define DARWIN_RTLD_FIRST 0x100 52 + } // namespace Darling 37 53 38 54 #endif
-925
src/dyld/MachOLoader.cpp
··· 1 - /* 2 - This file is part of Darling. 3 - 4 - Copyright (C) 2012-2013 Lubos Dolezel 5 - Copyright (C) 2011 Shinichiro Hamaji 6 - 7 - Darling is free software: you can redistribute it and/or modify 8 - it under the terms of the GNU General Public License as published by 9 - the Free Software Foundation, either version 3 of the License, or 10 - (at your option) any later version. 11 - 12 - Darling is distributed in the hope that it will be useful, 13 - but WITHOUT ANY WARRANTY; without even the implied warranty of 14 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 - GNU General Public License for more details. 16 - 17 - You should have received a copy of the GNU General Public License 18 - along with Darling. If not, see <http://www.gnu.org/licenses/>. 19 - */ 20 - 21 - #include "config.h" 22 - #include "MachOLoader.h" 23 - #include <libmach-o/MachO.h> 24 - #include "ld.h" 25 - #include "log.h" 26 - #include "trace.h" 27 - #include "FileMap.h" 28 - #include "stlutils.h" 29 - #include "public.h" 30 - #include "dyld.h" 31 - #include <limits.h> 32 - #include <iostream> 33 - #include <cstring> 34 - #include <cstdio> 35 - #include <cassert> 36 - #include <algorithm> 37 - #include <sstream> 38 - #include <stdexcept> 39 - #include <set> 40 - #include <sys/mman.h> 41 - #include <errno.h> 42 - #include <unistd.h> 43 - #include <dlfcn.h> 44 - #include <libgen.h> 45 - #include <pthread.h> 46 - #include "eh/EHSection.h" 47 - #include "TLS.h" 48 - 49 - FileMap g_file_map; 50 - static std::vector<std::string> g_bound_names; 51 - 52 - char g_darwin_loader_path[PATH_MAX] = ""; 53 - 54 - extern char g_darwin_executable_path[PATH_MAX], g_darwin_executable[PATH_MAX]; 55 - extern bool g_trampoline; 56 - extern bool g_noWeak; 57 - extern std::set<LoaderHookFunc*> g_machoLoaderHooks; 58 - extern MachOLoader* g_loader; 59 - 60 - // These are GCC internals 61 - extern "C" void __register_frame(void*); 62 - extern "C" void __unregister_frame(void*); 63 - 64 - static bool lookupDyldFunction(const char* name, void** addr) 65 - { 66 - LOG << "lookupDyldFunction: " << name <<std::endl; 67 - *addr = dlsym(dlopen(0, 0), name); 68 - 69 - if (!*addr) 70 - *addr = (void*) (void (*)()) []() { LOG << "Fake dyld function called\n"; }; 71 - 72 - return (*addr) != 0; 73 - } 74 - 75 - static uint64_t alignMem(uint64_t p, uint64_t a) 76 - { 77 - a--; 78 - return (p + a) & ~a; 79 - } 80 - 81 - MachOLoader::MachOLoader() 82 - : m_last_addr(0), m_pTrampolineMgr(0) 83 - { 84 - #ifdef DEBUG 85 - m_pUndefMgr = new UndefMgr; 86 - 87 - if (g_trampoline) 88 - { 89 - m_pTrampolineMgr = new TrampolineMgr; 90 - 91 - const char* info = getenv("TRAMPOLINE_INFO"); 92 - if (info) 93 - TrampolineMgr::loadFunctionInfo(info); 94 - } 95 - #endif 96 - 97 - static pthread_once_t once_control = PTHREAD_ONCE_INIT; 98 - pthread_once(&once_control, Darling::initLD); 99 - } 100 - 101 - MachOLoader::~MachOLoader() 102 - { 103 - } 104 - 105 - void MachOLoader::loadDylibs(const MachO& mach, bool nobind, bool bindLazy) 106 - { 107 - for (std::string dylib : mach.dylibs()) 108 - { 109 - // __darwin_dlopen checks if already loaded 110 - // automatically adds a reference if so 111 - 112 - int flags = DARWIN_RTLD_GLOBAL; 113 - if (nobind) 114 - flags |= __DARLING_RTLD_NOBIND; 115 - if (bindLazy) 116 - flags |= DARWIN_RTLD_LAZY; 117 - else 118 - flags |= DARWIN_RTLD_NOW; 119 - 120 - if (!Darling::DlopenWithContext(dylib.c_str(), flags, m_rpathContext)) 121 - { 122 - LOG << "Failed to dlopen " << dylib << ", throwing an exception\n"; 123 - std::stringstream ss; 124 - ss << "Cannot load " << dylib << ": " << __darwin_dlerror(); 125 - throw std::runtime_error(ss.str()); 126 - } 127 - } 128 - } 129 - 130 - void MachOLoader::doMProtect() 131 - { 132 - for (MProtect p : m_mprotects) 133 - ::mprotect(p.addr, p.len, p.prot); 134 - m_mprotects.clear(); 135 - } 136 - 137 - void MachOLoader::loadSegments(const MachO& mach, intptr* slide, intptr* base) 138 - { 139 - *base = 0; 140 - --*base; 141 - 142 - #ifdef DEBUG 143 - if (m_pTrampolineMgr) 144 - m_pTrampolineMgr->invalidateMemoryMap(); 145 - #endif 146 - 147 - const std::vector<Segment*>& segments = getSegments(mach); 148 - for (Segment* seg : segments) 149 - { 150 - const char* name = seg->segname; 151 - if (!strcmp(name, SEG_PAGEZERO)) 152 - continue; 153 - 154 - LOG << seg->segname << ": " << "fileoff=" << seg->fileoff << ", vmaddr=" << seg->vmaddr <<std::endl; 155 - 156 - int prot = 0, maxprot = 0; 157 - 158 - if (seg->initprot & VM_PROT_READ) 159 - prot |= PROT_READ; 160 - 161 - if (seg->initprot & VM_PROT_WRITE) 162 - prot |= PROT_WRITE; 163 - 164 - if (seg->initprot & VM_PROT_EXECUTE) 165 - prot |= PROT_EXEC; 166 - 167 - if (seg->maxprot & VM_PROT_READ) 168 - maxprot |= PROT_READ; 169 - 170 - if (seg->maxprot & VM_PROT_WRITE) 171 - maxprot |= PROT_WRITE; 172 - 173 - if (seg->maxprot & VM_PROT_EXECUTE) 174 - maxprot |= PROT_EXEC; 175 - 176 - 177 - intptr filesize = alignMem(seg->filesize, getpagesize()); 178 - intptr vmaddr = seg->vmaddr + *slide; 179 - 180 - if (vmaddr < m_last_addr) 181 - { 182 - LOG << "will rebase: filename=" << mach.filename() 183 - << ", vmaddr=" << (void*)vmaddr 184 - << ", last_addr=" << (void*)m_last_addr <<std::endl; 185 - assert(seg == segments[0]); 186 - vmaddr = m_last_addr; 187 - *slide = vmaddr - seg->vmaddr; 188 - } 189 - 190 - if (!vmaddr) 191 - throw std::runtime_error("Address 0x0 is invalid for mapping"); 192 - 193 - *base = std::min(*base, vmaddr); 194 - 195 - intptr vmsize = alignMem(seg->vmsize, getpagesize()); 196 - LOG << "mmap(file) " << mach.filename() << ' ' << name 197 - << ": " << (void*)vmaddr << "-" << (void*)(vmaddr + filesize) 198 - << " offset=" << mach.offset() + seg->fileoff <<std::endl; 199 - 200 - if (filesize == 0) 201 - continue; 202 - 203 - checkMmapMinAddr(vmaddr); 204 - 205 - void* mapped = ::mmap((void*)vmaddr, filesize, maxprot, MAP_PRIVATE | MAP_FIXED, mach.fd(), mach.offset() + seg->fileoff); 206 - 207 - m_mprotects.push_back(MProtect{(void*) vmaddr, filesize, prot}); 208 - 209 - if (mapped == MAP_FAILED) 210 - { 211 - std::stringstream ss; 212 - ss << "Failed to mmap '" << mach.filename() << "': " << strerror(errno); 213 - throw std::runtime_error(ss.str()); 214 - } 215 - 216 - assert(vmsize >= filesize); 217 - 218 - if (vmsize > filesize) 219 - { 220 - LOG << "mmap(anon) " << mach.filename() << ' ' << name 221 - << ": " << (void*)(vmaddr + filesize) << "-" 222 - << (void*)(vmaddr + vmsize) 223 - <<std::endl; 224 - 225 - void* mapped = ::mmap(reinterpret_cast<char*>(vmaddr) + filesize, vmsize - filesize, prot, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, 0); 226 - 227 - if (mapped == MAP_FAILED) 228 - { 229 - std::stringstream ss; 230 - ss << "mmap(anon) failed on '" << mach.filename() << "': " << strerror(errno); 231 - throw std::runtime_error(ss.str()); 232 - } 233 - } 234 - 235 - m_last_addr = std::max(m_last_addr, (intptr)vmaddr + vmsize); 236 - } 237 - } 238 - 239 - void MachOLoader::checkMmapMinAddr(intptr addr) 240 - { 241 - static intptr minimum = -1; 242 - if (minimum == intptr(-1)) 243 - { 244 - std::ifstream f("/proc/sys/vm/mmap_min_addr"); 245 - 246 - if (!f.is_open()) 247 - minimum = 0; 248 - else 249 - f >> minimum; 250 - } 251 - 252 - if (addr < minimum) 253 - { 254 - std::stringstream ss; 255 - ss << "Your vm.mmap_min_addr is too low for this application to be loaded. "; 256 - ss << "Try running `sysctl -w vm.mmap_min_addr=\"" << addr << "\"'"; 257 - throw std::runtime_error(ss.str()); 258 - } 259 - } 260 - 261 - void MachOLoader::doRebase(const MachO& mach, intptr slide) 262 - { 263 - for (const MachO::Rebase* rebase : mach.rebases()) 264 - { 265 - void* addr = reinterpret_cast<void*>(rebase->vmaddr + slide); 266 - switch (rebase->type) 267 - { 268 - case REBASE_TYPE_POINTER: 269 - { 270 - uintptr_t* ptr = reinterpret_cast<uintptr_t*>(addr); 271 - LOG << "rebase(ptr): " << addr << ' ' 272 - << (void*)*ptr << " => " 273 - << (void*)(*ptr + slide) << " @" << ptr <<std::endl; 274 - *ptr += slide; 275 - break; 276 - } 277 - case REBASE_TYPE_TEXT_ABSOLUTE32: 278 - { 279 - uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); 280 - LOG << "rebase(abs32): " << addr << ' ' 281 - << std::hex << *ptr << std::dec << " => " << (void*)(mach.fixEndian(*ptr) + slide) << std::endl; 282 - *ptr = mach.fixEndian(*ptr); 283 - *ptr += static_cast<uint32_t>(slide); 284 - break; 285 - } 286 - case REBASE_TYPE_TEXT_PCREL32: // TODO: test it 287 - { 288 - uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); 289 - LOG << "rebase(pcrel32): " << addr << ' ' 290 - << std::hex << *ptr << std::dec << " => " << (void*)(uintptr_t(addr) + 4 - mach.fixEndian(*ptr)) << std::endl; 291 - *ptr = mach.fixEndian(*ptr); 292 - *ptr = uintptr_t(addr) + 4 - (*ptr); 293 - break; 294 - } 295 - 296 - default: 297 - { 298 - std::stringstream ss; 299 - ss << "Unknown rebase type: " << int(rebase->type); 300 - 301 - throw std::runtime_error(ss.str()); 302 - } 303 - } 304 - } 305 - } 306 - 307 - void MachOLoader::doRelocations(const std::vector<MachO::Relocation*>& rels, intptr slide) 308 - { 309 - TRACE1(slide); 310 - m_lastResolvedSymbol.clear(); 311 - m_lastResolvedAddress = 0; 312 - 313 - for (const MachO::Relocation* rel : rels) 314 - { 315 - uintptr_t* ptr = (uintptr_t*) (uintptr_t(rel->addr) + slide); 316 - uintptr_t symbol; 317 - uintptr_t value = *ptr; 318 - 319 - symbol = getSymbolAddress(rel->name); 320 - 321 - value += symbol; 322 - 323 - #ifdef __i386__ 324 - if (rel->pcrel) 325 - { 326 - LOG << "reloc(pcrel): @" << ptr << " " << std::hex << *ptr << " -> " << (value - uintptr_t(ptr) - 4) << std::dec << std::endl; 327 - *ptr = value - uintptr_t(ptr) - 4; 328 - } 329 - else 330 - #endif 331 - { 332 - LOG << "reloc: @" << ptr << " " << std::hex << *ptr << " -> " << value << std::dec << std::endl; 333 - *ptr = value; 334 - } 335 - } 336 - } 337 - 338 - void MachOLoader::loadInitFuncs(const MachO& mach, intptr slide) 339 - { 340 - for (intptr addr : mach.init_funcs()) 341 - { 342 - addr += slide; 343 - LOG << "Registering init func " << (void*)addr << " from " << mach.filename() << std::endl; 344 - m_init_funcs.push_back(addr); 345 - } 346 - } 347 - 348 - void* MachOLoader::doBind(const std::vector<MachO::Bind*>& binds, intptr slide, bool resolveLazy) 349 - { 350 - std::string last_weak_name; 351 - uintptr_t last_weak_sym = 0; 352 - size_t seen_weak_bind_index = 0; 353 - size_t seen_weak_binds_orig_size = m_seen_weak_binds.size(); 354 - uintptr_t sym; 355 - 356 - g_bound_names.resize(binds.size()); 357 - 358 - m_lastResolvedSymbol.clear(); 359 - m_lastResolvedAddress = 0; 360 - 361 - for (const MachO::Bind* bind : binds) 362 - { 363 - if (bind->name.empty()) 364 - continue; // WTF... 365 - 366 - if (bind->is_lazy) 367 - { 368 - if (!resolveLazy) 369 - { 370 - LOG << "Delaying lazy bind resolution, offset=" << std::hex << bind->offset << std::dec << std::endl; 371 - continue; 372 - } 373 - else 374 - LOG << "Lazy bind resolution forced\n"; 375 - } 376 - 377 - if (bind->type == BIND_TYPE_POINTER || bind->type == BIND_TYPE_STUB) 378 - { 379 - std::string name = bind->name.substr(1); 380 - uintptr_t* ptr = (uintptr_t*)(bind->vmaddr + slide); 381 - 382 - sym = 0; 383 - 384 - // FIXME: This unholy mess needs to be fixed, weak bind handling shouldn't be implemented separately like this 385 - if (bind->is_weak) 386 - { 387 - if (g_noWeak) 388 - continue; 389 - if (last_weak_name == name) 390 - { 391 - sym = last_weak_sym; 392 - } 393 - else 394 - { 395 - last_weak_name = name; 396 - if (seen_weak_bind_index != seen_weak_binds_orig_size && !strcmp(m_seen_weak_binds[seen_weak_bind_index].first.c_str(), name.c_str())) 397 - { 398 - last_weak_sym = sym = 399 - m_seen_weak_binds[seen_weak_bind_index].second; 400 - seen_weak_bind_index++; 401 - } 402 - else 403 - { 404 - if (bind->is_classic) 405 - //if (false) 406 - { 407 - uintptr_t addr = bind->value; 408 - if (!addr) 409 - { 410 - LOG << "Trying to resolve classic,weak,null\n"; 411 - addr = (uintptr_t) __darwin_dlsym(__DARLING_RTLD_STRONG, name.c_str()); 412 - } 413 - LOG << "Bind (classic, weak) @" << ptr << " -> " << std::hex << uintptr_t(addr) << std::dec << std::endl; 414 - 415 - writeBind(bind->type, ptr, uintptr_t(addr)); 416 - last_weak_sym = uintptr_t(addr); 417 - } 418 - else 419 - { 420 - void* expAddr = __darwin_dlsym(__DARLING_RTLD_STRONG, name.c_str()); 421 - if (expAddr != nullptr) 422 - { 423 - LOG << "Weak reference overridden for " << name << std::endl; 424 - LOG << (void*)*ptr << " -> " << (void*)expAddr << " @" << ptr << std::endl; 425 - 426 - writeBind(bind->type, ptr, uintptr_t(expAddr)); 427 - 428 - *ptr = last_weak_sym = uintptr_t(expAddr); 429 - } 430 - else 431 - { 432 - LOG << "Weak reference not overriden for " << name << std::endl; 433 - last_weak_sym = *ptr; 434 - } 435 - } 436 - } 437 - 438 - m_seen_weak_binds.push_back(make_pair(name, last_weak_sym)); 439 - while (seen_weak_bind_index != seen_weak_binds_orig_size && strcmp(m_seen_weak_binds[seen_weak_bind_index].first.c_str(), name.c_str()) <= 0) 440 - seen_weak_bind_index++; 441 - 442 - continue; 443 - } 444 - } 445 - else // not weak 446 - { 447 - sym = getSymbolAddress(bind->name, bind, slide); 448 - 449 - if (!bind->is_classic) 450 - sym += bind->addend; 451 - } 452 - 453 - LOG << "bind " << bind->name << ": " 454 - << std::hex << *ptr << std::dec << " => " << (void*)sym << " @" << ptr << std::endl; 455 - #ifdef DEBUG 456 - if (g_trampoline) 457 - sym = (uintptr_t) m_pTrampolineMgr->generate((void*)sym, name.c_str()); 458 - #endif 459 - 460 - writeBind(bind->type, ptr, sym); 461 - } 462 - else 463 - { 464 - std::stringstream ss; 465 - ss << "Unknown bind type: " << bind->type; 466 - throw std::runtime_error(ss.str()); 467 - } 468 - } 469 - 470 - std::inplace_merge(m_seen_weak_binds.begin(), m_seen_weak_binds.begin() + seen_weak_binds_orig_size, m_seen_weak_binds.end()); 471 - 472 - // This return value is used by dyld_stub_binder 473 - return reinterpret_cast<void*>(sym); 474 - } 475 - 476 - uintptr_t MachOLoader::getSymbolAddress(const std::string& oname, const MachO::Bind* bind, intptr slide) 477 - { 478 - std::string name; 479 - uintptr_t sym; 480 - 481 - if (oname == m_lastResolvedSymbol) 482 - return m_lastResolvedAddress; 483 - if (bind && bind->is_classic && bind->is_local) 484 - return bind->value; 485 - 486 - if (oname[0] != '_') 487 - { 488 - // assume local (e.g. dyld_stub_binder) 489 - name = oname; 490 - sym = reinterpret_cast<uintptr_t>(dlsym(dlopen(0, 0), name.c_str())); 491 - } 492 - else 493 - { 494 - name = oname.substr(1); 495 - 496 - // TODO: remove, replace with aliases 497 - #ifndef __x86_64__ 498 - static const char* SUF_UNIX03 = "$UNIX2003"; 499 - static const size_t SUF_UNIX03_LEN = strlen(SUF_UNIX03); 500 - if (name.size() > SUF_UNIX03_LEN && !strcmp(name.c_str() + name.size() - SUF_UNIX03_LEN, SUF_UNIX03)) 501 - name = name.substr(0, name.size() - SUF_UNIX03_LEN); 502 - #endif 503 - sym = reinterpret_cast<uintptr_t>(__darwin_dlsym(DARWIN_RTLD_DEFAULT, name.c_str())); 504 - } 505 - 506 - if (!sym) 507 - { 508 - #ifdef DEBUG 509 - static const char* ign_sym = getenv("DYLD_IGN_MISSING_SYMS"); 510 - //if (!bind || !bind->is_classic || !bind->value) 511 - { 512 - if (ign_sym && atoi(ign_sym)) 513 - { 514 - std::cerr << "!!! Undefined symbol: " << name << std::endl; 515 - 516 - char* dname = new char[name.size()+1]; 517 - strcpy(dname, name.c_str()); 518 - 519 - sym = reinterpret_cast<uintptr_t>(m_pUndefMgr->generateNew(dname)); 520 - } 521 - else 522 - { 523 - std::stringstream ss; 524 - ss << "Undefined symbol: " << name; 525 - throw std::runtime_error(ss.str()); 526 - } 527 - } 528 - #endif 529 - //if (bind && bind->is_classic) 530 - // sym = uintptr_t(bind->value) + slide; 531 - } 532 - 533 - m_lastResolvedSymbol = oname; 534 - m_lastResolvedAddress = sym; 535 - 536 - return sym; 537 - } 538 - 539 - void MachOLoader::writeBind(int type, uintptr_t* ptr, uintptr_t newAddr) 540 - { 541 - if (type == BIND_TYPE_POINTER) 542 - *ptr = newAddr; 543 - 544 - #ifdef __i386__ 545 - else if (type == BIND_TYPE_STUB) 546 - { 547 - struct jmp_instr 548 - { 549 - uint8_t relJmp; 550 - uint32_t addr; 551 - } __attribute__((packed)); 552 - static_assert(sizeof(jmp_instr) == 5, "Incorrect jmp instruction size"); 553 - 554 - jmp_instr* instr = reinterpret_cast<jmp_instr*>(ptr); 555 - 556 - instr->relJmp = 0xE9; // x86 jmp rel32 557 - instr->addr = newAddr - uint32_t(ptr) - sizeof(jmp_instr); 558 - } 559 - #endif 560 - } 561 - 562 - void MachOLoader::loadExports(const MachO& mach, intptr slide, Exports* exports) 563 - { 564 - exports->rehash(exports->size() + mach.exports().size()); 565 - 566 - for (MachO::Export* exp : mach.exports()) 567 - { 568 - //std::cout << "EXP: " << exp->name << std::endl; 569 - exp->addr += slide; 570 - if (exp->resolver) // EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER support 571 - exp->resolver += slide; 572 - 573 - // TODO(hamaji): Not 100% sure, but we may need to consider weak symbols. 574 - if (!exports->insert(make_pair(exp->name, *exp)).second) 575 - { 576 - // Until we support two-level namespaces, duplicate symbols may happen where they would not happen on Darwin. 577 - // In this case we simply use the first known symbol. 578 - LOG << "Warning: duplicate exported symbol name: " << exp->name << " in " << mach.filename() << std::endl; 579 - } 580 - } 581 - } 582 - 583 - const std::string& MachOLoader::getCurrentLoader() const 584 - { 585 - assert(!m_loaderPath.empty()); 586 - return m_loaderPath.top(); 587 - } 588 - 589 - void MachOLoader::pushCurrentLoader(const char* currentLoader) 590 - { 591 - char path[4096]; 592 - strcpy(path, currentLoader); 593 - // @loader_path contains the directory where the Mach-O file currently loading other libraries resides 594 - m_loaderPath.push(dirname(path)); 595 - } 596 - 597 - void MachOLoader::popCurrentLoader() 598 - { 599 - m_loaderPath.pop(); 600 - } 601 - 602 - void MachOLoader::load(const MachO& mach, std::string sourcePath, Exports* exports, bool bindLater, bool bindLazy) 603 - { 604 - intptr slide = 0; 605 - intptr base = 0, segmentBase; 606 - const FileMap::ImageMap* img; 607 - size_t origRpathCount; 608 - 609 - m_exports.push_back(exports); 610 - pushCurrentLoader(sourcePath.c_str()); 611 - 612 - loadSegments(mach, &slide, &base); 613 - 614 - doRebase(mach, slide); 615 - 616 - origRpathCount = m_rpathContext.size(); 617 - 618 - for (const char* rpath : mach.rpaths()) 619 - m_rpathContext.push_back(rpath); 620 - loadDylibs(mach, bindLater, bindLazy); 621 - m_rpathContext.resize(origRpathCount); 622 - 623 - loadInitFuncs(mach, slide); 624 - 625 - loadExports(mach, slide, exports); 626 - fillInProgramVars(exports); 627 - 628 - img = g_file_map.add(mach, slide, base, bindLazy); 629 - 630 - if (!bindLater) 631 - doBind(mach.binds(), slide, !bindLazy); 632 - 633 - doRelocations(mach.relocations(), slide); 634 - doMProtect(); // decrease the segment protection value 635 - 636 - if (!bindLater) 637 - { 638 - setupTLS(mach, img, slide); 639 - for (LoaderHookFunc* func : g_machoLoaderHooks) 640 - func(img->header, slide); 641 - } 642 - else 643 - { 644 - LOG << mach.binds().size() << " binds pending\n"; 645 - m_pendingBinds.push_back(PendingBind{ &mach, img->header, slide, bindLazy }); 646 - m_pendingTLS.push_back(PendingTLS { &mach, img, slide} ); 647 - } 648 - 649 - popCurrentLoader(); 650 - } 651 - 652 - void MachOLoader::fillInProgramVars(Exports* exports) 653 - { 654 - auto it = exports->find("_NXArgc"); 655 - if (it != exports->end()) 656 - *((int*)it->second.addr) = g_argc; 657 - 658 - it = exports->find("_NXArgv"); 659 - if (it != exports->end()) 660 - *((char***)it->second.addr) = g_argv; 661 - 662 - it = exports->find("_environ"); 663 - if (it != exports->end()) 664 - *((char***)it->second.addr) = environ; 665 - 666 - it = exports->find("___progname"); 667 - if (it != exports->end()) 668 - *((const char**)it->second.addr) = g_argv[0]; 669 - } 670 - 671 - void MachOLoader::doPendingTLS() 672 - { 673 - for (PendingTLS& tls : m_pendingTLS) 674 - setupTLS(*tls.mach, tls.img, tls.slide); 675 - 676 - m_pendingTLS.clear(); 677 - } 678 - 679 - void MachOLoader::setupTLS(const MachO& mach, const FileMap::ImageMap* image, intptr slide) 680 - { 681 - std::vector<tlv_descriptor*> descriptors; 682 - const std::vector<MachO::TLVSection>& tlvSections = mach.tlv_sections(); 683 - std::vector<void*> initializers; 684 - 685 - if (tlvSections.empty()) 686 - return; 687 - 688 - for (MachO::TLVSection sect : tlvSections) 689 - { 690 - tlv_descriptor* des = reinterpret_cast<tlv_descriptor*>(sect.firstDescriptor+slide); 691 - for (size_t i = 0; i < sect.count; i++) 692 - descriptors.push_back(&des[i]); 693 - } 694 - 695 - for (uint64_t offset : mach.tlv_init_funcs()) 696 - initializers.push_back((void*) (offset+slide)); 697 - 698 - Darling::TLSSetup((void*) image, descriptors, initializers, (void*) mach.tlv_initial_values().first, mach.tlv_initial_values().second); 699 - } 700 - 701 - void MachOLoader::doPendingBinds() 702 - { 703 - for (const PendingBind& b : m_pendingBinds) 704 - { 705 - LOG << "Perform " << b.macho->binds().size() << " binds\n"; 706 - doBind(b.macho->binds(), b.slide, b.bindLazy); 707 - 708 - auto eh_frame = b.macho->get_eh_frame(); 709 - if (eh_frame.first) 710 - { 711 - try 712 - { 713 - EHSection ehSection; 714 - void *reworked_eh_data, *original_eh_data; 715 - 716 - // On Darwin/i386, esp and ebp register numbers are swapped 717 - #ifdef __i386__ 718 - static const std::map<int, int> regSwap = { 719 - std::make_pair<int, int>(4, 5), 720 - std::make_pair<int, int>(5, 4) 721 - }; 722 - #endif 723 - 724 - original_eh_data = (void*) (eh_frame.first + b.slide); 725 - LOG << "Reworking __eh_frame at " << original_eh_data << std::endl; 726 - 727 - ehSection.load(original_eh_data, eh_frame.second); 728 - 729 - #ifdef __i386__ 730 - ehSection.swapRegisterNumbers(regSwap); 731 - #endif 732 - 733 - ehSection.store(&reworked_eh_data, nullptr); 734 - 735 - LOG << "Registering reworked __eh_frame at " << reworked_eh_data << std::endl; 736 - __register_frame(reworked_eh_data); // TODO: free when unloading the image 737 - } 738 - catch (const std::exception& e) 739 - { 740 - LOG << "Failed to rework the __eh_frame: " << e.what() << std::endl; 741 - LOG << "Exception handling WILL NOT WORK!\n"; 742 - } 743 - } 744 - 745 - for (LoaderHookFunc* func : g_machoLoaderHooks) 746 - func(b.header, b.slide); 747 - } 748 - m_pendingBinds.clear(); 749 - } 750 - 751 - void MachOLoader::setupDyldData(const MachO& mach) 752 - { 753 - if (!mach.dyld_data()) 754 - return; 755 - 756 - void** dyld_data = (void**)mach.dyld_data(); 757 - dyld_data[1] = reinterpret_cast<void*>(&lookupDyldFunction); 758 - } 759 - 760 - void MachOLoader::runPendingInitFuncs(int argc, char** argv, char** envp, char** apple) 761 - { 762 - for (size_t i = 0; i < m_init_funcs.size(); i++) 763 - { 764 - void** init_func = (void**) m_init_funcs[i]; 765 - LOG << "calling initializer function " << *init_func << std::endl; 766 - 767 - // TODO: missing ProgramVars! http://blogs.embarcadero.com/eboling/2010/01/29/5639/ 768 - // This struct can be retrieved by looking up section "__program_vars" in main app 769 - /* 770 - * struct ProgramVars { 771 - const void* mh; 772 - int* NXArgcPtr; 773 - const char*** NXArgvPtr; 774 - const char*** environPtr; 775 - const char** __prognamePtr; 776 - }; 777 - */ 778 - 779 - if (argc >= 0) 780 - ((void(*)(int, char**, char**, char**))*init_func)(argc, argv, envp, apple); 781 - else 782 - ((void(*)())*init_func)(); // ?! 783 - } 784 - m_init_funcs.clear(); 785 - } 786 - 787 - 788 - void MachOLoader::run(MachO& mach, int argc, char** argv, char** envp, bool bindLazy) 789 - { 790 - char* apple[2] = { g_darwin_executable, 0 }; 791 - std::vector<char*> envCopy; 792 - 793 - //for (int i = 0; envp[i]; i++) 794 - // envCopy.push_back(envp[i]); 795 - envCopy.push_back(0); 796 - 797 - m_mainExports = new Exports; 798 - load(mach, g_darwin_executable, m_mainExports, true, bindLazy); 799 - setupDyldData(mach); 800 - 801 - g_file_map.addWatchDog(m_last_addr + 1); 802 - 803 - //g_timer.print(mach.filename().c_str()); 804 - 805 - doPendingBinds(); 806 - doPendingTLS(); 807 - runPendingInitFuncs(argc, argv, &envCopy[0], apple); 808 - 809 - mach.close(); 810 - 811 - fflush(stdout); 812 - assert(argc > 0); 813 - 814 - if (mach.entry()) 815 - { 816 - LOG << "booting from " << (void*)mach.entry() << "..." << std::endl; 817 - LOG << "==========\n"; 818 - boot(mach.entry(), argc, argv, envp, apple); 819 - } 820 - else if (mach.main()) 821 - { 822 - LOG << "running main at " << (void*) mach.main() << "...\n"; 823 - LOG << "==========\n"; 824 - 825 - int (*pMain)(int, char**, char**, char**) = reinterpret_cast<int (*)(int, char**, char**, char**)>(mach.main()); 826 - 827 - int rv = pMain(argc, argv, envp, apple); 828 - exit(rv); 829 - } 830 - else 831 - throw std::runtime_error("No entry point found"); 832 - } 833 - 834 - static inline int findLast(char** array) 835 - { 836 - for (int i = 0; ; i++) 837 - { 838 - if (!array[i]) 839 - return i; 840 - } 841 - } 842 - 843 - void MachOLoader::boot( uint64_t entry, int argc, char** argv, char** envp, char** apple) 844 - { 845 - #ifdef __x86_64__ 846 - # define PUSH(val) __asm__ volatile("pushq %0" :: "r"(uint64_t(val)) :) 847 - # define JUMP(addr) __asm__ volatile("jmpq *%0" :: "m"(addr) :) 848 - #else 849 - # define PUSH(val) __asm__ volatile("pushl %0" :: "r"(uint32_t(val)) :) 850 - # define JUMP(addr) __asm__ volatile("jmp *%0" :: "r"(addr) :) 851 - #endif 852 - 853 - for (int i = findLast(apple); i >= 0; i--) 854 - PUSH(apple[i]); 855 - 856 - for (int i = findLast(envp); i >= 0; i--) 857 - PUSH(envp[i]); 858 - 859 - assert(!argv[argc]); 860 - 861 - for (int i = argc; i >= 0; i--) 862 - PUSH(argv[i]); 863 - 864 - PUSH(argc); 865 - JUMP(entry); 866 - } 867 - 868 - extern "C" void* dyld_stub_binder_fixup(const FileMap::ImageMap** imageMap, uintptr_t lazyOffset) 869 - { 870 - if (!*imageMap) 871 - { 872 - LOG << "Finding image for address " << imageMap << std::endl; 873 - *imageMap = g_file_map.imageMapForAddr((void*) imageMap); 874 - 875 - if (!*imageMap) 876 - { 877 - std::cerr << "dyld_stub_binder_fixup(): Image map not found for " << imageMap << std::endl; 878 - abort(); 879 - } 880 - } 881 - 882 - std::vector<MachO::Bind*> toBind; // will hold only the single item we need to bind 883 - 884 - (*imageMap)->mutex_lazy_binds.lock(); 885 - 886 - for (auto it = (*imageMap)->lazy_binds.begin(); it != (*imageMap)->lazy_binds.end(); it++) 887 - { 888 - if (it->offset == lazyOffset) 889 - { 890 - toBind.push_back(const_cast<MachO::Bind*>(&*it)); 891 - break; 892 - } 893 - } 894 - 895 - if (toBind.empty()) 896 - { 897 - std::cerr << "dyld_stub_binder_fixup(): Lazy bind not found for offset " << std::hex << lazyOffset << std::dec << std::endl; 898 - abort(); 899 - } 900 - 901 - void* addr; 902 - try 903 - { 904 - addr = g_loader->doBind(toBind, (*imageMap)->slide, true); 905 - } 906 - catch (const std::exception& e) 907 - { 908 - std::cerr << "dyld_stub_binder_fixup(): Failed to resolve the symbol: " << e.what() << std::endl; 909 - abort(); 910 - } 911 - 912 - (*imageMap)->mutex_lazy_binds.unlock(); 913 - return addr; 914 - } 915 - 916 - #ifdef DEBUG 917 - // GDB helper 918 - extern "C" const char* dumpSymbol(void* p) 919 - { 920 - return g_file_map.gdbInfoForAddr(p); 921 - } 922 - #endif 923 - 924 - 925 -
-164
src/dyld/MachOLoader.h
··· 1 - /* 2 - This file is part of Darling. 3 - 4 - Copyright (C) 2012 Lubos Dolezel 5 - Copyright (C) 2011 Shinichiro Hamaji 6 - 7 - Darling is free software: you can redistribute it and/or modify 8 - it under the terms of the GNU General Public License as published by 9 - the Free Software Foundation, either version 3 of the License, or 10 - (at your option) any later version. 11 - 12 - Darling is distributed in the hope that it will be useful, 13 - but WITHOUT ANY WARRANTY; without even the implied warranty of 14 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 - GNU General Public License for more details. 16 - 17 - You should have received a copy of the GNU General Public License 18 - along with Darling. If not, see <http://www.gnu.org/licenses/>. 19 - */ 20 - 21 - #ifndef MACHOLOADER_H 22 - #define MACHOLOADER_H 23 - #include <vector> 24 - #include <string> 25 - #include <map> 26 - #include <utility> 27 - #include <stack> 28 - #include <stdint.h> 29 - #include <libmach-o/MachO.h> 30 - #include "arch.h" 31 - #include "ld.h" 32 - #include "UndefinedFunction.h" 33 - #include "Trampoline.h" 34 - #include "FileMap.h" 35 - 36 - class MachOLoader 37 - { 38 - #ifdef __x86_64__ 39 - public: 40 - typedef segment_command_64 Segment; 41 - private: 42 - static inline const std::vector<Segment*>& getSegments(const MachO& mach) { return mach.segments64(); } 43 - #else 44 - public: 45 - typedef segment_command Segment; 46 - private: 47 - static inline const std::vector<Segment*>& getSegments(const MachO& mach) { return mach.segments(); } 48 - #endif 49 - 50 - public: 51 - MachOLoader(); 52 - ~MachOLoader(); 53 - 54 - // Maps module segments into the memory 55 - void loadSegments(const MachO& mach, intptr* slide, intptr* base); 56 - 57 - 58 - void doRebase(const MachO& mach, intptr slide); 59 - 60 - // Puts initializer functions of that module into the list of initializers to be run 61 - void loadInitFuncs(const MachO& mach, intptr slide); 62 - 63 - // Loads libraries this module depends on 64 - void loadDylibs(const MachO& mach, bool nobinds, bool bindLazy); 65 - 66 - // Resolves all external symbols required by this module 67 - void* doBind(const std::vector<MachO::Bind*>& binds, intptr slide, bool resolveLazy = false); 68 - 69 - // Binds external relocations 70 - void doRelocations(const std::vector<MachO::Relocation*>& rels, intptr slide); 71 - 72 - // Calls mprotect() to switch segment protections to the "initial" value. 73 - // We initially set the maximum value. 74 - void doMProtect(); 75 - 76 - // Creates a list of publicly visible functions in this module 77 - void loadExports(const MachO& mach, intptr slide, Exports* exports); 78 - 79 - // Loads a Mach-O file and does all the processing 80 - void load(const MachO& mach, std::string sourcePath, Exports* exports = 0, bool bindLater = false, bool bindLazy = false); 81 - 82 - // Dyld data contains an accessor to internal dyld functionality. This stores the accessor pointer. 83 - void setupDyldData(const MachO& mach); 84 - 85 - // Runs initializer functions that have not been run yet 86 - void runPendingInitFuncs(int argc, char** argv, char** envp, char** apple); 87 - 88 - // Performs pending binds. Used when loading the main executable and its dependencies. 89 - void doPendingBinds(); 90 - 91 - void doPendingTLS(); 92 - 93 - // Processes information from MachO and calls the TLS infrastructure to set things up 94 - void setupTLS(const MachO& mach, const FileMap::ImageMap* img, intptr slide); 95 - 96 - // Starts an application 97 - void run(MachO& mach, int argc, char** argv, char** envp, bool bindLazy = false); 98 - 99 - const std::list<Exports*>& getExports() const { return m_exports; } 100 - Exports* getMainExecutableExports() const { return m_mainExports; } 101 - 102 - // Gets the path to the currently loaded Mach-O file 103 - const std::string& getCurrentLoader() const; 104 - 105 - private: 106 - // Jumps to the application entry 107 - void boot(uint64_t entry, int argc, char** argv, char** envp, char** apple); 108 - 109 - void writeBind(int type, uintptr_t* ptr, uintptr_t newAddr); 110 - // The name should include the extra underscore at the beginning 111 - uintptr_t getSymbolAddress(const std::string& name, const MachO::Bind* bind = nullptr, intptr slide = 0); 112 - 113 - // checks sysctl mmap_min_addr 114 - static void checkMmapMinAddr(intptr addr); 115 - void pushCurrentLoader(const char* currentLoader); 116 - void popCurrentLoader(); 117 - 118 - void fillInProgramVars(Exports* exports); 119 - private: 120 - intptr m_last_addr; 121 - std::vector<uint64_t> m_init_funcs; 122 - std::list<Exports*> m_exports; 123 - Exports* m_mainExports; 124 - std::vector<std::pair<std::string, uintptr_t> > m_seen_weak_binds; 125 - UndefMgr* m_pUndefMgr; 126 - TrampolineMgr* m_pTrampolineMgr; 127 - 128 - // Pending calls to mprotect 129 - struct MProtect 130 - { 131 - void* addr; 132 - size_t len; 133 - int prot; 134 - }; 135 - std::vector<MProtect> m_mprotects; 136 - 137 - // Pending libs that require binding 138 - struct PendingBind 139 - { 140 - const MachO* macho; 141 - const mach_header* header; 142 - intptr slide; 143 - bool bindLazy; 144 - }; 145 - std::vector<PendingBind> m_pendingBinds; 146 - 147 - // Pending TLS variables 148 - // Because of initializers, we need to run them after the binds are done 149 - struct PendingTLS 150 - { 151 - const MachO* mach; 152 - const FileMap::ImageMap* img; 153 - intptr slide; 154 - }; 155 - std::vector<PendingTLS> m_pendingTLS; 156 - 157 - std::vector<std::string> m_rpathContext; 158 - std::stack<std::string> m_loaderPath; 159 - 160 - std::string m_lastResolvedSymbol; 161 - uintptr_t m_lastResolvedAddress; 162 - }; 163 - 164 - #endif
+174 -33
src/dyld/MachOMgr.cpp
··· 3 3 #include <algorithm> 4 4 #include <bits/wordsize.h> 5 5 #include "MachOObject.h" 6 + #include "NativeObject.h" 7 + #include <dlfcn.h> 8 + 9 + namespace Darling { 6 10 7 11 MachOMgr::MachOMgr() 8 12 : m_mainModule(nullptr), m_bindAtLaunch(false), m_printInitializers(false), 9 - m_printLibraries(false), m_useTrampolines(false), m_ignoreMissingSymbols(false) 13 + m_printLibraries(false), 14 + m_printSegments(false), m_printBindings(false), m_printRpathExpansion(false), 15 + m_pUndefMgr(nullptr), m_pTrampolineMgr(nullptr), m_addedDefaultLoader(false) 10 16 { 11 17 } 12 18 13 19 MachOMgr::~MachOMgr() 14 20 { 15 - while (!m_objects.empty()) 21 + if (m_mainModule) 22 + m_mainModule->unload(); 23 + 24 + while (!m_loadablesInOrder.empty()) 16 25 { 17 - MachOObject* obj = m_objectsInOrder.front(); 26 + LoadableObject* obj = m_loadablesInOrder.front(); 18 27 obj->unload(); 19 28 } 20 29 } ··· 31 40 32 41 if (m_objects.empty()) 33 42 { 34 - // This is normally used only for: 35 - // a) DYLD_PRELOAD 36 - // b) Standalone use of libdyld 37 - 38 - #if (__WORDSIZE == 64) 39 - return (void*) 0x200000000L; 40 - #else 41 - return (void*) 0x1000000; 42 - #endif 43 + return nullptr; 43 44 } 44 45 else 45 46 { ··· 55 56 56 57 auto it = m_objects.upper_bound(addr); 57 58 58 - if (it == m_objects.begin() || it == m_objects.end()) 59 + if (it == m_objects.begin()) 59 60 return nullptr; 60 61 61 62 it--; 63 + 64 + if (it->second->maxAddress() < addr) 65 + return nullptr; 66 + 62 67 return it->second; 63 68 } 64 69 70 + void MachOMgr::registerLoadHook(LoaderHookFunc* func) 71 + { 72 + Darling::RWMutexWriteLock l(m_lock); 73 + 74 + m_loadHooks.insert(func); 75 + } 76 + 77 + void MachOMgr::registerUnloadHook(LoaderHookFunc* func) 78 + { 79 + Darling::RWMutexWriteLock l(m_lock); 80 + 81 + m_unloadHooks.insert(func); 82 + } 83 + 65 84 void MachOMgr::add(MachOObject* obj, bool mainModule) 66 85 { 67 86 Darling::RWMutexWriteLock l(m_lock); 87 + 88 + if (!m_addedDefaultLoader && mainModule) 89 + { 90 + add(new NativeObject(RTLD_DEFAULT, "<default>")); 91 + m_addedDefaultLoader = true; 92 + } 68 93 69 94 m_objects[obj->baseAddress()] = obj; 70 95 m_objectNames[obj->path()] = obj; 96 + m_objectHeaders[obj->getMachHeader()] = obj; 71 97 m_objectsInOrder.push_back(obj); 98 + m_loadablesInOrder.push_back(obj); 72 99 73 100 if (mainModule) 74 101 { 75 102 assert(m_mainModule == nullptr); 76 103 m_mainModule = obj; 77 104 } 78 - 79 - // TODO: add support for loader hooks 80 105 } 81 106 82 - template <typename Key, typename Value> void mapEraseByValue(std::map<Key, Value>& map, const Value& v) 107 + void MachOMgr::notifyAdd(MachOObject* obj) 83 108 { 84 - for (auto it = map.begin(); it != map.end(); it++) 85 - { 86 - if (it->second == v) 87 - { 88 - map.erase(it); 89 - break; 90 - } 91 - } 109 + assert(m_objects.find(obj->baseAddress()) != m_objects.end()); 110 + 111 + for (LoaderHookFunc* func : m_loadHooks) 112 + func(obj->getMachHeader(), obj->slide()); 92 113 } 93 114 94 115 void MachOMgr::remove(MachOObject* obj) 95 116 { 96 117 Darling::RWMutexWriteLock l(m_lock); 97 118 98 - // slow! 99 - mapEraseByValue(m_objects, obj); 100 - mapEraseByValue(m_objectNames, obj); 119 + for (LoaderHookFunc* func : m_unloadHooks) 120 + func(obj->getMachHeader(), obj->slide()); 121 + 122 + m_objects.erase(obj->baseAddress()); 123 + m_objectNames.erase(obj->path()); 124 + m_objectHeaders.erase(obj->getMachHeader()); 101 125 102 126 auto it = std::find(m_objectsInOrder.begin(), m_objectsInOrder.end(), obj); 103 127 if (it != m_objectsInOrder.end()) 104 128 m_objectsInOrder.erase(it); 129 + 130 + auto itl = std::find(m_loadablesInOrder.begin(), m_loadablesInOrder.end(), obj); 131 + if (itl != m_loadablesInOrder.end()) 132 + m_loadablesInOrder.erase(itl); 105 133 106 134 if (m_mainModule == obj) 107 135 m_mainModule = nullptr; 136 + } 137 + 138 + void MachOMgr::add(NativeObject* obj) 139 + { 140 + m_loadablesInOrder.push_back(obj); 141 + m_nativeRefToObject[obj->nativeRef()] = obj; 142 + } 143 + 144 + void MachOMgr::remove(NativeObject* obj) 145 + { 146 + auto it = std::find(m_loadablesInOrder.begin(), m_loadablesInOrder.end(), obj); 147 + if (it != m_loadablesInOrder.end()) 148 + m_loadablesInOrder.erase(it); 149 + m_nativeRefToObject.erase(obj->nativeRef()); 150 + } 151 + 152 + MachOObject* MachOMgr::objectByIndex(size_t index) 153 + { 154 + Darling::RWMutexReadLock l(m_lock); 108 155 109 - // TODO: add support for loader hooks 156 + if (index >= m_objectsInOrder.size()) 157 + return nullptr; 158 + else 159 + return m_objectsInOrder[index]; 110 160 } 111 161 112 - void* MachOMgr::getExportedSymbol(const std::string& symbolName) 162 + MachOObject* MachOMgr::objectByHeader(struct mach_header* hdr) 113 163 { 164 + Darling::RWMutexReadLock l(m_lock); 165 + 166 + auto it = m_objectHeaders.find(hdr); 167 + if (it == m_objectHeaders.end()) 168 + return nullptr; 169 + else 170 + return it->second; 171 + } 172 + 173 + NativeObject* MachOMgr::objectByNativeRef(void* nativeRef) 174 + { 175 + auto it = m_nativeRefToObject.find(nativeRef); 176 + if (it == m_nativeRefToObject.end()) 177 + return nullptr; 178 + else 179 + return it->second; 180 + } 181 + 182 + void* MachOMgr::getExportedSymbol(const std::string& symbolName, LoadableObject* nextAfter) 183 + { 184 + Darling::RWMutexReadLock l(m_lock); 114 185 void* weak = nullptr; 115 - for (MachOObject* obj : m_objectsInOrder) 186 + bool isAfter = false; 187 + 188 + // TODO: add default loader if missing 189 + 190 + for (auto it = m_loadablesInOrder.begin(); it != m_loadablesInOrder.end(); it++) 116 191 { 117 - void* p = obj->getExportedSymbol(symbolName, true); // try non-weak only 192 + void* p; 193 + 194 + if (nextAfter && !isAfter) 195 + { 196 + if (*it == nextAfter) 197 + isAfter = true; 198 + 199 + continue; 200 + } 201 + 202 + if (!(*it)->globalExports()) 203 + continue; 204 + 205 + p = (*it)->getExportedSymbol(symbolName, true); // try non-weak only 118 206 if (p) 119 207 return p; 120 208 121 209 if (!weak) 122 - weak = obj->getExportedSymbol(symbolName, false); // save the first weak export as a fallback 210 + weak = (*it)->getExportedSymbol(symbolName, false); // save the first weak export as a fallback 123 211 } 124 212 125 213 return weak; 126 214 } 127 215 128 - MachOObject* MachOMgr::lookup(const std::string& absolutePath) 216 + LoadableObject* MachOMgr::lookup(const std::string& absolutePath) 129 217 { 218 + Darling::RWMutexReadLock l(m_lock); 219 + 130 220 auto it = m_objectNames.find(absolutePath); 131 221 if (it != m_objectNames.end()) 132 222 return it->second; ··· 134 224 return nullptr; 135 225 } 136 226 227 + bool MachOMgr::detectSysRootFromPath(std::string path) 228 + { 229 + if (path.empty()) 230 + return false; 231 + if (path[0] != '/') 232 + { 233 + char* rp = realpath(path.c_str(), nullptr); 234 + if (!rp) 235 + return false; 236 + 237 + path = rp; 238 + free(rp); 239 + } 240 + 241 + size_t pos = path.find("/usr/"); 242 + if (pos != std::string::npos && pos != 0) 243 + { 244 + m_sysroot = path.substr(0, pos); 245 + return true; 246 + } 247 + 248 + return false; 249 + } 250 + 251 + void MachOMgr::setUseTrampolines(bool useTrampolines, const std::string& funcInfo) 252 + { 253 + delete m_pTrampolineMgr; 254 + 255 + if (useTrampolines) 256 + { 257 + m_pTrampolineMgr = new TrampolineMgr; 258 + m_pTrampolineMgr->loadFunctionInfo(funcInfo.c_str()); 259 + } 260 + else 261 + { 262 + m_pTrampolineMgr = nullptr; 263 + } 264 + } 265 + 266 + void MachOMgr::setIgnoreMissingSymbols(bool ignoreMissingSymbols) 267 + { 268 + delete m_pUndefMgr; 269 + 270 + if (ignoreMissingSymbols) 271 + m_pUndefMgr = new UndefMgr; 272 + else 273 + m_pUndefMgr = nullptr; 274 + } 275 + 276 + } // namespace Darling 277 +
+65 -11
src/dyld/MachOMgr.h
··· 3 3 #include <stdint.h> 4 4 #include <map> 5 5 #include <string> 6 - #include <list> 6 + #include <vector> 7 + #include <set> 7 8 #include <util/rwmutex.h> 8 9 #include "UndefinedFunction.h" 9 10 #include "Trampoline.h" 10 11 12 + struct mach_header; 13 + 14 + namespace Darling { 15 + 11 16 class MachOObject; 17 + class LoadableObject; 18 + class NativeObject; 12 19 13 20 class MachOMgr 14 21 { ··· 32 39 void remove(MachOObject* obj); 33 40 34 41 // Returns a loaded MachOObject for a given absolute path 35 - MachOObject* lookup(const std::string& absolutePath); 42 + LoadableObject* lookup(const std::string& absolutePath); 36 43 37 44 // Returns the main executable module - the one you can call run() on 38 45 MachOObject* mainModule() { return m_mainModule; } 39 46 40 47 // Searches all loaded modules for an exported symbol, prefering non-weak symbols 41 - void* getExportedSymbol(const std::string& symbolName); 48 + void* getExportedSymbol(const std::string& symbolName, LoadableObject* nextAfter = nullptr); 49 + 50 + typedef void (LoaderHookFunc)(const struct ::mach_header* mh, intptr_t vmaddr_slide); 51 + 52 + // Register callbacks to be invoked when a image is loaded or unloaded 53 + void registerLoadHook(LoaderHookFunc* func); 54 + void registerUnloadHook(LoaderHookFunc* func); 42 55 43 56 // DYLD_BIND_AT_LAUNCH 44 57 inline void setBindAtLaunch(bool bindAtLaunch) { m_bindAtLaunch = bindAtLaunch; } 45 - inline bool bindAtLaunch() const { return m_bindAtLaunch || m_useTrampolines; } 58 + inline bool bindAtLaunch() const { return m_bindAtLaunch || useTrampolines(); } 46 59 47 60 // DYLD_PRINT_INITIALIZERS 48 61 inline void setPrintInitializers(bool printInitializers) { m_printInitializers = printInitializers; } ··· 57 70 inline const std::string& libraryPath() const { return m_libraryPath; } 58 71 59 72 // Darling specific: DYLD_TRAMPOLINES 60 - inline void setUseTrampolines(bool useTrampolines) { m_useTrampolines = useTrampolines; } 61 - inline bool useTrampolines() const { return m_useTrampolines; } 73 + void setUseTrampolines(bool useTrampolines, const std::string& funcInfo); 74 + inline bool useTrampolines() const { return m_pTrampolineMgr != nullptr; } 62 75 63 76 // Darling specific: DYLD_IGN_MISSING_SYMS 64 - inline void setIgnoreMissingSymbols(bool ignoreMissingSymbols) { m_ignoreMissingSymbols = ignoreMissingSymbols; } 65 - inline bool ignoreMissingSymbols() const { return m_ignoreMissingSymbols; } 77 + void setIgnoreMissingSymbols(bool ignoreMissingSymbols); 78 + inline bool ignoreMissingSymbols() const { return m_pUndefMgr != nullptr; } 79 + 80 + // DYLD_PRINT_SEGMENTS 81 + inline void setPrintSegments(bool printSegments) { m_printSegments = printSegments; } 82 + inline bool printSegments() const { return m_printSegments; } 83 + 84 + // DYLD_PRINT_BINDINGS 85 + inline void setPrintBindings(bool printBindings) { m_printBindings = printBindings; } 86 + inline bool printBindings() const { return m_printBindings; } 87 + 88 + // DYLD_PRINT_RPATHS 89 + inline void setPrintRpathExpansion(bool print) { m_printRpathExpansion = print; } 90 + inline bool printRpathExpansion() const { return m_printRpathExpansion; } 66 91 92 + bool detectSysRootFromPath(std::string path); 67 93 inline void setSysRoot(const std::string& sysroot) { m_sysroot = sysroot; } 68 94 inline const std::string& sysRoot() const { return m_sysroot; } 95 + inline bool hasSysRoot() const { return !m_sysroot.empty(); } 96 + 97 + inline size_t objectCount() const { return m_objectsInOrder.size(); } 98 + MachOObject* objectByIndex(size_t index); 99 + MachOObject* objectByHeader(struct mach_header* hdr); 100 + 101 + NativeObject* objectByNativeRef(void* nativeRef); 102 + 103 + void add(NativeObject* obj); 104 + void remove(NativeObject* obj); 105 + void notifyAdd(MachOObject* obj); 106 + protected: 107 + friend class MachOObject; 108 + 109 + inline UndefMgr* undefMgr() { return m_pUndefMgr; } 110 + inline TrampolineMgr* trampolineMgr() { return m_pTrampolineMgr; } 69 111 private: 70 112 // map by base address 71 113 std::map<void*, MachOObject*> m_objects; 72 114 // map by absolute file name 73 - std::map<std::string, MachOObject*> m_objectNames; 115 + std::map<std::string, LoadableObject*> m_objectNames; 116 + // map by mach_header as needed by _dyld APIs 117 + std::map<struct mach_header*, MachOObject*> m_objectHeaders; 74 118 // list with load order 75 - std::list<MachOObject*> m_objectsInOrder; 119 + std::vector<MachOObject*> m_objectsInOrder; 120 + // this is needed for RTLD_NEXT only 121 + std::vector<LoadableObject*> m_loadablesInOrder; 122 + 123 + std::map<void*,NativeObject*> m_nativeRefToObject; 76 124 77 125 mutable Darling::RWMutex m_lock; 78 126 MachOObject* m_mainModule; 79 - bool m_bindAtLaunch, m_printInitializers, m_printLibraries, m_useTrampolines, m_ignoreMissingSymbols; 127 + bool m_bindAtLaunch, m_printInitializers, m_printLibraries; 128 + bool m_printSegments, m_printBindings, m_printRpathExpansion; 80 129 std::string m_libraryPath, m_sysroot; 81 130 82 131 UndefMgr* m_pUndefMgr; 83 132 TrampolineMgr* m_pTrampolineMgr; 133 + 134 + std::set<LoaderHookFunc*> m_loadHooks, m_unloadHooks; 135 + bool m_addedDefaultLoader; 84 136 }; 137 + 138 + } // namespace Darling 85 139 86 140 #endif
+224 -89
src/dyld/MachOObject.cpp
··· 1 + #include "dl_public.h" 1 2 #include "MachOObject.h" 2 3 #include <climits> 3 4 #include <cstring> ··· 12 13 #include <iostream> 13 14 #include "MachOMgr.h" 14 15 #include "eh/EHSection.h" 15 - #include "ld.h" 16 16 #include "DylibSearch.h" 17 17 #include "arch.h" 18 18 #include "TLS.h" 19 19 20 20 // FIXME: this needs to go away 21 - extern "C" int g_argc asm("NXArgc"); 22 - extern "C" char** g_argv asm("NXArgv"); 21 + extern "C" int g_argc asm("NXArgc") = 0; 22 + extern "C" char** g_argv asm("NXArgv") = nullptr; 23 + 24 + namespace Darling { 23 25 24 26 struct ProgramVars 25 27 { ··· 86 88 87 89 void MachOObject::load() 88 90 { 91 + if (isLoaded()) 92 + throw std::logic_error("Module already loaded"); 93 + if (strcmp(m_file->platform(), ARCH_NAME) != 0) 94 + { 95 + std::stringstream ss; 96 + ss << "This version of Darling dyld cannot load binaries for " << m_file->platform() << "."; 97 + throw std::runtime_error(ss.str()); 98 + } 99 + 89 100 m_base = MachOMgr::instance()->maxAddress(); 90 101 91 102 loadSegments(); ··· 95 106 96 107 readSymbols(); 97 108 readExports(); 109 + 110 + MachOMgr::instance()->add(this, isMainModule()); 111 + 98 112 loadDependencies(); 99 113 100 114 performRelocations(); ··· 109 123 setInitialSegmentProtection(); 110 124 setupTLS(); 111 125 126 + MachOMgr::instance()->notifyAdd(this); 112 127 runInitializers(); 113 128 114 - MachOMgr::instance()->add(this, isMainModule()); 115 - m_file->close(); 129 + m_file->closeFd(); 116 130 117 131 if (MachOMgr::instance()->printLibraries()) 118 132 std::cerr << "dyld: Loaded " << this->path() << std::endl; ··· 120 134 121 135 void MachOObject::unload() 122 136 { 137 + if (!isLoaded()) 138 + throw std::logic_error("Module not loaded"); 139 + 140 + MachOMgr::instance()->remove(this); 141 + 123 142 teardownTLS(); 124 143 runFinalizers(); 125 144 unloadSegments(); ··· 129 148 dep->delRef(); 130 149 131 150 m_dependencies.clear(); 132 - 133 - MachOMgr::instance()->remove(this); 151 + } 152 + 153 + bool MachOObject::isLoaded() const 154 + { 155 + return !m_mappings.empty(); 134 156 } 135 157 136 158 #if (__WORDSIZE == 64) ··· 165 187 m_base = (void*) seg->vmaddr; 166 188 167 189 if (!m_base) 168 - m_base = MachOMgr::instance()->maxAddress(); 190 + { 191 + // This is normally used only for: 192 + // a) DYLD_PRELOAD 193 + // b) Standalone use of libdyld 169 194 195 + #if (__WORDSIZE == 64) 196 + m_base = (void*) 0x200000000L; 197 + #else 198 + m_base = (void*) 0x1000000; 199 + #endif 200 + } 201 + 170 202 if ((void*)seg->vmaddr < m_base && !isMainModule()) 171 203 m_slide = uintptr_t(m_base) - seg->vmaddr; 172 204 ··· 176 208 initprot = machoProtectionFlagsToMmap(seg->initprot); 177 209 178 210 checkMappingAddr(mappingAddr); 179 - 180 - LOG << "Mapping segment " << seg->segname << " from " << m_file->filename() << " to " << mappingAddr << ", slide is " << m_slide << std::endl; 211 + 212 + if (MachOMgr::instance()->printSegments()) 213 + std::cerr << "dyld: Mapping segment " << seg->segname << " from " << m_file->filename() << " to " << mappingAddr << ", slide is " << m_slide << std::endl; 181 214 182 215 rv = ::mmap(mappingAddr, mappingSize, maxprot, MAP_FIXED | MAP_PRIVATE, m_file->fd(), m_file->offset() + seg->fileoff); 183 216 if (rv == MAP_FAILED) ··· 189 222 190 223 m_mappings.push_back(Mapping { mappingAddr, seg->vmsize, initprot, maxprot }); 191 224 192 - if (seg->vmsize < mappingSize) 225 + if (seg->vmsize > mappingSize) 193 226 { 194 227 // Map empty pages to cover the vmsize range 195 228 mappingAddr = (void*) (seg->vmaddr + m_slide + mappingSize); ··· 212 245 for (const Mapping& map : m_mappings) 213 246 { 214 247 if (::mprotect(map.start, map.size, map.initprot) == -1) 215 - throw std::runtime_error("Failed to mprotect() memory"); 248 + { 249 + std::stringstream ss; 250 + ss << "Failed to mprotect() memory: " << strerror(errno); 251 + throw std::runtime_error(ss.str()); 252 + } 216 253 } 217 254 } 218 255 ··· 292 329 { 293 330 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); 294 331 *ptr = m_file->fixEndian(*ptr); 295 - *ptr = uintptr_t(addr) + 4 - (*ptr); 332 + *ptr = uintptr_t(addr) - 4 - (*ptr); 296 333 break; 297 334 } 298 335 ··· 307 344 } 308 345 } 309 346 310 - void MachOObject::writeBind(int type, uintptr_t* ptr, uintptr_t newAddr) 347 + void MachOObject::writeBind(int type, void** ptr, void* newAddr, const std::string& name) 311 348 { 349 + if (MachOMgr::instance()->printBindings()) 350 + std::cerr << "dyld: Binding " << name << " at " << ptr << ": " << (void*)(*ptr) << " -> " << (void*)newAddr << std::endl; 351 + 312 352 if (type == BIND_TYPE_POINTER) 313 353 *ptr = newAddr; 314 354 ··· 326 366 327 367 instr->relJmp = 0xE9; // x86 jmp rel32 328 368 instr->addr = newAddr - uint32_t(ptr) - sizeof(jmp_instr); 369 + } 370 + else if (type == BIND_TYPE_PCREL) 371 + { 372 + *ptr = newAddr - uintptr_t(ptr) - 4; 329 373 } 330 374 #endif 331 375 } ··· 470 514 void MachOObject::fillInDyldData() 471 515 { 472 516 DyldSectData* dyld = (DyldSectData*) getSection("__DATA", "__dyld"); 473 - dyld->funcLookupPtr = lookupDyldFunction; 517 + if (dyld) 518 + dyld->funcLookupPtr = lookupDyldFunction; 474 519 } 475 520 476 521 bool MachOObject::lookupDyldFunction(const char* name, void** addr) 477 522 { 478 523 LOG << "lookupDyldFunction: " << name << std::endl; 479 524 480 - static void* self = dlopen(0, 0); 481 - 482 - *addr = dlsym(self, name); 525 + *addr = dlsym(RTLD_DEFAULT, name); 483 526 484 527 if (!*addr) 485 528 *addr = (void*) (void (*)()) []() { LOG << "Fake dyld function called\n"; }; ··· 497 540 uintptr_t size; 498 541 DyldSectData* dyld = (DyldSectData*) getSection("__DATA", "__dyld", &size); 499 542 500 - if (size > sizeof(void*)*2) 543 + if (dyld && size > sizeof(void*)*2) 501 544 vars = &dyld->vars; 502 545 } 503 546 ··· 572 615 #ifdef __i386__ 573 616 if (rel->pcrel) 574 617 { 575 - LOG << "reloc(pcrel): @" << ptr << " " << std::hex << *ptr << " -> " << (value - uintptr_t(ptr) - 4) << std::dec << std::endl; 576 - *ptr = value - uintptr_t(ptr) - 4; 618 + //LOG << "reloc(pcrel): @" << ptr << " " << std::hex << *ptr << " -> " << (value - uintptr_t(ptr) - 4) << std::dec << std::endl; 619 + writeBind(BIND_TYPE_PCREL, (void**) ptr, (void*) value, rel->name); 620 + //*ptr = value - uintptr_t(ptr) - 4; 577 621 } 578 622 else 579 623 #endif 580 624 { 581 - LOG << "reloc: @" << ptr << " " << std::hex << *ptr << " -> " << value << std::dec << std::endl; 625 + //LOG << "reloc: @" << ptr << " " << std::hex << *ptr << " -> " << value << std::dec << std::endl; 582 626 *ptr = value; 627 + writeBind(BIND_TYPE_POINTER, (void**) ptr, (void*) value, rel->name); 583 628 } 584 629 } 585 630 } ··· 609 654 610 655 if (!addr && !bind->is_weak) 611 656 { 612 - if (MachOMgr::instance()->ignoreMissingSymbols()) 657 + if (MachOMgr::instance()->ignoreMissingSymbols() && bind->name[0] == '_') 613 658 { 614 - // TODO: create a dummy function 659 + addr = MachOMgr::instance()->undefMgr()->generateNew(bind->name.c_str()+1); 615 660 bind->addend = 0; 616 661 } 617 662 else ··· 625 670 if (!bind->is_classic) 626 671 addr = (void*) (uintptr_t(addr) + bind->addend); 627 672 628 - if (addr && MachOMgr::instance()->useTrampolines()) 673 + if (addr && MachOMgr::instance()->useTrampolines() && bind->name[0] == '_') 629 674 { 630 - // TODO: swap addr for a trampoline 675 + TrampolineMgr* mgr = MachOMgr::instance()->trampolineMgr(); 676 + 677 + addr = mgr->generate(addr, bind->name.c_str()+1); 631 678 } 632 679 633 - writeBind(bind, addr); 680 + writeBind(bind->type, (void**)(bind->vmaddr + m_slide), addr, bind->name); 634 681 635 682 return addr; 636 683 } ··· 642 689 } 643 690 } 644 691 645 - void MachOObject::writeBind(MachO::Bind* bind, void* addr) 646 - { 647 - void** bindLoc = (void**)(bind->vmaddr + m_slide); 648 - 649 - if (bind->type == BIND_TYPE_POINTER) 650 - { 651 - if (*bindLoc != addr) 652 - *bindLoc = addr; 653 - } 654 - #ifdef __i386__ 655 - else if (bind->type == BIND_TYPE_STUB) 656 - { 657 - struct jmp_instr 658 - { 659 - uint8_t relJmp; 660 - uint32_t addr; 661 - } __attribute__((packed)); 662 - static_assert(sizeof(jmp_instr) == 5, "Incorrect jmp instruction size"); 663 - 664 - jmp_instr* instr = reinterpret_cast<jmp_instr*>(bindLoc); 665 - 666 - instr->relJmp = 0xE9; // x86 jmp rel32 667 - instr->addr = addr - uint32_t(bindLoc) - sizeof(jmp_instr); 668 - } 669 - #endif 670 - } 671 - 672 692 void* MachOObject::resolveSymbol(const std::string& name) 673 693 { 674 694 void* addr; 675 695 676 - if (!name.empty()) 696 + if (name.empty()) 677 697 return nullptr; 678 698 679 699 if (name[0] != '_') ··· 683 703 return addr; 684 704 } 685 705 686 - #ifndef __x86_64__ 687 - if (name.size() > 10 && name.compare(name.size()-10, 10, "$UNIX_2003") == 0) 688 - { 689 - name.resize(name.size() - 10); 690 - } 691 - #endif 692 - 693 - addr = __darwin_dlsym(DARWIN_RTLD_DEFAULT, name.c_str() + 1); 694 - 695 - 696 - 697 - return addr; 706 + return __darwin_dlsym(DARWIN_RTLD_DEFAULT, name.c_str() + 1); 698 707 } 699 708 700 709 void MachOObject::runInitializers() ··· 706 715 707 716 for (uint64_t offset : m_file->init_funcs()) 708 717 { 709 - Initializer init = Initializer(offset + m_slide); 718 + Initializer* init = (Initializer*)(offset + m_slide); 710 719 711 720 if (MachOMgr::instance()->printInitializers()) 712 - std::cerr << "dyld: Running initializer at " << (void*)init << std::endl; 721 + std::cerr << "dyld: Running initializer at " << (void*)*init << std::endl; 713 722 714 - init(g_argc, g_argv, environ, apple, pvars); 723 + (*init)(g_argc, g_argv, environ, apple, pvars); 715 724 } 716 725 } 717 726 ··· 721 730 722 731 for (uint64_t offset : m_file->exit_funcs()) 723 732 { 724 - Finalizer fini = Finalizer(offset + m_slide); 725 - fini(); 733 + Finalizer* fini = (Finalizer*)(offset + m_slide); 734 + (*fini)(); 726 735 } 727 736 } 728 737 729 738 void MachOObject::detectAbsolutePath() 730 739 { 731 740 char path[PATH_MAX]; 741 + size_t pos; 732 742 733 743 realpath(m_file->filename().c_str(), path); 734 744 735 745 m_absolutePath = path; 736 746 m_absolutePathDir = dirname(path); 747 + 748 + pos = m_absolutePath.rfind('/'); 749 + 750 + if (pos == std::string::npos) 751 + m_name = m_absolutePath; 752 + else 753 + m_name = m_absolutePath.substr(pos+1); 737 754 } 738 755 739 756 void MachOObject::setCommandLine(int argc, char** argv, char** envp) 740 757 { 741 - assert(m_argv[m_argc] == nullptr); 758 + if (argv[argc] != nullptr) 759 + throw std::invalid_argument("argv is not nullptr terminated"); 760 + if (!isMainModule()) 761 + throw std::logic_error("setCommandLine() used on a non-main module"); 742 762 743 763 m_argc = argc; 744 764 m_argv = argv; 745 765 m_envp = envp; 766 + 767 + // FIXME: this needs to go away 768 + g_argc = argc; 769 + g_argv = argv; 746 770 } 747 771 748 772 void MachOObject::commandLine(int* argc, char*** argv, char*** envp) 749 773 { 750 - *argc = m_argc; 751 - *argv = m_argv; 752 - *envp = m_envp; 774 + if (argc) 775 + *argc = m_argc; 776 + if (argv) 777 + *argv = m_argv; 778 + if (envp) 779 + *envp = m_envp; 780 + } 781 + 782 + void MachOObject::commandLine(int** argc, char**** argv, char**** envp) 783 + { 784 + if (argc) 785 + *argc = &m_argc; 786 + if (argv) 787 + *argv = &m_argv; 788 + if (envp) 789 + *envp = &m_envp; 753 790 } 754 791 755 792 void MachOObject::run() ··· 758 795 throw std::runtime_error("Tried to run a file that is not the main module"); 759 796 760 797 char* apple[2] = { const_cast<char*>(m_absolutePath.c_str()), nullptr }; 798 + 799 + if (MachOMgr::instance()->useTrampolines()) 800 + MachOMgr::instance()->trampolineMgr()->printPath(); 761 801 762 802 if (m_file->entry()) 763 803 { ··· 778 818 throw std::runtime_error("No entry point found"); 779 819 } 780 820 781 - static inline int findLast(char** array) 782 - { 783 - for (int i = 0; ; i++) 784 - { 785 - if (!array[i]) 786 - return i; 787 - } 788 - } 789 - 790 821 void MachOObject::jumpToStart() 791 822 { 792 823 char* apple[2] = { const_cast<char*>(m_absolutePath.c_str()), nullptr }; ··· 800 831 # define JUMP(addr) __asm__ volatile("jmp *%0" :: "r"(addr) :) 801 832 #endif 802 833 803 - for (int i = findLast(apple); i >= 0; i--) 834 + for (int i = std::char_traits<char*>::length(apple)-1; i >= 0; i--) 804 835 PUSH(apple[i]); 805 836 806 - for (int i = findLast(m_envp); i >= 0; i--) 837 + for (int i = std::char_traits<char*>::length(m_envp)-1; i >= 0; i--) 807 838 PUSH(m_envp[i]); 808 839 809 840 for (int i = m_argc; i >= 0; i--) ··· 811 842 812 843 PUSH(m_argc); 813 844 JUMP(entry); 845 + 846 + __builtin_unreachable(); 814 847 } 815 848 816 849 817 850 void* MachOObject::getSection(const std::string& segmentName, const std::string& sectionName, uintptr_t* sectionSize) 818 851 { 852 + LOG << "Looking for section " << sectionName << " in segment " << segmentName << std::endl; 853 + 819 854 for (const MachO::Section& sect : m_file->sections()) 820 855 { 821 - if (sect.segment == segmentName && sect.section == sectionName) 856 + if ((segmentName.empty() || sect.segment == segmentName) && sect.section == sectionName) 822 857 { 858 + void* addr; 859 + 823 860 if (sectionSize) 824 861 *sectionSize = sect.size; 825 - return (void*) (sect.addr + m_slide); 862 + 863 + addr = (void*) (sect.addr + m_slide); 864 + 865 + LOG << "...found at " << addr << std::endl; 866 + 867 + return addr; 826 868 } 827 869 } 870 + 871 + LOG << "...not found\n"; 828 872 return nullptr; 829 873 } 830 874 ··· 854 898 { 855 899 Darling::TLSTeardown(this); 856 900 } 901 + 902 + void* MachOObject::doLazyBind(uintptr_t lazyOffset) 903 + { 904 + for (MachO::Bind* bind : m_file->binds()) 905 + { 906 + if (bind->is_lazy && bind->offset == lazyOffset) 907 + { 908 + try 909 + { 910 + return performBind(bind); 911 + } 912 + catch (const std::exception& e) 913 + { 914 + std::cerr << "dyld_stub_binder_fixup(): Failed to resolve the symbol: " << e.what() << std::endl; 915 + abort(); 916 + } 917 + } 918 + } 919 + 920 + std::cerr << "dyld_stub_binder_fixup(): Lazy bind not found for offset " << std::hex << lazyOffset << std::dec << std::endl; 921 + abort(); 922 + } 923 + 924 + const char* MachOObject::name() const 925 + { 926 + return m_name.c_str(); 927 + } 928 + 929 + void* MachOObject::getExportedSymbolRecursive(const std::string& symbolName) const 930 + { 931 + std::set<const LoadableObject*> seen; 932 + void* addr; 933 + 934 + seen.insert(this); 935 + 936 + if ((addr = getExportedSymbol(symbolName, false))) 937 + return addr; 938 + 939 + return getExportedSymbolRecursive(symbolName, seen); 940 + } 941 + 942 + void* MachOObject::getExportedSymbolRecursive(const std::string& symbolName, std::set<const LoadableObject*>& visited) const 943 + { 944 + std::set<const MachOObject*> recurse; 945 + 946 + for (const LoadableObject* dep : m_dependencies) 947 + { 948 + void* addr; 949 + 950 + if (visited.find(dep) != visited.end()) 951 + continue; 952 + 953 + visited.insert(dep); 954 + 955 + if ((addr = dep->getExportedSymbol(symbolName, false))) 956 + return addr; 957 + 958 + if (const MachOObject* obj = dynamic_cast<const MachOObject*>(dep)) 959 + recurse.insert(obj); 960 + } 961 + 962 + for (const MachOObject* obj : recurse) 963 + { 964 + void* addr; 965 + 966 + if ((addr = obj->getExportedSymbolRecursive(symbolName, visited))) 967 + return addr; 968 + } 969 + 970 + return nullptr; 971 + } 972 + 973 + void* MachOObject::dyld_stub_binder_fixup(MachOObject** obj, uintptr_t lazyOffset) 974 + { 975 + if (!*obj) 976 + { 977 + LOG << "Finding MachOObject for address " << obj << std::endl; 978 + *obj = MachOMgr::instance()->objectForAddress((void*) obj); 979 + 980 + if (!*obj) 981 + { 982 + std::cerr << "dyld_stub_binder_fixup(): Mach-O object not found for " << obj << std::endl; 983 + abort(); 984 + } 985 + } 986 + 987 + return (*obj)->doLazyBind(lazyOffset); 988 + } 989 + 990 + 991 + } // namespace Darling
+54 -9
src/dyld/MachOObject.h
··· 3 3 #include <libmach-o/MachO.h> 4 4 #include <vector> 5 5 #include <string> 6 + #include <set> 6 7 #include <map> 7 8 #include <unordered_map> 8 9 #include <stdint.h> 9 10 #include <climits> 10 11 #include "LoadableObject.h" 12 + 13 + // friends 14 + 15 + namespace Darling { 11 16 12 17 struct ProgramVars; 13 18 ··· 24 29 inline bool valid() const { return m_file != nullptr; } 25 30 26 31 // Absolute path to this object 27 - inline const std::string& path() const { return m_absolutePath; } 32 + virtual const std::string& path() const override { return m_absolutePath; } 28 33 29 34 // The directory that contains this object 30 35 inline const std::string& directory() const { return m_absolutePathDir; } 36 + 37 + // Some name identifying this object 38 + virtual const char* name() const override; 31 39 32 40 // maximum address mapped by this object 33 41 void* maxAddress() const; ··· 39 47 // For libraries, slide() == baseAddress() 40 48 uintptr_t slide() const { return m_slide; } 41 49 50 + // Loads the Mach-O object into memory 51 + // Needs to be called before using almost all other functions 42 52 virtual void load() override; 53 + 54 + // Unloads the Mach-O object from memory 55 + // Images that are not unloaded manually will be unloaded automatically 56 + // upon the destruction of MachOMgr 43 57 virtual void unload() override; 44 - 58 + 59 + virtual bool isLoaded() const override; 60 + 45 61 virtual void* getExportedSymbol(const std::string& symbolName, bool nonWeakOnly) const override; 62 + 63 + void* getExportedSymbolRecursive(const std::string& symbolName) const; 64 + 65 + // Fills a Dl_info structure in a dladdr() manner 46 66 virtual bool findSymbolInfo(const void* addr, Dl_info* p) const override; 47 67 68 + // Returns true if this is a main module. Main module is an executable (as opposed to dynamic libraries) 48 69 bool isMainModule() const; 49 70 71 + // Set the command line arguments before using run() to start the program 72 + // Only applicable to main modules. 50 73 void setCommandLine(int argc, char** argv, char** envp); 51 74 void commandLine(int* argc, char*** argv, char*** envp); 52 75 53 - // Only possible on the main module 76 + // Should not be normally used 77 + void commandLine(int** argc, char**** argv, char**** envp); 78 + 79 + // Executes the application. Use setCommandLine() first. 80 + // Only possible on the main module. This method either never returns or throws an exception 81 + __attribute__((noreturn)) 54 82 void run(); 55 83 84 + // Returns a pointer to the beginning of a Mach-O section, identified by the segment and section name 85 + // Segment name can be left empty 56 86 void* getSection(const std::string& segmentName, const std::string& sectionName, uintptr_t* sectionSize = nullptr); 87 + 88 + // Returns the header of the Mach-O object 89 + inline struct ::mach_header* getMachHeader() { return &m_header; } 90 + 91 + // For RTLD_FIRST implementation, not useful outside of dl_public 92 + inline void setNoRecursion(bool noRecursion) { m_noRecursion = noRecursion; } 93 + inline bool noRecursion() const { return m_noRecursion; } 57 94 58 95 protected: 59 96 friend class DylibSearch; ··· 87 124 void performRelocations(); 88 125 void performBinds(); 89 126 void* performBind(MachO::Bind* bind); 90 - void writeBind(MachO::Bind* bind, void* addr); 91 127 92 128 void detectAbsolutePath(); 93 129 void* resolveSymbol(const std::string& name); 94 130 95 - void jumpToStart(); 131 + void jumpToStart() __attribute__((noreturn)); 96 132 97 133 void setupTLS(); 98 134 void teardownTLS(); 135 + 136 + void* getExportedSymbolRecursive(const std::string& symbolName, std::set<const LoadableObject*>& visited) const; 137 + 138 + static void* dyld_stub_binder_fixup(MachOObject** obj, uintptr_t lazyOffset) asm("dyld_stub_binder_fixup"); 139 + 140 + // Invoked by a lazy-binding stub 141 + void* doLazyBind(uintptr_t lazyOffset); 99 142 100 143 static int machoProtectionFlagsToMmap(int machoFlags); 101 144 static uintptr_t pageAlign(uintptr_t what); 102 145 static void checkMappingAddr(void* addr); 103 - static void writeBind(int type, uintptr_t* ptr, uintptr_t newAddr); 146 + static void writeBind(int type, void** ptr, void* newAddr, const std::string& name); 104 147 static bool lookupDyldFunction(const char* name, void** addr); 105 148 private: 106 149 MachO* m_file; ··· 123 166 std::vector<const char*> m_parentRpaths; 124 167 void* m_reworkedEHData = nullptr; 125 168 126 - std::string m_absolutePath, m_absolutePathDir; 169 + std::string m_absolutePath, m_absolutePathDir, m_name; 127 170 128 - mach_header m_header; 129 - bool m_bindAllAtLoad; 171 + ::mach_header m_header; 130 172 131 173 int m_argc = 0; 132 174 char** m_argv = nullptr; 133 175 char** m_envp = nullptr; 176 + bool m_noRecursion = false; 134 177 }; 178 + 179 + } // namespace Darling 135 180 136 181 #endif
+68 -21
src/dyld/NativeObject.cpp
··· 4 4 #include <stdexcept> 5 5 #include "MachOMgr.h" 6 6 #include <iostream> 7 + #include <cstdlib> 8 + #include <link.h> 9 + 10 + namespace Darling { 7 11 8 12 NativeObject::NativeObject(const std::string& path) 9 - : m_path(path) 13 + : m_path(path), m_name(path) 14 + { 15 + } 16 + 17 + NativeObject::NativeObject(void* nativeRef, const std::string& name) 18 + : m_nativeRef(nativeRef), m_path(name), m_name(name) 10 19 { 11 20 } 12 21 13 22 void NativeObject::load() 14 23 { 15 - m_nativeRef = ::dlopen(m_path.c_str(), translateFlags(m_attribs)); 24 + int flags = 0; 25 + 26 + flags |= globalExports() ? RTLD_GLOBAL : RTLD_LOCAL; 27 + flags |= bindAllAtLoad() ? RTLD_NOW : RTLD_LAZY; 28 + 29 + m_nativeRef = ::dlopen(m_path.c_str(), flags); 16 30 if (!m_nativeRef) 17 31 { 18 32 const char* err = ::dlerror(); ··· 23 37 } 24 38 else 25 39 { 40 + 41 + updateName(); 42 + 26 43 if (MachOMgr::instance()->printLibraries()) 27 44 std::cerr << "dyld: Loaded " << m_path << std::endl; 45 + 46 + MachOMgr::instance()->add(this); 28 47 } 29 48 } 30 49 31 50 void NativeObject::unload() 32 51 { 33 - ::dlclose(m_nativeRef); 52 + MachOMgr::instance()->remove(this); 53 + 54 + if (m_path.find('/') != std::string::npos) 55 + ::dlclose(m_nativeRef); 34 56 } 35 57 36 - int NativeObject::translateFlags(int flag) 58 + void NativeObject::updateName() 37 59 { 38 - int native_flags = 0; 39 - if (flag & DARWIN_RTLD_LAZY) 40 - native_flags |= RTLD_LAZY; 41 - if (flag & DARWIN_RTLD_NOW) 42 - native_flags |= RTLD_NOW; 43 - if (flag & DARWIN_RTLD_LOCAL) 44 - native_flags |= RTLD_LOCAL; 45 - if (flag & DARWIN_RTLD_GLOBAL) 46 - native_flags |= RTLD_GLOBAL; 47 - if (flag & DARWIN_RTLD_NOLOAD) 48 - native_flags |= RTLD_NOLOAD; 49 - if (flag & DARWIN_RTLD_NODELETE) 50 - native_flags |= RTLD_NODELETE; 51 - //if (flag & __DARLING_RTLD_NOBIND) 52 - // native_flags |= __DARLING_RTLD_NOBIND; 53 - return native_flags; 60 + struct link_map* map = nullptr; 61 + size_t pos; 62 + 63 + dlinfo(m_nativeRef, RTLD_DI_LINKMAP, &map); 64 + 65 + if (map) 66 + { 67 + char* real = realpath(map->l_name, nullptr); 68 + if (real) 69 + { 70 + m_path = real; 71 + free(real); 72 + } 73 + } 74 + 75 + pos = m_path.rfind('/'); 76 + if (pos == std::string::npos) 77 + m_name = m_path; 78 + else 79 + m_name = m_path.substr(pos+1); 54 80 } 55 81 56 82 void* NativeObject::getExportedSymbol(const std::string& symbolName, bool nonWeakOnly) const 57 83 { 58 - return ::dlsym(m_nativeRef, symbolName.c_str()); 84 + void* addr; 85 + std::string prefixed = "__darwin_" + symbolName; 86 + 87 + addr = ::dlsym(m_nativeRef, prefixed.c_str()); 88 + 89 + if (!addr) 90 + addr = ::dlsym(m_nativeRef, symbolName.c_str()); 91 + 92 + return addr; 59 93 } 60 94 61 95 bool NativeObject::findSymbolInfo(const void* addr, Dl_info* p) const 62 96 { 63 97 return ::dladdr(addr, p) != 0; 64 98 } 99 + 100 + const char* NativeObject::name() const 101 + { 102 + return m_name.c_str(); 103 + } 104 + 105 + const std::string& NativeObject::path() const 106 + { 107 + return m_path; 108 + } 109 + 110 + } // namespace Darling 111 +
+12 -2
src/dyld/NativeObject.h
··· 3 3 #include <string> 4 4 #include "LoadableObject.h" 5 5 6 + namespace Darling { 7 + 6 8 class NativeObject : public LoadableObject 7 9 { 8 10 public: 9 11 NativeObject(const std::string& path); 12 + NativeObject(void* nativeRef, const std::string& name); 10 13 11 14 virtual void load() override; 12 15 virtual void unload() override; 13 16 virtual void* getExportedSymbol(const std::string& symbolName, bool nonWeakOnly) const override; 14 17 virtual bool findSymbolInfo(const void* addr, Dl_info* p) const override; 18 + virtual const char* name() const override; 19 + virtual bool isLoaded() const override { return m_nativeRef != nullptr; } 20 + virtual const std::string& path() const override; 21 + 22 + inline void* nativeRef() { return m_nativeRef; } 15 23 private: 16 - int translateFlags(int flag); 24 + void updateName(); 17 25 private: 18 26 mutable void* m_nativeRef; 19 - std::string m_path; 27 + std::string m_name, m_path; 20 28 }; 29 + 30 + } // namespace Darling 21 31 22 32 #endif
+3 -1
src/dyld/TLS.cpp
··· 98 98 auto it = m_images.find(imageKey); 99 99 pthread_key_t key; 100 100 101 - assert(it != m_images.end()); 101 + if (it == m_images.end()) 102 + return; 103 + 102 104 key = it->second->key; 103 105 104 106 // TODO: What to do with live objects with C++11 destructors? Does Apple's dyld handle this?
+10 -6
src/dyld/Trampoline.cpp
··· 48 48 extern "C" void* trampoline_end; 49 49 50 50 #ifndef TEST 51 - # include "dyld.h" 51 + # include "MachOMgr.h" 52 + # include "MachOObject.h" 52 53 #else 53 54 const char* g_argv[] = { "Trampoline", 0 }; 54 55 #endif ··· 79 80 } 80 81 81 82 ::gettimeofday(&m_startup, nullptr); 83 + } 82 84 85 + void TrampolineMgr::printPath() 86 + { 83 87 std::cout << logPath() << std::endl; 84 88 } 85 89 ··· 254 258 { 255 259 pid_t pid = getpid(); 256 260 std::stringstream ss; 257 - std::string progname = g_argv[0]; 258 - size_t pos; 261 + const char* progname = Darling::MachOMgr::instance()->mainModule()->name(); 262 + //size_t pos; 259 263 260 - pos = progname.rfind('/'); 261 - if (pos != std::string::npos) 262 - progname = progname.substr(pos+1); 264 + //pos = progname.rfind('/'); 265 + //if (pos != std::string::npos) 266 + // progname = progname.substr(pos+1); 263 267 264 268 ss << m_wd << '/' << progname << '.' << pid << ".log"; 265 269 return ss.str();
+1
src/dyld/Trampoline.h
··· 35 35 TrampolineMgr(int minTrampolines = 4096); 36 36 ~TrampolineMgr(); 37 37 38 + void printPath(); 38 39 void* generate(void* targetAddr, const char* name); 39 40 bool isExecutable(void* targetAddr); 40 41 std::string inFile(void* addr);
+278
src/dyld/dl_public.cpp
··· 1 + #include "dl_public.h" 2 + #include "MachOMgr.h" 3 + #include "MachOObject.h" 4 + #include "NativeObject.h" 5 + #include "DylibSearch.h" 6 + #include <string> 7 + #include <cstring> 8 + #include <sstream> 9 + #include <set> 10 + #include <libmach-o/MachO.h> 11 + #include <util/debug.h> 12 + 13 + // This would require g++ 4.8 runtime 14 + //static thread_local std::string g_lastError; 15 + static thread_local char g_lastError[1024]; 16 + static thread_local bool g_lastErrorRead = false; 17 + 18 + static std::set<Darling::DlsymHookFunc> g_dlsymHooks; 19 + 20 + using namespace Darling; 21 + 22 + static void setLastError(const std::string& str) 23 + { 24 + strncpy(g_lastError, str.c_str(), sizeof(g_lastError)); 25 + g_lastError[sizeof(g_lastError)-1] = 0; 26 + g_lastErrorRead = false; 27 + } 28 + 29 + void* __darwin_dlopen(const char* filename, int flag) 30 + { 31 + std::string resolved; 32 + 33 + if (!filename) 34 + return MachOMgr::instance()->mainModule(); 35 + 36 + resolved = DylibSearch::instance()->resolve(filename, nullptr); 37 + 38 + if (resolved.empty()) 39 + resolved = filename; 40 + 41 + LoadableObject* obj; 42 + 43 + obj = MachOMgr::instance()->lookup(resolved); 44 + 45 + // Alternative search for native objects 46 + if (!obj && !MachO::isMachO(resolved.c_str())) 47 + { 48 + void* native = ::dlopen(resolved.c_str(), RTLD_NOLOAD); 49 + if (native) 50 + { 51 + obj = MachOMgr::instance()->objectByNativeRef(native); 52 + ::dlclose(native); 53 + } 54 + } 55 + 56 + if (!obj) 57 + { 58 + if (!(flag & DARWIN_RTLD_NOLOAD)) 59 + { 60 + try 61 + { 62 + if (MachO::isMachO(resolved.c_str())) 63 + { 64 + MachOObject* mach; 65 + 66 + obj = mach = new MachOObject(resolved); 67 + mach->setNoRecursion(flag & DARWIN_RTLD_FIRST); 68 + } 69 + else 70 + { 71 + obj = new NativeObject(resolved); 72 + } 73 + 74 + if (flag & DARWIN_RTLD_NOW) 75 + obj->setBindAllAtLoad(true); 76 + 77 + obj->load(); 78 + } 79 + catch (const std::exception& e) 80 + { 81 + setLastError(e.what()); 82 + return nullptr; 83 + } 84 + } 85 + } 86 + else 87 + obj->addRef(); 88 + 89 + if (obj) 90 + { 91 + obj->setGlobalExports(flag & DARWIN_RTLD_GLOBAL); 92 + obj->setNoDelete(flag & DARWIN_RTLD_NODELETE); 93 + } 94 + 95 + return obj; 96 + } 97 + 98 + int __darwin_dlclose(void* handle) 99 + { 100 + if (!handle) 101 + return 1; 102 + 103 + LoadableObject* obj = static_cast<LoadableObject*>(handle); 104 + obj->delRef(); 105 + 106 + return 0; 107 + } 108 + 109 + const char* __darwin_dlerror(void) 110 + { 111 + if (g_lastErrorRead || !g_lastError[0]) 112 + return nullptr; 113 + 114 + g_lastErrorRead = true; 115 + return g_lastError; 116 + } 117 + 118 + static std::string processSymbolViaHooks(const std::string& symbol) 119 + { 120 + char translated[1024]; 121 + 122 + strcpy(translated, symbol.c_str()); 123 + 124 + for (Darling::DlsymHookFunc hook : g_dlsymHooks) 125 + { 126 + if (hook(translated)) 127 + return translated; 128 + } 129 + 130 + return std::string(); 131 + } 132 + 133 + static void removeSuffix(std::string& str, const char* suf) 134 + { 135 + size_t pos = str.rfind(suf); 136 + if (pos != std::string::npos) 137 + str.resize(pos); 138 + } 139 + 140 + void* __darwin_dlsym(void* handle, const char* symbol) 141 + { 142 + std::string name = symbol; 143 + std::string translated; 144 + void* addr = nullptr; 145 + 146 + translated = processSymbolViaHooks(name); 147 + 148 + removeSuffix(name, "$UNIX2003"); 149 + removeSuffix(name, "$DARWIN_EXTSN"); 150 + removeSuffix(name, "$NOCANCEL"); 151 + 152 + if (handle == DARWIN_RTLD_DEFAULT) 153 + { 154 + if (!translated.empty()) 155 + addr = MachOMgr::instance()->getExportedSymbol(translated.c_str()); 156 + 157 + if (!addr) 158 + addr = MachOMgr::instance()->getExportedSymbol(name.c_str()); 159 + } 160 + else if (handle == DARWIN_RTLD_NEXT) 161 + { 162 + MachOObject* moduleAfter; 163 + void* callerLocation = __builtin_return_address(0); 164 + 165 + moduleAfter = MachOMgr::instance()->objectForAddress(callerLocation); 166 + 167 + if (!translated.empty()) 168 + addr = MachOMgr::instance()->getExportedSymbol(translated.c_str(), moduleAfter); 169 + 170 + if (!addr) 171 + addr = MachOMgr::instance()->getExportedSymbol(name.c_str(), moduleAfter); 172 + } 173 + else 174 + { 175 + MachOObject* module; 176 + 177 + if (handle == DARWIN_RTLD_MAIN_ONLY) 178 + module = MachOMgr::instance()->mainModule(); 179 + else if (handle == DARWIN_RTLD_SELF) 180 + { 181 + void* callerLocation = __builtin_return_address(0); 182 + module = MachOMgr::instance()->objectForAddress(callerLocation); 183 + } 184 + 185 + if (!translated.empty()) 186 + addr = module->getExportedSymbol(translated.c_str(), false); 187 + 188 + if (!addr) 189 + addr = module->getExportedSymbol(name.c_str(), false); 190 + } 191 + 192 + if (!addr) 193 + setLastError("Symbol not found"); 194 + 195 + return addr; 196 + } 197 + 198 + int __darwin_dladdr(void *addr, Dl_info *info) 199 + { 200 + MachOObject* obj; 201 + 202 + obj = MachOMgr::instance()->objectForAddress(addr); 203 + 204 + if (obj) 205 + return obj->findSymbolInfo(addr, info); 206 + else 207 + return dladdr(addr, info); 208 + } 209 + 210 + NSSymbol NSLookupAndBindSymbol(const char* symbolName) 211 + { 212 + return __darwin_dlsym(DARWIN_RTLD_DEFAULT, symbolName); 213 + } 214 + 215 + NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName) 216 + { 217 + return __darwin_dlsym(module, symbolName); 218 + } 219 + 220 + const char* NSNameOfSymbol(NSSymbol symbolAddr) 221 + { 222 + Dl_info info; 223 + 224 + if (!__darwin_dladdr(symbolAddr, &info)) 225 + return nullptr; 226 + 227 + return info.dli_sname; 228 + } 229 + 230 + void* NSAddressOfSymbol(NSSymbol nssymbol) 231 + { 232 + return nssymbol; 233 + } 234 + 235 + int NSIsSymbolNameDefined(const char* name) 236 + { 237 + return NSLookupAndBindSymbol(name) != nullptr; 238 + } 239 + 240 + NSModule NSModuleForSymbol(NSSymbol symbol) 241 + { 242 + return MachOMgr::instance()->objectForAddress(symbol); 243 + } 244 + 245 + int NSIsSymbolNameDefinedInImage(const struct mach_header *image, const char *symbolName) 246 + { 247 + MachOObject* obj; 248 + 249 + obj = MachOMgr::instance()->objectByHeader((struct mach_header*) image); 250 + 251 + if (!obj) 252 + return false; 253 + 254 + return obj->getExportedSymbol(symbolName, false) != nullptr; 255 + } 256 + 257 + const char* NSNameOfModule(NSModule m) 258 + { 259 + STUB(); 260 + return nullptr; 261 + } 262 + 263 + const char* NSLibraryNameForModule(NSModule m) 264 + { 265 + STUB(); 266 + return nullptr; 267 + } 268 + 269 + void Darling::registerDlsymHook(DlsymHookFunc func) 270 + { 271 + g_dlsymHooks.insert(func); 272 + } 273 + 274 + void Darling::deregisterDlsymHook(DlsymHookFunc func) 275 + { 276 + //g_dlsymHooks.erase(func); 277 + } 278 +
+54
src/dyld/dl_public.h
··· 1 + #ifndef DL_PUBLIC_H 2 + #define DL_PUBLIC_H 3 + #include <dlfcn.h> 4 + 5 + #define DARWIN_RTLD_LAZY 0x1 6 + #define DARWIN_RTLD_NOW 0x2 7 + #define DARWIN_RTLD_LOCAL 0x4 8 + #define DARWIN_RTLD_GLOBAL 0x8 9 + #define DARWIN_RTLD_NOLOAD 0x10 10 + #define DARWIN_RTLD_NODELETE 0x80 11 + #define DARWIN_RTLD_FIRST 0x100 12 + 13 + #define DARWIN_RTLD_NEXT ((void*)-1) 14 + #define DARWIN_RTLD_DEFAULT ((void*)-2) 15 + #define DARWIN_RTLD_SELF ((void*)-3) 16 + #define DARWIN_RTLD_MAIN_ONLY ((void*)-5) 17 + 18 + namespace Darling 19 + { 20 + class LoadableObject; 21 + 22 + typedef bool (*DlsymHookFunc)(char* symName); 23 + void registerDlsymHook(DlsymHookFunc func); 24 + void deregisterDlsymHook(DlsymHookFunc func); 25 + } 26 + 27 + typedef void* NSSymbol; 28 + typedef Darling::LoadableObject* NSModule; 29 + 30 + extern "C" 31 + { 32 + 33 + void* __darwin_dlopen(const char* filename, int flag); 34 + int __darwin_dlclose(void* handle); 35 + const char* __darwin_dlerror(void); 36 + void* __darwin_dlsym(void* handle, const char* symbol); 37 + int __darwin_dladdr(void *addr, Dl_info *info); 38 + 39 + // Obsolete (or "not recommended") APIs 40 + NSSymbol NSLookupAndBindSymbol(const char* symbolName); 41 + void* NSAddressOfSymbol(NSSymbol nssymbol); 42 + NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName); 43 + const char* NSNameOfSymbol(NSSymbol nssymbol); 44 + int NSIsSymbolNameDefined(const char* name); 45 + NSModule NSModuleForSymbol(NSSymbol symbol); 46 + int NSIsSymbolNameDefinedInImage(const struct mach_header *image, const char *symbolName); 47 + const char* NSNameOfModule(NSModule m); 48 + const char* NSLibraryNameForModule(NSModule m); 49 + // TODO: rest of these NS* calls if used anywhere 50 + 51 + } 52 + 53 + #endif 54 +
+46 -209
src/dyld/dyld.cpp
··· 1 - /* 2 - This file is part of Darling. 3 - 4 - Copyright (C) 2012-2013 Lubos Dolezel 5 - Copyright (C) 2011 Shinichiro Hamaji 6 - 7 - Darling is free software: you can redistribute it and/or modify 8 - it under the terms of the GNU General Public License as published by 9 - the Free Software Foundation, either version 3 of the License, or 10 - (at your option) any later version. 11 - 12 - Darling is distributed in the hope that it will be useful, 13 - but WITHOUT ANY WARRANTY; without even the implied warranty of 14 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 - GNU General Public License for more details. 16 - 17 - You should have received a copy of the GNU General Public License 18 - along with Darling. If not, see <http://www.gnu.org/licenses/>. 19 - */ 20 - 21 - #include <libmach-o/MachO.h> 22 - #include "MachOLoader.h" 23 - #include "arch.h" 24 - #include "log.h" 25 - #include "binfmt_misc.h" 1 + #include "MachOMgr.h" 2 + #include "MachOObject.h" 26 3 #include <iostream> 27 - #include <limits.h> 28 - #include <unistd.h> 29 - #include <cstdlib> 30 4 #include <stdexcept> 31 - #include <cstring> 32 - #include <cassert> 33 - #include <algorithm> 34 - #include <locale.h> 35 - #include <mcheck.h> 36 - #include <libgen.h> 37 - #include "dyld.h" 38 - #include <darwin/mach/machine.h> 39 - 40 - char g_darwin_executable_path[4096] = ""; 41 - char g_darwin_executable[4096] = ""; 42 - char g_dyld_path[4096] = ""; 43 - char g_sysroot[4096] = ""; 44 - bool g_trampoline = false; 45 - bool g_noWeak = false; 5 + #include <cstdlib> 6 + #include "arch.h" 46 7 47 - MachO* g_mainBinary = 0; 48 - MachOLoader* g_loader = 0; 49 - int g_argc; 50 - char** g_argv; 8 + static void printHelp(const char* argv0); 51 9 52 - static void autoSysrootSearch(); 53 - static void setupExecutablePath(const char* relativePath); 54 - static void setupDyldPath(const char* relativePath); 55 - static void checkPlatform(const char* arg1, const MachO* macho); 10 + using namespace Darling; 56 11 57 12 int main(int argc, char** argv, char** envp) 58 13 { 59 - if (argc == 1) 14 + if (argc < 2) 60 15 { 61 - std::cerr << "This is Darling dyld for " ARCH_NAME ".\n"; 62 - std::cerr << "Copyright (C) 2012-2013 Lubos Dolezel\n" 63 - "Copyright (C) 2011 Shinichiro Hamaji\n\n"; 64 - 65 - std::cerr << "Usage: " << argv[0] << " program-path [arguments...]\n\n"; 66 - std::cerr << "Environment variables:\n" 67 - "\tDYLD_DEBUG=1 - enable debug info (lots of output)\n" 68 - "\tDYLD_MTRACE=1 - enable mtrace\n" 69 - #ifdef DEBUG 70 - "\tDYLD_IGN_MISSING_SYMS=1 - replace missing symbol references with a stub function\n" 71 - "\tDYLD_TRAMPOLINE=1 - access all bound functions via a debug trampoline\n" 72 - #endif 73 - "\tDYLD_ROOT_PATH=<path> - set the base for library path resolution (overrides autodetection)\n" 74 - "\tDYLD_BIND_AT_LAUNCH=1 - force dyld to bind all lazy references on startup\n"; 16 + printHelp(argv[0]); 75 17 return 1; 76 18 } 77 - 19 + 78 20 try 79 21 { 80 - if (!::realpath(argv[0], g_dyld_path)) 81 - ::strcpy(g_dyld_path, argv[0]); 82 - 83 - if (argc == 2) 84 - { 85 - if (!strcmp(argv[1], "--register")) 86 - { 87 - Darling::binfmtRegister(g_dyld_path); 88 - return 0; 89 - } 90 - else if (!strcmp(argv[1], "--deregister")) 91 - { 92 - Darling::binfmtDeregister(); 93 - return 0; 94 - } 95 - } 22 + MachOObject* obj; 23 + MachOMgr* mgr = MachOMgr::instance(); 96 24 97 - setupDyldPath(argv[0]); 98 - // sets up @executable_path 99 - setupExecutablePath(argv[1]); 100 - 101 - // setlocale(LC_CTYPE, ""); 102 - if (getenv("DYLD_MTRACE") && atoi(getenv("DYLD_MTRACE"))) 103 - mtrace(); 104 - if (getenv("DYLD_TRAMPOLINE") && atoi(getenv("DYLD_TRAMPOLINE"))) 105 - g_trampoline = true; 106 - if (getenv("DYLD_NO_WEAK")) 107 - g_noWeak = true; 25 + mgr->detectSysRootFromPath(argv[1]); 26 + mgr->setPrintInitializers(getenv("DYLD_PRINT_INITIALIZERS") != nullptr); 27 + mgr->setPrintLibraries(getenv("DYLD_PRINT_LIBRARIES") != nullptr); 28 + mgr->setBindAtLaunch(getenv("DYLD_BIND_AT_LAUNCH") != nullptr); 29 + mgr->setIgnoreMissingSymbols(getenv("DYLD_IGN_MISSING_SYMS") != nullptr); 30 + mgr->setPrintSegments(getenv("DYLD_PRINT_SEGMENTS") != nullptr); 31 + mgr->setPrintBindings(getenv("DYLD_PRINT_BINDINGS") != nullptr); 32 + mgr->setPrintRpathExpansion(getenv("DYLD_PRINT_RPATHS") != nullptr); 108 33 109 - g_mainBinary = MachO::readFile(argv[1], ARCH_NAME); 34 + if (const char* path = getenv("DYLD_LIBRARY_PATH")) 35 + mgr->setLibraryPath(path); 36 + if (const char* path = getenv("DYLD_ROOT_PATH")) 37 + mgr->setSysRoot(path); 38 + if (const char* path = getenv("DYLD_TRAMPOLINE")) 39 + mgr->setUseTrampolines(true, path); 110 40 111 - if (!g_mainBinary) 112 - throw std::runtime_error("Cannot open binary file"); 113 - 114 - checkPlatform(argv[1], g_mainBinary); 41 + obj = new MachOObject(argv[1]); 42 + obj->setCommandLine(argc-1, &argv[1], envp); 115 43 116 - // Modify the argument list so that the dyld name disappears from the process list. 117 - // The Linux kernel doesn't really support this - it remembers the byte length of the cmdline, which will now decrease. 118 - // Any app that examines this process' /proc/.../cmdline will from now on see a group of empty arguments after the real arguments. 119 - // We fix this for NSProcessInfo in libobjcdarwin. 120 - /* 121 - uintptr_t totalLen = argv[argc-1] + strlen(argv[argc-1]) + 1 - argv[0]; 122 - uintptr_t shortenedLen = totalLen - (strlen(argv[0]) + 1); 123 - 124 - memmove(argv[0], argv[1], shortenedLen); 125 - memset(argv[0]+shortenedLen, 0, totalLen - shortenedLen); 126 - 127 - // Reconstruct the argv array 128 - for (int pos = 0, index = 1; index < argc-1; pos++) 129 - { 130 - if (!argv[0][pos]) 131 - argv[index++] = &argv[0][pos+1]; 132 - } 133 - */ 134 - 135 - g_argv = argv+1; 136 - g_argc = argc-1; 137 - g_loader = new MachOLoader; 138 - 139 - autoSysrootSearch(); 140 - bool forceBind = false; 141 - 142 - if (g_trampoline || getenv("DYLD_BIND_AT_LAUNCH") != nullptr) 143 - forceBind = true; 144 - 145 - g_loader->run(*g_mainBinary, g_argc, g_argv, envp, forceBind); 146 - 147 - delete g_loader; 148 - g_loader = 0; 149 - return 2; 44 + obj->load(); 45 + obj->run(); 150 46 } 151 - catch (fat_architecture_not_supported& e) 152 - { 153 - if (char* p = strstr(argv[0], "/" DYLD_FULL_NAME)) // multilib 154 - { 155 - // Try to automatically execute "the other" dyld on multilib systems 156 - // if that other dyld's platform is supported in the fat binary 157 - if (std::find(e.archs().begin(), e.archs().end(), ARCH_CROSS_NAME) != e.archs().end()) 158 - { 159 - strcpy(p+1, DYLD_CROSS_NAME); 160 - execvp(argv[0], argv); 161 - } 162 - } 163 - 164 - std::cerr << argv[1] << " is a fat binary, but doesn't support the following architecture: " << ARCH_NAME << std::endl; 165 - } 166 - catch (std::exception& e) 47 + catch (const std::exception& e) 167 48 { 168 49 std::cerr << e.what() << std::endl; 169 50 return 1; 170 51 } 171 52 } 172 53 173 - extern "C" const char* dyld_getDarwinExecutablePath() 54 + static void printHelp(const char* argv0) 174 55 { 175 - return g_darwin_executable; 176 - } 56 + std::cerr << "This is Darling dyld for " ARCH_NAME ", a dynamic loader for Mach-O executables.\n\n"; 57 + std::cerr << "Copyright (C) 2012-2013 Lubos Dolezel\n" 58 + << "Originally based on maloader by Shinichiro Hamaji.\n\n"; 177 59 178 - extern "C" const char* dyld_getLoaderPath() 179 - { 180 - return g_loader->getCurrentLoader().c_str(); 181 - } 60 + std::cerr << "Usage: " << argv0 << " program-path [arguments...]\n\n"; 182 61 183 - void setupExecutablePath(const char* relativePath) 184 - { 185 - char path[PATH_MAX]; 186 - 187 - if (!::realpath(relativePath, path)) 188 - { 189 - // We'll probably fail a bit later anyway 190 - return; 191 - } 192 - 193 - ::strcpy(g_darwin_executable, path); 194 - ::strcpy(g_darwin_executable_path, dirname(path)); 195 - LOG << "@executable_path is " << g_darwin_executable_path << std::endl; 196 - } 197 - 198 - void setupDyldPath(const char* relativePath) 199 - { 200 - if (!::realpath(relativePath, g_dyld_path)) 201 - ::strcpy(g_dyld_path, relativePath); 202 - } 203 - 204 - void autoSysrootSearch() 205 - { 206 - if (const char* s = getenv("DYLD_ROOT_PATH")) 207 - { 208 - strncpy(g_sysroot, s, PATH_MAX-1); 209 - g_sysroot[PATH_MAX-1] = 0; 210 - } 211 - else 212 - { 213 - std::string path = g_darwin_executable_path; 214 - size_t pos = path.rfind("/usr/"); 215 - 216 - LOG << "Looking for SYSROOT signs in " << g_darwin_executable_path << std::endl; 217 - 218 - if (pos != std::string::npos && pos > 0) 219 - { 220 - std::string sysroot = path.substr(0, pos); 221 - LOG << "SYSROOT detected to be " << sysroot << std::endl; 222 - strncpy(g_sysroot, sysroot.c_str(), PATH_MAX-1); 223 - g_sysroot[PATH_MAX-1] = 0; 224 - } 225 - } 226 - } 227 - 228 - void checkPlatform(const char* argv1, const MachO* macho) 229 - { 230 - const char* plat = macho->platform(); 231 - if (strcmp(plat, ARCH_NAME) != 0) 232 - { 233 - std::cerr << argv1 << ": Cannot execute binary file.\nThis version of Darwin dyld cannot run binaries for " << plat << ".\n"; 234 - exit(-ENOEXEC); 235 - } 62 + std::cerr << "Environment variables:\n" 63 + "\tDYLD_DEBUG=expr - enable(+) or disable(-) debugging channels (debug, trace, error), e.g. +debug,-error\n" 64 + "\tDYLD_TRAMPOLINE=file - enable debugging trampolines, with argument info in file\n" 65 + "\tDYLD_IGN_MISSING_SYMS - replace missing symbols with a stub function\n\n" 66 + "\tDYLD_ROOT_PATH=<path> - set the base for library path resolution (overrides autodetection)\n" 67 + "\tDYLD_BIND_AT_LAUNCH - force dyld to bind all lazy references on startup\n" 68 + "\tDYLD_PRINT_INITIALIZERS - print initializers when they are invoked\n" 69 + "\tDYLD_PRINT_LIBRARIES - print libraries when they are loaded\n" 70 + "\tDYLD_PRINT_SEGMENTS - print segments when they are mapped into memory\n" 71 + "\tDYLD_PRINT_BINDINGS - print out when binds/ext. relocs are being resolved\n" 72 + "\tDYLD_PRINT_RPATHS - print @rpath resolution attempts\n\n"; 236 73 } 237 74
-8
src/dyld/dyld.h
··· 1 - #ifndef DYLD_H 2 - #define DYLD_H 3 - 4 - extern "C" int g_argc asm("NXArgc"); 5 - extern "C" char** g_argv asm("NXArgv"); 6 - 7 - #endif 8 -
+162
src/dyld/dyld_public.cpp
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2012-2013 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include "config.h" 21 + #include "dyld_public.h" 22 + #include "MachOMgr.h" 23 + #include "MachOObject.h" 24 + #include <util/debug.h> 25 + #include <cstring> 26 + #include <cstdlib> 27 + #include <map> 28 + #include <set> 29 + #include <link.h> 30 + #include <stddef.h> 31 + #include "../util/log.h" 32 + #include "../util/leb.h" 33 + 34 + using namespace Darling; 35 + 36 + uint32_t _dyld_image_count(void) 37 + { 38 + return MachOMgr::instance()->objectCount(); 39 + } 40 + 41 + const struct ::mach_header* _dyld_get_image_header(uint32_t image_index) 42 + { 43 + return MachOMgr::instance()->objectByIndex(image_index)->getMachHeader(); 44 + } 45 + 46 + intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index) 47 + { 48 + return MachOMgr::instance()->objectByIndex(image_index)->slide(); 49 + } 50 + 51 + const char* _dyld_get_image_name(uint32_t image_index) 52 + { 53 + return MachOMgr::instance()->objectByIndex(image_index)->path().c_str(); 54 + } 55 + 56 + char* getsectdata(const struct mach_header* header, const char* segname, const char* sectname, unsigned long* size) 57 + { 58 + MachOObject* obj = MachOMgr::instance()->objectByHeader((mach_header*) header); 59 + 60 + if (!obj || !sectname) 61 + { 62 + if (size) 63 + *size = 0; 64 + return nullptr; 65 + } 66 + if (!segname) 67 + segname = ""; 68 + 69 + return (char*) obj->getSection(segname, sectname, size); 70 + } 71 + 72 + void _dyld_register_func_for_add_image(MachOMgr::LoaderHookFunc* func) 73 + { 74 + MachOMgr::instance()->registerLoadHook(func); 75 + } 76 + 77 + void _dyld_register_func_for_remove_image(MachOMgr::LoaderHookFunc* func) 78 + { 79 + MachOMgr::instance()->registerUnloadHook(func); 80 + } 81 + 82 + 83 + const char* dyld_image_path_containing_address(const void* addr) 84 + { 85 + MachOObject* module = MachOMgr::instance()->objectForAddress((void*) addr); 86 + if (!module) 87 + return nullptr; 88 + else 89 + return module->path().c_str(); 90 + } 91 + 92 + 93 + bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info) 94 + { 95 + #if 0 96 + TRACE1(addr); 97 + const FileMap::ImageMap* map = g_file_map.imageMapForAddr(addr); 98 + 99 + if (!map) // in ELF 100 + { 101 + memset(info, 0, sizeof(*info)); 102 + 103 + CBData data = { addr, info }; 104 + 105 + dl_iterate_phdr(dlCallback, &data); 106 + std::cout << "Dwarf section at " << info->dwarf_section << std::endl; 107 + return info->dwarf_section != 0; 108 + } 109 + else // in Mach-O 110 + { 111 + info->mh = map->header; 112 + info->dwarf_section = reinterpret_cast<const void*>(map->eh_frame.first + map->slide); 113 + info->dwarf_section_length = map->eh_frame.second; 114 + 115 + // FIXME: we would get "malformed __unwind_info" warnings otherwise 116 + // info->compact_unwind_section = reinterpret_cast<const void*>(map->unwind_info.first + map->slide); 117 + // info->compact_unwind_section_length = map->unwind_info.second; 118 + info->compact_unwind_section = 0; 119 + info->compact_unwind_section_length = 0; 120 + 121 + return true; 122 + } 123 + #endif 124 + return false; 125 + } 126 + 127 + int32_t NSVersionOfRunTimeLibrary(const char* libraryName) 128 + { 129 + return -1; 130 + } 131 + 132 + int32_t NSVersionOfLinkTimeLibrary(const char* libraryName) 133 + { 134 + return -1; 135 + } 136 + 137 + int _NSGetExecutablePath(char* buf, unsigned int* size) 138 + { 139 + std::string path; 140 + 141 + MachOObject* mainModule = MachOMgr::instance()->mainModule(); 142 + 143 + if (mainModule) 144 + path = mainModule->path(); 145 + 146 + if (*size > path.length()+1) 147 + *size = path.length()+1; 148 + 149 + strncpy(buf, path.c_str(), *size); 150 + buf[(*size)-1] = 0; 151 + 152 + return 0; 153 + } 154 + 155 + void __dyld_make_delayed_module_initializer_calls() 156 + { 157 + } 158 + 159 + void __dyld_mod_term_funcs() 160 + { 161 + } 162 +
-843
src/dyld/ld.cpp
··· 1 - /* 2 - This file is part of Darling. 3 - 4 - Copyright (C) 2012 Lubos Dolezel 5 - 6 - Darling is free software: you can redistribute it and/or modify 7 - it under the terms of the GNU General Public License as published by 8 - the Free Software Foundation, either version 3 of the License, or 9 - (at your option) any later version. 10 - 11 - Darling is distributed in the hope that it will be useful, 12 - but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - GNU General Public License for more details. 15 - 16 - You should have received a copy of the GNU General Public License 17 - along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #include "config.h" 21 - #define DARWIN_LD_INTERNAL 22 - #include "MachOLoader.h" 23 - #include "ld.h" 24 - #include "arch.h" 25 - #include <libmach-o/MachO.h> 26 - #include "mutex.h" 27 - #include "trace.h" 28 - #include "FileMap.h" 29 - #include "log.h" 30 - #include "IniConfig.h" 31 - #include "stlutils.h" 32 - #include <unistd.h> 33 - #include <map> 34 - #include <string> 35 - #include <cstring> 36 - #include <sys/types.h> 37 - #include <sys/stat.h> 38 - #include <limits.h> 39 - #include <regex.h> 40 - #include <libgen.h> 41 - #include <cassert> 42 - #include <list> 43 - #include <algorithm> 44 - #include <execinfo.h> 45 - #include "dyld.h" 46 - #include <glob.h> 47 - 48 - static Darling::Mutex g_ldMutex; 49 - static std::map<std::string, LoadedLibrary*> g_ldLibraries; 50 - static __thread char g_ldError[256] = ""; 51 - static regex_t g_reFrameworkPath; 52 - static LoadedLibrary g_dummyLibrary; 53 - 54 - static std::list<std::string> g_searchPath; 55 - 56 - static const char* g_suffixes[] = { "$DARWIN_EXTSN", "$UNIX2003", "$NOCANCEL" }; 57 - static IniConfig* g_iniConfig = 0; 58 - 59 - static void* attemptDlopen(const char* filename, int flag); 60 - static int translateFlags(int flags); 61 - 62 - static std::list<Darling::DlsymHookFunc> g_dlsymHooks; 63 - 64 - static void* g_libStdCxxDarwin = nullptr; 65 - 66 - extern MachOLoader* g_loader; 67 - extern char g_darwin_executable_path[PATH_MAX]; 68 - extern char g_sysroot[PATH_MAX]; 69 - extern FileMap g_file_map; 70 - 71 - #define RET_IF(x) { if (void* p = x) return p; } 72 - 73 - static void findSearchpathsWildcard(std::string ldconfig_file_pattern); 74 - 75 - static void findSearchpaths(std::string ldconfig_file) 76 - { 77 - std::ifstream read(ldconfig_file); 78 - 79 - if(!read.is_open()) 80 - LOG << "can't read ldconfig config file - " << ldconfig_file << std::endl; 81 - 82 - std::string line; 83 - while(std::getline(read,line)) 84 - { 85 - line.erase(line.begin(), std::find_if(line.begin(), line.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); 86 - 87 - if(line.find("include") == 0) 88 - { 89 - line = line.substr(7); 90 - line.erase(line.begin(), std::find_if(line.begin(), line.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); 91 - 92 - if (line.find('*') == std::string::npos) 93 - findSearchpaths(line); 94 - else 95 - findSearchpathsWildcard(line); 96 - } 97 - else 98 - { 99 - size_t pos = line.find('#'); 100 - if (pos != std::string::npos) 101 - line.resize(pos); 102 - // TODO: trim 103 - g_searchPath.push_back(line); 104 - } 105 - } 106 - } 107 - 108 - static void findSearchpathsWildcard(std::string ldconfig_file_pattern) 109 - { 110 - // Use glob to break down wildcards (ex. "/etc/ld.so.conf.d/*.conf") 111 - glob_t globbuf; 112 - 113 - glob(ldconfig_file_pattern.c_str(), GLOB_NOSORT, nullptr, &globbuf); 114 - 115 - for (size_t i = 0; i < globbuf.gl_pathc; i++) 116 - findSearchpaths(globbuf.gl_pathv[i]); 117 - 118 - globfree(&globbuf); 119 - } 120 - 121 - void Darling::initLD() 122 - { 123 - int rv = regcomp(&g_reFrameworkPath, "/System/Library/Frameworks/([a-zA-Z0-9\\.]+)/Versions/([a-zA-Z0-9\\.]+)/.*", REG_EXTENDED); 124 - assert(rv == 0); 125 - 126 - g_dummyLibrary.name = "/dev/null"; 127 - g_dummyLibrary.refCount = 1; 128 - g_dummyLibrary.type = LoadedLibraryDummy; 129 - g_dummyLibrary.nativeRef = 0; 130 - g_dummyLibrary.exports = 0; 131 - 132 - try 133 - { 134 - g_iniConfig = new IniConfig(ETC_DARLING_PATH "/dylib.conf"); 135 - } 136 - catch (const std::exception& e) 137 - { 138 - std::cerr << e.what() << std::endl; 139 - } 140 - //add hardcoded library paths 141 - g_searchPath.push_back(LIB_PATH); 142 - g_searchPath.push_back("/lib"); 143 - g_searchPath.push_back("/usr/lib"); 144 - //find paths from ldconfig 145 - findSearchpathsWildcard(LD_SO_CONFIG); 146 - } 147 - 148 - static std::string replacePathPrefix(const char* prefix, const char* prefixed, const char* replacement) 149 - { 150 - std::string path = replacement; 151 - path += (prefixed + strlen(prefix)); 152 - return path; 153 - } 154 - 155 - void* __darwin_dlopen(const char* filename, int flag) 156 - { 157 - void* callerLocation; 158 - std::vector<std::string> rpathList; 159 - const FileMap::ImageMap *mainExecutable, *callerExecutable; 160 - 161 - callerLocation = __builtin_return_address(0); 162 - mainExecutable = g_file_map.mainExecutable(); 163 - callerExecutable = g_file_map.imageMapForAddr(callerLocation); 164 - 165 - rpathList.insert(rpathList.end(), mainExecutable->rpaths.begin(), mainExecutable->rpaths.end()); 166 - if (callerExecutable != nullptr && callerExecutable != mainExecutable) 167 - rpathList.insert(rpathList.end(), callerExecutable->rpaths.begin(), callerExecutable->rpaths.end()); 168 - 169 - return Darling::DlopenWithContext(filename, flag, rpathList); 170 - } 171 - 172 - static const char* resolveAlias(const char* library) 173 - { 174 - if (!g_iniConfig) 175 - return nullptr; 176 - if (g_iniConfig->hasSection("dylibs")) 177 - { 178 - const IniConfig::ValueMap* m = g_iniConfig->getSection("dylibs"); 179 - auto it = m->find(library); 180 - if (it != m->end()) 181 - return it->second.c_str(); 182 - } 183 - if (strncmp(library, "/System/Library/Frameworks/", 27) == 0) 184 - { 185 - regmatch_t match[3]; 186 - if (regexec(&g_reFrameworkPath, library, sizeof(match)/sizeof(match[0]), match, 0) != REG_NOMATCH) 187 - { 188 - std::string name, version; 189 - 190 - name = std::string(library+match[1].rm_so, match[1].rm_eo - match[1].rm_so); 191 - version = std::string(library+match[2].rm_so, match[2].rm_eo - match[2].rm_so); 192 - 193 - if (g_iniConfig->hasSection(name.c_str())) 194 - { 195 - const IniConfig::ValueMap* m = g_iniConfig->getSection(name.c_str()); 196 - auto it = m->find(version); 197 - 198 - if (it != m->end()) 199 - return it->second.c_str(); 200 - } 201 - } 202 - } 203 - return nullptr; 204 - } 205 - 206 - void* Darling::DlopenWithContext(const char* filename, int flag, const std::vector<std::string>& rpaths, bool* notFoundError) 207 - { 208 - TRACE2(filename, flag); 209 - 210 - Darling::MutexLock l(g_ldMutex); 211 - std::string path; 212 - 213 - g_ldError[0] = 0; 214 - 215 - if (notFoundError != nullptr) 216 - *notFoundError = false; 217 - 218 - if (!filename) 219 - { 220 - strcpy(g_ldError, "Invalid argument"); 221 - return 0; 222 - } 223 - 224 - flag = translateFlags(flag); 225 - 226 - if (strncmp(filename, "@executable_path", 16) == 0) 227 - { 228 - path = replacePathPrefix("@executable_path", filename, g_darwin_executable_path); 229 - LOG << "Full path after replacing @executable_path: " << path << std::endl; 230 - if (::access(path.c_str(), R_OK) == 0) 231 - RET_IF( attemptDlopen(path.c_str(), flag) ); 232 - } 233 - else if (strncmp(filename, "@loader_path", 12) == 0) 234 - { 235 - path = replacePathPrefix("@loader_path", filename, g_loader->getCurrentLoader().c_str()); 236 - LOG << "Current ldr: " << g_loader->getCurrentLoader() << std::endl; 237 - LOG << "Full path after replacing @loader_path: " << path << std::endl; 238 - if (::access(path.c_str(), R_OK) == 0) 239 - RET_IF( attemptDlopen(path.c_str(), flag) ); 240 - } 241 - else if (strncmp(filename, "@rpath", 6) == 0) 242 - { 243 - // @rpath - https://wincent.com/wiki/@executable_path,_@load_path_and_@rpath 244 - for (std::string rpathSearch : rpaths) 245 - { 246 - bool recNotFoundError; 247 - path = replacePathPrefix("@rpath", filename, rpathSearch.c_str()); 248 - 249 - RET_IF( DlopenWithContext(path.c_str(), flag, rpaths, &recNotFoundError) ); 250 - 251 - // Stop if there was an error, vs just not found 252 - if (!recNotFoundError) 253 - return nullptr; 254 - } 255 - } 256 - else 257 - { 258 - if (const char* ldp = getenv("DYLD_LIBRARY_PATH")) 259 - { 260 - path = std::string(ldp) + "/" + filename; 261 - if (::access(path.c_str(), R_OK) == 0) 262 - RET_IF( attemptDlopen(path.c_str(), flag) ); 263 - } 264 - 265 - if (const char* realPath = resolveAlias(filename)) 266 - RET_IF( attemptDlopen(realPath, flag) ); 267 - 268 - if (strncmp(filename, "/usr/lib/", 9) == 0) 269 - filename = filename + 9; 270 - 271 - if (g_sysroot[0]) 272 - { 273 - path = g_sysroot; 274 - path += filename; 275 - LOG << "Trying " << path << std::endl; 276 - RET_IF( attemptDlopen(path.c_str(), flag) ); 277 - } 278 - 279 - std::list<std::string>::iterator it; 280 - for (it=g_searchPath.begin(); it!=g_searchPath.end(); ++it) 281 - { 282 - path = *it + "/" + filename; 283 - LOG << "Trying " << path << std::endl; 284 - if (::access(path.c_str(), R_OK) == 0) 285 - { 286 - RET_IF( attemptDlopen(path.c_str(), flag) ); 287 - } 288 - else 289 - { 290 - if (::access((path+".so").c_str(), R_OK) == 0) 291 - RET_IF( attemptDlopen(path.c_str(), flag) ); 292 - } 293 - } 294 - 295 - // Unlike ld-linux, dyld seems to search in . too 296 - if (!strchr(filename, '/')) 297 - { 298 - if (::access(filename, R_OK) == 0) 299 - RET_IF( attemptDlopen(filename, flag) ); 300 - } 301 - } 302 - 303 - if (!g_ldError[0]) 304 - { 305 - snprintf(g_ldError, sizeof(g_ldError)-1, "File not found: %s", filename); 306 - 307 - if (notFoundError != nullptr) 308 - *notFoundError = true; 309 - } 310 - 311 - return nullptr; 312 - } 313 - 314 - static int translateFlags(int flag) 315 - { 316 - int native_flags = 0; 317 - if (flag & DARWIN_RTLD_LAZY) 318 - native_flags |= RTLD_LAZY; 319 - if (flag & DARWIN_RTLD_NOW) 320 - native_flags |= RTLD_NOW; 321 - if (flag & DARWIN_RTLD_LOCAL) 322 - native_flags |= RTLD_LOCAL; 323 - if (flag & DARWIN_RTLD_GLOBAL) 324 - native_flags |= RTLD_GLOBAL; 325 - if (flag & DARWIN_RTLD_NOLOAD) 326 - native_flags |= RTLD_NOLOAD; 327 - if (flag & DARWIN_RTLD_NODELETE) 328 - native_flags |= RTLD_NODELETE; 329 - if (flag & __DARLING_RTLD_NOBIND) 330 - native_flags |= __DARLING_RTLD_NOBIND; 331 - return native_flags; 332 - } 333 - 334 - static bool isSymlink(const char* path) 335 - { 336 - struct stat st; 337 - if (::lstat(path, &st) == -1) 338 - return false; 339 - return S_ISLNK(st.st_mode); 340 - } 341 - 342 - void* attemptDlopen(const char* filename, int flag) 343 - { 344 - char name[2048]; 345 - 346 - TRACE2(filename,flag); 347 - 348 - // We need to run access() here not to use realpath for "libncurses.so.5" for example 349 - if (::access(filename, R_OK) == 0) 350 - { 351 - if (!realpath(filename, name)) 352 - { 353 - strcpy(g_ldError, strerror(errno)); 354 - return 0; 355 - } 356 - } 357 - else 358 - strcpy(name, filename); 359 - 360 - if (strcmp(name, "/dev/null") == 0) 361 - { 362 - // We return a dummy 363 - return &g_dummyLibrary; 364 - } 365 - 366 - std::map<std::string,LoadedLibrary*>::iterator it = g_ldLibraries.find(name); 367 - if (it != g_ldLibraries.end()) 368 - { 369 - // TODO: flags 370 - it->second->refCount++; 371 - if (it->second->type == LoadedLibraryNative) 372 - { 373 - // add a reference in native ld 374 - ::dlopen(name, RTLD_NOW); 375 - } 376 - 377 - return it->second; 378 - } 379 - else 380 - { 381 - // actually load the library 382 - char* p = strstr(name, ".so"); 383 - // we followed a link, so we need to check for .so., too 384 - if ((p && name+strlen(name)-p == 3) || strstr(name, ".so.")) // endsWith() 385 - { 386 - LOG << "Loading a native library " << name << std::endl; 387 - // We're loading a native library 388 - // TODO: flags 389 - int flags = RTLD_NOW | RTLD_GLOBAL; 390 - void* d; 391 - 392 - // TODO: another hack location for libstdc++darwin.so 393 - if (strcmp(name, "libstdc++darwin.so") == 0) 394 - flags |= RTLD_DEEPBIND; 395 - 396 - d = ::dlopen(name, flags); 397 - 398 - if (d != 0) 399 - { 400 - LOG << "Native library loaded\n"; 401 - 402 - LoadedLibrary* lib = new LoadedLibrary; 403 - lib->name = name; 404 - lib->refCount = 1; 405 - lib->type = LoadedLibraryNative; 406 - lib->nativeRef = d; 407 - //lib->slide = lib->base = 0; 408 - 409 - if (strstr(name, "libstdc++darwin") != nullptr) 410 - g_libStdCxxDarwin = d; 411 - 412 - g_ldLibraries[name] = lib; 413 - return lib; 414 - } 415 - else 416 - { 417 - const char* err = ::dlerror(); 418 - LOG << "Native library failed to load: " << err << std::endl; 419 - 420 - if (err && !g_ldError[0]) // we don't overwrite previous errors 421 - { 422 - LOG << "Library failed to load: " << err << std::endl; 423 - strcpy(g_ldError, err); 424 - } 425 - return 0; 426 - } 427 - } 428 - else 429 - { 430 - LOG << "Loading a Mach-O library\n"; 431 - // We're loading a Mach-O library 432 - try 433 - { 434 - MachO* machO = MachO::readFile(name, ARCH_NAME); 435 - if (!machO) 436 - { 437 - snprintf(g_ldError, sizeof(g_ldError)-1, "Cannot parse Mach-O library: %s", name); 438 - return 0; 439 - } 440 - 441 - LoadedLibrary* lib = new LoadedLibrary; 442 - bool nobind = (flag & __DARLING_RTLD_NOBIND) != 0; 443 - 444 - lib->name = name; 445 - lib->refCount = 1; 446 - lib->type = LoadedLibraryDylib; 447 - lib->machoRef = machO; 448 - 449 - bool global = flag & RTLD_GLOBAL && !(flag & RTLD_LOCAL); 450 - bool lazy = flag & RTLD_LAZY && !(flag & RTLD_NOW); 451 - 452 - // Insert an entry before doing the full load to prevent recursive loading 453 - g_ldLibraries[name] = lib; 454 - 455 - //if (!global) 456 - //{ 457 - lib->exports = new Exports; 458 - g_loader->load(*machO, name, lib->exports, nobind, lazy); 459 - //} 460 - //else 461 - // g_loader->load(*machO, name, 0, nobind, lazy); 462 - 463 - if (!nobind) 464 - { 465 - char* apple[2] = { g_darwin_executable_path, 0 }; 466 - g_loader->runPendingInitFuncs(g_argc, g_argv, environ, apple); 467 - } 468 - 469 - return lib; 470 - } 471 - catch (const std::exception& e) 472 - { 473 - strcpy(g_ldError, e.what()); 474 - return 0; 475 - } 476 - } 477 - } 478 - } 479 - 480 - int __darwin_dlclose(void* handle) 481 - { 482 - TRACE1(handle); 483 - 484 - Darling::MutexLock l(g_ldMutex); 485 - g_ldError[0] = 0; 486 - 487 - if (!handle) 488 - return 0; 489 - 490 - LoadedLibrary* lib = reinterpret_cast<LoadedLibrary*>(handle); 491 - /*if (!lib) 492 - { 493 - strcpy(g_ldError, "Invalid handle passed to __darwin_dlclose()"); 494 - return -1; 495 - }*/ 496 - 497 - lib->refCount--; 498 - 499 - if (lib->type == LoadedLibraryNative) 500 - ::dlclose(lib->nativeRef); 501 - if (!lib->refCount) 502 - { 503 - if (lib->type == LoadedLibraryDylib) 504 - { 505 - // TODO: unmap in g_loader! 506 - delete lib->exports; 507 - 508 - for (std::map<std::string,LoadedLibrary*>::iterator it = g_ldLibraries.begin(); it != g_ldLibraries.end(); it++) 509 - { 510 - if (it->second == lib) 511 - { 512 - g_ldLibraries.erase(it); 513 - delete lib; 514 - break; 515 - } 516 - } 517 - } 518 - } 519 - 520 - return 0; 521 - } 522 - 523 - const char* __darwin_dlerror(void) 524 - { 525 - //TRACE(); 526 - 527 - return g_ldError[0] ? g_ldError : 0; 528 - } 529 - 530 - static const char* translateSymbol(const char* symbol) 531 - { 532 - bool translated = false; 533 - static char symbuffer[255]; 534 - 535 - strcpy(symbuffer, symbol); 536 - 537 - for (auto f : g_dlsymHooks) 538 - { 539 - if (f(symbuffer)) 540 - { 541 - translated = true; 542 - break; 543 - } 544 - } 545 - 546 - if (!translated) 547 - { 548 - std::string s = symbol; 549 - for (int i = 0; i < sizeof(g_suffixes) / sizeof(g_suffixes[0]); i++) 550 - { 551 - size_t pos = s.find(g_suffixes[i]); 552 - if (pos != std::string::npos) 553 - s.erase(pos, strlen(g_suffixes[i])); 554 - } 555 - 556 - strcpy(symbuffer, s.c_str()); 557 - } 558 - 559 - return symbuffer; 560 - } 561 - 562 - NSSymbol NSLookupAndBindSymbol(const char* symbolName) 563 - { 564 - return __darwin_dlsym(DARWIN_RTLD_DEFAULT, symbolName); 565 - } 566 - 567 - NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName) 568 - { 569 - return __darwin_dlsym(module, symbolName); 570 - } 571 - 572 - const char* NSNameOfSymbol(NSSymbol symbolAddr) 573 - { 574 - Dl_info info; 575 - 576 - if (!__darwin_dladdr(symbolAddr, &info)) 577 - return nullptr; 578 - 579 - return info.dli_sname; 580 - } 581 - 582 - void* NSAddressOfSymbol(NSSymbol nssymbol) 583 - { 584 - return nssymbol; 585 - } 586 - 587 - int NSIsSymbolNameDefined(const char* name) 588 - { 589 - return NSLookupAndBindSymbol(name) != nullptr; 590 - } 591 - 592 - NSModule NSModuleForSymbol(NSSymbol symbol) 593 - { 594 - const FileMap::ImageMap* map = g_file_map.imageMapForAddr(symbol); 595 - 596 - if (!map) 597 - return nullptr; 598 - 599 - auto it = g_ldLibraries.find(map->filename); 600 - if (it == g_ldLibraries.end()) 601 - return nullptr; 602 - 603 - return it->second; 604 - } 605 - 606 - int NSIsSymbolNameDefinedInImage(const struct mach_header *image, const char *symbolName) 607 - { 608 - // TODO: this inefficient double search will be avoided when we unite LoadedLibrary and FileMap::ImageMap 609 - const FileMap::ImageMap* map = g_file_map.imageMapForHeader(image); 610 - LoadedLibrary* ldlib = g_ldLibraries[map->filename]; 611 - 612 - return __darwin_dlsym(ldlib, symbolName) != nullptr; 613 - } 614 - 615 - const char* NSNameOfModule(NSModule m) 616 - { 617 - if (!m) 618 - return nullptr; 619 - 620 - LoadedLibrary* ldlib = static_cast<LoadedLibrary*>(m); 621 - return ldlib->name.c_str(); 622 - } 623 - 624 - const char* NSLibraryNameForModule(NSModule m) 625 - { 626 - // TODO: we need to check what these two functions return on a real system 627 - return NSNameOfModule(m); 628 - } 629 - 630 - void* __darwin_dlsym(void* handle, const char* symbol, void* extra) 631 - { 632 - // TRACE2(handle, symbol); 633 - 634 - Darling::MutexLock l(g_ldMutex); 635 - g_ldError[0] = 0; 636 - 637 - if (!handle) 638 - handle = DARWIN_RTLD_DEFAULT; 639 - 640 - //if (handle == DARWIN_RTLD_NEXT || handle == DARWIN_RTLD_SELF || handle == DARWIN_RTLD_MAIN_ONLY || !handle) 641 - //{ 642 - // LOG << "Cannot yet handle certain DARWIN_RTLD_* search strategies, falling back to RTLD_DEFAULT\n"; 643 - // handle = DARWIN_RTLD_DEFAULT; 644 - //} 645 - 646 - //handling: 647 - if (handle == DARWIN_RTLD_DEFAULT || handle == __DARLING_RTLD_STRONG) 648 - { 649 - // First try native with the __darwin prefix 650 - void* sym; 651 - char* buf = reinterpret_cast<char*>(malloc(strlen(symbol)+20)); 652 - strcpy(buf, "__darwin_"); 653 - strcat(buf, symbol); 654 - 655 - sym = ::dlsym(RTLD_DEFAULT, buf); 656 - if (sym) 657 - return sym; 658 - 659 - // Now try Darwin libraries 660 - const std::list<Exports*>& le = g_loader->getExports(); 661 - std::list<Exports*>::const_iterator it = le.begin(); 662 - 663 - while (it != le.end()) 664 - { 665 - Exports* e = *it; 666 - Exports::iterator itSym = e->find(symbol); 667 - 668 - if (itSym == e->end()) 669 - itSym = e->find(std::string("_") + symbol); // TODO: WTF? 670 - 671 - if (itSym != e->end()) 672 - { 673 - if (handle != __DARLING_RTLD_STRONG || !(itSym->second.flag & 4)) 674 - { 675 - MachO::Export& exp = itSym->second; 676 - 677 - // If there is a resolver function, we lazily call it now 678 - // and update the original stub address with the real one returned. 679 - 680 - if (exp.resolver) 681 - { 682 - typedef uintptr_t (ResolverFunc)(); 683 - ResolverFunc* func = (ResolverFunc*) exp.resolver; 684 - exp.addr = func(); 685 - exp.resolver = 0; 686 - } 687 - return reinterpret_cast<void*>(itSym->second.addr); 688 - } 689 - } 690 - it++; 691 - } 692 - 693 - // Now try without a prefix 694 - const char* translated = translateSymbol(symbol); 695 - LOG << "Trying " << translated << std::endl; 696 - #if 0 // FIXME: This causes serious regressions! 697 - for (auto& pair : g_ldLibraries) 698 - { 699 - if (pair.second->type == LoadedLibraryNative) 700 - { 701 - LOG << "Trying in " << pair.first << std::endl; 702 - RET_IF(::dlsym(pair.second->nativeRef, translated)); 703 - if (strcmp(translated, symbol) != 0) 704 - RET_IF(::dlsym(pair.second->nativeRef, symbol)); 705 - } 706 - } 707 - #endif 708 - 709 - // FIXME: this is very crude, but simple and effective... 710 - // "St" == namespace std 711 - if (g_libStdCxxDarwin && strstr(translated, "St") != nullptr) 712 - { 713 - //static void* self = ::dlopen(nullptr, RTLD_LAZY); 714 - //RET_IF(::dlsym(self, translated)); 715 - if (strcmp(translated, "_ZSt4cout") && strcmp(translated, "_ZSt4cin") && strcmp(translated, "_ZSt4cerr")) 716 - { 717 - RET_IF(::dlsym(g_libStdCxxDarwin, translated)); 718 - } 719 - } 720 - 721 - RET_IF(::dlsym(RTLD_DEFAULT, translated)); 722 - 723 - if (strcmp(translated, symbol) != 0) 724 - RET_IF(::dlsym(RTLD_DEFAULT, symbol)); 725 - 726 - // Now we fail 727 - snprintf(g_ldError, sizeof(g_ldError)-1, "Cannot find symbol '%s'", symbol); 728 - return nullptr; 729 - } 730 - else if (handle == DARWIN_RTLD_NEXT) 731 - { 732 - // For this, we'll have to rethink and integrate Exports in MachOLoader and LoadedLibrary in here 733 - abort(); 734 - } 735 - else if (handle == DARWIN_RTLD_MAIN_ONLY || handle == DARWIN_RTLD_SELF) 736 - { 737 - Exports* exports = nullptr; 738 - if (handle == DARWIN_RTLD_MAIN_ONLY) 739 - exports = g_loader->getMainExecutableExports(); 740 - else 741 - { 742 - void* retaddr; 743 - const char* name; 744 - 745 - backtrace(&retaddr, 1); 746 - 747 - name = g_file_map.fileNameForAddr(retaddr); 748 - if (!name) 749 - { 750 - strcpy(g_ldError, "Couldn't determine the current module"); 751 - return nullptr; 752 - } 753 - 754 - auto it = g_ldLibraries.find(name); 755 - if (it == g_ldLibraries.end()) 756 - { 757 - strcpy(g_ldError, "Couldn't determine the current module by path"); 758 - return nullptr; 759 - } 760 - 761 - exports = it->second->exports; 762 - } 763 - 764 - Exports::iterator itSym = exports->find(symbol); 765 - if (itSym == exports->end()) 766 - { 767 - snprintf(g_ldError, sizeof(g_ldError)-1, "Cannot find symbol '%s'", symbol); 768 - return 0; 769 - } 770 - else 771 - return reinterpret_cast<void*>(itSym->second.addr); 772 - } 773 - else 774 - { 775 - LoadedLibrary* lib = nullptr; 776 - 777 - lib = reinterpret_cast<LoadedLibrary*>(handle); 778 - 779 - if (lib->type == LoadedLibraryNative) 780 - { 781 - void* rv = ::dlsym(lib->nativeRef, symbol); 782 - if (!rv) 783 - strcpy(g_ldError, ::dlerror()); 784 - return rv; 785 - } 786 - else if (lib->type == LoadedLibraryDummy) 787 - { 788 - snprintf(g_ldError, sizeof(g_ldError)-1, "Cannot find symbol '%s'", symbol); 789 - return 0; 790 - } 791 - //else if (!lib->exports) 792 - //{ 793 - // // TODO: this isn't 100% correct 794 - // handle = DARWIN_RTLD_DEFAULT; 795 - // goto handling; 796 - //} 797 - else 798 - { 799 - Exports::iterator itSym = lib->exports->find(symbol); 800 - if (itSym == lib->exports->end()) 801 - { 802 - snprintf(g_ldError, sizeof(g_ldError)-1, "Cannot find symbol '%s'", symbol); 803 - return 0; 804 - } 805 - else 806 - return reinterpret_cast<void*>(itSym->second.addr); 807 - } 808 - } 809 - } 810 - 811 - int __darwin_dladdr(void *addr, Dl_info *info) 812 - { 813 - TRACE2(addr, info); 814 - 815 - Darling::MutexLock l(g_ldMutex); 816 - g_ldError[0] = 0; 817 - 818 - if (!g_file_map.findSymbolInfo(addr, info)) 819 - { 820 - strcpy(g_ldError, "Specified address not mapped to a Mach-O file"); 821 - return -1; 822 - } 823 - if (!info->dli_fbase) 824 - { 825 - strcpy(g_ldError, "Specified address not resolvable to a symbol"); 826 - return -1; 827 - } 828 - 829 - return 0; 830 - } 831 - 832 - void Darling::registerDlsymHook(Darling::DlsymHookFunc func) 833 - { 834 - g_dlsymHooks.push_front(func); 835 - } 836 - 837 - void Darling::deregisterDlsymHook(Darling::DlsymHookFunc func) 838 - { 839 - //auto it = std::find(g_dlsymHooks.begin(), g_dlsymHooks.end(), func); 840 - //if (it != g_dlsymHooks.end()) 841 - // g_dlsymHooks.erase(it); 842 - } 843 -
-103
src/dyld/ld.h
··· 1 - /* 2 - This file is part of Darling. 3 - 4 - Copyright (C) 2012 Lubos Dolezel 5 - 6 - Darling is free software: you can redistribute it and/or modify 7 - it under the terms of the GNU General Public License as published by 8 - the Free Software Foundation, either version 3 of the License, or 9 - (at your option) any later version. 10 - 11 - Darling is distributed in the hope that it will be useful, 12 - but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - GNU General Public License for more details. 15 - 16 - You should have received a copy of the GNU General Public License 17 - along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef DARWIN_LD_H 21 - #define DARWIN_LD_H 22 - #include <dlfcn.h> 23 - #include <unordered_map> 24 - //#include "MachOLoader.h" 25 - 26 - #define DARWIN_RTLD_LAZY 0x1 27 - #define DARWIN_RTLD_NOW 0x2 28 - #define DARWIN_RTLD_LOCAL 0x4 29 - #define DARWIN_RTLD_GLOBAL 0x8 30 - #define DARWIN_RTLD_NOLOAD 0x10 31 - #define DARWIN_RTLD_NODELETE 0x80 32 - #define DARWIN_RTLD_FIRST 0x100 33 - #define __DARLING_RTLD_NOBIND 0x20000000 34 - 35 - #define DARWIN_RTLD_NEXT ((void*)-1) 36 - #define DARWIN_RTLD_DEFAULT ((void*)-2) 37 - #define DARWIN_RTLD_SELF ((void*)-3) 38 - #define DARWIN_RTLD_MAIN_ONLY ((void*)-5) 39 - 40 - // Internal, only for weak symbol resolution 41 - #define __DARLING_RTLD_STRONG ((void*)-20) 42 - 43 - #define LD_SO_CONFIG "/etc/ld.so.conf" 44 - 45 - typedef void* NSSymbol; 46 - typedef void* NSModule; 47 - 48 - extern "C" 49 - { 50 - 51 - void* __darwin_dlopen(const char* filename, int flag); 52 - int __darwin_dlclose(void* handle); 53 - const char* __darwin_dlerror(void); 54 - void* __darwin_dlsym(void* handle, const char* symbol, void* extra = nullptr); 55 - int __darwin_dladdr(void *addr, Dl_info *info); 56 - 57 - // Obsolete (or "not recommended") APIs 58 - NSSymbol NSLookupAndBindSymbol(const char* symbolName); 59 - void* NSAddressOfSymbol(NSSymbol nssymbol); 60 - NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName); 61 - const char* NSNameOfSymbol(NSSymbol nssymbol); 62 - int NSIsSymbolNameDefined(const char* name); 63 - NSModule NSModuleForSymbol(NSSymbol symbol); 64 - int NSIsSymbolNameDefinedInImage(const struct mach_header *image, const char *symbolName); 65 - const char* NSNameOfModule(NSModule m); 66 - const char* NSLibraryNameForModule(NSModule m); 67 - // TODO: rest of these NS* calls if used anywhere 68 - 69 - } 70 - 71 - // FIXME: cleanup urgently needed! 72 - #ifdef MACHOLOADER_H 73 - enum LoadedLibraryType { LoadedLibraryDylib, LoadedLibraryNative, LoadedLibraryDummy }; 74 - 75 - typedef std::unordered_map<std::string, MachO::Export> Exports; 76 - 77 - // TODO: this should be united with the list in FileMap 78 - struct LoadedLibrary 79 - { 80 - std::string name; 81 - int refCount; 82 - LoadedLibraryType type; 83 - union 84 - { 85 - void* nativeRef; 86 - MachO* machoRef; 87 - }; 88 - //intptr slide; 89 - //intptr base; 90 - Exports* exports; 91 - }; 92 - #endif 93 - 94 - namespace Darling 95 - { 96 - typedef bool (*DlsymHookFunc)(char* symName); 97 - void registerDlsymHook(DlsymHookFunc func); 98 - void deregisterDlsymHook(DlsymHookFunc func); 99 - void* DlopenWithContext(const char* filename, int flag, const std::vector<std::string>& rpaths, bool* notFoundError = nullptr); 100 - void initLD(); 101 - }; 102 - 103 - #endif
-299
src/dyld/public.cpp
··· 1 - /* 2 - This file is part of Darling. 3 - 4 - Copyright (C) 2012 Lubos Dolezel 5 - 6 - Darling is free software: you can redistribute it and/or modify 7 - it under the terms of the GNU General Public License as published by 8 - the Free Software Foundation, either version 3 of the License, or 9 - (at your option) any later version. 10 - 11 - Darling is distributed in the hope that it will be useful, 12 - but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - GNU General Public License for more details. 15 - 16 - You should have received a copy of the GNU General Public License 17 - along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #include "config.h" 21 - #include "public.h" 22 - #include "MachOLoader.h" 23 - #include "FileMap.h" 24 - #include "trace.h" 25 - #include <cstring> 26 - #include <cstdlib> 27 - #include <map> 28 - #include <set> 29 - #include <link.h> 30 - #include <stddef.h> 31 - #include "../util/log.h" 32 - #include "../util/leb.h" 33 - 34 - extern FileMap g_file_map; 35 - extern "C" char* dyld_getDarwinExecutablePath(); 36 - 37 - std::set<LoaderHookFunc*> g_machoLoaderHooks; 38 - 39 - uint32_t _dyld_image_count(void) 40 - { 41 - return g_file_map.images().size(); 42 - } 43 - 44 - const struct mach_header* _dyld_get_image_header(uint32_t image_index) 45 - { 46 - return g_file_map.images().at(image_index)->header; 47 - } 48 - 49 - intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index) 50 - { 51 - return g_file_map.images().at(image_index)->slide; 52 - } 53 - 54 - const char* _dyld_get_image_name(uint32_t image_index) 55 - { 56 - return g_file_map.images().at(image_index)->filename.c_str(); 57 - } 58 - 59 - char* getsectdata(const struct mach_header* header, const char* segname, const char* sectname, unsigned long* size) 60 - { 61 - FileMap::ImageMap* imageMap = 0; 62 - 63 - if (!segname || !sectname || !size) 64 - { 65 - LOG << "Warning: getsectdata() called with NULL pointers\n"; 66 - // abort(); 67 - return nullptr; 68 - } 69 - 70 - // Find the loaded image the header belongs to 71 - for (FileMap::ImageMap* entry : g_file_map.images()) 72 - { 73 - if (entry->header == header) 74 - { 75 - imageMap = entry; 76 - break; 77 - } 78 - } 79 - 80 - if (!imageMap) 81 - return 0; // Original dyld's man page indicates that it would still somehow proceed, but we don't bother 82 - 83 - for (const MachO::Section& sect : imageMap->sections) 84 - { 85 - if (sect.segment == segname && sect.section == sectname) 86 - { 87 - char* addr = reinterpret_cast<char*>(sect.addr); 88 - 89 - *size = sect.size; 90 - addr += imageMap->slide; 91 - 92 - return addr; 93 - } 94 - } 95 - return 0; 96 - } 97 - 98 - void _dyld_register_func_for_add_image(LoaderHookFunc* func) 99 - { 100 - // Needed for ObjC 101 - g_machoLoaderHooks.insert(func); 102 - } 103 - 104 - void _dyld_register_func_for_remove_image(LoaderHookFunc* func) 105 - { 106 - g_machoLoaderHooks.erase(func); 107 - } 108 - 109 - int32_t NSVersionOfRunTimeLibrary(const char* libraryName) 110 - { 111 - return -1; 112 - } 113 - 114 - int32_t NSVersionOfLinkTimeLibrary(const char* libraryName) 115 - { 116 - return -1; 117 - } 118 - 119 - int _NSGetExecutablePath(char* buf, unsigned int* size) 120 - { 121 - strncpy(buf, dyld_getDarwinExecutablePath(), (*size)-1); 122 - buf[(*size)-1] = 0; 123 - 124 - *size = strlen(buf); 125 - 126 - return 0; 127 - } 128 - 129 - const char* dyld_image_path_containing_address(const void* addr) 130 - { 131 - return g_file_map.fileNameForAddr(addr); 132 - } 133 - 134 - struct CBData 135 - { 136 - void* addr; 137 - struct dyld_unwind_sections* info; 138 - }; 139 - 140 - #pragma pack(1) 141 - struct eh_frame_hdr 142 - { 143 - uint8_t version, eh_frame_ptr_enc, fde_count_enc, table_enc; 144 - uint8_t eh_frame_ptr[]; 145 - }; 146 - #pragma pack() 147 - 148 - static uintptr_t readEncodedPointer(const eh_frame_hdr* hdr) 149 - { 150 - uint8_t format = hdr->eh_frame_ptr_enc & 0xf; 151 - uint8_t rel = hdr->eh_frame_ptr_enc & 0xf0; 152 - uintptr_t val; 153 - bool isSigned = false; 154 - 155 - if (hdr->eh_frame_ptr_enc == 0xff) 156 - return 0; 157 - 158 - switch (format) 159 - { 160 - case 1: // unsigned LEB 161 - { 162 - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(hdr->eh_frame_ptr); 163 - val = uleb128(ptr); 164 - break; 165 - } 166 - case 2: // 2 bytes 167 - val = *reinterpret_cast<const uint16_t*>(hdr->eh_frame_ptr); 168 - break; 169 - case 3: 170 - val = *reinterpret_cast<const uint32_t*>(hdr->eh_frame_ptr); 171 - break; 172 - case 4: 173 - val = *reinterpret_cast<const uint64_t*>(hdr->eh_frame_ptr); 174 - break; 175 - case 9: // signed LEB 176 - { 177 - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(hdr->eh_frame_ptr); 178 - val = sleb128(ptr); 179 - break; 180 - } 181 - // FIXME: add 'dlpi_addr' (base address) to these? 182 - case 0xa: 183 - val = *reinterpret_cast<const int16_t*>(hdr->eh_frame_ptr); 184 - break; 185 - case 0xb: 186 - val = *reinterpret_cast<const int32_t*>(hdr->eh_frame_ptr); 187 - break; 188 - case 0xc: 189 - val = *reinterpret_cast<const int64_t*>(hdr->eh_frame_ptr); 190 - break; 191 - default: 192 - return 0; 193 - } 194 - 195 - switch (rel) 196 - { 197 - case 0: // no change 198 - break; 199 - case 0x10: // pcrel 200 - val += reinterpret_cast<uintptr_t>(hdr) + 4; 201 - break; 202 - case 0x30: // eh_frame_hdr rel 203 - val += reinterpret_cast<uintptr_t>(hdr); 204 - break; 205 - default: 206 - return 0; 207 - } 208 - 209 - return val; 210 - } 211 - 212 - static int dlCallback(struct dl_phdr_info *info, size_t size, void *data) 213 - { 214 - CBData* cbdata = static_cast<CBData*>(data); 215 - bool addrMatch = false; 216 - void* maxAddr = 0; 217 - const eh_frame_hdr* ehdr = 0; 218 - 219 - if (cbdata->info->dwarf_section) // we already have a match 220 - return 0; 221 - 222 - //std::cout << "Looking into " << info->dlpi_name << std::endl; 223 - 224 - if (size < offsetof(struct dl_phdr_info, dlpi_phnum)) 225 - return 0; 226 - 227 - for (int i = 0; i < info->dlpi_phnum; i++) 228 - { 229 - const ElfW(Phdr)* phdr = &info->dlpi_phdr[i]; 230 - /* 231 - if (strstr(info->dlpi_name, "cxxdarwin")) 232 - { 233 - std::cout << "type: " << phdr->p_type << "; vaddr: " << phdr->p_vaddr << std::endl; 234 - } 235 - */ 236 - 237 - if (phdr->p_type == PT_LOAD) 238 - { 239 - void* from = reinterpret_cast<void*>(uintptr_t(info->dlpi_addr) + uintptr_t(phdr->p_vaddr)); 240 - void* to = reinterpret_cast<char*>(from) + phdr->p_memsz; 241 - 242 - if (cbdata->addr >= from && cbdata->addr < to) 243 - addrMatch = true; 244 - if (to > maxAddr) 245 - maxAddr = to; // TODO: could this be improved? libunwind does the same 246 - } 247 - else if (phdr->p_type == PT_GNU_EH_FRAME) 248 - { 249 - //std::cout << "Found .eh_frame_hdr in " << info->dlpi_name << std::endl; 250 - ehdr = reinterpret_cast<eh_frame_hdr*>(uintptr_t(info->dlpi_addr) + phdr->p_vaddr); 251 - // cbdata->info->dwarf_section_length = phdr->p_memsz; 252 - } 253 - } 254 - 255 - if (addrMatch && ehdr) 256 - { 257 - //std::cout << "*** Match found! " << info->dlpi_name << std::endl; 258 - 259 - // Now we find .eh_frame from .eh_frame_hdr 260 - if (ehdr->version != 1) 261 - return 0; 262 - cbdata->info->dwarf_section = reinterpret_cast<void*>(readEncodedPointer(ehdr)); 263 - cbdata->info->dwarf_section_length = uintptr_t(maxAddr) - uintptr_t(cbdata->info->dwarf_section); 264 - } 265 - 266 - return 0; 267 - } 268 - 269 - bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info) 270 - { 271 - TRACE1(addr); 272 - const FileMap::ImageMap* map = g_file_map.imageMapForAddr(addr); 273 - 274 - if (!map) // in ELF 275 - { 276 - memset(info, 0, sizeof(*info)); 277 - 278 - CBData data = { addr, info }; 279 - 280 - dl_iterate_phdr(dlCallback, &data); 281 - std::cout << "Dwarf section at " << info->dwarf_section << std::endl; 282 - return info->dwarf_section != 0; 283 - } 284 - else // in Mach-O 285 - { 286 - info->mh = map->header; 287 - info->dwarf_section = reinterpret_cast<const void*>(map->eh_frame.first + map->slide); 288 - info->dwarf_section_length = map->eh_frame.second; 289 - 290 - // FIXME: we would get "malformed __unwind_info" warnings otherwise 291 - // info->compact_unwind_section = reinterpret_cast<const void*>(map->unwind_info.first + map->slide); 292 - // info->compact_unwind_section_length = map->unwind_info.second; 293 - info->compact_unwind_section = 0; 294 - info->compact_unwind_section_length = 0; 295 - 296 - return true; 297 - } 298 - } 299 -
+15 -8
src/dyld/public.h src/dyld/dyld_public.h
··· 1 1 /* 2 2 This file is part of Darling. 3 3 4 - Copyright (C) 2012 Lubos Dolezel 4 + Copyright (C) 2012-2013 Lubos Dolezel 5 5 6 6 Darling is free software: you can redistribute it and/or modify 7 7 it under the terms of the GNU General Public License as published by ··· 20 20 #ifndef DYLD_PUBLIC_H 21 21 #define DYLD_PUBLIC_H 22 22 #include <stdint.h> 23 + #include "MachOMgr.h" 24 + 25 + namespace Darling { 26 + class MachOObject; 27 + } 23 28 24 29 #ifdef __cplusplus 25 30 extern "C" { ··· 34 39 uintptr_t compact_unwind_section_length; 35 40 }; 36 41 37 - typedef void (LoaderHookFunc)(const struct mach_header* mh, intptr_t vmaddr_slide); 38 - 39 42 uint32_t _dyld_image_count(void); 40 43 const struct mach_header* _dyld_get_image_header(uint32_t image_index); 41 44 intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index); 42 45 const char* _dyld_get_image_name(uint32_t image_index); 46 + void* dyld_stub_binder_fixup(Darling::MachOObject** obj, uintptr_t lazyOffset); 43 47 44 48 char* getsectdata(const struct mach_header* header, const char* segname, const char* sectname, unsigned long* size); 45 49 46 - void _dyld_register_func_for_add_image(LoaderHookFunc* func); 47 - void _dyld_register_func_for_remove_image(LoaderHookFunc* func); 50 + void _dyld_register_func_for_add_image(Darling::MachOMgr::LoaderHookFunc* func); 51 + void _dyld_register_func_for_remove_image(Darling::MachOMgr::LoaderHookFunc* func); 52 + 53 + void __dyld_make_delayed_module_initializer_calls(); 54 + void __dyld_mod_term_funcs(); 55 + 56 + const char* dyld_image_path_containing_address(const void* addr); 57 + bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info); 48 58 49 59 int32_t NSVersionOfRunTimeLibrary(const char* libraryName); 50 60 51 61 int32_t NSVersionOfLinkTimeLibrary(const char* libraryName); 52 62 53 63 int _NSGetExecutablePath(char* buf, uint32_t* bufsize); 54 - 55 - const char* dyld_image_path_containing_address(const void* addr); 56 - bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info); 57 64 58 65 #ifdef __cplusplus 59 66 }
+4 -4
src/dyld/trampoline_helper.nasm
··· 87 87 mov rsi, rsp 88 88 mov rcx, qword 0xaabbccddeeff ; print function (saves orig ret address) 89 89 90 - sub rsp, 8 ; align stack to 16 90 + ;sub rsp, 8 ; align stack to 16 91 91 call rcx 92 - add rsp, 8 92 + ;add rsp, 8 93 93 94 94 mov r11, rax ; save the right addr 95 95 ··· 111 111 mov rsi, rsp 112 112 mov rcx, qword 0xa0a1a2a3a4a5a6 ; retval print function (returns orig ret address) 113 113 114 - sub rsp, 8 ; align stack to 16 114 + ;sub rsp, 8 ; align stack to 16 115 115 call rcx 116 - add rsp, 8 116 + ;add rsp, 8 117 117 118 118 mov r11, rax 119 119
+3 -4
src/libSystem/kernel-bsd/fopsmisc.cpp
··· 11 11 #include <cstdlib> 12 12 #include <iostream> 13 13 #include <limits.h> 14 - 15 - extern char g_sysroot[PATH_MAX]; 14 + #include <dyld/MachOMgr.h> 16 15 17 16 int __darwin_access(const char *pathname, int mode) 18 17 { 19 18 //std::cout << "access: " << pathname << std::endl; 20 - if ((mode & W_OK) == 0 && g_sysroot[0]) 19 + if ((mode & W_OK) == 0 && Darling::MachOMgr::instance()->hasSysRoot()) 21 20 { 22 21 // Try to apply a sysroot prefix 23 22 const char* prefixed; 24 - std::string lpath = g_sysroot; 23 + std::string lpath = Darling::MachOMgr::instance()->sysRoot(); 25 24 26 25 lpath += '/'; 27 26 lpath += pathname;
+3 -4
src/libSystem/kernel-bsd/io.cpp
··· 8 8 #include "common/auto.h" 9 9 #include <limits.h> 10 10 #include <errno.h> 11 - 12 - extern char g_sysroot[PATH_MAX]; 11 + #include <dyld/MachOMgr.h> 13 12 14 13 static const Darling::MappedFlag g_openflags[] = { 15 14 { DARWIN_O_ASYNC, O_ASYNC}, { DARWIN_O_SYNC, O_SYNC }, { DARWIN_O_NOFOLLOW, O_NOFOLLOW}, ··· 60 59 //std::cout << "File: " << path << std::endl; 61 60 //std::cout << "Sysroot: " << g_sysroot << std::endl; 62 61 // std::cout << "Flag: " << (linux_flags & O_RDONLY) << std::endl; 63 - if ( (linux_flags & O_ACCMODE) == 0 && g_sysroot[0]) 62 + if ( (linux_flags & O_ACCMODE) == 0 && Darling::MachOMgr::instance()->hasSysRoot()) 64 63 { 65 64 const char* prefixed; 66 - std::string lpath = g_sysroot; 65 + std::string lpath = Darling::MachOMgr::instance()->sysRoot(); 67 66 68 67 lpath += '/'; 69 68 lpath += path;
+3 -8
src/libSystem/kernel-bsd/stat.cpp
··· 7 7 #include <sys/stat.h> 8 8 #include <unistd.h> 9 9 #include <limits.h> 10 - 11 - extern char g_sysroot[PATH_MAX]; 10 + #include <dyld/MachOMgr.h> 12 11 13 12 static void convertStat64(struct stat64* linux_buf, struct __darwin_stat64* mac) 14 13 { 15 - // TODO(hamaji): this memset seems to cause overflow... why? 16 - //memset(mac, 0, sizeof(*mac)); 17 14 mac->st_dev = linux_buf->st_dev; 18 15 mac->st_mode = linux_buf->st_mode; 19 16 mac->st_nlink = linux_buf->st_nlink; ··· 31 28 32 29 static void convertStat(struct stat64* linux_buf, struct __darwin_stat* mac) 33 30 { 34 - // TODO(hamaji): this memset seems to cause overflow... why? 35 - //memset(mac, 0, sizeof(*mac)); 36 31 mac->st_dev = linux_buf->st_dev; 37 32 mac->st_mode = linux_buf->st_mode; 38 33 mac->st_nlink = linux_buf->st_nlink; ··· 53 48 TRACE2(path, mac); 54 49 struct stat64 linux_buf; 55 50 56 - if (g_sysroot[0]) 51 + if (Darling::MachOMgr::instance()->hasSysRoot()) 57 52 { 58 53 const char* prefixed; 59 - std::string lpath = g_sysroot; 54 + std::string lpath = Darling::MachOMgr::instance()->sysRoot(); 60 55 61 56 lpath += '/'; 62 57 lpath += path;
+7 -1
src/libSystem/libc/OSAtomic.cpp
··· 207 207 { 208 208 // We cannot use pthread spinlocks, these need init and destruction 209 209 while (!OSSpinLockTry(lock)) 210 - sched_yield(); // TODO: still a busy wait... 210 + sched_yield(); 211 211 } 212 212 213 213 void OSSpinLockUnlock(OSSpinLock *lock) ··· 236 236 void* OSAtomicDequeue(OSQueueHead *list, size_t offset) 237 237 { 238 238 LIBC_STUB(); 239 + return nullptr; 240 + } 241 + 242 + __attribute__((naked)) void OSMemoryBarrier() 243 + { 244 + __atomic_thread_fence(__ATOMIC_SEQ_CST); 239 245 } 240 246
+2
src/libSystem/libc/OSAtomic.h
··· 102 102 103 103 void* OSAtomicDequeue(struct OSQueueHead *list, size_t offset); 104 104 105 + void OSMemoryBarrier(); 106 + 105 107 #ifdef __cplusplus 106 108 } 107 109 #endif
+3 -4
src/libSystem/libc/dir.cpp
··· 8 8 #include <cstdlib> 9 9 #include <cstring> 10 10 #include <limits.h> 11 - 12 - extern char g_sysroot[PATH_MAX]; 11 + #include <dyld/MachOMgr.h> 13 12 14 13 static darwin_dirent* convertDirent(const struct dirent* ent); 15 14 static darwin_dirent64* convertDirent64(const struct dirent* ent); ··· 88 87 { 89 88 TRACE1(name); 90 89 91 - if (g_sysroot[0]) 90 + if (Darling::MachOMgr::instance()->hasSysRoot()) 92 91 { 93 92 const char* prefixed; 94 - std::string lpath = g_sysroot; 93 + std::string lpath = Darling::MachOMgr::instance()->sysRoot(); 95 94 96 95 lpath += '/'; 97 96 lpath += name;
+18 -5
src/libSystem/libc/exec.cpp
··· 16 16 #include <linux/limits.h> 17 17 #include "MachO.h" 18 18 19 - extern char g_dyld_path[4096]; 19 + // FIXME: this will fail when a 32-bit OS X app exec()s a 64-bit OS X app (or vice versa)! 20 + static const char* getSelfPath() 21 + { 22 + static char selfpath[PATH_MAX]; 23 + 24 + if (!selfpath[0]) 25 + { 26 + int rd = readlink("/proc/self/exe", selfpath, sizeof(selfpath)-1); 27 + if (rd != -1) 28 + selfpath[rd] = 0; 29 + } 30 + 31 + return selfpath; 32 + } 20 33 21 34 const char* Darling::findInPath(const char* file) 22 35 { ··· 75 88 while (argv[count++]); 76 89 77 90 rv = new const char*[count+1]; 78 - rv[0] = g_dyld_path; 91 + rv[0] = getSelfPath(); 79 92 memcpy(rv+1, argv, count * sizeof(char*)); 80 93 81 94 rv[1] = fullMachoPath; ··· 157 170 else 158 171 { 159 172 argv = Darling::prependLoaderPath(argv, path); 160 - int rv = execvp(g_dyld_path, argv); // TODO: change to execv? 173 + int rv = execvp(getSelfPath(), argv); // TODO: change to execv? 161 174 162 - LOG << "Executing with loader at " << g_dyld_path << std::endl; 175 + LOG << "Executing with loader at " << getSelfPath() << std::endl; 163 176 164 177 errnoOut(); 165 178 ··· 203 216 else 204 217 { 205 218 argv = Darling::prependLoaderPath(argv, path); 206 - int rv = execvpe(g_dyld_path, argv, envp); 219 + int rv = execvpe(getSelfPath(), argv, envp); 207 220 errnoOut(); 208 221 209 222 delete [] argv;
+3
src/libSystem/libc/getpwent.cpp
··· 22 22 23 23 static __darwin_passwd* passwdLinuxToDarwin(const struct passwd* in) 24 24 { 25 + if (!in) 26 + return nullptr; 27 + 25 28 static __thread __darwin_passwd pwd; 26 29 passwdLinuxToDarwin(in, &pwd); 27 30 return &pwd;
+43 -2
src/libSystem/libc/nextstep.cpp
··· 2 2 #include "nextstep.h" 3 3 #include <cstring> 4 4 #include <unistd.h> 5 + #include <dyld/MachOMgr.h> 6 + #include <dyld/MachOObject.h> 5 7 6 - static char** my_environ = environ; 8 + using namespace Darling; 7 9 8 10 char*** _NSGetEnviron() 9 11 { 10 - return &my_environ; 12 + MachOObject* mainModule = MachOMgr::instance()->mainModule(); 13 + 14 + // When dyld is used as a simple loader, we fall back to direct access to global environ 15 + if (!mainModule) 16 + return &environ; 17 + else 18 + { 19 + char*** env; 20 + mainModule->commandLine(nullptr, nullptr, &env); 21 + return env; 22 + } 23 + } 24 + 25 + int* _NSGetArgc() 26 + { 27 + MachOObject* mainModule = MachOMgr::instance()->mainModule(); 28 + 29 + if (!mainModule) 30 + return nullptr; 31 + else 32 + { 33 + int* argc; 34 + mainModule->commandLine(&argc, nullptr, nullptr); 35 + return argc; 36 + } 11 37 } 38 + 39 + char*** _NSGetArgv() 40 + { 41 + MachOObject* mainModule = MachOMgr::instance()->mainModule(); 42 + 43 + if (!mainModule) 44 + return nullptr; 45 + else 46 + { 47 + char*** argv; 48 + mainModule->commandLine(nullptr, &argv, nullptr); 49 + return argv; 50 + } 51 + } 52 +
+2 -4
src/libSystem/libc/nextstep.h
··· 1 1 #ifndef LIBC_NEXTSTEP_H 2 2 #define LIBC_NEXTSTEP_H 3 3 4 - extern "C" char* __darwin_executable_path; 5 - extern "C" char* __loader_path; 6 - 7 4 extern "C" 8 5 { 9 6 10 - int _NSGetExecutablePath(char* buf, unsigned int* size); 11 7 char*** _NSGetEnviron(); 8 + int* _NSGetArgc(); 9 + char*** _NSGetArgv(); 12 10 13 11 } 14 12
+3 -4
src/libSystem/libc/stdio.cpp
··· 18 18 #include <typeinfo> 19 19 #include "log.h" 20 20 #include <ext/stdio_filebuf.h> 21 + #include <dyld/MachOMgr.h> 21 22 22 23 template class __gnu_cxx::stdio_filebuf<char, std::char_traits<char> >; 23 24 template class std::basic_filebuf<char, std::char_traits<char> >; 24 - 25 - extern char g_sysroot[PATH_MAX]; 26 25 27 26 //extern "C" 28 27 //{ ··· 68 67 __darwin_FILE* __darwin_fopen(const char* path, const char* mode) 69 68 { 70 69 TRACE2(path, mode); 71 - if (!strchr(mode, 'w') && g_sysroot[0]) 70 + if (!strchr(mode, 'w') && Darling::MachOMgr::instance()->hasSysRoot()) 72 71 { 73 72 const char* prefixed; 74 - std::string lpath = g_sysroot; 73 + std::string lpath = Darling::MachOMgr::instance()->sysRoot(); 75 74 lpath += '/'; 76 75 lpath += path; 77 76
+1
src/libmach-o/MachO.h
··· 44 44 45 45 virtual ~MachO() {} 46 46 virtual void close() = 0; 47 + inline void closeFd() { ::close(m_fd); m_fd = -1; } 47 48 48 49 const std::string& filename() const { return m_filename; } 49 50
+7 -8
src/libobjcdarwin/ClassRegister.cpp
··· 1 1 #include "ClassRegister.h" 2 - #include "../dyld/public.h" 3 - #include "../util/trace.h" 4 - #include "../util/log.h" 2 + #include <dyld/dyld_public.h> 3 + #include <util/debug.h> 5 4 6 5 #ifndef OBJC_ABI_2 7 6 # include "old/protocol.h" ··· 37 36 __attribute__((constructor)) 38 37 void RegisterAlreadyLoadedClasses() 39 38 { 40 - for (uint32_t i = 0; i < _dyld_image_count(); i++) 41 - { 42 - const struct mach_header* hdr = _dyld_get_image_header(i); 43 - ProcessImageLoad(hdr, 0); 44 - } 39 + //for (uint32_t i = 0; i < _dyld_image_count(); i++) 40 + //{ 41 + // const struct mach_header* hdr = _dyld_get_image_header(i); 42 + // ProcessImageLoad(hdr, 0); 43 + //} 45 44 46 45 _dyld_register_func_for_add_image(ProcessImageLoad); 47 46 _dyld_register_func_for_remove_image(ProcessImageUnload);
+1 -1
src/libobjcdarwin/common/cfstring.cpp
··· 1 - #include "../../dyld/public.h" 1 + #include <dyld/dyld_public.h> 2 2 #include <stdint.h> 3 3 #include <cstring> 4 4 #include <algorithm>
+2 -2
src/libobjcdarwin/common/selector.cpp
··· 1 1 #include "selector.h" 2 2 #include "../new/AppleLayout.h" 3 3 #include "../old/AppleLayout.h" 4 - #include "../../dyld/public.h" 5 - #include "../../util/log.h" 4 + #include <dyld/dyld_public.h> 5 + #include <util/debug.h> 6 6 7 7 void UpdateSelectors(const struct mach_header* mh, intptr_t slide) 8 8 {
+1 -1
src/libobjcdarwin/new/category.h
··· 3 3 #include "./AppleLayout.h" 4 4 #include <objc/runtime.h> 5 5 #include <stdint.h> 6 - #include "../../dyld/public.h" 6 + #include <dyld/dyld_public.h> 7 7 8 8 void ProcessCategoriesNew(const struct mach_header* mh, intptr_t slide); 9 9
+1 -1
src/libobjcdarwin/new/class.h
··· 4 4 #include <objc/runtime.h> 5 5 #include <stdint.h> 6 6 #include <vector> 7 - #include "../../dyld/public.h" 7 + #include <dyld/dyld_public.h> 8 8 9 9 Class RegisterClass(const class_t* cls, intptr_t slide); 10 10 std::vector<const char*> ProcessClassesNew(const struct mach_header* mh, intptr_t slide, const class_t** classes, unsigned long size);
+4 -4
src/libobjcdarwin/new/exceptions.cpp
··· 5 5 extern "C" void* __cxa_begin_catch(void*); 6 6 extern "C" void __cxa_end_catch(); 7 7 8 - static __thread bool m_cxx = false; 8 + static thread_local bool m_cxx = false; 9 9 10 - void objc_exception_rethrow() 10 + void __darwin_objc_exception_rethrow() 11 11 { 12 12 __cxa_rethrow(); 13 13 } 14 14 15 - void* objc_begin_catch(void* p) 15 + void* __darwin_objc_begin_catch(void* p) 16 16 { 17 17 void *rv = returnReturn(); 18 18 void* cpp = __cxa_begin_catch(p); ··· 28 28 } 29 29 } 30 30 31 - void objc_end_catch() 31 + void __darwin_objc_end_catch() 32 32 { 33 33 if (m_cxx) 34 34 __cxa_end_catch();
+3 -3
src/libobjcdarwin/new/exceptions.h
··· 4 4 5 5 extern "C" { 6 6 7 - DARLING_VISIBLE void objc_exception_rethrow(); 8 - DARLING_VISIBLE void* objc_begin_catch(void*); 9 - DARLING_VISIBLE void objc_end_catch(); 7 + DARLING_VISIBLE void __darwin_objc_exception_rethrow(); 8 + DARLING_VISIBLE void* __darwin_objc_begin_catch(void*); 9 + DARLING_VISIBLE void __darwin_objc_end_catch(); 10 10 11 11 } 12 12
+2 -2
src/libobjcdarwin/new/protocol.cpp
··· 1 1 #include "./protocol.h" 2 2 #include <cstring> 3 - #include "../../util/log.h" 4 - #include "../../dyld/public.h" 3 + #include <util/debug.h> 4 + #include <dyld/dyld_public.h> 5 5 #include "../common/ref.h" 6 6 #include "../common/property.h" 7 7 #include "../TopologySort.h"
+4 -1
src/thin/CMakeLists.txt
··· 13 13 target_link_libraries(Carbon CoreServices) 14 14 SET_TARGET_PROPERTIES(Carbon PROPERTIES LINKER_LANGUAGE C) 15 15 16 - install(TARGETS AppKit Carbon DESTINATION "lib${SUFFIX}/darling") 16 + add_library(auto SHARED) 17 + SET_TARGET_PROPERTIES(auto PROPERTIES LINKER_LANGUAGE C) 18 + 19 + install(TARGETS AppKit Carbon auto DESTINATION "lib${SUFFIX}/darling") 17 20
+1 -1
src/util/IniConfig.cpp
··· 103 103 return str; 104 104 } 105 105 106 - const IniConfig::ValueMap* IniConfig::getSection(std::string section) const 106 + const IniConfig::ValueMap* IniConfig::getSection(const std::string& section) const 107 107 { 108 108 SectionMap::const_iterator it = m_sections.find(section); 109 109 if (it == m_sections.end())
+2 -2
src/util/IniConfig.h
··· 15 15 typedef std::map<std::string, ValueMap*> SectionMap; 16 16 17 17 std::vector<std::string> getSections() const; 18 - const ValueMap* getSection(std::string section) const; 18 + const ValueMap* getSection(const std::string& section) const; 19 19 20 - inline bool hasSection(const char* name) const { return getSection(name) != 0; } 20 + inline bool hasSection(const std::string& name) const { return getSection(name) != 0; } 21 21 protected: 22 22 void loadConfig(std::ifstream& f); 23 23 static std::string& trim(std::string& str);