diff --git a/mozglue/linker/CustomElf.cpp b/mozglue/linker/CustomElf.cpp index bcd26b0fef52..158d9f9d7409 100644 --- a/mozglue/linker/CustomElf.cpp +++ b/mozglue/linker/CustomElf.cpp @@ -746,3 +746,13 @@ CustomElf::CallFini() if (fini) CallFunction(fini); } + +Mappable * +CustomElf::GetMappable() const +{ + if (!mappable) + return NULL; + if (mappable->GetKind() == Mappable::MAPPABLE_EXTRACT_FILE) + return mappable; + return ElfLoader::GetMappableFromPath(GetPath()); +} diff --git a/mozglue/linker/CustomElf.h b/mozglue/linker/CustomElf.h index 74f789b27c3f..4a29727af1ea 100644 --- a/mozglue/linker/CustomElf.h +++ b/mozglue/linker/CustomElf.h @@ -39,6 +39,10 @@ public: virtual void *GetSymbolPtr(const char *symbol) const; virtual bool Contains(void *addr) const; +protected: + virtual Mappable *GetMappable() const; + +public: /** * Shows some stats about the Mappable instance. The when argument is to be * used by the caller to give an identifier of the when the stats call is diff --git a/mozglue/linker/ElfLoader.cpp b/mozglue/linker/ElfLoader.cpp index 61f5df90181b..aad2829ea7e1 100644 --- a/mozglue/linker/ElfLoader.cpp +++ b/mozglue/linker/ElfLoader.cpp @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include #include #include @@ -130,6 +131,34 @@ __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data) return 0; } +/** + * faulty.lib public API + */ + +MFBT_API size_t +__dl_get_mappable_length(void *handle) { + if (!handle) + return 0; + return reinterpret_cast(handle)->GetMappableLength(); +} + +MFBT_API void * +__dl_mmap(void *handle, void *addr, size_t length, off_t offset) +{ + if (!handle) + return NULL; + return reinterpret_cast(handle)->MappableMMap(addr, length, + offset); +} + +MFBT_API void +__dl_munmap(void *handle, void *addr, size_t length) +{ + if (!handle) + return; + return reinterpret_cast(handle)->MappableMUnmap(addr, length); +} + namespace { /** @@ -152,6 +181,8 @@ LeafName(const char *path) LibHandle::~LibHandle() { free(path); + if (mappable->GetKind() != Mappable::MAPPABLE_EXTRACT_FILE) + delete mappable; } const char * @@ -160,6 +191,33 @@ LibHandle::GetName() const return path ? LeafName(path) : NULL; } +size_t +LibHandle::GetMappableLength() const +{ + MOZ_ASSERT(mappable != NULL, "GetMappableLength needs to be called first," + " and only once"); + mappable = GetMappable(); + if (!mappable) + return 0; + return mappable->GetLength(); +} + +void * +LibHandle::MappableMMap(void *addr, size_t length, off_t offset) const +{ + MOZ_ASSERT(mappable == NULL, "MappableMMap must be called after" + " GetMappableLength"); + return mappable->mmap(addr, length, PROT_READ, MAP_PRIVATE, offset); +} + +void +LibHandle::MappableMUnmap(void *addr, size_t length) const +{ + MOZ_ASSERT(mappable == NULL, "MappableMUnmap must be called after" + " MappableMMap and GetMappableLength"); + mappable->munmap(addr, length); +} + /** * SystemElf */ @@ -203,6 +261,26 @@ SystemElf::GetSymbolPtr(const char *symbol) const return sym; } +Mappable * +SystemElf::GetMappable() const +{ + const char *path = GetPath(); + if (!path) + return NULL; +#ifdef ANDROID + /* On Android, if we don't have the full path, try in /system/lib */ + const char *name = LeafName(path); + std::string systemPath; + if (name == path) { + systemPath = "/system/lib/"; + systemPath += path; + path = systemPath.c_str(); + } +#endif + + return MappableFile::Create(path); +} + /** * ElfLoader */ @@ -253,38 +331,7 @@ ElfLoader::Load(const char *path, int flags, LibHandle *parent) 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; - 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); + Mappable *mappable = GetMappableFromPath(path); /* Try loading with the custom linker if we have a Mappable */ if (mappable) @@ -318,6 +365,42 @@ ElfLoader::GetHandleByPtr(void *addr) return NULL; } +Mappable * +ElfLoader::GetMappableFromPath(const char *path) +{ + const char *name = LeafName(path); + Mappable *mappable = NULL; + RefPtr 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; +} + void ElfLoader::Register(LibHandle *handle) { diff --git a/mozglue/linker/ElfLoader.h b/mozglue/linker/ElfLoader.h index 528718d781af..90e742baeeda 100644 --- a/mozglue/linker/ElfLoader.h +++ b/mozglue/linker/ElfLoader.h @@ -44,6 +44,19 @@ extern "C" { typedef int (*dl_phdr_cb)(struct dl_phdr_info *, size_t, void *); int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data); + +/** + * faulty.lib public API + */ +MFBT_API size_t +__dl_get_mappable_length(void *handle); + +MFBT_API void * +__dl_mmap(void *handle, void *addr, size_t length, off_t offset); + +MFBT_API void +__dl_munmap(void *handle, void *addr, size_t length); + } /** @@ -65,6 +78,9 @@ template <> inline RefCounted::~RefCounted() } /* namespace mozilla */ +/* Forward declaration */ +class Mappable; + /** * Abstract class for loaded libraries. Libraries may be loaded through the * system linker or this linker, both cases will be derived from this class. @@ -77,7 +93,7 @@ public: * of the leaf name. */ LibHandle(const char *path) - : directRefCnt(0), path(path ? strdup(path) : NULL) { } + : directRefCnt(0), path(path ? strdup(path) : NULL), mappable(NULL) { } /** * Destructor. @@ -147,7 +163,30 @@ public: return directRefCnt; } + /** + * Returns the complete size of the file or stream behind the library + * handle. + */ + size_t GetMappableLength() const; + + /** + * Returns a memory mapping of the file or stream behind the library + * handle. + */ + void *MappableMMap(void *addr, size_t length, off_t offset) const; + + /** + * Unmaps a memory mapping of the file or stream behind the library + * handle. + */ + void MappableMUnmap(void *addr, size_t length) const; + protected: + /** + * Returns a mappable object for use by MappableMMap and related functions. + */ + virtual Mappable *GetMappable() const = 0; + /** * Returns whether the handle is a SystemElf or not. (short of a better way * to do this without RTTI) @@ -160,6 +199,9 @@ protected: private: int directRefCnt; char *path; + + /* Mappable object keeping the result of GetMappable() */ + mutable Mappable *mappable; }; /** @@ -212,6 +254,8 @@ public: virtual bool Contains(void *addr) const { return false; /* UNIMPLEMENTED */ } protected: + virtual Mappable *GetMappable() const; + /** * Returns whether the handle is a SystemElf or not. (short of a better way * to do this without RTTI) @@ -314,6 +358,14 @@ public: */ mozilla::TemporaryRef GetHandleByPtr(void *addr); + /** + * Returns a Mappable object for the 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. + */ + static Mappable *GetMappableFromPath(const char *path); + protected: /** * Registers the given handle. This method is meant to be called by diff --git a/mozglue/linker/Makefile.in b/mozglue/linker/Makefile.in index e057acc500de..7d305e3a803a 100644 --- a/mozglue/linker/Makefile.in +++ b/mozglue/linker/Makefile.in @@ -33,6 +33,8 @@ CPPSRCS += \ SeekableZStream.cpp \ $(NULL) +DEFINES += -DIMPL_MFBT + include $(topsrcdir)/config/rules.mk ifeq (arm,$(TARGET_CPU)) diff --git a/mozglue/linker/Mappable.cpp b/mozglue/linker/Mappable.cpp index 6497c4e06a5c..338c735537ac 100644 --- a/mozglue/linker/Mappable.cpp +++ b/mozglue/linker/Mappable.cpp @@ -65,6 +65,13 @@ MappableFile::finalize() fd = -1; } +size_t +MappableFile::GetLength() const +{ + struct stat st; + return fstat(fd, &st) ? 0 : st.st_size; +} + Mappable * MappableExtractFile::Create(const char *name, Zip *zip, Zip::Stream *stream) { @@ -342,6 +349,12 @@ MappableDeflate::finalize() zip = NULL; } +size_t +MappableDeflate::GetLength() const +{ + return buffer->GetLength(); +} + Mappable * MappableSeekableZStream::Create(const char *name, Zip *zip, Zip::Stream *stream) @@ -543,3 +556,9 @@ MappableSeekableZStream::stats(const char *when, const char *name) const } } } + +size_t +MappableSeekableZStream::GetLength() const +{ + return buffer->GetLength(); +} diff --git a/mozglue/linker/Mappable.h b/mozglue/linker/Mappable.h index d776d1b45d9c..dea213d22cbe 100644 --- a/mozglue/linker/Mappable.h +++ b/mozglue/linker/Mappable.h @@ -30,6 +30,15 @@ public: virtual void *mmap(const void *addr, size_t length, int prot, int flags, off_t offset) = 0; + enum Kind { + MAPPABLE_FILE, + MAPPABLE_EXTRACT_FILE, + MAPPABLE_DEFLATE, + MAPPABLE_SEEKABLE_ZSTREAM + }; + + virtual Kind GetKind() const = 0; + private: virtual void munmap(void *addr, size_t length) { ::munmap(addr, length); @@ -37,6 +46,7 @@ private: /* Limit use of Mappable::munmap to classes that keep track of the address * and size of the mapping. This allows to ignore ::munmap return value. */ friend class Mappable1stPagePtr; + friend class LibHandle; public: /** @@ -60,6 +70,12 @@ public: * the stats call is made. */ virtual void stats(const char *when, const char *name) const { } + + /** + * Returns the maximum length that can be mapped from this Mappable for + * offset = 0. + */ + virtual size_t GetLength() const = 0; }; /** @@ -78,7 +94,9 @@ public: /* Inherited from Mappable */ virtual void *mmap(const void *addr, size_t length, int prot, int flags, off_t offset); virtual void finalize(); + virtual size_t GetLength() const; + virtual Kind GetKind() const { return MAPPABLE_FILE; }; protected: MappableFile(int fd): fd(fd) { } @@ -102,6 +120,7 @@ public: */ static Mappable *Create(const char *name, Zip *zip, Zip::Stream *stream); + virtual Kind GetKind() const { return MAPPABLE_EXTRACT_FILE; }; private: MappableExtractFile(int fd, char *path) : MappableFile(fd), path(path), pid(getpid()) { } @@ -150,7 +169,9 @@ public: /* Inherited from Mappable */ virtual void *mmap(const void *addr, size_t length, int prot, int flags, off_t offset); virtual void finalize(); + virtual size_t GetLength() const; + virtual Kind GetKind() const { return MAPPABLE_DEFLATE; }; private: MappableDeflate(_MappableBuffer *buf, Zip *zip, Zip::Stream *stream); @@ -188,7 +209,9 @@ public: virtual void finalize(); virtual bool ensure(const void *addr); virtual void stats(const char *when, const char *name) const; + virtual size_t GetLength() const; + virtual Kind GetKind() const { return MAPPABLE_SEEKABLE_ZSTREAM; }; private: MappableSeekableZStream(Zip *zip);