Bug 802240 - Expose an API to mmap the underlying file for a library loaded by faulty.lib. r=nfroyd

This commit is contained in:
Mike Hommey 2013-04-12 10:23:12 +02:00
Родитель 112f6bd92e
Коммит 1cb6364a2e
7 изменённых файлов: 226 добавлений и 33 удалений

Просмотреть файл

@ -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);