mozglue/linker/ElfLoader.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include <string>
michael@0 6 #include <cstring>
michael@0 7 #include <cstdlib>
michael@0 8 #include <cstdio>
michael@0 9 #include <dlfcn.h>
michael@0 10 #include <unistd.h>
michael@0 11 #include <algorithm>
michael@0 12 #include <fcntl.h>
michael@0 13 #include "ElfLoader.h"
michael@0 14 #include "CustomElf.h"
michael@0 15 #include "Mappable.h"
michael@0 16 #include "Logging.h"
michael@0 17 #include <inttypes.h>
michael@0 18
michael@0 19 #if defined(ANDROID)
michael@0 20 #include <sys/syscall.h>
michael@0 21
michael@0 22 #include <android/api-level.h>
michael@0 23 #if __ANDROID_API__ < 8
michael@0 24 /* Android API < 8 doesn't provide sigaltstack */
michael@0 25
michael@0 26 extern "C" {
michael@0 27
michael@0 28 inline int sigaltstack(const stack_t *ss, stack_t *oss) {
michael@0 29 return syscall(__NR_sigaltstack, ss, oss);
michael@0 30 }
michael@0 31
michael@0 32 } /* extern "C" */
michael@0 33 #endif /* __ANDROID_API__ */
michael@0 34 #endif /* ANDROID */
michael@0 35
michael@0 36 #ifdef __ARM_EABI__
michael@0 37 extern "C" const void *
michael@0 38 __gnu_Unwind_Find_exidx(void *pc, int *pcount) __attribute__((weak));
michael@0 39 #endif
michael@0 40
michael@0 41 using namespace mozilla;
michael@0 42
michael@0 43 /**
michael@0 44 * dlfcn.h replacements functions
michael@0 45 */
michael@0 46
michael@0 47 void *
michael@0 48 __wrap_dlopen(const char *path, int flags)
michael@0 49 {
michael@0 50 RefPtr<LibHandle> handle = ElfLoader::Singleton.Load(path, flags);
michael@0 51 if (handle)
michael@0 52 handle->AddDirectRef();
michael@0 53 return handle;
michael@0 54 }
michael@0 55
michael@0 56 const char *
michael@0 57 __wrap_dlerror(void)
michael@0 58 {
michael@0 59 const char *error = ElfLoader::Singleton.lastError;
michael@0 60 ElfLoader::Singleton.lastError = nullptr;
michael@0 61 return error;
michael@0 62 }
michael@0 63
michael@0 64 void *
michael@0 65 __wrap_dlsym(void *handle, const char *symbol)
michael@0 66 {
michael@0 67 if (!handle) {
michael@0 68 ElfLoader::Singleton.lastError = "dlsym(NULL, sym) unsupported";
michael@0 69 return nullptr;
michael@0 70 }
michael@0 71 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
michael@0 72 LibHandle *h = reinterpret_cast<LibHandle *>(handle);
michael@0 73 return h->GetSymbolPtr(symbol);
michael@0 74 }
michael@0 75 return dlsym(handle, symbol);
michael@0 76 }
michael@0 77
michael@0 78 int
michael@0 79 __wrap_dlclose(void *handle)
michael@0 80 {
michael@0 81 if (!handle) {
michael@0 82 ElfLoader::Singleton.lastError = "No handle given to dlclose()";
michael@0 83 return -1;
michael@0 84 }
michael@0 85 reinterpret_cast<LibHandle *>(handle)->ReleaseDirectRef();
michael@0 86 return 0;
michael@0 87 }
michael@0 88
michael@0 89 int
michael@0 90 __wrap_dladdr(void *addr, Dl_info *info)
michael@0 91 {
michael@0 92 RefPtr<LibHandle> handle = ElfLoader::Singleton.GetHandleByPtr(addr);
michael@0 93 if (!handle)
michael@0 94 return 0;
michael@0 95 info->dli_fname = handle->GetPath();
michael@0 96 return 1;
michael@0 97 }
michael@0 98
michael@0 99 int
michael@0 100 __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data)
michael@0 101 {
michael@0 102 if (!ElfLoader::Singleton.dbg)
michael@0 103 return -1;
michael@0 104
michael@0 105 for (ElfLoader::DebuggerHelper::iterator it = ElfLoader::Singleton.dbg.begin();
michael@0 106 it < ElfLoader::Singleton.dbg.end(); ++it) {
michael@0 107 dl_phdr_info info;
michael@0 108 info.dlpi_addr = reinterpret_cast<Elf::Addr>(it->l_addr);
michael@0 109 info.dlpi_name = it->l_name;
michael@0 110 info.dlpi_phdr = nullptr;
michael@0 111 info.dlpi_phnum = 0;
michael@0 112
michael@0 113 // Assuming l_addr points to Elf headers (in most cases, this is true),
michael@0 114 // get the Phdr location from there.
michael@0 115 uint8_t mapped;
michael@0 116 // If the page is not mapped, mincore returns an error.
michael@0 117 if (!mincore(const_cast<void*>(it->l_addr), PageSize(), &mapped)) {
michael@0 118 const Elf::Ehdr *ehdr = Elf::Ehdr::validate(it->l_addr);
michael@0 119 if (ehdr) {
michael@0 120 info.dlpi_phdr = reinterpret_cast<const Elf::Phdr *>(
michael@0 121 reinterpret_cast<const char *>(ehdr) + ehdr->e_phoff);
michael@0 122 info.dlpi_phnum = ehdr->e_phnum;
michael@0 123 }
michael@0 124 }
michael@0 125
michael@0 126 int ret = callback(&info, sizeof(dl_phdr_info), data);
michael@0 127 if (ret)
michael@0 128 return ret;
michael@0 129 }
michael@0 130 return 0;
michael@0 131 }
michael@0 132
michael@0 133 #ifdef __ARM_EABI__
michael@0 134 const void *
michael@0 135 __wrap___gnu_Unwind_Find_exidx(void *pc, int *pcount)
michael@0 136 {
michael@0 137 RefPtr<LibHandle> handle = ElfLoader::Singleton.GetHandleByPtr(pc);
michael@0 138 if (handle)
michael@0 139 return handle->FindExidx(pcount);
michael@0 140 if (__gnu_Unwind_Find_exidx)
michael@0 141 return __gnu_Unwind_Find_exidx(pc, pcount);
michael@0 142 *pcount = 0;
michael@0 143 return nullptr;
michael@0 144 }
michael@0 145 #endif
michael@0 146
michael@0 147 /**
michael@0 148 * faulty.lib public API
michael@0 149 */
michael@0 150
michael@0 151 MFBT_API size_t
michael@0 152 __dl_get_mappable_length(void *handle) {
michael@0 153 if (!handle)
michael@0 154 return 0;
michael@0 155 return reinterpret_cast<LibHandle *>(handle)->GetMappableLength();
michael@0 156 }
michael@0 157
michael@0 158 MFBT_API void *
michael@0 159 __dl_mmap(void *handle, void *addr, size_t length, off_t offset)
michael@0 160 {
michael@0 161 if (!handle)
michael@0 162 return nullptr;
michael@0 163 return reinterpret_cast<LibHandle *>(handle)->MappableMMap(addr, length,
michael@0 164 offset);
michael@0 165 }
michael@0 166
michael@0 167 MFBT_API void
michael@0 168 __dl_munmap(void *handle, void *addr, size_t length)
michael@0 169 {
michael@0 170 if (!handle)
michael@0 171 return;
michael@0 172 return reinterpret_cast<LibHandle *>(handle)->MappableMUnmap(addr, length);
michael@0 173 }
michael@0 174
michael@0 175 MFBT_API bool
michael@0 176 IsSignalHandlingBroken()
michael@0 177 {
michael@0 178 return ElfLoader::Singleton.isSignalHandlingBroken();
michael@0 179 }
michael@0 180
michael@0 181 namespace {
michael@0 182
michael@0 183 /**
michael@0 184 * Returns the part after the last '/' for the given path
michael@0 185 */
michael@0 186 const char *
michael@0 187 LeafName(const char *path)
michael@0 188 {
michael@0 189 const char *lastSlash = strrchr(path, '/');
michael@0 190 if (lastSlash)
michael@0 191 return lastSlash + 1;
michael@0 192 return path;
michael@0 193 }
michael@0 194
michael@0 195 } /* Anonymous namespace */
michael@0 196
michael@0 197 /**
michael@0 198 * LibHandle
michael@0 199 */
michael@0 200 LibHandle::~LibHandle()
michael@0 201 {
michael@0 202 free(path);
michael@0 203 }
michael@0 204
michael@0 205 const char *
michael@0 206 LibHandle::GetName() const
michael@0 207 {
michael@0 208 return path ? LeafName(path) : nullptr;
michael@0 209 }
michael@0 210
michael@0 211 size_t
michael@0 212 LibHandle::GetMappableLength() const
michael@0 213 {
michael@0 214 if (!mappable)
michael@0 215 mappable = GetMappable();
michael@0 216 if (!mappable)
michael@0 217 return 0;
michael@0 218 return mappable->GetLength();
michael@0 219 }
michael@0 220
michael@0 221 void *
michael@0 222 LibHandle::MappableMMap(void *addr, size_t length, off_t offset) const
michael@0 223 {
michael@0 224 if (!mappable)
michael@0 225 mappable = GetMappable();
michael@0 226 if (!mappable)
michael@0 227 return MAP_FAILED;
michael@0 228 void* mapped = mappable->mmap(addr, length, PROT_READ, MAP_PRIVATE, offset);
michael@0 229 if (mapped != MAP_FAILED) {
michael@0 230 /* Ensure the availability of all pages within the mapping */
michael@0 231 for (size_t off = 0; off < length; off += PageSize()) {
michael@0 232 mappable->ensure(reinterpret_cast<char *>(mapped) + off);
michael@0 233 }
michael@0 234 }
michael@0 235 return mapped;
michael@0 236 }
michael@0 237
michael@0 238 void
michael@0 239 LibHandle::MappableMUnmap(void *addr, size_t length) const
michael@0 240 {
michael@0 241 if (mappable)
michael@0 242 mappable->munmap(addr, length);
michael@0 243 }
michael@0 244
michael@0 245 /**
michael@0 246 * SystemElf
michael@0 247 */
michael@0 248 TemporaryRef<LibHandle>
michael@0 249 SystemElf::Load(const char *path, int flags)
michael@0 250 {
michael@0 251 /* The Android linker returns a handle when the file name matches an
michael@0 252 * already loaded library, even when the full path doesn't exist */
michael@0 253 if (path && path[0] == '/' && (access(path, F_OK) == -1)){
michael@0 254 DEBUG_LOG("dlopen(\"%s\", 0x%x) = %p", path, flags, (void *)nullptr);
michael@0 255 return nullptr;
michael@0 256 }
michael@0 257
michael@0 258 void *handle = dlopen(path, flags);
michael@0 259 DEBUG_LOG("dlopen(\"%s\", 0x%x) = %p", path, flags, handle);
michael@0 260 ElfLoader::Singleton.lastError = dlerror();
michael@0 261 if (handle) {
michael@0 262 SystemElf *elf = new SystemElf(path, handle);
michael@0 263 ElfLoader::Singleton.Register(elf);
michael@0 264 return elf;
michael@0 265 }
michael@0 266 return nullptr;
michael@0 267 }
michael@0 268
michael@0 269 SystemElf::~SystemElf()
michael@0 270 {
michael@0 271 if (!dlhandle)
michael@0 272 return;
michael@0 273 DEBUG_LOG("dlclose(%p [\"%s\"])", dlhandle, GetPath());
michael@0 274 dlclose(dlhandle);
michael@0 275 ElfLoader::Singleton.lastError = dlerror();
michael@0 276 ElfLoader::Singleton.Forget(this);
michael@0 277 }
michael@0 278
michael@0 279 void *
michael@0 280 SystemElf::GetSymbolPtr(const char *symbol) const
michael@0 281 {
michael@0 282 void *sym = dlsym(dlhandle, symbol);
michael@0 283 DEBUG_LOG("dlsym(%p [\"%s\"], \"%s\") = %p", dlhandle, GetPath(), symbol, sym);
michael@0 284 ElfLoader::Singleton.lastError = dlerror();
michael@0 285 return sym;
michael@0 286 }
michael@0 287
michael@0 288 Mappable *
michael@0 289 SystemElf::GetMappable() const
michael@0 290 {
michael@0 291 const char *path = GetPath();
michael@0 292 if (!path)
michael@0 293 return nullptr;
michael@0 294 #ifdef ANDROID
michael@0 295 /* On Android, if we don't have the full path, try in /system/lib */
michael@0 296 const char *name = LeafName(path);
michael@0 297 std::string systemPath;
michael@0 298 if (name == path) {
michael@0 299 systemPath = "/system/lib/";
michael@0 300 systemPath += path;
michael@0 301 path = systemPath.c_str();
michael@0 302 }
michael@0 303 #endif
michael@0 304
michael@0 305 return MappableFile::Create(path);
michael@0 306 }
michael@0 307
michael@0 308 #ifdef __ARM_EABI__
michael@0 309 const void *
michael@0 310 SystemElf::FindExidx(int *pcount) const
michael@0 311 {
michael@0 312 /* TODO: properly implement when ElfLoader::GetHandleByPtr
michael@0 313 does return SystemElf handles */
michael@0 314 *pcount = 0;
michael@0 315 return nullptr;
michael@0 316 }
michael@0 317 #endif
michael@0 318
michael@0 319 /**
michael@0 320 * ElfLoader
michael@0 321 */
michael@0 322
michael@0 323 /* Unique ElfLoader instance */
michael@0 324 ElfLoader ElfLoader::Singleton;
michael@0 325
michael@0 326 TemporaryRef<LibHandle>
michael@0 327 ElfLoader::Load(const char *path, int flags, LibHandle *parent)
michael@0 328 {
michael@0 329 /* Ensure logging is initialized or refresh if environment changed. */
michael@0 330 Logging::Init();
michael@0 331
michael@0 332 RefPtr<LibHandle> handle;
michael@0 333
michael@0 334 /* Handle dlopen(nullptr) directly. */
michael@0 335 if (!path) {
michael@0 336 handle = SystemElf::Load(nullptr, flags);
michael@0 337 return handle;
michael@0 338 }
michael@0 339
michael@0 340 /* TODO: Handle relative paths correctly */
michael@0 341 const char *name = LeafName(path);
michael@0 342
michael@0 343 /* Search the list of handles we already have for a match. When the given
michael@0 344 * path is not absolute, compare file names, otherwise compare full paths. */
michael@0 345 if (name == path) {
michael@0 346 for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it)
michael@0 347 if ((*it)->GetName() && (strcmp((*it)->GetName(), name) == 0))
michael@0 348 return *it;
michael@0 349 } else {
michael@0 350 for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it)
michael@0 351 if ((*it)->GetPath() && (strcmp((*it)->GetPath(), path) == 0))
michael@0 352 return *it;
michael@0 353 }
michael@0 354
michael@0 355 char *abs_path = nullptr;
michael@0 356 const char *requested_path = path;
michael@0 357
michael@0 358 /* When the path is not absolute and the library is being loaded for
michael@0 359 * another, first try to load the library from the directory containing
michael@0 360 * that parent library. */
michael@0 361 if ((name == path) && parent) {
michael@0 362 const char *parentPath = parent->GetPath();
michael@0 363 abs_path = new char[strlen(parentPath) + strlen(path)];
michael@0 364 strcpy(abs_path, parentPath);
michael@0 365 char *slash = strrchr(abs_path, '/');
michael@0 366 strcpy(slash + 1, path);
michael@0 367 path = abs_path;
michael@0 368 }
michael@0 369
michael@0 370 Mappable *mappable = GetMappableFromPath(path);
michael@0 371
michael@0 372 /* Try loading with the custom linker if we have a Mappable */
michael@0 373 if (mappable)
michael@0 374 handle = CustomElf::Load(mappable, path, flags);
michael@0 375
michael@0 376 /* Try loading with the system linker if everything above failed */
michael@0 377 if (!handle)
michael@0 378 handle = SystemElf::Load(path, flags);
michael@0 379
michael@0 380 /* If we didn't have an absolute path and haven't been able to load
michael@0 381 * a library yet, try in the system search path */
michael@0 382 if (!handle && abs_path)
michael@0 383 handle = SystemElf::Load(name, flags);
michael@0 384
michael@0 385 delete [] abs_path;
michael@0 386 DEBUG_LOG("ElfLoader::Load(\"%s\", 0x%x, %p [\"%s\"]) = %p", requested_path, flags,
michael@0 387 reinterpret_cast<void *>(parent), parent ? parent->GetPath() : "",
michael@0 388 static_cast<void *>(handle));
michael@0 389
michael@0 390 return handle;
michael@0 391 }
michael@0 392
michael@0 393 mozilla::TemporaryRef<LibHandle>
michael@0 394 ElfLoader::GetHandleByPtr(void *addr)
michael@0 395 {
michael@0 396 /* Scan the list of handles we already have for a match */
michael@0 397 for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it) {
michael@0 398 if ((*it)->Contains(addr))
michael@0 399 return *it;
michael@0 400 }
michael@0 401 return nullptr;
michael@0 402 }
michael@0 403
michael@0 404 Mappable *
michael@0 405 ElfLoader::GetMappableFromPath(const char *path)
michael@0 406 {
michael@0 407 const char *name = LeafName(path);
michael@0 408 Mappable *mappable = nullptr;
michael@0 409 RefPtr<Zip> zip;
michael@0 410 const char *subpath;
michael@0 411 if ((subpath = strchr(path, '!'))) {
michael@0 412 char *zip_path = strndup(path, subpath - path);
michael@0 413 while (*(++subpath) == '/') { }
michael@0 414 zip = ZipCollection::GetZip(zip_path);
michael@0 415 Zip::Stream s;
michael@0 416 if (zip && zip->GetStream(subpath, &s)) {
michael@0 417 /* When the MOZ_LINKER_EXTRACT environment variable is set to "1",
michael@0 418 * compressed libraries are going to be (temporarily) extracted as
michael@0 419 * files, in the directory pointed by the MOZ_LINKER_CACHE
michael@0 420 * environment variable. */
michael@0 421 const char *extract = getenv("MOZ_LINKER_EXTRACT");
michael@0 422 if (extract && !strncmp(extract, "1", 2 /* Including '\0' */))
michael@0 423 mappable = MappableExtractFile::Create(name, zip, &s);
michael@0 424 if (!mappable) {
michael@0 425 if (s.GetType() == Zip::Stream::DEFLATE) {
michael@0 426 mappable = MappableDeflate::Create(name, zip, &s);
michael@0 427 } else if (s.GetType() == Zip::Stream::STORE) {
michael@0 428 mappable = MappableSeekableZStream::Create(name, zip, &s);
michael@0 429 }
michael@0 430 }
michael@0 431 }
michael@0 432 }
michael@0 433 /* If we couldn't load above, try with a MappableFile */
michael@0 434 if (!mappable && !zip)
michael@0 435 mappable = MappableFile::Create(path);
michael@0 436
michael@0 437 return mappable;
michael@0 438 }
michael@0 439
michael@0 440 void
michael@0 441 ElfLoader::Register(LibHandle *handle)
michael@0 442 {
michael@0 443 handles.push_back(handle);
michael@0 444 if (dbg && !handle->IsSystemElf())
michael@0 445 dbg.Add(static_cast<CustomElf *>(handle));
michael@0 446 }
michael@0 447
michael@0 448 void
michael@0 449 ElfLoader::Forget(LibHandle *handle)
michael@0 450 {
michael@0 451 /* Ensure logging is initialized or refresh if environment changed. */
michael@0 452 Logging::Init();
michael@0 453
michael@0 454 LibHandleList::iterator it = std::find(handles.begin(), handles.end(), handle);
michael@0 455 if (it != handles.end()) {
michael@0 456 DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"])", reinterpret_cast<void *>(handle),
michael@0 457 handle->GetPath());
michael@0 458 if (dbg && !handle->IsSystemElf())
michael@0 459 dbg.Remove(static_cast<CustomElf *>(handle));
michael@0 460 handles.erase(it);
michael@0 461 } else {
michael@0 462 DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"]): Handle not found",
michael@0 463 reinterpret_cast<void *>(handle), handle->GetPath());
michael@0 464 }
michael@0 465 }
michael@0 466
michael@0 467 ElfLoader::~ElfLoader()
michael@0 468 {
michael@0 469 LibHandleList list;
michael@0 470 /* Build up a list of all library handles with direct (external) references.
michael@0 471 * We actually skip system library handles because we want to keep at least
michael@0 472 * some of these open. Most notably, Mozilla codebase keeps a few libgnome
michael@0 473 * libraries deliberately open because of the mess that libORBit destruction
michael@0 474 * is. dlclose()ing these libraries actually leads to problems. */
michael@0 475 for (LibHandleList::reverse_iterator it = handles.rbegin();
michael@0 476 it < handles.rend(); ++it) {
michael@0 477 if ((*it)->DirectRefCount()) {
michael@0 478 if ((*it)->IsSystemElf()) {
michael@0 479 static_cast<SystemElf *>(*it)->Forget();
michael@0 480 } else {
michael@0 481 list.push_back(*it);
michael@0 482 }
michael@0 483 }
michael@0 484 }
michael@0 485 /* Force release all external references to the handles collected above */
michael@0 486 for (LibHandleList::iterator it = list.begin(); it < list.end(); ++it) {
michael@0 487 while ((*it)->ReleaseDirectRef()) { }
michael@0 488 }
michael@0 489 /* Remove the remaining system handles. */
michael@0 490 if (handles.size()) {
michael@0 491 list = handles;
michael@0 492 for (LibHandleList::reverse_iterator it = list.rbegin();
michael@0 493 it < list.rend(); ++it) {
michael@0 494 if ((*it)->IsSystemElf()) {
michael@0 495 DEBUG_LOG("ElfLoader::~ElfLoader(): Remaining handle for \"%s\" "
michael@0 496 "[%d direct refs, %d refs total]", (*it)->GetPath(),
michael@0 497 (*it)->DirectRefCount(), (*it)->refCount());
michael@0 498 } else {
michael@0 499 DEBUG_LOG("ElfLoader::~ElfLoader(): Unexpected remaining handle for \"%s\" "
michael@0 500 "[%d direct refs, %d refs total]", (*it)->GetPath(),
michael@0 501 (*it)->DirectRefCount(), (*it)->refCount());
michael@0 502 /* Not removing, since it could have references to other libraries,
michael@0 503 * destroying them as a side effect, and possibly leaving dangling
michael@0 504 * pointers in the handle list we're scanning */
michael@0 505 }
michael@0 506 }
michael@0 507 }
michael@0 508 }
michael@0 509
michael@0 510 void
michael@0 511 ElfLoader::stats(const char *when)
michael@0 512 {
michael@0 513 for (LibHandleList::iterator it = Singleton.handles.begin();
michael@0 514 it < Singleton.handles.end(); ++it)
michael@0 515 if (!(*it)->IsSystemElf())
michael@0 516 static_cast<CustomElf *>(*it)->stats(when);
michael@0 517 }
michael@0 518
michael@0 519 #ifdef __ARM_EABI__
michael@0 520 int
michael@0 521 ElfLoader::__wrap_aeabi_atexit(void *that, ElfLoader::Destructor destructor,
michael@0 522 void *dso_handle)
michael@0 523 {
michael@0 524 Singleton.destructors.push_back(
michael@0 525 DestructorCaller(destructor, that, dso_handle));
michael@0 526 return 0;
michael@0 527 }
michael@0 528 #else
michael@0 529 int
michael@0 530 ElfLoader::__wrap_cxa_atexit(ElfLoader::Destructor destructor, void *that,
michael@0 531 void *dso_handle)
michael@0 532 {
michael@0 533 Singleton.destructors.push_back(
michael@0 534 DestructorCaller(destructor, that, dso_handle));
michael@0 535 return 0;
michael@0 536 }
michael@0 537 #endif
michael@0 538
michael@0 539 void
michael@0 540 ElfLoader::__wrap_cxa_finalize(void *dso_handle)
michael@0 541 {
michael@0 542 /* Call all destructors for the given DSO handle in reverse order they were
michael@0 543 * registered. */
michael@0 544 std::vector<DestructorCaller>::reverse_iterator it;
michael@0 545 for (it = Singleton.destructors.rbegin();
michael@0 546 it < Singleton.destructors.rend(); ++it) {
michael@0 547 if (it->IsForHandle(dso_handle)) {
michael@0 548 it->Call();
michael@0 549 }
michael@0 550 }
michael@0 551 }
michael@0 552
michael@0 553 void
michael@0 554 ElfLoader::DestructorCaller::Call()
michael@0 555 {
michael@0 556 if (destructor) {
michael@0 557 DEBUG_LOG("ElfLoader::DestructorCaller::Call(%p, %p, %p)",
michael@0 558 FunctionPtr(destructor), object, dso_handle);
michael@0 559 destructor(object);
michael@0 560 destructor = nullptr;
michael@0 561 }
michael@0 562 }
michael@0 563
michael@0 564 ElfLoader::DebuggerHelper::DebuggerHelper(): dbg(nullptr)
michael@0 565 {
michael@0 566 /* Find ELF auxiliary vectors.
michael@0 567 *
michael@0 568 * The kernel stores the following data on the stack when starting a
michael@0 569 * program:
michael@0 570 * argc
michael@0 571 * argv[0] (pointer into argv strings defined below)
michael@0 572 * argv[1] (likewise)
michael@0 573 * ...
michael@0 574 * argv[argc - 1] (likewise)
michael@0 575 * nullptr
michael@0 576 * envp[0] (pointer into environment strings defined below)
michael@0 577 * envp[1] (likewise)
michael@0 578 * ...
michael@0 579 * envp[n] (likewise)
michael@0 580 * nullptr
michael@0 581 * ... (more NULLs on some platforms such as Android 4.3)
michael@0 582 * auxv[0] (first ELF auxiliary vector)
michael@0 583 * auxv[1] (second ELF auxiliary vector)
michael@0 584 * ...
michael@0 585 * auxv[p] (last ELF auxiliary vector)
michael@0 586 * (AT_NULL, nullptr)
michael@0 587 * padding
michael@0 588 * argv strings, separated with '\0'
michael@0 589 * environment strings, separated with '\0'
michael@0 590 * nullptr
michael@0 591 *
michael@0 592 * What we are after are the auxv values defined by the following struct.
michael@0 593 */
michael@0 594 struct AuxVector {
michael@0 595 Elf::Addr type;
michael@0 596 Elf::Addr value;
michael@0 597 };
michael@0 598
michael@0 599 /* Pointer to the environment variables list */
michael@0 600 extern char **environ;
michael@0 601
michael@0 602 /* The environment may have changed since the program started, in which
michael@0 603 * case the environ variables list isn't the list the kernel put on stack
michael@0 604 * anymore. But in this new list, variables that didn't change still point
michael@0 605 * to the strings the kernel put on stack. It is quite unlikely that two
michael@0 606 * modified environment variables point to two consecutive strings in memory,
michael@0 607 * so we assume that if two consecutive environment variables point to two
michael@0 608 * consecutive strings, we found strings the kernel put on stack. */
michael@0 609 char **env;
michael@0 610 for (env = environ; *env; env++)
michael@0 611 if (*env + strlen(*env) + 1 == env[1])
michael@0 612 break;
michael@0 613 if (!*env)
michael@0 614 return;
michael@0 615
michael@0 616 /* Next, we scan the stack backwards to find a pointer to one of those
michael@0 617 * strings we found above, which will give us the location of the original
michael@0 618 * envp list. As we are looking for pointers, we need to look at 32-bits or
michael@0 619 * 64-bits aligned values, depening on the architecture. */
michael@0 620 char **scan = reinterpret_cast<char **>(
michael@0 621 reinterpret_cast<uintptr_t>(*env) & ~(sizeof(void *) - 1));
michael@0 622 while (*env != *scan)
michael@0 623 scan--;
michael@0 624
michael@0 625 /* Finally, scan forward to find the last environment variable pointer and
michael@0 626 * thus the first auxiliary vector. */
michael@0 627 while (*scan++);
michael@0 628
michael@0 629 /* Some platforms have more NULLs here, so skip them if we encounter them */
michael@0 630 while (!*scan)
michael@0 631 scan++;
michael@0 632
michael@0 633 AuxVector *auxv = reinterpret_cast<AuxVector *>(scan);
michael@0 634
michael@0 635 /* The two values of interest in the auxiliary vectors are AT_PHDR and
michael@0 636 * AT_PHNUM, which gives us the the location and size of the ELF program
michael@0 637 * headers. */
michael@0 638 Array<Elf::Phdr> phdrs;
michael@0 639 char *base = nullptr;
michael@0 640 while (auxv->type) {
michael@0 641 if (auxv->type == AT_PHDR) {
michael@0 642 phdrs.Init(reinterpret_cast<Elf::Phdr*>(auxv->value));
michael@0 643 /* Assume the base address is the first byte of the same page */
michael@0 644 base = reinterpret_cast<char *>(PageAlignedPtr(auxv->value));
michael@0 645 }
michael@0 646 if (auxv->type == AT_PHNUM)
michael@0 647 phdrs.Init(auxv->value);
michael@0 648 auxv++;
michael@0 649 }
michael@0 650
michael@0 651 if (!phdrs) {
michael@0 652 DEBUG_LOG("Couldn't find program headers");
michael@0 653 return;
michael@0 654 }
michael@0 655
michael@0 656 /* In some cases, the address for the program headers we get from the
michael@0 657 * auxiliary vectors is not mapped, because of the PT_LOAD segments
michael@0 658 * definitions in the program executable. Trying to map anonymous memory
michael@0 659 * with a hint giving the base address will return a different address
michael@0 660 * if something is mapped there, and the base address otherwise. */
michael@0 661 MappedPtr mem(MemoryRange::mmap(base, PageSize(), PROT_NONE,
michael@0 662 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
michael@0 663 if (mem == base) {
michael@0 664 /* If program headers aren't mapped, try to map them */
michael@0 665 int fd = open("/proc/self/exe", O_RDONLY);
michael@0 666 if (fd == -1) {
michael@0 667 DEBUG_LOG("Failed to open /proc/self/exe");
michael@0 668 return;
michael@0 669 }
michael@0 670 mem.Assign(MemoryRange::mmap(base, PageSize(), PROT_READ, MAP_PRIVATE,
michael@0 671 fd, 0));
michael@0 672 /* If we don't manage to map at the right address, just give up. */
michael@0 673 if (mem != base) {
michael@0 674 DEBUG_LOG("Couldn't read program headers");
michael@0 675 return;
michael@0 676 }
michael@0 677 }
michael@0 678 /* Sanity check: the first bytes at the base address should be an ELF
michael@0 679 * header. */
michael@0 680 if (!Elf::Ehdr::validate(base)) {
michael@0 681 DEBUG_LOG("Couldn't find program base");
michael@0 682 return;
michael@0 683 }
michael@0 684
michael@0 685 /* Search for the program PT_DYNAMIC segment */
michael@0 686 Array<Elf::Dyn> dyns;
michael@0 687 for (Array<Elf::Phdr>::iterator phdr = phdrs.begin(); phdr < phdrs.end();
michael@0 688 ++phdr) {
michael@0 689 /* While the program headers are expected within the first mapped page of
michael@0 690 * the program executable, the executable PT_LOADs may actually make them
michael@0 691 * loaded at an address that is not the wanted base address of the
michael@0 692 * library. We thus need to adjust the base address, compensating for the
michael@0 693 * virtual address of the PT_LOAD segment corresponding to offset 0. */
michael@0 694 if (phdr->p_type == PT_LOAD && phdr->p_offset == 0)
michael@0 695 base -= phdr->p_vaddr;
michael@0 696 if (phdr->p_type == PT_DYNAMIC)
michael@0 697 dyns.Init(base + phdr->p_vaddr, phdr->p_filesz);
michael@0 698 }
michael@0 699 if (!dyns) {
michael@0 700 DEBUG_LOG("Failed to find PT_DYNAMIC section in program");
michael@0 701 return;
michael@0 702 }
michael@0 703
michael@0 704 /* Search for the DT_DEBUG information */
michael@0 705 for (Array<Elf::Dyn>::iterator dyn = dyns.begin(); dyn < dyns.end(); ++dyn) {
michael@0 706 if (dyn->d_tag == DT_DEBUG) {
michael@0 707 dbg = reinterpret_cast<r_debug *>(dyn->d_un.d_ptr);
michael@0 708 break;
michael@0 709 }
michael@0 710 }
michael@0 711 DEBUG_LOG("DT_DEBUG points at %p", static_cast<void *>(dbg));
michael@0 712 }
michael@0 713
michael@0 714 /**
michael@0 715 * Helper class to ensure the given pointer is writable within the scope of
michael@0 716 * an instance. Permissions to the memory page where the pointer lies are
michael@0 717 * restored to their original value when the instance is destroyed.
michael@0 718 */
michael@0 719 class EnsureWritable
michael@0 720 {
michael@0 721 public:
michael@0 722 template <typename T>
michael@0 723 EnsureWritable(T *ptr, size_t length_ = sizeof(T))
michael@0 724 {
michael@0 725 MOZ_ASSERT(length_ < PageSize());
michael@0 726 prot = -1;
michael@0 727 page = MAP_FAILED;
michael@0 728
michael@0 729 char *firstPage = PageAlignedPtr(reinterpret_cast<char *>(ptr));
michael@0 730 char *lastPageEnd = PageAlignedEndPtr(reinterpret_cast<char *>(ptr) + length_);
michael@0 731 length = lastPageEnd - firstPage;
michael@0 732 uintptr_t start = reinterpret_cast<uintptr_t>(firstPage);
michael@0 733 uintptr_t end;
michael@0 734
michael@0 735 prot = getProt(start, &end);
michael@0 736 if (prot == -1 || (start + length) > end)
michael@0 737 MOZ_CRASH();
michael@0 738
michael@0 739 if (prot & PROT_WRITE)
michael@0 740 return;
michael@0 741
michael@0 742 page = firstPage;
michael@0 743 mprotect(page, length, prot | PROT_WRITE);
michael@0 744 }
michael@0 745
michael@0 746 ~EnsureWritable()
michael@0 747 {
michael@0 748 if (page != MAP_FAILED) {
michael@0 749 mprotect(page, length, prot);
michael@0 750 }
michael@0 751 }
michael@0 752
michael@0 753 private:
michael@0 754 int getProt(uintptr_t addr, uintptr_t *end)
michael@0 755 {
michael@0 756 /* The interesting part of the /proc/self/maps format looks like:
michael@0 757 * startAddr-endAddr rwxp */
michael@0 758 int result = 0;
michael@0 759 AutoCloseFILE f(fopen("/proc/self/maps", "r"));
michael@0 760 while (f) {
michael@0 761 unsigned long long startAddr, endAddr;
michael@0 762 char perms[5];
michael@0 763 if (fscanf(f, "%llx-%llx %4s %*1024[^\n] ", &startAddr, &endAddr, perms) != 3)
michael@0 764 return -1;
michael@0 765 if (addr < startAddr || addr >= endAddr)
michael@0 766 continue;
michael@0 767 if (perms[0] == 'r')
michael@0 768 result |= PROT_READ;
michael@0 769 else if (perms[0] != '-')
michael@0 770 return -1;
michael@0 771 if (perms[1] == 'w')
michael@0 772 result |= PROT_WRITE;
michael@0 773 else if (perms[1] != '-')
michael@0 774 return -1;
michael@0 775 if (perms[2] == 'x')
michael@0 776 result |= PROT_EXEC;
michael@0 777 else if (perms[2] != '-')
michael@0 778 return -1;
michael@0 779 *end = endAddr;
michael@0 780 return result;
michael@0 781 }
michael@0 782 return -1;
michael@0 783 }
michael@0 784
michael@0 785 int prot;
michael@0 786 void *page;
michael@0 787 size_t length;
michael@0 788 };
michael@0 789
michael@0 790 /**
michael@0 791 * The system linker maintains a doubly linked list of library it loads
michael@0 792 * for use by the debugger. Unfortunately, it also uses the list pointers
michael@0 793 * in a lot of operations and adding our data in the list is likely to
michael@0 794 * trigger crashes when the linker tries to use data we don't provide or
michael@0 795 * that fall off the amount data we allocated. Fortunately, the linker only
michael@0 796 * traverses the list forward and accesses the head of the list from a
michael@0 797 * private pointer instead of using the value in the r_debug structure.
michael@0 798 * This means we can safely add members at the beginning of the list.
michael@0 799 * Unfortunately, gdb checks the coherency of l_prev values, so we have
michael@0 800 * to adjust the l_prev value for the first element the system linker
michael@0 801 * knows about. Fortunately, it doesn't use l_prev, and the first element
michael@0 802 * is not ever going to be released before our elements, since it is the
michael@0 803 * program executable, so the system linker should not be changing
michael@0 804 * r_debug::r_map.
michael@0 805 */
michael@0 806 void
michael@0 807 ElfLoader::DebuggerHelper::Add(ElfLoader::link_map *map)
michael@0 808 {
michael@0 809 if (!dbg->r_brk)
michael@0 810 return;
michael@0 811 dbg->r_state = r_debug::RT_ADD;
michael@0 812 dbg->r_brk();
michael@0 813 map->l_prev = nullptr;
michael@0 814 map->l_next = dbg->r_map;
michael@0 815 if (!firstAdded) {
michael@0 816 firstAdded = map;
michael@0 817 /* When adding a library for the first time, r_map points to data
michael@0 818 * handled by the system linker, and that data may be read-only */
michael@0 819 EnsureWritable w(&dbg->r_map->l_prev);
michael@0 820 dbg->r_map->l_prev = map;
michael@0 821 } else
michael@0 822 dbg->r_map->l_prev = map;
michael@0 823 dbg->r_map = map;
michael@0 824 dbg->r_state = r_debug::RT_CONSISTENT;
michael@0 825 dbg->r_brk();
michael@0 826 }
michael@0 827
michael@0 828 void
michael@0 829 ElfLoader::DebuggerHelper::Remove(ElfLoader::link_map *map)
michael@0 830 {
michael@0 831 if (!dbg->r_brk)
michael@0 832 return;
michael@0 833 dbg->r_state = r_debug::RT_DELETE;
michael@0 834 dbg->r_brk();
michael@0 835 if (dbg->r_map == map)
michael@0 836 dbg->r_map = map->l_next;
michael@0 837 else
michael@0 838 map->l_prev->l_next = map->l_next;
michael@0 839 if (map == firstAdded) {
michael@0 840 firstAdded = map->l_prev;
michael@0 841 /* When removing the first added library, its l_next is going to be
michael@0 842 * data handled by the system linker, and that data may be read-only */
michael@0 843 EnsureWritable w(&map->l_next->l_prev);
michael@0 844 map->l_next->l_prev = map->l_prev;
michael@0 845 } else
michael@0 846 map->l_next->l_prev = map->l_prev;
michael@0 847 dbg->r_state = r_debug::RT_CONSISTENT;
michael@0 848 dbg->r_brk();
michael@0 849 }
michael@0 850
michael@0 851 #if defined(ANDROID)
michael@0 852 /* As some system libraries may be calling signal() or sigaction() to
michael@0 853 * set a SIGSEGV handler, effectively breaking MappableSeekableZStream,
michael@0 854 * or worse, restore our SIGSEGV handler with wrong flags (which using
michael@0 855 * signal() will do), we want to hook into the system's sigaction() to
michael@0 856 * replace it with our own wrapper instead, so that our handler is never
michael@0 857 * replaced. We used to only do that with libraries this linker loads,
michael@0 858 * but it turns out at least one system library does call signal() and
michael@0 859 * breaks us (libsc-a3xx.so on the Samsung Galaxy S4).
michael@0 860 * As libc's signal (bsd_signal/sysv_signal, really) calls sigaction
michael@0 861 * under the hood, instead of calling the signal system call directly,
michael@0 862 * we only need to hook sigaction. This is true for both bionic and
michael@0 863 * glibc.
michael@0 864 */
michael@0 865
michael@0 866 /* libc's sigaction */
michael@0 867 extern "C" int
michael@0 868 sigaction(int signum, const struct sigaction *act,
michael@0 869 struct sigaction *oldact);
michael@0 870
michael@0 871 /* Simple reimplementation of sigaction. This is roughly equivalent
michael@0 872 * to the assembly that comes in bionic, but not quite equivalent to
michael@0 873 * glibc's implementation, so we only use this on Android. */
michael@0 874 int
michael@0 875 sys_sigaction(int signum, const struct sigaction *act,
michael@0 876 struct sigaction *oldact)
michael@0 877 {
michael@0 878 return syscall(__NR_sigaction, signum, act, oldact);
michael@0 879 }
michael@0 880
michael@0 881 /* Replace the first instructions of the given function with a jump
michael@0 882 * to the given new function. */
michael@0 883 template <typename T>
michael@0 884 static bool
michael@0 885 Divert(T func, T new_func)
michael@0 886 {
michael@0 887 void *ptr = FunctionPtr(func);
michael@0 888 uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
michael@0 889
michael@0 890 #if defined(__i386__)
michael@0 891 // A 32-bit jump is a 5 bytes instruction.
michael@0 892 EnsureWritable w(ptr, 5);
michael@0 893 *reinterpret_cast<unsigned char *>(addr) = 0xe9; // jmp
michael@0 894 *reinterpret_cast<intptr_t *>(addr + 1) =
michael@0 895 reinterpret_cast<uintptr_t>(new_func) - addr - 5; // target displacement
michael@0 896 return true;
michael@0 897 #elif defined(__arm__)
michael@0 898 const unsigned char trampoline[] = {
michael@0 899 // .thumb
michael@0 900 0x46, 0x04, // nop
michael@0 901 0x78, 0x47, // bx pc
michael@0 902 0x46, 0x04, // nop
michael@0 903 // .arm
michael@0 904 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
michael@0 905 // .word <new_func>
michael@0 906 };
michael@0 907 const unsigned char *start;
michael@0 908 if (addr & 0x01) {
michael@0 909 /* Function is thumb, the actual address of the code is without the
michael@0 910 * least significant bit. */
michael@0 911 addr--;
michael@0 912 /* The arm part of the trampoline needs to be 32-bit aligned */
michael@0 913 if (addr & 0x02)
michael@0 914 start = trampoline;
michael@0 915 else
michael@0 916 start = trampoline + 2;
michael@0 917 } else {
michael@0 918 /* Function is arm, we only need the arm part of the trampoline */
michael@0 919 start = trampoline + 6;
michael@0 920 }
michael@0 921
michael@0 922 size_t len = sizeof(trampoline) - (start - trampoline);
michael@0 923 EnsureWritable w(reinterpret_cast<void *>(addr), len + sizeof(void *));
michael@0 924 memcpy(reinterpret_cast<void *>(addr), start, len);
michael@0 925 *reinterpret_cast<void **>(addr + len) = FunctionPtr(new_func);
michael@0 926 cacheflush(addr, addr + len + sizeof(void *), 0);
michael@0 927 return true;
michael@0 928 #else
michael@0 929 return false;
michael@0 930 #endif
michael@0 931 }
michael@0 932 #else
michael@0 933 #define sys_sigaction sigaction
michael@0 934 template <typename T>
michael@0 935 static bool
michael@0 936 Divert(T func, T new_func)
michael@0 937 {
michael@0 938 return false;
michael@0 939 }
michael@0 940 #endif
michael@0 941
michael@0 942 namespace {
michael@0 943
michael@0 944 /* Clock that only accounts for time spent in the current process. */
michael@0 945 static uint64_t ProcessTimeStamp_Now()
michael@0 946 {
michael@0 947 struct timespec ts;
michael@0 948 int rv = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
michael@0 949
michael@0 950 if (rv != 0) {
michael@0 951 return 0;
michael@0 952 }
michael@0 953
michael@0 954 uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000;
michael@0 955 return baseNs + (uint64_t)ts.tv_nsec;
michael@0 956 }
michael@0 957
michael@0 958 }
michael@0 959
michael@0 960 /* Data structure used to pass data to the temporary signal handler,
michael@0 961 * as well as triggering a test crash. */
michael@0 962 struct TmpData {
michael@0 963 volatile int crash_int;
michael@0 964 volatile uint64_t crash_timestamp;
michael@0 965 };
michael@0 966
michael@0 967 SEGVHandler::SEGVHandler()
michael@0 968 : registeredHandler(false), signalHandlingBroken(false)
michael@0 969 , signalHandlingSlow(false)
michael@0 970 {
michael@0 971 /* Initialize oldStack.ss_flags to an invalid value when used to set
michael@0 972 * an alternative stack, meaning we haven't got information about the
michael@0 973 * original alternative stack and thus don't mean to restore it */
michael@0 974 oldStack.ss_flags = SS_ONSTACK;
michael@0 975 if (!Divert(sigaction, __wrap_sigaction))
michael@0 976 return;
michael@0 977
michael@0 978 /* Get the current segfault signal handler. */
michael@0 979 sys_sigaction(SIGSEGV, nullptr, &this->action);
michael@0 980
michael@0 981 /* Some devices don't provide useful information to their SIGSEGV handlers,
michael@0 982 * making it impossible for on-demand decompression to work. To check if
michael@0 983 * we're on such a device, setup a temporary handler and deliberately
michael@0 984 * trigger a segfault. The handler will set signalHandlingBroken if the
michael@0 985 * provided information is bogus.
michael@0 986 * Some other devices have a kernel option enabled that makes SIGSEGV handler
michael@0 987 * have an overhead so high that it affects how on-demand decompression
michael@0 988 * performs. The handler will also set signalHandlingSlow if the triggered
michael@0 989 * SIGSEGV took too much time. */
michael@0 990 struct sigaction action;
michael@0 991 action.sa_sigaction = &SEGVHandler::test_handler;
michael@0 992 sigemptyset(&action.sa_mask);
michael@0 993 action.sa_flags = SA_SIGINFO | SA_NODEFER;
michael@0 994 action.sa_restorer = nullptr;
michael@0 995 stackPtr.Assign(MemoryRange::mmap(nullptr, PageSize(),
michael@0 996 PROT_READ | PROT_WRITE,
michael@0 997 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
michael@0 998 if (stackPtr.get() == MAP_FAILED)
michael@0 999 return;
michael@0 1000 if (sys_sigaction(SIGSEGV, &action, nullptr))
michael@0 1001 return;
michael@0 1002
michael@0 1003 TmpData *data = reinterpret_cast<TmpData*>(stackPtr.get());
michael@0 1004 data->crash_timestamp = ProcessTimeStamp_Now();
michael@0 1005 mprotect(stackPtr, stackPtr.GetLength(), PROT_NONE);
michael@0 1006 data->crash_int = 123;
michael@0 1007 /* Restore the original segfault signal handler. */
michael@0 1008 sys_sigaction(SIGSEGV, &this->action, nullptr);
michael@0 1009 stackPtr.Assign(MAP_FAILED, 0);
michael@0 1010 if (signalHandlingBroken || signalHandlingSlow)
michael@0 1011 return;
michael@0 1012
michael@0 1013 /* Setup an alternative stack if the already existing one is not big
michael@0 1014 * enough, or if there is none. */
michael@0 1015 if (sigaltstack(nullptr, &oldStack) == 0) {
michael@0 1016 if (oldStack.ss_flags == SS_ONSTACK)
michael@0 1017 oldStack.ss_flags = 0;
michael@0 1018 if (!oldStack.ss_sp || oldStack.ss_size < stackSize) {
michael@0 1019 stackPtr.Assign(MemoryRange::mmap(nullptr, stackSize,
michael@0 1020 PROT_READ | PROT_WRITE,
michael@0 1021 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
michael@0 1022 if (stackPtr.get() == MAP_FAILED)
michael@0 1023 return;
michael@0 1024 stack_t stack;
michael@0 1025 stack.ss_sp = stackPtr;
michael@0 1026 stack.ss_size = stackSize;
michael@0 1027 stack.ss_flags = 0;
michael@0 1028 if (sigaltstack(&stack, nullptr) != 0)
michael@0 1029 return;
michael@0 1030 }
michael@0 1031 }
michael@0 1032 /* Register our own handler, and store the already registered one in
michael@0 1033 * SEGVHandler's struct sigaction member */
michael@0 1034 action.sa_sigaction = &SEGVHandler::handler;
michael@0 1035 action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
michael@0 1036 registeredHandler = !sys_sigaction(SIGSEGV, &action, nullptr);
michael@0 1037 }
michael@0 1038
michael@0 1039 SEGVHandler::~SEGVHandler()
michael@0 1040 {
michael@0 1041 /* Restore alternative stack for signals */
michael@0 1042 if (oldStack.ss_flags != SS_ONSTACK)
michael@0 1043 sigaltstack(&oldStack, nullptr);
michael@0 1044 /* Restore original signal handler */
michael@0 1045 if (registeredHandler)
michael@0 1046 sys_sigaction(SIGSEGV, &this->action, nullptr);
michael@0 1047 }
michael@0 1048
michael@0 1049 /* Test handler for a deliberately triggered SIGSEGV that determines whether
michael@0 1050 * useful information is provided to signal handlers, particularly whether
michael@0 1051 * si_addr is filled in properly, and whether the segfault handler is called
michael@0 1052 * quickly enough. */
michael@0 1053 void SEGVHandler::test_handler(int signum, siginfo_t *info, void *context)
michael@0 1054 {
michael@0 1055 SEGVHandler &that = ElfLoader::Singleton;
michael@0 1056 if (signum != SIGSEGV ||
michael@0 1057 info == nullptr || info->si_addr != that.stackPtr.get())
michael@0 1058 that.signalHandlingBroken = true;
michael@0 1059 mprotect(that.stackPtr, that.stackPtr.GetLength(), PROT_READ | PROT_WRITE);
michael@0 1060 TmpData *data = reinterpret_cast<TmpData*>(that.stackPtr.get());
michael@0 1061 uint64_t latency = ProcessTimeStamp_Now() - data->crash_timestamp;
michael@0 1062 DEBUG_LOG("SEGVHandler latency: %" PRIu64, latency);
michael@0 1063 /* See bug 886736 for timings on different devices, 150 µs is reasonably above
michael@0 1064 * the latency on "working" devices and seems to be reasonably fast to incur
michael@0 1065 * a huge overhead to on-demand decompression. */
michael@0 1066 if (latency > 150000)
michael@0 1067 that.signalHandlingSlow = true;
michael@0 1068 }
michael@0 1069
michael@0 1070 /* TODO: "properly" handle signal masks and flags */
michael@0 1071 void SEGVHandler::handler(int signum, siginfo_t *info, void *context)
michael@0 1072 {
michael@0 1073 //ASSERT(signum == SIGSEGV);
michael@0 1074 DEBUG_LOG("Caught segmentation fault @%p", info->si_addr);
michael@0 1075
michael@0 1076 /* Check whether we segfaulted in the address space of a CustomElf. We're
michael@0 1077 * only expecting that to happen as an access error. */
michael@0 1078 if (info->si_code == SEGV_ACCERR) {
michael@0 1079 mozilla::RefPtr<LibHandle> handle =
michael@0 1080 ElfLoader::Singleton.GetHandleByPtr(info->si_addr);
michael@0 1081 if (handle && !handle->IsSystemElf()) {
michael@0 1082 DEBUG_LOG("Within the address space of a CustomElf");
michael@0 1083 CustomElf *elf = static_cast<CustomElf *>(static_cast<LibHandle *>(handle));
michael@0 1084 if (elf->mappable->ensure(info->si_addr))
michael@0 1085 return;
michael@0 1086 }
michael@0 1087 }
michael@0 1088
michael@0 1089 /* Redispatch to the registered handler */
michael@0 1090 SEGVHandler &that = ElfLoader::Singleton;
michael@0 1091 if (that.action.sa_flags & SA_SIGINFO) {
michael@0 1092 DEBUG_LOG("Redispatching to registered handler @%p",
michael@0 1093 FunctionPtr(that.action.sa_sigaction));
michael@0 1094 that.action.sa_sigaction(signum, info, context);
michael@0 1095 } else if (that.action.sa_handler == SIG_DFL) {
michael@0 1096 DEBUG_LOG("Redispatching to default handler");
michael@0 1097 /* Reset the handler to the default one, and trigger it. */
michael@0 1098 sys_sigaction(signum, &that.action, nullptr);
michael@0 1099 raise(signum);
michael@0 1100 } else if (that.action.sa_handler != SIG_IGN) {
michael@0 1101 DEBUG_LOG("Redispatching to registered handler @%p",
michael@0 1102 FunctionPtr(that.action.sa_handler));
michael@0 1103 that.action.sa_handler(signum);
michael@0 1104 } else {
michael@0 1105 DEBUG_LOG("Ignoring");
michael@0 1106 }
michael@0 1107 }
michael@0 1108
michael@0 1109 int
michael@0 1110 SEGVHandler::__wrap_sigaction(int signum, const struct sigaction *act,
michael@0 1111 struct sigaction *oldact)
michael@0 1112 {
michael@0 1113 SEGVHandler &that = ElfLoader::Singleton;
michael@0 1114
michael@0 1115 /* Use system sigaction() function for all but SIGSEGV signals. */
michael@0 1116 if (!that.registeredHandler || (signum != SIGSEGV))
michael@0 1117 return sys_sigaction(signum, act, oldact);
michael@0 1118
michael@0 1119 if (oldact)
michael@0 1120 *oldact = that.action;
michael@0 1121 if (act)
michael@0 1122 that.action = *act;
michael@0 1123 return 0;
michael@0 1124 }
michael@0 1125
michael@0 1126 Logging Logging::Singleton;

mercurial