/src/mozilla-central/tools/profiler/lul/AutoObjectMapper.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include <sys/mman.h> |
8 | | #include <unistd.h> |
9 | | #include <sys/types.h> |
10 | | #include <sys/stat.h> |
11 | | #include <fcntl.h> |
12 | | |
13 | | #include "mozilla/Assertions.h" |
14 | | #include "mozilla/Sprintf.h" |
15 | | |
16 | | #include "PlatformMacros.h" |
17 | | #include "AutoObjectMapper.h" |
18 | | |
19 | | #if defined(GP_OS_android) |
20 | | # include <dlfcn.h> |
21 | | # include "mozilla/Types.h" |
22 | | // FIXME move these out of mozglue/linker/ElfLoader.h into their |
23 | | // own header, so as to avoid conflicts arising from two definitions |
24 | | // of Array |
25 | | extern "C" { |
26 | | MFBT_API size_t |
27 | | __dl_get_mappable_length(void *handle); |
28 | | MFBT_API void * |
29 | | __dl_mmap(void *handle, void *addr, size_t length, off_t offset); |
30 | | MFBT_API void |
31 | | __dl_munmap(void *handle, void *addr, size_t length); |
32 | | } |
33 | | // The following are for get_installation_lib_dir() |
34 | | # include "nsString.h" |
35 | | # include "nsDirectoryServiceUtils.h" |
36 | | # include "nsDirectoryServiceDefs.h" |
37 | | #endif |
38 | | |
39 | | |
40 | | // A helper function for creating failure error messages in |
41 | | // AutoObjectMapper*::Map. |
42 | | static void |
43 | | failedToMessage(void(*aLog)(const char*), |
44 | | const char* aHowFailed, std::string aFileName) |
45 | 0 | { |
46 | 0 | char buf[300]; |
47 | 0 | SprintfLiteral(buf, "AutoObjectMapper::Map: Failed to %s \'%s\'", |
48 | 0 | aHowFailed, aFileName.c_str()); |
49 | 0 | buf[sizeof(buf)-1] = 0; |
50 | 0 | aLog(buf); |
51 | 0 | } |
52 | | |
53 | | |
54 | | AutoObjectMapperPOSIX::AutoObjectMapperPOSIX(void(*aLog)(const char*)) |
55 | | : mImage(nullptr) |
56 | | , mSize(0) |
57 | | , mLog(aLog) |
58 | | , mIsMapped(false) |
59 | 0 | {} |
60 | | |
61 | 0 | AutoObjectMapperPOSIX::~AutoObjectMapperPOSIX() { |
62 | 0 | if (!mIsMapped) { |
63 | 0 | // There's nothing to do. |
64 | 0 | MOZ_ASSERT(!mImage); |
65 | 0 | MOZ_ASSERT(mSize == 0); |
66 | 0 | return; |
67 | 0 | } |
68 | 0 | MOZ_ASSERT(mSize > 0); |
69 | 0 | // The following assertion doesn't necessarily have to be true, |
70 | 0 | // but we assume (reasonably enough) that no mmap facility would |
71 | 0 | // be crazy enough to map anything at page zero. |
72 | 0 | MOZ_ASSERT(mImage); |
73 | 0 | munmap(mImage, mSize); |
74 | 0 | } |
75 | | |
76 | | bool AutoObjectMapperPOSIX::Map(/*OUT*/void** start, /*OUT*/size_t* length, |
77 | | std::string fileName) |
78 | 0 | { |
79 | 0 | MOZ_ASSERT(!mIsMapped); |
80 | 0 |
|
81 | 0 | int fd = open(fileName.c_str(), O_RDONLY); |
82 | 0 | if (fd == -1) { |
83 | 0 | failedToMessage(mLog, "open", fileName); |
84 | 0 | return false; |
85 | 0 | } |
86 | 0 | |
87 | 0 | struct stat st; |
88 | 0 | int err = fstat(fd, &st); |
89 | 0 | size_t sz = (err == 0) ? st.st_size : 0; |
90 | 0 | if (err != 0 || sz == 0) { |
91 | 0 | failedToMessage(mLog, "fstat", fileName); |
92 | 0 | close(fd); |
93 | 0 | return false; |
94 | 0 | } |
95 | 0 | |
96 | 0 | void* image = mmap(nullptr, sz, PROT_READ, MAP_SHARED, fd, 0); |
97 | 0 | if (image == MAP_FAILED) { |
98 | 0 | failedToMessage(mLog, "mmap", fileName); |
99 | 0 | close(fd); |
100 | 0 | return false; |
101 | 0 | } |
102 | 0 | |
103 | 0 | close(fd); |
104 | 0 | mIsMapped = true; |
105 | 0 | mImage = *start = image; |
106 | 0 | mSize = *length = sz; |
107 | 0 | return true; |
108 | 0 | } |
109 | | |
110 | | |
111 | | #if defined(GP_OS_android) |
112 | | // A helper function for AutoObjectMapperFaultyLib::Map. Finds out |
113 | | // where the installation's lib directory is, since we'll have to look |
114 | | // in there to get hold of libmozglue.so. Returned C string is heap |
115 | | // allocated and the caller must deallocate it. |
116 | | static char* |
117 | | get_installation_lib_dir() |
118 | | { |
119 | | nsCOMPtr<nsIProperties> |
120 | | directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); |
121 | | if (!directoryService) { |
122 | | return nullptr; |
123 | | } |
124 | | nsCOMPtr<nsIFile> greDir; |
125 | | nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), |
126 | | getter_AddRefs(greDir)); |
127 | | if (NS_FAILED(rv)) return nullptr; |
128 | | nsCString path; |
129 | | rv = greDir->GetNativePath(path); |
130 | | if (NS_FAILED(rv)) { |
131 | | return nullptr; |
132 | | } |
133 | | return strdup(path.get()); |
134 | | } |
135 | | |
136 | | AutoObjectMapperFaultyLib::AutoObjectMapperFaultyLib(void(*aLog)(const char*)) |
137 | | : AutoObjectMapperPOSIX(aLog) |
138 | | , mHdl(nullptr) |
139 | | {} |
140 | | |
141 | | AutoObjectMapperFaultyLib::~AutoObjectMapperFaultyLib() { |
142 | | if (mHdl) { |
143 | | // We've got an object mapped by faulty.lib. Unmap it via faulty.lib. |
144 | | MOZ_ASSERT(mSize > 0); |
145 | | // Assert on the basis that no valid mapping would start at page zero. |
146 | | MOZ_ASSERT(mImage); |
147 | | __dl_munmap(mHdl, mImage, mSize); |
148 | | dlclose(mHdl); |
149 | | // Stop assertions in ~AutoObjectMapperPOSIX from failing. |
150 | | mImage = nullptr; |
151 | | mSize = 0; |
152 | | } |
153 | | // At this point the parent class destructor, ~AutoObjectMapperPOSIX, |
154 | | // gets called. If that has something mapped in the normal way, it |
155 | | // will unmap it in the normal way. Unfortunately there's no |
156 | | // obvious way to enforce the requirement that the object is mapped |
157 | | // either by faulty.lib or by the parent class, but not by both. |
158 | | } |
159 | | |
160 | | bool AutoObjectMapperFaultyLib::Map(/*OUT*/void** start, /*OUT*/size_t* length, |
161 | | std::string fileName) |
162 | | { |
163 | | MOZ_ASSERT(!mHdl); |
164 | | |
165 | | if (fileName == "libmozglue.so") { |
166 | | |
167 | | // Do (2) in the comment above. |
168 | | char* libdir = get_installation_lib_dir(); |
169 | | if (libdir) { |
170 | | fileName = std::string(libdir) + "/lib/" + fileName; |
171 | | free(libdir); |
172 | | } |
173 | | // Hand the problem off to the standard mapper. |
174 | | return AutoObjectMapperPOSIX::Map(start, length, fileName); |
175 | | |
176 | | } else { |
177 | | |
178 | | // Do cases (1) and (3) in the comment above. We have to |
179 | | // grapple with faulty.lib directly. |
180 | | void* hdl = dlopen(fileName.c_str(), RTLD_GLOBAL | RTLD_LAZY); |
181 | | if (!hdl) { |
182 | | failedToMessage(mLog, "get handle for ELF file", fileName); |
183 | | return false; |
184 | | } |
185 | | |
186 | | size_t sz = __dl_get_mappable_length(hdl); |
187 | | if (sz == 0) { |
188 | | dlclose(hdl); |
189 | | failedToMessage(mLog, "get size for ELF file", fileName); |
190 | | return false; |
191 | | } |
192 | | |
193 | | void* image = __dl_mmap(hdl, nullptr, sz, 0); |
194 | | if (image == MAP_FAILED) { |
195 | | dlclose(hdl); |
196 | | failedToMessage(mLog, "mmap ELF file", fileName); |
197 | | return false; |
198 | | } |
199 | | |
200 | | mHdl = hdl; |
201 | | mImage = *start = image; |
202 | | mSize = *length = sz; |
203 | | return true; |
204 | | } |
205 | | } |
206 | | |
207 | | #endif // defined(GP_OS_android) |