DylibSearch::DylibSearch() : m_reFrameworkPath("/System/Library/Frameworks/([a-zA-Z0-9\\.]+)/Versions/([a-zA-Z0-9\\.]+)/.*"), m_reDefaultFrameworkPath("/System/Library/Frameworks/([a-zA-Z0-9\\.]+)/([a-zA-Z0-9\\.]+)") { try { if (__prefix_get() != nullptr) m_config = new IniConfig(__prefix_translate_path(ETC_DARLING_PATH "/dylib.conf")); else m_config = new IniConfig(LIBEXEC_PATH ETC_DARLING_PATH "/dylib.conf"); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } }
std::string DylibSearch::resolveInPathList(std::string name, const std::vector<std::string>& paths) { const char* prefix = __prefix_get(); for (const std::string& e : paths) { std::string path; if (prefix) path = prefix; path += e + "/" + name; if (::access(path.c_str(), F_OK) == 0) return path; } return std::string(); }
std::string DylibSearch::resolve(std::string dylib, MachOObject* requester) { if (dylib.empty()) return std::string(); // expand @rpath, @executable_path and @loader_path if (requester != nullptr && dylib[0] == '@') { if (dylib.compare(0, 16, "@executable_path") == 0) { MachOObject* mainModule = MachOMgr::instance()->mainModule(); if (!mainModule) throw std::runtime_error("Cannot resolve @executable_path without a main module"); dylib.replace(0, 16, mainModule->directory()); } else if (dylib.compare(0, 12, "@loader_path") == 0) { dylib.replace(0, 12, requester->directory()); } else if (dylib.compare(0, 6, "@rpath") == 0) { return resolveViaRpath(dylib, requester); } } // Search in configuration if (const char* aliasTarget = resolveAlias(dylib)) { std::string p; if (!strchr(aliasTarget, '/')) { p = LIB_PATH; p += '/'; p += aliasTarget; // std::cout << p << std::endl; } return p; } // Search in extra paths std::string epath; epath = resolveInPathList(dylib, m_extraPaths); if (!epath.empty()) return epath; // Search in DYLD_LIBRARY_PATH epath = resolveInLdPath(dylib); if (!epath.empty()) return epath; // Try the path as is epath = checkPresence(dylib); if (!epath.empty()) return epath; // If absolute, search in sysroot if (dylib[0] == '/') { const char* prefix = __prefix_get(); if (!MachOMgr::instance()->sysRoot().empty()) { std::vector<std::string> roots = string_explode(MachOMgr::instance()->sysRoot(), ':'); for (const std::string& in_path : roots) { std::string path; if (prefix != nullptr) path = prefix; path += in_path; path += '/'; path += dylib; epath = checkPresence(path); if (!epath.empty()) return epath; } } if (prefix != nullptr) { std::string path = prefix; path += dylib; epath = checkPresence(path); if (!epath.empty()) return epath; } } /*if (MachOMgr::instance()->ignoreMissingDependencies()) { }*/ return std::string(); }
long sys_execve(char* fname, char** argvp, char** envp) { int ret, fd; char dyld_path[256]; union { uint32_t magic; char magic_array[256]; } m; // Ideally, if everybody used binfmt_misc to allow direct // execution of Mach-O binaries under Darling, this wouldn't // be necessary. But we cannot rely on that. fd = sys_open(fname, BSD_O_RDONLY, 0); if (fd < 0) return fd; ret = sys_read(fd, m.magic_array, sizeof(m.magic_array)); if (ret < 4) goto no_macho; if (__prefix_get() != NULL) { // Inject DPREFIX if DPREFIX is missing int i; bool has_dprefix = false; char** new_envp; for (i = 0; envp[i] != NULL; i++) { if (strncmp(envp[i], "DPREFIX=", 8) == 0) { has_dprefix = true; break; } } if (!has_dprefix) { char* dprefix; new_envp = (char**) __builtin_alloca(sizeof(char*) * (i+1)); dprefix = (char*) __builtin_alloca(strlen(__prefix_get()) + 9); for (i = 0; envp[i] != NULL; i++) new_envp[i] = envp[i]; strcpy(dprefix, "DPREFIX="); strcat(dprefix, __prefix_get()); new_envp[i++] = dprefix; new_envp[i] = NULL; envp = new_envp; } } if (m.magic == MH_MAGIC || m.magic == MH_CIGAM || m.magic == MH_MAGIC_64 || m.magic == MH_CIGAM_64 || m.magic == FAT_MAGIC || m.magic == FAT_CIGAM) { // It is a Mach-O file int len, i; char** modargvp; len = __prefix_get_dyld_path(dyld_path, sizeof(dyld_path)-1); if (len < 0) goto no_macho; // Remove 64 or 32 suffix if present if (strcmp(&dyld_path[len - 2], "32") == 0 || strcmp(&dyld_path[len - 2], "64") == 0) { dyld_path[len-2] = '\0'; } // Prepend dyld path len = 0; // Count arguments while (argvp[len++]); // Allocate a new argvp, execute dyld_path modargvp = (char**) __builtin_alloca(sizeof(void*) * (len+1)); modargvp[0] = dyld_path; modargvp[1] = (char*) __prefix_translate_path_link(fname); for (i = 2; i < len+1; i++) modargvp[i] = argvp[i-1]; argvp = modargvp; fname = dyld_path; } else if (__prefix_get() != NULL) { // shebang handling... if (m.magic_array[0] == '#' && m.magic_array[1] == '!') { char *nl, *interp, *arg; char** modargvp; int i, j, len; nl = memchr(m.magic_array, '\n', sizeof(m.magic_array)); if (nl == NULL) goto no_macho; *nl = '\0'; for (i = 2; isspace(m.magic_array[i]); i++); interp = &m.magic_array[i]; for (i = 0; !isspace(interp[i]) && interp[i]; i++); if (interp[i] == '\0') arg = NULL; else arg = &interp[i]; if (arg != NULL) { *arg = '\0'; // terminate interp while (isspace(*arg)) arg++; if (*arg == '\0') arg = NULL; // no argument, just whitespace } // Count original arguments while (argvp[len++]); // Allocate a new argvp modargvp = (char**) __builtin_alloca(sizeof(void*) * (len+2)); i = 0; modargvp[i++] = interp; if (arg != NULL) modargvp[i++] = arg; modargvp[i] = fname; // Append original arguments for (j = 1; j < len+1; j++) modargvp[i+j] = argvp[j]; argvp = modargvp; fname = (char*) __prefix_translate_path(modargvp[0]); } else { fname = (char*) __prefix_translate_path_link(fname); } } no_macho: sys_close(fd); ret = LINUX_SYSCALL(__NR_execve, fname, argvp, envp); if (ret < 0) ret = errno_linux_to_bsd(ret); return ret; }