mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-30 01:59:29 +00:00
Bug 802240 - Expose an API to mmap the underlying file for a library loaded by faulty.lib. r=nfroyd
This commit is contained in:
parent
112f6bd92e
commit
1cb6364a2e
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 <string>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
@ -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<LibHandle *>(handle)->GetMappableLength();
|
||||
}
|
||||
|
||||
MFBT_API void *
|
||||
__dl_mmap(void *handle, void *addr, size_t length, off_t offset)
|
||||
{
|
||||
if (!handle)
|
||||
return NULL;
|
||||
return reinterpret_cast<LibHandle *>(handle)->MappableMMap(addr, length,
|
||||
offset);
|
||||
}
|
||||
|
||||
MFBT_API void
|
||||
__dl_munmap(void *handle, void *addr, size_t length)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
return reinterpret_cast<LibHandle *>(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> 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> 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)
|
||||
{
|
||||
|
@ -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<LibHandle>::~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<LibHandle> 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
|
||||
|
@ -33,6 +33,8 @@ CPPSRCS += \
|
||||
SeekableZStream.cpp \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DIMPL_MFBT
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifeq (arm,$(TARGET_CPU))
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user