1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/profiler/AutoObjectMapper.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,207 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include <sys/mman.h> 1.11 +#include <unistd.h> 1.12 +#include <sys/types.h> 1.13 +#include <sys/stat.h> 1.14 +#include <fcntl.h> 1.15 + 1.16 +#include "mozilla/Assertions.h" 1.17 +#include "mozilla/NullPtr.h" 1.18 + 1.19 +#include "PlatformMacros.h" 1.20 +#include "AutoObjectMapper.h" 1.21 + 1.22 +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) 1.23 +# include <dlfcn.h> 1.24 +# include "mozilla/Types.h" 1.25 + // FIXME move these out of mozglue/linker/ElfLoader.h into their 1.26 + // own header, so as to avoid conflicts arising from two definitions 1.27 + // of Array 1.28 + extern "C" { 1.29 + MFBT_API size_t 1.30 + __dl_get_mappable_length(void *handle); 1.31 + MFBT_API void * 1.32 + __dl_mmap(void *handle, void *addr, size_t length, off_t offset); 1.33 + MFBT_API void 1.34 + __dl_munmap(void *handle, void *addr, size_t length); 1.35 + } 1.36 + // The following are for get_installation_lib_dir() 1.37 +# include "nsString.h" 1.38 +# include "nsDirectoryServiceUtils.h" 1.39 +# include "nsDirectoryServiceDefs.h" 1.40 +#endif 1.41 + 1.42 + 1.43 +// A helper function for creating failure error messages in 1.44 +// AutoObjectMapper*::Map. 1.45 +static void 1.46 +failedToMessage(void(*aLog)(const char*), 1.47 + const char* aHowFailed, std::string aFileName) 1.48 +{ 1.49 + char buf[300]; 1.50 + snprintf(buf, sizeof(buf), "AutoObjectMapper::Map: Failed to %s \'%s\'", 1.51 + aHowFailed, aFileName.c_str()); 1.52 + buf[sizeof(buf)-1] = 0; 1.53 + aLog(buf); 1.54 +} 1.55 + 1.56 + 1.57 +AutoObjectMapperPOSIX::AutoObjectMapperPOSIX(void(*aLog)(const char*)) 1.58 + : mImage(nullptr) 1.59 + , mSize(0) 1.60 + , mLog(aLog) 1.61 + , mIsMapped(false) 1.62 +{} 1.63 + 1.64 +AutoObjectMapperPOSIX::~AutoObjectMapperPOSIX() { 1.65 + if (!mIsMapped) { 1.66 + // There's nothing to do. 1.67 + MOZ_ASSERT(!mImage); 1.68 + MOZ_ASSERT(mSize == 0); 1.69 + return; 1.70 + } 1.71 + MOZ_ASSERT(mSize > 0); 1.72 + // The following assertion doesn't necessarily have to be true, 1.73 + // but we assume (reasonably enough) that no mmap facility would 1.74 + // be crazy enough to map anything at page zero. 1.75 + MOZ_ASSERT(mImage); 1.76 + munmap(mImage, mSize); 1.77 +} 1.78 + 1.79 +bool AutoObjectMapperPOSIX::Map(/*OUT*/void** start, /*OUT*/size_t* length, 1.80 + std::string fileName) 1.81 +{ 1.82 + MOZ_ASSERT(!mIsMapped); 1.83 + 1.84 + int fd = open(fileName.c_str(), O_RDONLY); 1.85 + if (fd == -1) { 1.86 + failedToMessage(mLog, "open", fileName); 1.87 + return false; 1.88 + } 1.89 + 1.90 + struct stat st; 1.91 + int err = fstat(fd, &st); 1.92 + size_t sz = (err == 0) ? st.st_size : 0; 1.93 + if (err != 0 || sz == 0) { 1.94 + failedToMessage(mLog, "fstat", fileName); 1.95 + close(fd); 1.96 + return false; 1.97 + } 1.98 + 1.99 + void* image = mmap(nullptr, sz, PROT_READ, MAP_SHARED, fd, 0); 1.100 + if (image == MAP_FAILED) { 1.101 + failedToMessage(mLog, "mmap", fileName); 1.102 + close(fd); 1.103 + return false; 1.104 + } 1.105 + 1.106 + close(fd); 1.107 + mIsMapped = true; 1.108 + mImage = *start = image; 1.109 + mSize = *length = sz; 1.110 + return true; 1.111 +} 1.112 + 1.113 + 1.114 +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) 1.115 +// A helper function for AutoObjectMapperFaultyLib::Map. Finds out 1.116 +// where the installation's lib directory is, since we'll have to look 1.117 +// in there to get hold of libmozglue.so. Returned C string is heap 1.118 +// allocated and the caller must deallocate it. 1.119 +static char* 1.120 +get_installation_lib_dir() 1.121 +{ 1.122 + nsCOMPtr<nsIProperties> 1.123 + directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); 1.124 + if (!directoryService) { 1.125 + return nullptr; 1.126 + } 1.127 + nsCOMPtr<nsIFile> greDir; 1.128 + nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), 1.129 + getter_AddRefs(greDir)); 1.130 + if (NS_FAILED(rv)) return nullptr; 1.131 + nsCString path; 1.132 + rv = greDir->GetNativePath(path); 1.133 + if (NS_FAILED(rv)) { 1.134 + return nullptr; 1.135 + } 1.136 + return strdup(path.get()); 1.137 +} 1.138 + 1.139 +AutoObjectMapperFaultyLib::AutoObjectMapperFaultyLib(void(*aLog)(const char*)) 1.140 + : AutoObjectMapperPOSIX(aLog) 1.141 + , mHdl(nullptr) 1.142 +{} 1.143 + 1.144 +AutoObjectMapperFaultyLib::~AutoObjectMapperFaultyLib() { 1.145 + if (mHdl) { 1.146 + // We've got an object mapped by faulty.lib. Unmap it via faulty.lib. 1.147 + MOZ_ASSERT(mSize > 0); 1.148 + // Assert on the basis that no valid mapping would start at page zero. 1.149 + MOZ_ASSERT(mImage); 1.150 + __dl_munmap(mHdl, mImage, mSize); 1.151 + dlclose(mHdl); 1.152 + // Stop assertions in ~AutoObjectMapperPOSIX from failing. 1.153 + mImage = nullptr; 1.154 + mSize = 0; 1.155 + } 1.156 + // At this point the parent class destructor, ~AutoObjectMapperPOSIX, 1.157 + // gets called. If that has something mapped in the normal way, it 1.158 + // will unmap it in the normal way. Unfortunately there's no 1.159 + // obvious way to enforce the requirement that the object is mapped 1.160 + // either by faulty.lib or by the parent class, but not by both. 1.161 +} 1.162 + 1.163 +bool AutoObjectMapperFaultyLib::Map(/*OUT*/void** start, /*OUT*/size_t* length, 1.164 + std::string fileName) 1.165 +{ 1.166 + MOZ_ASSERT(!mHdl); 1.167 + 1.168 + if (fileName == "libmozglue.so") { 1.169 + 1.170 + // Do (2) in the comment above. 1.171 + char* libdir = get_installation_lib_dir(); 1.172 + if (libdir) { 1.173 + fileName = std::string(libdir) + "/lib/" + fileName; 1.174 + free(libdir); 1.175 + } 1.176 + // Hand the problem off to the standard mapper. 1.177 + return AutoObjectMapperPOSIX::Map(start, length, fileName); 1.178 + 1.179 + } else { 1.180 + 1.181 + // Do cases (1) and (3) in the comment above. We have to 1.182 + // grapple with faulty.lib directly. 1.183 + void* hdl = dlopen(fileName.c_str(), RTLD_GLOBAL | RTLD_LAZY); 1.184 + if (!hdl) { 1.185 + failedToMessage(mLog, "get handle for ELF file", fileName); 1.186 + return false; 1.187 + } 1.188 + 1.189 + size_t sz = __dl_get_mappable_length(hdl); 1.190 + if (sz == 0) { 1.191 + dlclose(hdl); 1.192 + failedToMessage(mLog, "get size for ELF file", fileName); 1.193 + return false; 1.194 + } 1.195 + 1.196 + void* image = __dl_mmap(hdl, nullptr, sz, 0); 1.197 + if (image == MAP_FAILED) { 1.198 + dlclose(hdl); 1.199 + failedToMessage(mLog, "mmap ELF file", fileName); 1.200 + return false; 1.201 + } 1.202 + 1.203 + mHdl = hdl; 1.204 + mImage = *start = image; 1.205 + mSize = *length = sz; 1.206 + return true; 1.207 + } 1.208 +} 1.209 + 1.210 +#endif // defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)