Loads of work on dyld and BSD functions

This commit is contained in:
Lubos Dolezel 2012-08-15 12:17:58 +02:00
parent 6a563706cd
commit 45a369fdf9
26 changed files with 695 additions and 694 deletions

View File

@ -27,7 +27,7 @@
set follow-fork-mode child set follow-fork-mode child
python sys.path.insert(0, '.') python sys.path.insert(0, './tools/')
python import gdb_maloader python import gdb_maloader
define mreload define mreload

View File

@ -53,7 +53,7 @@ set(fatmacho-extract_SRCS
add_executable(fatmacho-extract ${fatmacho-extract_SRCS}) add_executable(fatmacho-extract ${fatmacho-extract_SRCS})
target_link_libraries(fatmacho-extract -ldl -lpthread mach-o) target_link_libraries(fatmacho-extract -ldl -lpthread mach-o -Wl,-export-dynamic)
install(TARGETS dyld fatmacho-extract DESTINATION bin) install(TARGETS dyld fatmacho-extract DESTINATION bin)

View File

@ -165,8 +165,13 @@ void MachOLoader::loadDylibs(const MachO& mach)
// __darwin_dlopen checks if already loaded // __darwin_dlopen checks if already loaded
// automatically adds a reference if so // automatically adds a reference if so
if (!__darwin_dlopen(dylib.c_str(), DARWIN_RTLD_GLOBAL)) if (!__darwin_dlopen(dylib.c_str(), DARWIN_RTLD_GLOBAL|DARWIN_RTLD_NOW))
throw std::runtime_error("Cannot load " + dylib + "!"); {
LOG << "Failed to dlopen " << dylib << ", throwing an exception\n";
std::stringstream ss;
ss << "Cannot load " << dylib << ": " << __darwin_dlerror();
throw std::runtime_error(ss.str());
}
} }
} }
@ -380,12 +385,21 @@ void MachOLoader::doBind(const MachO& mach, intptr slide)
sym = reinterpret_cast<char*>(__darwin_dlsym(DARWIN_RTLD_DEFAULT, name.c_str())); sym = reinterpret_cast<char*>(__darwin_dlsym(DARWIN_RTLD_DEFAULT, name.c_str()));
if (!sym) if (!sym)
{ {
std::stringstream ss; const char* ign_sym = getenv("DYLD_IGN_MISSING_SYMS");
ss << "Undefined symbol: " << name; if (ign_sym && atoi(ign_sym))
throw std::runtime_error(ss.str()); {
std::cerr << "!!! Undefined symbol: " << name << std::endl;
sym = reinterpret_cast<char*>(undefinedFunction);
}
else
{
std::stringstream ss;
ss << "Undefined symbol: " << name;
throw std::runtime_error(ss.str());
}
} }
else
sym += bind->addend; sym += bind->addend;
} }
LOG << "bind " << name << ": " LOG << "bind " << name << ": "

View File

