std::string Environment::system_prefix() { if(!system_prefix_.empty()) return system_prefix_; // 1. Check if our configure prefix is overridden by the environment. const char* path = getenv("RBX_PREFIX_PATH"); if(path && verify_paths(path)) { system_prefix_ = path; return path; } // 2. Check if our configure prefix is valid. path = RBX_PREFIX_PATH; if(verify_paths(path)) { system_prefix_ = path; return path; } // 3. Check if we can derive paths from the executable name. // TODO: For Windows, substitute '/' for '\\' std::string name = executable_name(); size_t exe = name.rfind('/'); if(exe != std::string::npos) { std::string prefix = name.substr(0, exe - strlen(RBX_BIN_PATH)); if(verify_paths(prefix)) { system_prefix_ = prefix; return prefix; } } throw MissingRuntime("FATAL ERROR: unable to find Rubinius runtime directories."); }
TEST(dlfcn, dladdr) { dlerror(); // Clear any pending errors. void* self = dlopen(NULL, RTLD_NOW); ASSERT_TRUE(self != NULL); ASSERT_TRUE(dlerror() == NULL); void* sym = dlsym(self, "DlSymTestFunction"); ASSERT_TRUE(sym != NULL); // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address. void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2); Dl_info info; int rc = dladdr(addr, &info); ASSERT_NE(rc, 0); // Zero on error, non-zero on success. // Get the name of this executable. char executable_path[PATH_MAX]; rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path)); ASSERT_NE(rc, -1); executable_path[rc] = '\0'; std::string executable_name(basename(executable_path)); // The filename should be that of this executable. // Note that we don't know whether or not we have the full path, so we want an "ends_with" test. std::string dli_fname(info.dli_fname); dli_fname = basename(&dli_fname[0]); ASSERT_EQ(dli_fname, executable_name); // The symbol name should be the symbol we looked up. ASSERT_STREQ(info.dli_sname, "DlSymTestFunction"); // The address should be the exact address of the symbol. ASSERT_EQ(info.dli_saddr, sym); // Look in /proc/pid/maps to find out what address we were loaded at. // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic. void* base_address = NULL; char path[PATH_MAX]; snprintf(path, sizeof(path), "/proc/%d/maps", getpid()); char line[BUFSIZ]; FILE* fp = fopen(path, "r"); ASSERT_TRUE(fp != NULL); while (fgets(line, sizeof(line), fp) != NULL) { uintptr_t start = strtoul(line, 0, 16); line[strlen(line) - 1] = '\0'; // Chomp the '\n'. char* path = strchr(line, '/'); if (path != NULL && strcmp(executable_path, path) == 0) { base_address = reinterpret_cast<void*>(start); break; } } fclose(fp); // The base address should be the address we were loaded at. ASSERT_EQ(info.dli_fbase, base_address); ASSERT_EQ(0, dlclose(self)); }
bstring resolve_path(STATE, bstring path) { char *absolute_path = malloc(PATH_MAX); bstring h = executable_name(state->binary); struct bstrList *x = bsplit(h, '/'); bdestroy(h); bstring slash = bfromcstr("/"); x->qty--; h = bjoin(x, slash); x->qty++; bstrListDestroy(x); bconcat(h, slash); bconcat(h, path); bdestroy(slash); realpath(bdata(h), absolute_path); bstring bpath = bfromcstr(absolute_path); bdestroy(h); free(absolute_path); return bpath; }
std::string Environment::system_prefix() { if(!system_prefix_.empty()) return system_prefix_; std::string failure_reason; // 1. Check if our configure prefix is overridden by the environment. const char* path = getenv("RBX_PREFIX_PATH"); if(path && verify_paths(path, failure_reason)) { system_prefix_ = path; return path; } // 2. Check if our configure prefix is valid. path = RBX_PREFIX_PATH; if(verify_paths(path, failure_reason)) { system_prefix_ = path; return path; } // 3. Check if we can derive paths from the executable name. // TODO: For Windows, substitute '/' for '\\' std::string name = executable_name(); size_t exe = name.rfind('/'); if(exe != std::string::npos) { std::string prefix = name.substr(0, exe - strlen(RBX_BIN_PATH)); if(verify_paths(prefix, failure_reason)) { system_prefix_ = prefix; return prefix; } } std::string error("Unable to find Rubinius runtime directories: "); error.append(failure_reason); missing_core(error.c_str()); }