Mappable * ElfLoader::GetMappableFromPath(const char *path) { const char *name = LeafName(path); Mappable *mappable = NULL; RefPtr<Zip> zip; const char *subpath; if ((subpath = strchr(path, '!'))) { char *zip_path = strndup(path, subpath - path); while (*(++subpath) == '/') { } zip = ZipCollection::GetZip(zip_path); Zip::Stream s; if (zip && zip->GetStream(subpath, &s)) { /* When the MOZ_LINKER_EXTRACT environment variable is set to "1", * compressed libraries are going to be (temporarily) extracted as * files, in the directory pointed by the MOZ_LINKER_CACHE * environment variable. */ const char *extract = getenv("MOZ_LINKER_EXTRACT"); if (extract && !strncmp(extract, "1", 2 /* Including '\0' */)) mappable = MappableExtractFile::Create(name, zip, &s); if (!mappable) { if (s.GetType() == Zip::Stream::DEFLATE) { mappable = MappableDeflate::Create(name, zip, &s); } else if (s.GetType() == Zip::Stream::STORE) { mappable = MappableSeekableZStream::Create(name, zip, &s); } } } } /* If we couldn't load above, try with a MappableFile */ if (!mappable && !zip) mappable = MappableFile::Create(path); return mappable; }
jobject MOZ_JNICALL Java_org_mozilla_gecko_mozglue_NativeZip__1getInputStream(JNIEnv *jenv, jobject jzip, jlong obj, jstring path) { Zip *zip = (Zip *)obj; const char* str; str = jenv->GetStringUTFChars(path, nullptr); Zip::Stream stream; bool res = zip->GetStream(str, &stream); jenv->ReleaseStringUTFChars(path, str); if (!res) { return nullptr; } jobject buf = jenv->NewDirectByteBuffer(const_cast<void *>(stream.GetBuffer()), stream.GetSize()); if (!buf) { JNI_Throw(jenv, "java/lang/RuntimeException", "Failed to create ByteBuffer"); return nullptr; } jclass nativeZip = jenv->GetObjectClass(jzip); jmethodID method = jenv->GetMethodID(nativeZip, "createInputStream", "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;"); // Since this function is only expected to be called from Java, it is safe // to skip exception checking for the method call below, as long as no // other Native -> Java call doesn't happen before returning to Java. return jenv->CallObjectMethod(jzip, method, buf, (jint) stream.GetType()); }
static void * extractBuf(const char * path, Zip *zip) { Zip::Stream s; if (!zip->GetStream(path, &s)) return NULL; void * buf = malloc(s.GetUncompressedSize()); if (buf == (void *)-1) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't alloc decompression buffer for %s", path); return NULL; } if (s.GetType() == Zip::Stream::DEFLATE) extractLib(s, buf); else memcpy(buf, s.GetBuffer(), s.GetUncompressedSize()); return buf; }
static void * extractBuf(const char * path, Zip *zip) { Zip::Stream s; if (!zip->GetStream(path, &s)) return NULL; // allocate space for a trailing null byte void * buf = malloc(s.GetUncompressedSize() + 1); if (buf == (void *)-1) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't alloc decompression buffer for %s", path); return NULL; } if (s.GetType() == Zip::Stream::DEFLATE) extractLib(s, buf); else memcpy(buf, s.GetBuffer(), s.GetUncompressedSize()); // null terminate it ((unsigned char*) buf)[s.GetUncompressedSize()] = 0; return buf; }
static void * mozload(const char * path, Zip *zip) { #ifdef DEBUG struct timeval t0, t1; gettimeofday(&t0, 0); #endif void *handle; Zip::Stream s; if (!zip->GetStream(path, &s)) return NULL; if (extractLibs) { char fullpath[PATH_MAX]; snprintf(fullpath, PATH_MAX, "%s/%s", getenv("MOZ_LINKER_CACHE"), path); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "resolved %s to %s", path, fullpath); extractFile(fullpath, s); handle = __wrap_dlopen(fullpath, RTLD_LAZY); if (!handle) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't load %s because %s", fullpath, __wrap_dlerror()); #ifdef DEBUG gettimeofday(&t1, 0); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: spent %d", path, (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)); #endif return handle; } int fd; void * buf = NULL; uint32_t lib_size = s.GetUncompressedSize(); int cache_fd = 0; if (s.GetType() == Zip::Stream::DEFLATE) { cache_fd = lookupLibCacheFd(path); fd = cache_fd; if (fd < 0) fd = createAshmem(lib_size, path); #ifdef DEBUG else __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loading %s from cache", path); #endif if (fd < 0) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't open " ASHMEM_NAME_DEF ", Error %d, %s, bailing out", errno, strerror(errno)); return NULL; } buf = mmap(NULL, lib_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buf == (void *)-1) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't mmap decompression buffer"); close(fd); return NULL; } if (cache_fd < 0) { extractLib(s, buf); #ifdef ANDROID_ARM_LINKER /* We just extracted data that is going to be executed in the future. * We thus need to ensure Instruction and Data cache coherency. */ cacheflush((unsigned) buf, (unsigned) buf + s.GetUncompressedSize(), 0); #endif addLibCacheFd(path, fd, lib_size, buf); } // preload libxul, to avoid slowly demand-paging it if (!strcmp(path, "libxul.so")) madvise(buf, s.GetUncompressedSize(), MADV_WILLNEED); } #ifdef DEBUG __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loading %s with len %d (0x%08x)", path, lib_size, lib_size); #endif handle = moz_mapped_dlopen(path, RTLD_LAZY, fd, buf, lib_size, 0); if (!handle) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't load %s because %s", path, __wrap_dlerror()); if (buf) munmap(buf, lib_size); #ifdef DEBUG gettimeofday(&t1, 0); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: spent %d", path, (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)); #endif return handle; }
static void extractFile(const char * path, Zip::Stream &s) { uint32_t size = s.GetUncompressedSize(); struct stat status; if (!stat(path, &status) && status.st_size == size && apk_mtime < status.st_mtime) return; int fd = open(path, O_CREAT | O_NOATIME | O_TRUNC | O_RDWR, S_IRWXU); if (fd == -1) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't open %s to decompress library", path); return; } if (ftruncate(fd, size) == -1) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't ftruncate %s to decompress library", path); close(fd); return; } void * buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buf == (void *)-1) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't mmap decompression buffer"); close(fd); return; } z_stream strm = { next_in: (Bytef *)s.GetBuffer(), avail_in: s.GetSize(), total_in: 0, next_out: (Bytef *)buf, avail_out: size, total_out: 0 }; int ret; ret = inflateInit2(&strm, -MAX_WBITS); if (ret != Z_OK) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflateInit failed: %s", strm.msg); if (inflate(&strm, Z_FINISH) != Z_STREAM_END) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflate failed: %s", strm.msg); if (strm.total_out != size) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "extracted %d, expected %d!", strm.total_out, size); ret = inflateEnd(&strm); if (ret != Z_OK) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflateEnd failed: %s", strm.msg); close(fd); #ifdef ANDROID_ARM_LINKER /* We just extracted data that is going to be executed in the future. * We thus need to ensure Instruction and Data cache coherency. */ cacheflush((unsigned) buf, (unsigned) buf + size, 0); #endif munmap(buf, size); }
TemporaryRef<LibHandle> ElfLoader::Load(const char *path, int flags, LibHandle *parent) { RefPtr<LibHandle> handle; /* Handle dlopen(NULL) directly. */ if (!path) { handle = SystemElf::Load(NULL, flags); return handle; } /* TODO: Handle relative paths correctly */ const char *name = LeafName(path); /* Search the list of handles we already have for a match. When the given * path is not absolute, compare file names, otherwise compare full paths. */ if (name == path) { for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it) if ((*it)->GetName() && (strcmp((*it)->GetName(), name) == 0)) return *it; } else { for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it) if ((*it)->GetPath() && (strcmp((*it)->GetPath(), path) == 0)) return *it; } char *abs_path = NULL; const char *requested_path = path; /* When the path is not absolute and the library is being loaded for * another, first try to load the library from the directory containing * that parent library. */ if ((name == path) && parent) { const char *parentPath = parent->GetPath(); abs_path = new char[strlen(parentPath) + strlen(path)]; strcpy(abs_path, parentPath); char *slash = strrchr(abs_path, '/'); strcpy(slash + 1, path); path = abs_path; } /* Create a mappable object for the given path. Paths in the form * /foo/bar/baz/archive!/directory/lib.so * try to load the directory/lib.so in /foo/bar/baz/archive, provided * that file is a Zip archive. */ Mappable *mappable = NULL; RefPtr<Zip> zip; const char *subpath; if ((subpath = strchr(path, '!'))) { char *zip_path = strndup(path, subpath - path); while (*(++subpath) == '/') { } zip = zips.GetZip(zip_path); Zip::Stream s; if (zip && zip->GetStream(subpath, &s)) { /* When the MOZ_LINKER_EXTRACT environment variable is set to "1", * compressed libraries are going to be (temporarily) extracted as * files, in the directory pointed by the MOZ_LINKER_CACHE * environment variable. */ const char *extract = getenv("MOZ_LINKER_EXTRACT"); if (extract && !strncmp(extract, "1", 2 /* Including '\0' */)) mappable = MappableExtractFile::Create(name, zip, &s); if (!mappable) { if (s.GetType() == Zip::Stream::DEFLATE) { mappable = MappableDeflate::Create(name, zip, &s); } else if (s.GetType() == Zip::Stream::STORE) { mappable = MappableSeekableZStream::Create(name, zip, &s); } } } } /* If we couldn't load above, try with a MappableFile */ if (!mappable && !zip) mappable = MappableFile::Create(path); /* Try loading with the custom linker if we have a Mappable */ if (mappable) handle = CustomElf::Load(mappable, path, flags); /* Try loading with the system linker if everything above failed */ if (!handle) handle = SystemElf::Load(path, flags); /* If we didn't have an absolute path and haven't been able to load * a library yet, try in the system search path */ if (!handle && abs_path) handle = SystemElf::Load(name, flags); delete [] abs_path; debug("ElfLoader::Load(\"%s\", 0x%x, %p [\"%s\"]) = %p", requested_path, flags, reinterpret_cast<void *>(parent), parent ? parent->GetPath() : "", static_cast<void *>(handle)); return handle; }