@ -1,25 +1,35 @@
#include "MachO.h" #include "MachO.h"
#include "MachOLoader.h" #include "MachOLoader.h"
#include "arch.h" #include "arch.h"
#include "log.h"
#include <iostream> #include <iostream>
#include <limits.h> #include <limits.h>
#include <cstdlib> #include <cstdlib>
#include <stdexcept> #include <stdexcept>
#include <cstring> #include <cstring>
#include <cassert>
char g_darwin_executable_path[PATH_MAX]; char g_darwin_executable_path[PATH_MAX];
char g_loader_path[PATH_MAX]; char g_loader_path[PATH_MAX];
char g_sysroot[PATH_MAX] = "";
MachO* g_mainBinary = 0; MachO* g_mainBinary = 0;
MachOLoader* g_loader = 0; MachOLoader* g_loader = 0;
int g_argc; int g_argc;
char** g_argv; char** g_argv;
static void autoSysrootSearch();
int main(int argc, char** argv, char** envp) int main(int argc, char** argv, char** envp)
{ {
if (argc == 1) if (argc == 1)
{ {
std::cerr << "This is Darwin dyld for " ARCH_NAME ". "; std::cerr << "This is Darwin dyld for " ARCH_NAME ". ";
std::cerr << "Usage: " << argv[0] << " program-path [arguments...]\n"; std::cerr << "Usage: " << argv[0] << " program-path [arguments...]\n\n";
std::cerr << "Environment variables:\n"
"\tDYLD_DEBUG=1 - enable debug info (lots of output)\n"
"\tDYLD_IGN_MISSING_SYMS=1 - replace missing symbol references with a stub function\n"
"\tDYLD_SYSROOT=<path> - set the base for library path resolution (overrides autodetection)\n";
return 1; return 1;
} }
@ -35,25 +45,30 @@ int main(int argc, char** argv, char** envp)
//initDlfcn(); //initDlfcn();
g_mainBinary = MachO::readFile(argv[1], ARCH_NAME); g_mainBinary = MachO::readFile(argv[1], ARCH_NAME);
#ifdef __x86_64__
if (!g_mainBinary->is64())
{
std::cerr << argv[1] << ": Cannot execute binary file.\nThis version of Darwin dyld cannot run binaries for x86.\n";
return -ENOEXEC;
}
#else
if (g_mainBinary->is64())
{
td::cerr << argv[1] << ": Cannot execute binary file.\nThis version of Darwin dyld cannot run binaries for x86-64.\n";
return -ENOEXEC;
}
#endif
try try
{ {
if (!g_mainBinary)
throw std::runtime_error("Cannot open binary file");
#ifdef __x86_64__
if (!g_mainBinary->is64())
{
std::cerr << argv[1] << ": Cannot execute binary file.\nThis version of Darwin dyld cannot run binaries for x86.\n";
return -ENOEXEC;
}
#else
if (g_mainBinary->is64())
{
std::cerr << argv[1] << ": Cannot execute binary file.\nThis version of Darwin dyld cannot run binaries for x86-64.\n";
return -ENOEXEC;
}
#endif
g_loader = new MachOLoader; g_loader = new MachOLoader;
g_argv = argv+1; g_argv = argv+1;
g_argc = argc-1; g_argc = argc-1;
autoSysrootSearch();
g_loader->run(*g_mainBinary, argc-1, argv+1, envp); g_loader->run(*g_mainBinary, argc-1, argv+1, envp);
delete g_loader; delete g_loader;
@ -77,4 +92,27 @@ extern "C" const char* dyld_getLoaderPath()
return g_loader_path; return g_loader_path;
} }
void autoSysrootSearch()
{
if (const char* s = getenv("DYLD_SYSROOT"))
{
strncpy(g_sysroot, s, PATH_MAX-1);
g_sysroot[PATH_MAX-1] = 0;
}
else
{
std::string path = g_darwin_executable_path;
size_t pos = path.rfind("/usr/");
LOG << "Looking for SYSROOT signs in " << g_darwin_executable_path << std::endl;
if (pos != std::string::npos && pos > 0)
{
std::string sysroot = path.substr(0, pos);
LOG << "SYSROOT detected to be " << sysroot << std::endl;
strncpy(g_sysroot, sysroot.c_str(), PATH_MAX-1);
g_sysroot[PATH_MAX-1] = 0;
}
}
}

View File

@ -1,470 +0,0 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
// A Mach-O loader for linux.
#include <assert.h>
#include <dlfcn.h>
#include <err.h>
#include <errno.h>
#include <execinfo.h>
#include <fcntl.h>
#include <limits.h>
#include <memory>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <ucontext.h>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <tr1/unordered_map>
#include <vector>
#include "env_flags.h"
#include "FatMachO.h"
#include "log.h"
#include "MachO.h"
#include "FileMap.h"
#include "arch.h"
using namespace std;
using namespace std::tr1;
DEFINE_bool(TRACE_FUNCTIONS, false, "Show calling functions");
DEFINE_bool(PRINT_TIME, false, "Print time spent in this loader");
class MachO;
static map<string, string> g_rename;
static vector<string> g_bound_names;
static set<string> g_no_trampoline;
static FileMap g_file_map;
static char* g_darwin_executable_path;
static Timer g_timer;
class MachOLoader;
static MachOLoader* g_loader;
/*
static void initRename() {
#define RENAME(src, dst) g_rename.insert(make_pair(#src, #dst));
#define WRAP(src) RENAME(src, __darwin_ ## src)
#include "rename.tab"
#undef RENAME
#undef WRAP
}
*/
class MachOLoader {
#ifdef __x86_64__
typedef uint64_t intptr;
typedef segment_command_64 Segment;
static const vector<Segment*>& getSegments(const MachO& mach) {
return mach.segments64();
}
#else
typedef uint32_t intptr;
typedef segment_command Segment;
static const vector<Segment*>& getSegments(const MachO& mach) {
return mach.segments();
}
#endif
public:
MachOLoader()
: last_addr_(0) {
// TODO: this is very wrong
/*
dylib_to_so_.insert(make_pair(
"/System/Library/Frameworks/CoreFoundation.framework"
"/Versions/A/CoreFoundation",
"libCoreFoundation.so"));
dylib_to_so_.insert(make_pair(
"/usr/lib/libncurses.5.4.dylib",
"libncurses.so"));
symbol_to_so_.insert(make_pair("uuid_clear", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_compare", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_copy", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_generate", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_generate_random", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_generate_time", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_is_null", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_pack", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_parse", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_unpack", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_unparse", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_unparse_lower", "libuuid.so"));
symbol_to_so_.insert(make_pair("uuid_unparse_upper", "libuuid.so"));
*/
}
void run(MachO& mach, int argc, char** argv, char** envp) {
// I don't understand what it is.
char* apple[2];
apple[0] = argv[0];
apple[1] = NULL;
load(mach);
setupDyldData(mach);
g_file_map.addWatchDog(last_addr_ + 1);
char* trampoline_start_addr =
(char*)(((uintptr_t)&trampoline_[0]) & ~0xfff);
uint64_t trampoline_size =
alignMem(&trampoline_[0] + trampoline_.size() - trampoline_start_addr,
0x1000);
mprotect(trampoline_start_addr, trampoline_size,
PROT_READ | PROT_WRITE | PROT_EXEC);
g_timer.print(mach.filename().c_str());
mach.close();
runInitFuncs(argc, argv, envp, apple);
LOG << "booting from " << (void*)mach.entry() << "..." << endl;
fflush(stdout);
CHECK(argc > 0);
boot(mach.entry(), argc, argv, envp);
/*
int (*fp)(int, char**, char**) =
(int(*)(int, char**, char**))mach.entry();
int ret = fp(argc, argv, envp);
exit(ret);
*/
}
private:
void boot(uint64_t entry, int argc, char** argv, char** envp);
void pushTrampolineCode(unsigned int c) {
while (c) {
trampoline_.push_back(c & 255);
c = c >> 8;
}
}
void pushTrampolineCode64(unsigned long long c) {
for (int i = 0; i < 8; i++) {
trampoline_.push_back(c & 255);
c = c >> 8;
}
}
void pushTrampolineCode32(unsigned int c) {
for (int i = 0; i < 4; i++) {
trampoline_.push_back(c & 255);
c = c >> 8;
}
}
string trampoline_;
intptr last_addr_;
vector<uint64_t> init_funcs_;
Exports exports_;
vector<pair<string, char*> > seen_weak_binds_;
map<string, string> dylib_to_so_;
map<string, string> symbol_to_so_;
set<string> loaded_dylibs_;
};
void MachOLoader::boot(
uint64_t entry, int argc, char** argv, char** envp) {
#ifdef __x86_64__
// 0x08: argc
// 0x10: argv[0]
// 0x18: argv[1]
// ...: argv[n]
// 0
// envp[0]
// envp[1]
// envp[n]
// TODO: add 'apple'!
__asm__ volatile(" mov %1, %%rax;\n"
" mov %2, %%rdx;\n"
" push $0;\n"
// TODO(hamaji): envp
" push $0;\n"
".loop64:\n"
" sub $8, %%rdx;\n"
" push (%%rdx);\n"
" dec %%eax;\n"
" jnz .loop64;\n"
" mov %1, %%eax;\n"
" push %%rax;\n"
" jmp *%0;\n"
::"r"(entry), "r"(argc), "r"(argv + argc), "r"(envp)
:"%rax", "%rdx");
//fprintf(stderr, "done!\n");
#else
__asm__ volatile(" mov %1, %%eax;\n"
" mov %2, %%edx;\n"
" push $0;\n"
".loop32:\n"
" sub $4, %%edx;\n"
" push (%%edx);\n"
" dec %%eax;\n"
" jnz .loop32;\n"
" mov %1, %%eax;\n"
" push %%eax;\n"
" jmp *%0;\n"
// TODO(hamaji): Fix parameters
::"r"(entry), "r"(argc), "r"(argv + argc), "g"(envp)
:"%eax", "%edx");
#endif
}
void runMachO(MachO& mach, int argc, char** argv, char** envp) {
MachOLoader loader;
g_loader = &loader;
loader.run(mach, argc, argv, envp);
g_loader = NULL;
}
#if 0
static int getBacktrace(void** trace, int max_depth) {
typedef struct frame {
struct frame *bp;
void *ret;
} frame;
int depth;
frame* bp = (frame*)__builtin_frame_address(0);
for (depth = 0; bp && depth < max_depth; depth++) {
trace[depth] = bp->ret;
bp = bp->bp;
}
return depth;
}
#endif
extern "C" {
const char* dumpSymbol(void* p) {
return g_file_map.dumpSymbol(p);
}
}
/* signal handler for fatal errors */
static void handleSignal(int signum, siginfo_t* siginfo, void* vuc) {
ucontext_t *uc = (ucontext_t*)vuc;
void* pc = (void*)uc->uc_mcontext.gregs[
#ifdef __x86_64__
REG_RIP
#else
REG_EIP
#endif
];
fprintf(stderr, "%s(%d) %d (@%p) PC: %p\n\n",
strsignal(signum), signum, siginfo->si_code, siginfo->si_addr, pc);
void* trace[100];
int len = backtrace(trace, 99);
//int len = getBacktrace(trace, 99);
char** syms = backtrace_symbols(trace, len);
for (int i = len - 1; i > 0; i--) {
if (syms[i] && syms[i][0] != '[') {
fprintf(stderr, "%s\n", syms[i]);
} else {
const char* s = dumpSymbol(trace[i]);
if (s) {
fprintf(stderr, "%s\n", s);
} else {
fprintf(stderr, "%p\n", trace[i]);
}
}
}
}
/* Generate a stack backtrace when a CPU exception occurs. */
static void initSignalHandler() {
struct sigaction sigact;
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
sigact.sa_sigaction = handleSignal;
sigemptyset(&sigact.sa_mask);
sigaction(SIGFPE, &sigact, NULL);
sigaction(SIGILL, &sigact, NULL);
sigaction(SIGSEGV, &sigact, NULL);
sigaction(SIGBUS, &sigact, NULL);
sigaction(SIGABRT, &sigact, NULL);
}
/*
static bool loadLibMac(const char* mypath) {
if (dlopen("libmac.so", RTLD_LAZY | RTLD_GLOBAL)) {
return true;
}
char buf[PATH_MAX + 100];
strcpy(buf, mypath);
char* p = strrchr(buf, '/');
if (!p) {
fprintf(stderr, "Weird loader path: %s\n", mypath);
exit(1);
}
strcpy(p, "/libmac.so");
if (dlopen(buf, RTLD_LAZY | RTLD_GLOBAL)) {
return true;
}
sprintf(p, "/libmac%d.so", BITS);
if (dlopen(buf, RTLD_LAZY | RTLD_GLOBAL)) {
return true;
}
return false;
}
*/
/*
static void initLibMac() {
char mypath[PATH_MAX + 1];
ssize_t l = readlink("/proc/self/exe", mypath, PATH_MAX);
if (l < 0) {
err(1, "readlink for /proc/self/exe");
}
mypath[l] = '\0';
if (!loadLibMac(mypath)) {
fprintf(stderr, "libmac not found\n");
exit(1);
}
int* LIBMAC_LOG = (int*)dlsym(RTLD_DEFAULT, "LIBMAC_LOG");
if (LIBMAC_LOG) {
*LIBMAC_LOG = FLAGS_LOG;
}
char* loader_path = (char*)dlsym(RTLD_DEFAULT, "__loader_path");
if (!loader_path) {
fprintf(stderr, "wrong libmac: __loader_path not found\n");
exit(1);
}
strcpy(loader_path, mypath);
}
*/
// TODO: OMG
static string ld_mac_dlerror_buf;
static bool ld_mac_dlerror_is_set;
// TODO: broken - should support multiple loads and native libs
void* __darwin_dlopen(const char* filename, int flag) {
LOG << "ld_mac_dlopen: " << filename << " " << flag << endl;
// TODO: should return main executable on filename == NULL
Timer timer;
timer.start();
// TODO(hamaji): Handle failures.
auto_ptr<MachO> dylib_mach(loadDylib(filename));
MachOLoader* loader = g_loader;
CHECK(loader);
Exports* exports = new Exports();
loader->load(*dylib_mach, exports);
timer.print(filename);
loader->runInitFuncs(-1, NULL, NULL, NULL);
return exports;
}
// TODO: broken - should decrease the reference count
static int __darwin_dlclose(void* handle) {
LOG << "ld_mac_dlclose" << endl;
delete (Exports*)handle;
return 0;
}
static const char* __darwin_dlerror(void) {
LOG << "ld_mac_dlerror" << endl;
if (!ld_mac_dlerror_is_set)
return NULL;
ld_mac_dlerror_is_set = false;
return ld_mac_dlerror_buf.c_str();
}
static void* __darwin_dlsym(void* handle, const char* symbol) {
LOG << "ld_mac_dlsym: " << symbol << endl;
// TODO: support RTLD_DEFAULT
Exports* exports = (Exports*)handle;
Exports::const_iterator found = exports->find(string("_") + symbol);
if (found == exports->end()) {
ld_mac_dlerror_is_set = true;
ld_mac_dlerror_buf = string("undefined symbol: ") + symbol;
return NULL;
}
return (void*)found->second.addr;
}
/*
void initDlfcn() {
#define SET_DLFCN_FUNC(f) \
do { \
void** p = (void**)dlsym(RTLD_DEFAULT, "ld_mac_" #f); \
*p = (void*)&ld_mac_ ## f; \
} while (0)
SET_DLFCN_FUNC(dlopen);
SET_DLFCN_FUNC(dlclose);
SET_DLFCN_FUNC(dlerror);
SET_DLFCN_FUNC(dlsym);
}
*/

View File

@ -15,10 +15,14 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <limits.h> #include <limits.h>
#include <regex.h>
#include <cassert>
static Darling::Mutex g_ldMutex; static Darling::Mutex g_ldMutex;
static std::map<std::string, LoadedLibrary*> g_ldLibraries; static std::map<std::string, LoadedLibrary*> g_ldLibraries;
static __thread char g_ldError[256] = ""; static __thread char g_ldError[256] = "";
static regex_t g_reAutoMappable;
static LoadedLibrary g_dummyLibrary;
extern char g_darwin_executable_path[PATH_MAX]; extern char g_darwin_executable_path[PATH_MAX];
@ -27,17 +31,33 @@ static const char* g_searchPath[] = {
LIB_PATH, "/usr/lib", "/usr/local/lib" LIB_PATH, "/usr/lib", "/usr/local/lib"
}; };
static const char* g_suffixes[] = { "$DARWIN_EXTSN", "$UNIX2003", "$NOCANCEL" };
static void* attemptDlopen(const char* filename, int flag); static void* attemptDlopen(const char* filename, int flag);
static int translateFlags(int flags); static int translateFlags(int flags);
__attribute__((constructor)) static void initLD();
extern MachOLoader* g_loader; extern MachOLoader* g_loader;
extern char g_darwin_executable_path[PATH_MAX]; extern char g_darwin_executable_path[PATH_MAX];
extern char g_sysroot[PATH_MAX];
extern int g_argc; extern int g_argc;
extern char** g_argv; extern char** g_argv;
extern FileMap g_file_map; extern FileMap g_file_map;
#define RET_IF(x) { if (void* p = x) return p; } #define RET_IF(x) { if (void* p = x) return p; }
static void initLD()
{
int rv = regcomp(&g_reAutoMappable, "/(lib[[:alnum:]\\-]+)\\.([[:digit:]]+)(\\.[[:digit:]]+)?\\.dylib", REG_EXTENDED);
assert(rv == 0);
g_dummyLibrary.name = "/dev/null";
g_dummyLibrary.refCount = 1;
g_dummyLibrary.type = LoadedLibraryDummy;
g_dummyLibrary.nativeRef = 0;
g_dummyLibrary.exports = 0;
}
void* __darwin_dlopen(const char* filename, int flag) void* __darwin_dlopen(const char* filename, int flag)
{ {
TRACE2(filename, flag); TRACE2(filename, flag);
@ -58,6 +78,18 @@ void* __darwin_dlopen(const char* filename, int flag)
start_search: start_search:
if (*filename == '/') if (*filename == '/')
{ {
if (g_sysroot[0])
{
path = g_sysroot + std::string(filename) + ".so";
LOG << "Trying " << path << std::endl;
if (::access(path.c_str(), R_OK) == 0)
RET_IF( attemptDlopen(path.c_str(), flag) );
path = std::string(g_sysroot) + filename;
if (::access(path.c_str(), R_OK) == 0)
RET_IF( attemptDlopen(path.c_str(), flag) );
}
path = std::string(filename) + ".so"; path = std::string(filename) + ".so";
LOG << "Trying " << path << std::endl; LOG << "Trying " << path << std::endl;
if (::access(path.c_str(), R_OK) == 0) if (::access(path.c_str(), R_OK) == 0)
@ -74,6 +106,34 @@ start_search:
if (::access(path.c_str(), R_OK) == 0) if (::access(path.c_str(), R_OK) == 0)
RET_IF( attemptDlopen(path.c_str(), flag) ); RET_IF( attemptDlopen(path.c_str(), flag) );
regmatch_t matches[3];
if (regexec(&g_reAutoMappable, filename, 3, matches, 0) == 0)
{
path = std::string(filename, matches[0].rm_so+1);
path += std::string(filename + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
path += ".so.";
path += std::string(filename + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
if (::access(path.c_str(), R_OK) == 0)
{
LOG << "Warning: Automatically mapping " << filename << " to " << path << std::endl;
RET_IF( attemptDlopen(path.c_str(), flag) );
}
//path = std::string(filename, matches[0].rm_so+1);
path = std::string(filename + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
path += ".so.";
path += std::string(filename + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
LOG << path << std::endl;
//if (::access(path.c_str(), R_OK) == 0)
//{
LOG << "Warning: Trying to remap " << filename << " to " << path << std::endl;
RET_IF( attemptDlopen(path.c_str(), flag) );
//}
}
if (strcmp(INSTALL_PREFIX, "/usr") != 0) if (strcmp(INSTALL_PREFIX, "/usr") != 0)
{ {
// We need to change the prefix in filename if present // We need to change the prefix in filename if present
@ -123,7 +183,8 @@ start_search:
} }
} }
strcpy(g_ldError, "File not found"); if (!g_ldError[0])
snprintf(g_ldError, sizeof(g_ldError)-1, "File not found: %s", filename);
return 0; return 0;
} }
@ -148,7 +209,7 @@ static int translateFlags(int flag)
static bool isSymlink(const char* path) static bool isSymlink(const char* path)
{ {
struct stat st; struct stat st;
if (::stat(path, &st) == -1) if (::lstat(path, &st) == -1)
return false; return false;
return S_ISLNK(st.st_mode); return S_ISLNK(st.st_mode);
} }
@ -159,14 +220,26 @@ void* attemptDlopen(const char* filename, int flag)
TRACE2(filename,flag); TRACE2(filename,flag);
strcpy(name, filename);
// Resolve symlinks so that we don't load the same library multiple times // Resolve symlinks so that we don't load the same library multiple times
if (isSymlink(filename) && ::readlink(filename, name, sizeof name) == -1) if (isSymlink(filename))
{ {
LOG << "Invalid symlink found: " << filename << std::endl; ssize_t len = ::readlink(filename, name, sizeof name);
return 0; if (len == -1)
{
LOG << "Invalid symlink found: " << filename << std::endl;
return 0;
}
else
name[len] = 0;
}
if (strcmp(name, "/dev/null") == 0)
{
// We return a dummy
return &g_dummyLibrary;
} }
else
strcpy(name, filename);
std::map<std::string,LoadedLibrary*>::iterator it = g_ldLibraries.find(name); std::map<std::string,LoadedLibrary*>::iterator it = g_ldLibraries.find(name);
if (it != g_ldLibraries.end()) if (it != g_ldLibraries.end())
@ -191,9 +264,11 @@ void* attemptDlopen(const char* filename, int flag)
LOG << "Loading a native library " << name << std::endl; LOG << "Loading a native library " << name << std::endl;
// We're loading a native library // We're loading a native library
// TODO: flags // TODO: flags
void* d = ::dlopen(name, RTLD_NOW); void* d = ::dlopen(name, RTLD_NOW|RTLD_GLOBAL);
if (d != 0) if (d != 0)
{ {
LOG << "Native library loaded\n";
LoadedLibrary* lib = new LoadedLibrary; LoadedLibrary* lib = new LoadedLibrary;
lib->name = name; lib->name = name;
lib->refCount = 1; lib->refCount = 1;
@ -206,13 +281,20 @@ void* attemptDlopen(const char* filename, int flag)
} }
else else
{ {
LOG << "Library failed to load: " << ::dlerror() << std::endl; LOG << "Native library failed to load\n";
strcpy(g_ldError, ::dlerror());
const char* err;
if ((err = ::dlerror()) && !g_ldError[0]) // we don't overwrite previous errors
{
LOG << "Library failed to load: " << err << std::endl;
strcpy(g_ldError, err);
}
return 0; return 0;
} }
} }
else else
{ {
LOG << "Loading a Mach-O library\n";
// We're loading a Mach-O library // We're loading a Mach-O library
try try
{ {
@ -299,6 +381,22 @@ const char* __darwin_dlerror(void)
return g_ldError[0] ? g_ldError : 0; return g_ldError[0] ? g_ldError : 0;
} }
static const char* translateSymbol(const char* symbol)
{
std::string s = symbol;
static char symbuffer[255];
for (int i = 0; i < sizeof(g_suffixes) / sizeof(g_suffixes[0]); i++)
{
size_t pos = s.find(g_suffixes[i]);
if (pos != std::string::npos)
s.erase(pos, strlen(g_suffixes[i]));
}
strcpy(symbuffer, s.c_str());
return symbuffer;
}
void* __darwin_dlsym(void* handle, const char* symbol) void* __darwin_dlsym(void* handle, const char* symbol)
{ {
TRACE2(handle, symbol); TRACE2(handle, symbol);
@ -306,6 +404,8 @@ void* __darwin_dlsym(void* handle, const char* symbol)
Darling::MutexLock l(g_ldMutex); Darling::MutexLock l(g_ldMutex);
g_ldError[0] = 0; g_ldError[0] = 0;
symbol = translateSymbol(symbol);
if (handle == DARWIN_RTLD_NEXT || handle == DARWIN_RTLD_SELF || handle == DARWIN_RTLD_MAIN_ONLY || !handle) if (handle == DARWIN_RTLD_NEXT || handle == DARWIN_RTLD_SELF || handle == DARWIN_RTLD_MAIN_ONLY || !handle)
{ {
LOG << "Cannot yet handle certain DARWIN_RTLD_* search strategies, falling back to RTLD_DEFAULT\n"; LOG << "Cannot yet handle certain DARWIN_RTLD_* search strategies, falling back to RTLD_DEFAULT\n";
@ -317,7 +417,7 @@ handling:
{ {
// First try native with the __darwin prefix // First try native with the __darwin prefix
void* sym; void* sym;
char* buf = reinterpret_cast<char*>(malloc(strlen(symbol+20))); char* buf = reinterpret_cast<char*>(malloc(strlen(symbol)+20));
strcpy(buf, "__darwin_"); strcpy(buf, "__darwin_");
strcat(buf, symbol); strcat(buf, symbol);
@ -358,6 +458,11 @@ handling:
strcpy(g_ldError, ::dlerror()); strcpy(g_ldError, ::dlerror());
return rv; return rv;
} }
else if (lib->type == LoadedLibraryDummy)
{
snprintf(g_ldError, sizeof(g_ldError)-1, "Cannot find symbol '%s'", symbol);
return 0;
}
else if (!lib->exports) else if (!lib->exports)
{ {
// TODO: this isn't 100% correct // TODO: this isn't 100% correct

View File

@ -28,7 +28,7 @@ int __darwin_dladdr(void *addr, Dl_info *info);
} }
enum LoadedLibraryType { LoadedLibraryDylib, LoadedLibraryNative }; enum LoadedLibraryType { LoadedLibraryDylib, LoadedLibraryNative, LoadedLibraryDummy };
typedef std::unordered_map<std::string, MachO::Export> Exports; typedef std::unordered_map<std::string, MachO::Export> Exports;

View File

@ -1,155 +0,0 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
// A translation table from Mac symbols to Linux's.
RENAME(__stderrp, __darwin_stderr)
RENAME(__stdoutp, __darwin_stdout)
RENAME(__stdinp, __darwin_stdin)
WRAP(stderr)
WRAP(stdout)
WRAP(stdin)
WRAP(fopen)
WRAP(fdopen)
WRAP(freopen)
WRAP(fclose)
WRAP(fread)
WRAP(fwrite)
WRAP(fseek)
WRAP(ftell)
WRAP(rewind)
WRAP(getc)
WRAP(fgetc)
WRAP(ungetc)
WRAP(fgets)
WRAP(putc)
WRAP(fputc)
WRAP(fputs)
WRAP(fscanf)
WRAP(vfscanf)
WRAP(fprintf)
WRAP(vfprintf)
WRAP(fflush)
WRAP(setbuf)
WRAP(setbuffer)
WRAP(ferror)
RENAME(_ferror, __darwin_ferror)
WRAP(fileno)
WRAP(tmpfile)
RENAME(__srget, __darwin_fgetc)
RENAME(__swbuf, __darwin_fputc)
RENAME(__toupper, toupper)
RENAME(__tolower, tolower)
RENAME(opendir$INODE64, opendir)
RENAME(readdir$INODE64, __darwin_readdir64)
WRAP(readdir)
WRAP(stat)
WRAP(fstat)
WRAP(lstat)
RENAME(stat$INODE64, __darwin_stat64)
RENAME(fstat$INODE64, __darwin_fstat64)
RENAME(lstat$INODE64, __darwin_lstat64)
WRAP(open)
WRAP(mmap)
WRAP(sysctl)
RENAME(realpath$DARWIN_EXTSN, realpath)
WRAP(execv)
WRAP(execvp)
WRAP(execl)
WRAP(execlp)
WRAP(execve)
WRAP(execle)
WRAP(posix_spawn)
WRAP(posix_spawnp)
WRAP(posix_spawn_file_actions_init)
WRAP(posix_spawn_file_actions_destroy)
WRAP(posix_spawn_file_actions_addopen)
WRAP(posix_spawn_file_actions_addclose)
WRAP(posix_spawn_file_actions_adddup2)
RENAME(CC_MD5_Init, MD5_Init)
RENAME(CC_MD5_Update, MD5_Update)
RENAME(CC_MD5_Final, MD5_Final)
RENAME(CC_MD5, MD5)
WRAP(__cxa_throw)
RENAME(atexit, __cxa_atexit)
WRAP(signal)
WRAP(sigaction)
WRAP(sigaltstack)
#ifdef __x86_64__
RENAME(__ashldi3, __ashlti3)
RENAME(__ashrdi3, __ashrti3)
RENAME(__cmpdi2, __cmpti2)
RENAME(__divdi3, __divti3)
RENAME(__fixdfdi, __fixdfti)
RENAME(__fixsfdi, __fixsfti)
RENAME(__floatdidf, __floattidf)
RENAME(__floatdisf, __floattisf)
RENAME(__lshrdi3, __lshrti3)
RENAME(__moddi3, __modti3)
RENAME(__udivdi3, __udivti3)
RENAME(__umoddi3, __umodti3)
#endif
// TODO(hamaji): *attr_gettype and *attr_getpshared
WRAP(pthread_mutexattr_settype)
WRAP(pthread_mutexattr_setpshared)
WRAP(pthread_rwlockattr_setpshared)
WRAP(dlopen)
WRAP(dlclose)
WRAP(dlerror)
WRAP(dlsym)
// TODO(hamaji): dladdr?
RENAME(_ZNSt12__basic_fileIcE8sys_openEP7__sFILESt13_Ios_Openmode,
_ZNSt12__basic_fileIcE8sys_openEP8_IO_FILESt13_Ios_Openmode)
WRAP(uname)
// TODO(hamaji): Not sure if this is right...
RENAME(select$1050, select)
WRAP(qsort_r)
WRAP(newlocale)
WRAP(compat_mode)

View File

@ -51,6 +51,7 @@ set(libc_SRCS
libc/stdio.cpp libc/stdio.cpp
libc/fopsmisc.cpp libc/fopsmisc.cpp
libc/aio.cpp libc/aio.cpp
libc/mount.cpp
common/path.cpp common/path.cpp
) )
@ -60,6 +61,7 @@ set(bsdkern_SRCS
kernel-bsd/io.cpp kernel-bsd/io.cpp
kernel-bsd/wait.cpp kernel-bsd/wait.cpp
kernel-bsd/sockets.cpp kernel-bsd/sockets.cpp
kernel-bsd/fs.cpp
) )
set(machkern_SRCS set(machkern_SRCS
@ -71,9 +73,9 @@ set(machkern_SRCS
kernel-mach/vm.cpp kernel-mach/vm.cpp
) )
add_library(System.dylib SHARED ${libc_SRCS} ${bsdkern_SRCS} ${machkern_SRCS}) add_library(System.B.dylib SHARED ${libc_SRCS} ${bsdkern_SRCS} ${machkern_SRCS})
# -luuid to make uuid_ functions available for Darwin apps # -luuid to make uuid_ functions available for Darwin apps
target_link_libraries(System.dylib -ldl -lpthread -luuid -lmach-o -l:libobjc.so.4 -lrt -lssl) target_link_libraries(System.B.dylib -ldl -lpthread -luuid -lmach-o -l:libobjc.so.4 -lrt -lssl)
install(TARGETS System.dylib DESTINATION lib) install(TARGETS System.B.dylib DESTINATION lib)

View File

@ -0,0 +1,161 @@
#include "config.h"
#include "fs.h"
#include <cstring>
#include "common/path.h"
#include "libc/errno.h"
#include "libc/darwin_errno_codes.h"
#include <mntent.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/statvfs.h>
#include <unistd.h>
#include "log.h"
template<typename Out> void StatfsLinuxToDarwinGen(const char* path, const struct statvfs* in, Out* out)
{
out->f_bsize = in->f_bsize;
out->f_blocks = out->f_iosize = in->f_blocks;
out->f_bfree = in->f_bfree;
out->f_bavail = in->f_bavail;
out->f_files = in->f_files;
out->f_ffree = in->f_ffree;
out->f_fsid.val[0] = in->f_fsid;
if (in->f_flag & ST_RDONLY)
out->f_flags |= DARWIN_MNT_RDONLY;
if (in->f_flag & ST_NOSUID)
out->f_flags |= DARWIN_MNT_NOSUID;
struct mntent* ent = findMountForPath(path);
if (ent)
{
strncpy(out->f_mntfromname, ent->mnt_fsname, sizeof(out->f_mntfromname)-1); // we assume zeroed out, no need to set the last char to NUL
strncpy(out->f_mntonname, ent->mnt_dir, sizeof(out->f_mntonname)-1);
strncpy(out->f_fstypename, ent->mnt_fsname, sizeof(out->f_fstypename)-1);
}
}
template<typename T> int __darwin_statfsGen(const char* path, T* buf)
{
struct statvfs st;
int rv;
::memset(buf, 0, sizeof(*buf));
rv = statvfs(path, &st);
if (rv == -1)
errnoOut();
else
StatfsLinuxToDarwinGen(path, &st, buf);
return rv;
}
int __darwin_statfs(const char* path, struct __darwin_statfs* buf)
{
return __darwin_statfsGen(translatePathCI(path), buf);
}
int __darwin_statfs64(const char* path, struct __darwin_statfs64* buf)
{
return __darwin_statfsGen(translatePathCI(path), buf);
}
template <typename T> int __darwin_fstatfsGen(int fd, T* out)
{
char buf[PATH_MAX], buf2[PATH_MAX];
sprintf(buf, "/proc/%d/fd/%d", getpid(), fd);
memset(out, 0, sizeof(*out));
if (::readlink(buf, buf2, sizeof buf2) == -1)
{
errnoOut();
return -1;
}
return __darwin_statfsGen(buf2, out);
}
int __darwin_fstatfs(int fd, struct __darwin_statfs* buf)
{
return __darwin_fstatfsGen(fd, buf);
}
int __darwin_fstatfs64(int fd, struct __darwin_statfs64* buf)
{
return __darwin_fstatfsGen(fd, buf);
}
template<typename Stat> int __darwin_getfsstatGen(Stat* buf, int bufsize, int flags)
{
FILE* f = setmntent("/proc/mounts", "r");
struct mntent *ent;
if (!f)
{
LOG << "Cannot access /proc/mounts!\n";
errno = DARWIN_ENOENT;
return -1;
}
int count = 0;
while ( (ent = getmntent(f)) != 0 && ((count+1)*sizeof(*buf) < bufsize || !buf) )
{
if (buf)
{
int rv = __darwin_statfsGen(ent->mnt_dir, buf+count);
if (rv == -1)
break;
}
count++;
}
endmntent(f);
return count;
}
int __darwin_getfsstat(struct __darwin_statfs* buf, int bufsize, int flags)
{
return __darwin_getfsstatGen(buf, bufsize, flags);
}
int __darwin_getfsstat64(struct __darwin_statfs* buf, int bufsize, int flags)
{
return __darwin_getfsstatGen(buf, bufsize, flags);
}
void StatfsLinuxToDarwin(const char* path, const struct statvfs* in, struct __darwin_statfs* out)
{
StatfsLinuxToDarwinGen(path, in, out);
}
void StatfsLinuxToDarwin(const char* path, const struct statvfs* in, struct __darwin_statfs64* out)
{
StatfsLinuxToDarwinGen(path, in, out);
}
struct mntent* findMountForPath(const char* path)
{
FILE* f = setmntent("/proc/mounts", "r");
struct mntent *ent, *rv = 0;
if (!f)
{
LOG << "Cannot access /proc/mounts!\n";
return 0;
}
while ((ent = getmntent(f)))
{
if (strncmp(ent->mnt_dir, path, strlen(ent->mnt_dir)) == 0)
{
rv = ent;
break;
}
}
endmntent(f);
return rv;
}

View File

@ -0,0 +1,86 @@
#ifndef BSD_FS_H
#define BSD_FS_H
#include <stdint.h>
#include "common/path.h"
#define MFSNAMELEN 15
#define MFSTYPENAMELEN 16
#define MNAMELEN 90
#define DARWIN_MNT_RDONLY 0x1
#define DARWIN_MNT_SYNCHRONOUS 0x2
#define DARWIN_MNT_NOEXEC 0x4
#define DARWIN_MNT_NOSUID 0x8
#define DARWIN_MNT_NODEV 0x10
#define DARWIN_MNT_UNION 0x20
#define DARWIN_MNT_ASYNC 0x40
#define DARWIN_MNT_CPROTECT 0x80
typedef struct { int32_t val[2]; } darwin_fsid_t;
struct __darwin_statfs64
{
uint32_t f_bsize;
int32_t f_iosize;
uint64_t f_blocks;
uint64_t f_bfree;
uint64_t f_bavail;
uint64_t f_files;
uint64_t f_ffree;
darwin_fsid_t f_fsid;
uint32_t f_owner;
uint32_t f_type;
uint32_t f_flags;
uint32_t f_fssubtype;
char f_fstypename[MFSTYPENAMELEN];
char f_mntonname[DARWIN_MAXPATHLEN];
char f_mntfromname[DARWIN_MAXPATHLEN];
uint32_t f_reserved[8];
};
struct __darwin_statfs
{
short f_otype;
short f_oflags;
long f_bsize;
long f_iosize;
long f_blocks;
long f_bfree;
long f_bavail;
long f_files;
long f_ffree;
darwin_fsid_t f_fsid;
uint32_t f_owner;
short f_reserved1;
short f_type;
long f_flags;
long f_reserved2[2];
char f_fstypename[MFSNAMELEN];
char f_mntonname[MNAMELEN];
char f_mntfromname[MNAMELEN];
char f_reserved3;
long f_reserved4[4];
};
extern "C"
{
int __darwin_statfs(const char* path, struct __darwin_statfs* buf);
int __darwin_statfs64(const char* path, struct __darwin_statfs64* buf) asm("__darwin_statfs$INODE64");
int __darwin_fstatfs(int fd, struct __darwin_statfs* buf);
int __darwin_fstatfs64(int fd, struct __darwin_statfs64* buf) asm("__darwin_fstatfs$INODE64");
int __darwin_getfsstat(struct __darwin_statfs* buf, int bufsize, int flags);
int __darwin_getfsstat64(struct __darwin_statfs64* buf, int bufsize, int flags) asm("__darwin_getfsstat$INODE64");
}
// out assumed to have been zeroed out
void StatfsLinuxToDarwin(const char* path, const struct statvfs* in, struct __darwin_statfs* out);
void StatfsLinuxToDarwin(const char* path, const struct statvfs* in, struct __darwin_statfs64* out);
struct mntent;
struct mntent* findMountForPath(const char* path);
#endif

View File

@ -1,3 +1,4 @@
#include "config.h"
#include "wait.h" #include "wait.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/darwin_errno_codes.h" #include "libc/darwin_errno_codes.h"

View File

@ -120,8 +120,73 @@ extern __darwin_opendir
__darwin_opendir$INODE64: __darwin_opendir$INODE64:
jmp __darwin_opendir WRT ..plt jmp __darwin_opendir WRT ..plt
global __darwin_rewinddir$INODE64
extern __darwin_rewinddir
__darwin_rewinddir$INODE64:
jmp __darwin_rewinddir WRT ..plt
global __darwin_telldir$INODE64 global __darwin_telldir$INODE64
extern telldir extern telldir
__darwin_telldir$INODE64: __darwin_telldir$INODE64:
jmp telldir WRT ..plt jmp telldir WRT ..plt
global __darwin_curl_mfprintf
extern __darwin_fprintf
__darwin_curl_mfprintf:
jmp __darwin_fprintf WRT ..plt
global __darwin_curl_mvfprintf
extern __darwin_vfprintf
__darwin_curl_mvfprintf:
jmp __darwin_vfprintf WRT ..plt
global realpath$DARWIN_EXTSN
extern __darwin_realpath
realpath$DARWIN_EXTSN:
jmp __darwin_realpath WRT ..plt
global libintl_gettext
extern gettext
libintl_gettext:
jmp gettext WRT ..plt
global libintl_dgettext
extern dgettext
libintl_dgettext:
jmp dgettext WRT ..plt
global libintl_ngettext
extern ngettext
libintl_ngettext:
jmp ngettext WRT ..plt
global libintl_dngettext
extern dngettext
libintl_dngettext:
jmp dngettext WRT ..plt
global libintl_dcngettext
extern dcngettext
libintl_dcngettext:
jmp dcngettext WRT ..plt
global libintl_textdomain
extern textdomain
libintl_textdomain:
jmp textdomain WRT ..plt
global libintl_bindtextdomain
extern bindtextdomain
libintl_bindtextdomain:
jmp bindtextdomain WRT ..plt
global libintl_bind_textdomain
extern bind_textdomain_codeset
libintl_bind_textdomain:
jmp bind_textdomain_codeset WRT ..plt
global libintl_setlocale
extern setlocale
libintl_setlocale:
jmp setlocale WRT ..plt

View File

@ -24,4 +24,22 @@ __darwin_err;__darwin__err
;;; dir.cpp ;;; dir.cpp
__darwin_opendir$INODE64;__darwin_opendir __darwin_opendir$INODE64;__darwin_opendir
__darwin_rewinddir$INODE64;__darwin_rewinddir
__darwin_telldir$INODE64;telldir __darwin_telldir$INODE64;telldir
__darwin_curl_mfprintf;__darwin_fprintf
__darwin_curl_mvfprintf;__darwin_vfprintf
realpath$DARWIN_EXTSN;__darwin_realpath
libintl_gettext;gettext
libintl_dgettext;dgettext
libintl_ngettext;ngettext
libintl_dngettext;dngettext
libintl_dcngettext;dcngettext
libintl_textdomain;textdomain
libintl_bindtextdomain;bindtextdomain
libintl_bind_textdomain;bind_textdomain_codeset
libintl_setlocale;setlocale

View File

@ -17,6 +17,9 @@ char *__darwin_realpath(const char *path, char *resolved_path)
path = translatePathCI(path); path = translatePathCI(path);
if (!resolved_path) // DARWIN_EXTSN
resolved_path = static_cast<char*>(malloc(DARWIN_MAXPATHLEN));
char* rv = realpath(path, resolved_path); char* rv = realpath(path, resolved_path);
if (!rv) if (!rv)
errnoOut(); errnoOut();

View File

@ -0,0 +1,52 @@
#include "mount.h"
#include <mntent.h>
#include "libc/darwin_errno_codes.h"
#include <errno.h>
template<typename Statfs, typename Fsstatfun> int __darwin_getmntinfoGen(Fsstatfun f, Statfs** mntbufp, int flags)
{
static __thread Statfs* lastMntbufp = 0;
*mntbufp = 0;
if (lastMntbufp)
{
delete [] lastMntbufp;
lastMntbufp = 0;
}
int count = f(0, 0, 0);
if (count < 0)
return -1;
lastMntbufp = new Statfs[count];
if (!lastMntbufp)
{
errno = DARWIN_ENOMEM;
return -1;
}
count = f(lastMntbufp, count*sizeof(Statfs), 0);
if (count < 0)
{
delete [] lastMntbufp;
lastMntbufp = 0;
return -1;
}
*mntbufp = lastMntbufp;
return count;
}
int __darwin_getmntinfo(struct __darwin_statfs** mntbufp, int flags)
{
return __darwin_getmntinfoGen(__darwin_getfsstat, mntbufp, flags);
}
int __darwin_getmntinfo64(struct __darwin_statfs64** mntbufp, int flags)
{
return __darwin_getmntinfoGen(__darwin_getfsstat64, mntbufp, flags);
}

View File

@ -0,0 +1,13 @@
#ifndef LIBC_MOUNT_H
#define LIBC_MOUNT_H
#include "kernel-bsd/fs.h"
extern "C"
{
int __darwin_getmntinfo(struct __darwin_statfs** mntbufp, int flags);
int __darwin_getmntinfo64(struct __darwin_statfs64** mntbufp, int flags) asm("__darwin_getmntinfo$INODE64");
}
#endif

View File

@ -1,3 +1,4 @@
#include "config.h"
#include "stdio.h" #include "stdio.h"
#include "errno.h" #include "errno.h"
#include "common/path.h" #include "common/path.h"
@ -7,11 +8,19 @@
#include <cstdlib> #include <cstdlib>
#include <errno.h> #include <errno.h>
#include <stdio_ext.h> #include <stdio_ext.h>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "log.h" #include "log.h"
extern "C" __darwin_FILE* __stdinp = 0; //extern "C"
extern "C" __darwin_FILE* __stdoutp = 0; //{
extern "C" __darwin_FILE* __stderrp = 0; __darwin_FILE* __stdinp asm("__stdinp") = 0;
__darwin_FILE* __stdoutp asm("__stdoutp") = 0;
__darwin_FILE* __stderrp asm("__stderrp") = 0;
//}
static __darwin_FILE* InitDarwinFILE(FILE* linux_fp) static __darwin_FILE* InitDarwinFILE(FILE* linux_fp)
{ {
@ -39,7 +48,30 @@ template<typename RetVal, typename Func, typename... Params> RetVal AutoFileErrn
__darwin_FILE* __darwin_fopen(const char* path, const char* mode) __darwin_FILE* __darwin_fopen(const char* path, const char* mode)
{ {
return InitDarwinFILE(fopen(translatePathCI(path), mode)); path = translatePathCI(path);
if (!strchr(mode, 'x'))
return InitDarwinFILE(fopen(path, mode));
else // DARWIN_EXTSN
{
std::string m = mode;
size_t pos = m.find('x');
m.erase(pos, 1);
int flags = O_CREAT | O_EXCL;
if (m.find('a') != std::string::npos)
flags |= O_APPEND;
if (m.find('+') != std::string::npos)
flags |= O_RDWR;
else
flags |= O_WRONLY;
int fd = ::open(path, flags, 0666);
if (fd == -1)
return 0;
else
return __darwin_fdopen(fd, m.c_str());
}
} }
__darwin_FILE* __darwin_fdopen(int fd, const char* mode) __darwin_FILE* __darwin_fdopen(int fd, const char* mode)
@ -296,9 +328,9 @@ wint_t __darwin_ungetwc(wint_t wc, __darwin_FILE *stream)
__attribute__((constructor)) static void initStdio() __attribute__((constructor)) static void initStdio()
{ {
__stderrp = InitDarwinFILE(stdin); __stderrp = InitDarwinFILE(stderr);
__stdoutp = InitDarwinFILE(stdout); __stdoutp = InitDarwinFILE(stdout);
__stdinp = InitDarwinFILE(stderr); __stdinp = InitDarwinFILE(stdin);
} }
int __darwin_remove(const char* path) int __darwin_remove(const char* path)

View File

@ -1,5 +1,6 @@
#include "string.h" #include "string.h"
#include <cstdlib> #include <cstdlib>
#include <ctype.h>
size_t strlcpy(char* dst, const char* src, size_t size) size_t strlcpy(char* dst, const char* src, size_t size)
{ {
@ -40,3 +41,14 @@ int __mb_cur_max()
{ {
return MB_CUR_MAX; return MB_CUR_MAX;
} }
int __toupper(int c)
{
return toupper(c);
}
int __tolower(int c)
{
return tolower(c);
}

View File

@ -12,6 +12,9 @@ void memset_pattern8(char* b, const char* pattern4, size_t len);
void memset_pattern16(char* b, const char* pattern4, size_t len); void memset_pattern16(char* b, const char* pattern4, size_t len);
int __mb_cur_max(); int __mb_cur_max();
int __toupper(int c);
int __tolower(int c);
} }

View File

@ -37,6 +37,7 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <stdexcept>
#define N_WEAK_DEF 0x0080 #define N_WEAK_DEF 0x0080
#define FLAGS_READ_SYMTAB 1 #define FLAGS_READ_SYMTAB 1
@ -235,7 +236,7 @@ MachOImpl::MachOImpl(const char* filename, int fd, size_t offset, size_t len, bo
m_fd = fd; m_fd = fd;
m_offset = offset; m_offset = offset;
m_text_offset = 0; m_text_offset = 0;
m_main = 0; m_main = m_entry = 0;
if (!m_mapped_size) if (!m_mapped_size)
m_mapped_size = ::lseek(m_fd, 0, SEEK_END); m_mapped_size = ::lseek(m_fd, 0, SEEK_END);
@ -245,15 +246,14 @@ MachOImpl::MachOImpl(const char* filename, int fd, size_t offset, size_t len, bo
char* bin = m_mapped = reinterpret_cast<char*>( char* bin = m_mapped = reinterpret_cast<char*>(
::mmap(NULL, m_mapped_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, m_fd, offset) ::mmap(NULL, m_mapped_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, m_fd, offset)
); );
if (bin == MAP_FAILED)
throw std::runtime_error("Cannot mmap Mach-O file");
m_base = bin; m_base = bin;
mach_header* header = reinterpret_cast<mach_header*>(bin); mach_header* header = reinterpret_cast<mach_header*>(bin);
LOGF("magic=%x cpu=%d cpusub=%d file=%d ncmds=%d sizecmd=%d flags=%x\n",
header->magic, header->cputype, header->cpusubtype,
header->filetype, header->ncmds, header->sizeofcmds,
header->flags);
m_is64 = false; m_is64 = false;
if (header->magic == MH_MAGIC_64) if (header->magic == MH_MAGIC_64)
m_is64 = true; m_is64 = true;
@ -262,6 +262,12 @@ MachOImpl::MachOImpl(const char* filename, int fd, size_t offset, size_t len, bo
fprintf(stderr, "Not mach-o: %s\n", filename); fprintf(stderr, "Not mach-o: %s\n", filename);
exit(1); // TODO: throw instead exit(1); // TODO: throw instead
} }
LOGF("magic=%x cpu=%d cpusub=%d file=%d ncmds=%d sizecmd=%d flags=%x\n",
header->magic, header->cputype, header->cpusubtype,
header->filetype, header->ncmds, header->sizeofcmds,
header->flags);
m_ptrsize = m_is64 ? 8 : 4; m_ptrsize = m_is64 ? 8 : 4;
if ((header->cputype & 0x00ffffff) != CPU_TYPE_X86) if ((header->cputype & 0x00ffffff) != CPU_TYPE_X86)

View File

@ -27,4 +27,13 @@
#include "env_flags.h" #include "env_flags.h"
DEFINE_bool(LOG, false, "Output bunch of logs"); // DEFINE_bool(LOG, false, "Output bunch of logs");
extern "C" bool g_loggingEnabled = false;
__attribute__((constructor)) static void initLogging()
{
const char* v = getenv("DYLD_DEBUG");
if (v && atoi(v))
g_loggingEnabled = true;
}

View File

@ -31,10 +31,15 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#ifdef __cplusplus
# include <iostream>
#endif
//#include "env_flags.h" //#include "env_flags.h"
//DECLARE_bool(LOG); //DECLARE_bool(LOG);
#define FLAGS_LOG 1 extern bool g_loggingEnabled;
#define FLAGS_LOG g_loggingEnabled
#ifdef NOLOG #ifdef NOLOG
# define LOG if (0) std::cout # define LOG if (0) std::cout

View File

@ -11,7 +11,10 @@ class Mutex
public: public:
Mutex() Mutex()
{ {
pthread_mutex_init(&m_mutex, 0); pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m_mutex, &attr);
} }
~Mutex() ~Mutex()
{ {

View File

@ -2,31 +2,29 @@
#include <stdarg.h> #include <stdarg.h>
#include <iostream> #include <iostream>
bool g_enableTrace = false;
TraceHelper::TraceHelper(const char* funcName) TraceHelper::TraceHelper(const char* funcName)
{ {
std::cerr << "TRACE(): " << funcName << ""; if (g_loggingEnabled)
std::cerr << "TRACE(): " << funcName << "";
} }
TraceHelper::~TraceHelper() TraceHelper::~TraceHelper()
{ {
std::cerr << std::endl; if (g_loggingEnabled)
} std::cerr << std::endl;
void enableTrace(bool enable)
{
g_enableTrace = enable;
} }
template<> void logPrint<std::string>(std::string value) template<> void logPrint<std::string>(std::string value)
{ {
std::cerr << '\"' << value << '\"'; if (g_loggingEnabled)
std::cerr << '\"' << value << '\"';
} }
template<> void logPrint<const char*>(const char* value) template<> void logPrint<const char*>(const char* value)
{ {
std::cerr << '\"' << value << '\"'; if (g_loggingEnabled)
std::cerr << '\"' << value << '\"';
} }
template<> void logPrint<ArgName>(ArgName value) template<> void logPrint<ArgName>(ArgName value)
{ {
std::cerr << value.name; if (g_loggingEnabled)
std::cerr << value.name;
} }

View File

@ -1,10 +1,9 @@
#ifndef DARLING_TRACE_H #ifndef DARLING_TRACE_H
#define DARLING_TRACE_H #define DARLING_TRACE_H
#include <iostream> #include <iostream>
#include "log.h"
extern bool g_enableTrace;
void logTrace(const char* funcName, ...); void logTrace(const char* funcName, ...);
void enableTrace(bool enable);
struct ArgName struct ArgName
{ {
@ -14,7 +13,8 @@ struct ArgName
template<typename T> void logPrint(T value) template<typename T> void logPrint(T value)
{ {
std::cerr << value; if (g_loggingEnabled)
std::cerr << value;
} }
template<> void logPrint<const char*>(const char* value); template<> void logPrint<const char*>(const char* value);
template<> void logPrint<std::string>(std::string value); template<> void logPrint<std::string>(std::string value);