Line data Source code
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 "shared-libraries.h"
8 :
9 : #define PATH_MAX_TOSTRING(x) #x
10 : #define PATH_MAX_STRING(x) PATH_MAX_TOSTRING(x)
11 : #include <stdlib.h>
12 : #include <stdio.h>
13 : #include <string.h>
14 : #include <limits.h>
15 : #include <unistd.h>
16 : #include <fstream>
17 : #include "platform.h"
18 : #include "shared-libraries.h"
19 : #include "mozilla/Sprintf.h"
20 : #include "mozilla/Unused.h"
21 : #include "nsDebug.h"
22 : #include "nsNativeCharsetUtils.h"
23 :
24 : #include "common/linux/file_id.h"
25 : #include <algorithm>
26 : #include <dlfcn.h>
27 : #include <features.h>
28 : #include <sys/types.h>
29 :
30 : #if defined(GP_OS_linux)
31 : # include <link.h> // dl_phdr_info
32 : #elif defined(GP_OS_android)
33 : # include "ElfLoader.h" // dl_phdr_info
34 : extern "C" MOZ_EXPORT __attribute__((weak))
35 : int dl_iterate_phdr(
36 : int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
37 : void *data);
38 : #else
39 : # error "Unexpected configuration"
40 : #endif
41 :
42 : // Get the breakpad Id for the binary file pointed by bin_name
43 0 : static std::string getId(const char *bin_name)
44 : {
45 : using namespace google_breakpad;
46 : using namespace std;
47 :
48 0 : PageAllocator allocator;
49 0 : auto_wasteful_vector<uint8_t, sizeof(MDGUID)> identifier(&allocator);
50 :
51 0 : FileID file_id(bin_name);
52 0 : if (file_id.ElfFileIdentifier(identifier)) {
53 0 : return FileID::ConvertIdentifierToUUIDString(identifier) + "0";
54 : }
55 :
56 0 : return "";
57 : }
58 :
59 : static SharedLibrary
60 0 : SharedLibraryAtPath(const char* path, unsigned long libStart,
61 : unsigned long libEnd, unsigned long offset = 0)
62 : {
63 0 : nsAutoString pathStr;
64 : mozilla::Unused <<
65 0 : NS_WARN_IF(NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(path),
66 : pathStr)));
67 :
68 0 : nsAutoString nameStr = pathStr;
69 0 : int32_t pos = nameStr.RFindChar('/');
70 0 : if (pos != kNotFound) {
71 0 : nameStr.Cut(0, pos + 1);
72 : }
73 :
74 0 : return SharedLibrary(libStart, libEnd, offset, getId(path),
75 : nameStr, pathStr, nameStr, pathStr,
76 0 : "", "");
77 : }
78 :
79 : static int
80 0 : dl_iterate_callback(struct dl_phdr_info *dl_info, size_t size, void *data)
81 : {
82 0 : SharedLibraryInfo& info = *reinterpret_cast<SharedLibraryInfo*>(data);
83 :
84 0 : if (dl_info->dlpi_phnum <= 0)
85 0 : return 0;
86 :
87 0 : unsigned long libStart = -1;
88 0 : unsigned long libEnd = 0;
89 :
90 0 : for (size_t i = 0; i < dl_info->dlpi_phnum; i++) {
91 0 : if (dl_info->dlpi_phdr[i].p_type != PT_LOAD) {
92 0 : continue;
93 : }
94 0 : unsigned long start = dl_info->dlpi_addr + dl_info->dlpi_phdr[i].p_vaddr;
95 0 : unsigned long end = start + dl_info->dlpi_phdr[i].p_memsz;
96 0 : if (start < libStart)
97 0 : libStart = start;
98 0 : if (end > libEnd)
99 0 : libEnd = end;
100 : }
101 :
102 : info.AddSharedLibrary(
103 0 : SharedLibraryAtPath(dl_info->dlpi_name, libStart, libEnd));
104 :
105 0 : return 0;
106 : }
107 :
108 0 : SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
109 : {
110 0 : SharedLibraryInfo info;
111 :
112 : #if defined(GP_OS_linux)
113 : // We need to find the name of the executable (exeName, exeNameLen) and the
114 : // address of its executable section (exeExeAddr) in the running image.
115 : char exeName[PATH_MAX];
116 0 : memset(exeName, 0, sizeof(exeName));
117 :
118 0 : ssize_t exeNameLen = readlink("/proc/self/exe", exeName, sizeof(exeName) - 1);
119 0 : if (exeNameLen == -1) {
120 : // readlink failed for whatever reason. Note this, but keep going.
121 0 : exeName[0] = '\0';
122 0 : exeNameLen = 0;
123 0 : LOG("SharedLibraryInfo::GetInfoForSelf(): readlink failed");
124 : } else {
125 : // Assert no buffer overflow.
126 0 : MOZ_RELEASE_ASSERT(exeNameLen >= 0 &&
127 : exeNameLen < static_cast<ssize_t>(sizeof(exeName)));
128 : }
129 :
130 0 : unsigned long exeExeAddr = 0;
131 : #endif
132 :
133 : #if defined(GP_OS_android)
134 : // If dl_iterate_phdr doesn't exist, we give up immediately.
135 : if (!dl_iterate_phdr) {
136 : // On ARM Android, dl_iterate_phdr is provided by the custom linker.
137 : // So if libxul was loaded by the system linker (e.g. as part of
138 : // xpcshell when running tests), it won't be available and we should
139 : // not call it.
140 : return info;
141 : }
142 : #endif
143 :
144 : // Read info from /proc/self/maps. We ignore most of it.
145 0 : pid_t pid = getpid();
146 : char path[PATH_MAX];
147 0 : SprintfLiteral(path, "/proc/%d/maps", pid);
148 0 : std::ifstream maps(path);
149 0 : std::string line;
150 0 : while (std::getline(maps, line)) {
151 : int ret;
152 : unsigned long start;
153 : unsigned long end;
154 0 : char perm[6 + 1] = "";
155 : unsigned long offset;
156 0 : char modulePath[PATH_MAX + 1] = "";
157 0 : ret = sscanf(line.c_str(),
158 : "%lx-%lx %6s %lx %*s %*x %" PATH_MAX_STRING(PATH_MAX) "s\n",
159 0 : &start, &end, perm, &offset, modulePath);
160 0 : if (!strchr(perm, 'x')) {
161 : // Ignore non executable entries
162 0 : continue;
163 : }
164 0 : if (ret != 5 && ret != 4) {
165 0 : LOG("SharedLibraryInfo::GetInfoForSelf(): "
166 : "reading /proc/self/maps failed");
167 0 : continue;
168 : }
169 :
170 : #if defined(GP_OS_linux)
171 : // Try to establish the main executable's load address.
172 0 : if (exeNameLen > 0 && strcmp(modulePath, exeName) == 0) {
173 0 : exeExeAddr = start;
174 : }
175 : #elif defined(GP_OS_android)
176 : // Use /proc/pid/maps to get the dalvik-jit section since it has no
177 : // associated phdrs.
178 : if (0 == strcmp(modulePath, "/dev/ashmem/dalvik-jit-code-cache")) {
179 : info.AddSharedLibrary(SharedLibraryAtPath(modulePath, start, end,
180 : offset));
181 : if (info.GetSize() > 10000) {
182 : LOG("SharedLibraryInfo::GetInfoForSelf(): "
183 : "implausibly large number of mappings acquired");
184 : break;
185 : }
186 : }
187 : #endif
188 : }
189 :
190 : // We collect the bulk of the library info using dl_iterate_phdr.
191 0 : dl_iterate_phdr(dl_iterate_callback, &info);
192 :
193 : #if defined(GP_OS_linux)
194 : // Make another pass over the information we just harvested from
195 : // dl_iterate_phdr. If we see a nameless object mapped at what we earlier
196 : // established to be the main executable's load address, attach the
197 : // executable's name to that entry.
198 0 : for (size_t i = 0; i < info.GetSize(); i++) {
199 0 : SharedLibrary& lib = info.GetMutableEntry(i);
200 0 : if (lib.GetStart() == exeExeAddr && lib.GetNativeDebugPath() == "") {
201 0 : lib = SharedLibraryAtPath(exeName, lib.GetStart(), lib.GetEnd(),
202 0 : lib.GetOffset());
203 :
204 : // We only expect to see one such entry.
205 0 : break;
206 : }
207 : }
208 : #endif
209 :
210 0 : return info;
211 : }
212 :
213 : void
214 3 : SharedLibraryInfo::Initialize()
215 : {
216 : /* do nothing */
217 3 : }
|