148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Copyright (c) 2013 The Chromium Authors. All rights reserved.
248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Use of this source code is governed by a BSD-style license that can be
348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// found in the LICENSE file.
448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_rdebug.h"
648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include <elf.h>
848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include <inttypes.h>
948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include <sys/mman.h>
1048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include <unistd.h>
1148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
1248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_debug.h"
1348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_proc_maps.h"
1448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_util.h"
1548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_system.h"
1648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "elf_traits.h"
1748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
1848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnernamespace crazy {
1948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
2048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnernamespace {
2148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
2248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Find the full path of the current executable. On success return true
2348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// and sets |exe_path|. On failure, return false and sets errno.
2448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerbool FindExecutablePath(String* exe_path) {
2548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // /proc/self/exe is a symlink to the full path. Read it with
2648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // readlink().
2748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  exe_path->Resize(512);
2848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ssize_t ret = TEMP_FAILURE_RETRY(
2948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      readlink("/proc/self/exe", exe_path->ptr(), exe_path->size()));
3048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (ret < 0) {
3148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG_ERRNO("%s: Could not get /proc/self/exe link", __FUNCTION__);
3248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
3348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
3448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
3548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  exe_path->Resize(static_cast<size_t>(ret));
3648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LOG("%s: Current executable: %s\n", __FUNCTION__, exe_path->c_str());
3748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return true;
3848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
3948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
4048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Given an ELF binary at |path| that is _already_ mapped in the process,
4148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// find the address of its dynamic section and its size.
4248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// |path| is the full path of the binary (as it appears in /proc/self/maps.
4348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// |self_maps| is an instance of ProcMaps that is used to inspect
4448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// /proc/self/maps. The function rewind + iterates over it.
4548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// On success, return true and set |*dynamic_offset| and |*dynamic_size|.
4648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerbool FindElfDynamicSection(const char* path,
4748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                           ProcMaps* self_maps,
4848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                           size_t* dynamic_address,
4948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                           size_t* dynamic_size) {
5048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Read the ELF header first.
5148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Ehdr header[1];
5248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
5348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  crazy::FileDescriptor fd;
5448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!fd.OpenReadOnly(path) ||
5548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      fd.Read(header, sizeof(header)) != static_cast<int>(sizeof(header))) {
5648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG_ERRNO("%s: Could not load ELF binary header", __FUNCTION__);
5748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
5848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
5948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
6048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Sanity check.
6148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (header->e_ident[0] != 127 || header->e_ident[1] != 'E' ||
6248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      header->e_ident[2] != 'L' || header->e_ident[3] != 'F' ||
6320be525cb9d553a19826ae134a00f317ff7b84c1David 'Digit' Turner      header->e_ident[4] != ELF::kElfClass) {
6420be525cb9d553a19826ae134a00f317ff7b84c1David 'Digit' Turner    LOG("%s: Not a %d-bit ELF binary: %s\n",
6520be525cb9d553a19826ae134a00f317ff7b84c1David 'Digit' Turner        __FUNCTION__,
6620be525cb9d553a19826ae134a00f317ff7b84c1David 'Digit' Turner        ELF::kElfBits,
6720be525cb9d553a19826ae134a00f317ff7b84c1David 'Digit' Turner        path);
6848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
6948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
7048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
7148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (header->e_phoff == 0 || header->e_phentsize != sizeof(ELF::Phdr)) {
7248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG("%s: Invalid program header values: %s\n", __FUNCTION__, path);
7348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
7448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
7548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
7648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Scan the program header table.
7748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (fd.SeekTo(header->e_phoff) < 0) {
7848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG_ERRNO("%s: Could not find ELF program header table", __FUNCTION__);
7948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
8048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
8148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
8248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Phdr phdr_load0 = {0, };
8348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Phdr phdr_dyn = {0, };
8448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool found_load0 = false;
8548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool found_dyn = false;
8648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
8748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  for (size_t n = 0; n < header->e_phnum; ++n) {
8848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ELF::Phdr phdr;
8948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (fd.Read(&phdr, sizeof(phdr)) != sizeof(phdr)) {
9048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      LOG_ERRNO("%s: Could not read program header entry", __FUNCTION__);
9148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      return false;
9248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    }
9348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
9448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (phdr.p_type == PT_LOAD && !found_load0) {
9548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      phdr_load0 = phdr;
9648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      found_load0 = true;
9748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    } else if (phdr.p_type == PT_DYNAMIC && !found_dyn) {
9848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      phdr_dyn = phdr;
9948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      found_dyn = true;
10048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    }
10148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
10248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
10348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!found_load0) {
104927cc3dfe25ade04ded6940e691bc4e21dc8ffc1Simon Baldwin    LOG("%s: Could not find loadable segment!?\n", __FUNCTION__);
10548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
10648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
10748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!found_dyn) {
108927cc3dfe25ade04ded6940e691bc4e21dc8ffc1Simon Baldwin    LOG("%s: Could not find dynamic segment!?\n", __FUNCTION__);
10948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
11048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
11148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
11248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LOG("%s: Found first loadable segment [offset=%p vaddr=%p]\n",
11348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      __FUNCTION__,
11448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      (void*)phdr_load0.p_offset,
11548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      (void*)phdr_load0.p_vaddr);
11648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
11748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LOG("%s: Found dynamic segment [offset=%p vaddr=%p size=%p]\n",
11848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      __FUNCTION__,
11948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      (void*)phdr_dyn.p_offset,
12048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      (void*)phdr_dyn.p_vaddr,
12148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      (void*)phdr_dyn.p_memsz);
12248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
12348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Parse /proc/self/maps to find the load address of the first
12448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // loadable segment.
12548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  size_t path_len = strlen(path);
12648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  self_maps->Rewind();
12748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ProcMaps::Entry entry;
12848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  while (self_maps->GetNextEntry(&entry)) {
12948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (!entry.path || entry.path_len != path_len ||
13048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        memcmp(entry.path, path, path_len) != 0)
13148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      continue;
13248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
13348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG("%s: Found executable segment mapped [%p-%p offset=%p]\n",
13448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        __FUNCTION__,
13548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        (void*)entry.vma_start,
13648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        (void*)entry.vma_end,
13748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        (void*)entry.load_offset);
13848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
13948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    size_t load_bias = entry.vma_start - phdr_load0.p_vaddr;
14048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG("%s: Load bias is %p\n", __FUNCTION__, (void*)load_bias);
14148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
14248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    *dynamic_address = load_bias + phdr_dyn.p_vaddr;
14348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    *dynamic_size = phdr_dyn.p_memsz;
14448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG("%s: Dynamic section addr=%p size=%p\n",
14548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        __FUNCTION__,
14648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        (void*)*dynamic_address,
14748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        (void*)*dynamic_size);
14848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return true;
14948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
15048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
15148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LOG("%s: Executable is not mapped in current process.\n", __FUNCTION__);
15248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return false;
15348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
15448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
15548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Helper class to temporarily remap a page to readable+writable until
15648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// scope exit.
15748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerclass ScopedPageMapper {
15848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner public:
15948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ScopedPageMapper() : page_address_(0), page_prot_(0) {}
16048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  void MapReadWrite(void* address);
16148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ~ScopedPageMapper();
16248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
16348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner private:
16448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  static const uintptr_t kPageSize = 4096;
16548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  uintptr_t page_address_;
16648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  int page_prot_;
16748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner};
16848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
16948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnervoid ScopedPageMapper::MapReadWrite(void* address) {
17048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  page_address_ = reinterpret_cast<uintptr_t>(address) & ~(kPageSize - 1);
17148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  page_prot_ = 0;
17248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!FindProtectionFlagsForAddress(address, &page_prot_) ||
17348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      (page_prot_ & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) {
17448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    // If the address is invalid, or if the page is already read+write,
17548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    // no need to do anything here.
17648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    page_address_ = 0;
17748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return;
17848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
17948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  int new_page_prot = page_prot_ | PROT_READ | PROT_WRITE;
18048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  int ret = mprotect(
18148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      reinterpret_cast<void*>(page_address_), kPageSize, new_page_prot);
18248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (ret < 0) {
18348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG_ERRNO("Could not remap page to read/write");
18448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    page_address_ = 0;
18548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
18648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
18748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
18848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' TurnerScopedPageMapper::~ScopedPageMapper() {
18948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (page_address_) {
19048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    int ret =
19148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        mprotect(reinterpret_cast<void*>(page_address_), kPageSize, page_prot_);
19248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (ret < 0)
19348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      LOG_ERRNO("Could not remap page to old protection flags");
19448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
19548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
19648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
19748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}  // namespace
19848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
19948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerbool RDebug::Init() {
20048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // The address of '_r_debug' is in the DT_DEBUG entry of the current
20148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // executable.
20248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  init_ = true;
20348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
20448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  size_t dynamic_addr = 0;
20548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  size_t dynamic_size = 0;
20648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  String path;
20748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
20848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Find the current executable's full path, and its dynamic section
20948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // information.
21048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!FindExecutablePath(&path))
21148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
21248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
21348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ProcMaps self_maps;
21448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!FindElfDynamicSection(
21548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner           path.c_str(), &self_maps, &dynamic_addr, &dynamic_size)) {
21648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return false;
21748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
21848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
21948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Parse the dynamic table and find the DT_DEBUG entry.
22048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  const ELF::Dyn* dyn_section = reinterpret_cast<const ELF::Dyn*>(dynamic_addr);
22148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
22248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  while (dynamic_size >= sizeof(*dyn_section)) {
22348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (dyn_section->d_tag == DT_DEBUG) {
22448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      // Found it!
22548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      LOG("%s: Found DT_DEBUG entry inside %s at %p, pointing to %p\n",
22648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner          __FUNCTION__,
22748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner          path.c_str(),
22848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner          dyn_section,
22948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner          dyn_section->d_un.d_ptr);
23048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      if (dyn_section->d_un.d_ptr) {
23148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        r_debug_ = reinterpret_cast<r_debug*>(dyn_section->d_un.d_ptr);
23248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        LOG("%s: r_debug [r_version=%d r_map=%p r_brk=%p r_ldbase=%p]\n",
23348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner            __FUNCTION__,
23448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner            r_debug_->r_version,
23548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner            r_debug_->r_map,
23648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner            r_debug_->r_brk,
23748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner            r_debug_->r_ldbase);
23848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        // Only version 1 of the struct is supported.
23948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        if (r_debug_->r_version != 1) {
24048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner          LOG("%s: r_debug.r_version is %d, 1 expected.\n",
24148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner              __FUNCTION__,
24248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner              r_debug_->r_version);
24348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner          r_debug_ = NULL;
24448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        }
24548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
24648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        // The linker of recent Android releases maps its link map entries
24748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        // in read-only pages. Determine if this is the case and record it
24848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        // for later. The first entry in the list corresponds to the
24948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        // executable.
25048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        int prot = self_maps.GetProtectionFlagsForAddress(r_debug_->r_map);
25148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        readonly_entries_ = (prot & PROT_WRITE) == 0;
25248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
25348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        LOG("%s: r_debug.readonly_entries=%s\n",
25448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner            __FUNCTION__,
25548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner            readonly_entries_ ? "true" : "false");
25648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner        return true;
25748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      }
25848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    }
25948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    dyn_section++;
26048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    dynamic_size -= sizeof(*dyn_section);
26148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
26248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
26348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  LOG("%s: There is no non-0 DT_DEBUG entry in this process\n", __FUNCTION__);
26448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  return false;
26548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
26648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
2676788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinnamespace {
2686788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
2696788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// Helper runnable class. Handler is one of the two static functions
2706788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// AddEntryInternal() or DelEntryInternal(). Calling these invokes
2716788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// AddEntryImpl() or DelEntryImpl() respectively on rdebug.
2726788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinclass RDebugRunnable {
2736788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin public:
2746788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  RDebugRunnable(rdebug_callback_handler_t handler,
2756788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                 RDebug* rdebug,
2766788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                 link_map_t* entry)
2776788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin      : handler_(handler), rdebug_(rdebug), entry_(entry) { }
2786788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
2796788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  static void Run(void* opaque);
2806788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
2816788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin private:
2826788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  rdebug_callback_handler_t handler_;
2836788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  RDebug* rdebug_;
2846788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  link_map_t* entry_;
2856788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin};
2866788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
2876788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// Callback entry point.
2886788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinvoid RDebugRunnable::Run(void* opaque) {
2896788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  RDebugRunnable* runnable = static_cast<RDebugRunnable*>(opaque);
2906788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
2916788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  LOG("%s: Callback received, runnable=%p\n", __FUNCTION__, runnable);
2926788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  (*runnable->handler_)(runnable->rdebug_, runnable->entry_);
2936788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  delete runnable;
2946788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin}
2956788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
2966788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin}  // namespace
2976788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
2986788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// Helper function to schedule AddEntry() and DelEntry() calls onto another
2996788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// thread where possible. Running them there avoids races with the system
3006788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// linker, which expects to be able to set r_map pages readonly when it
3016788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin// is not using them and which may run simultaneously on the main thread.
3026788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinbool RDebug::PostCallback(rdebug_callback_handler_t handler,
3036788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin                          link_map_t* entry) {
3046788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  if (!post_for_later_execution_) {
3056788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    LOG("%s: Deferred execution disabled\n", __FUNCTION__);
3066788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    return false;
3076788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  }
3086788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
3096788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  RDebugRunnable* runnable = new RDebugRunnable(handler, this, entry);
3106788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  void* context = post_for_later_execution_context_;
3116788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
3126788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  if (!(*post_for_later_execution_)(context, &RDebugRunnable::Run, runnable)) {
3136788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    LOG("%s: Deferred execution enabled, but posting failed\n", __FUNCTION__);
3146788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    delete runnable;
3156788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin    return false;
3166788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  }
3176788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
3186788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  LOG("%s: Posted for later execution, runnable=%p\n", __FUNCTION__, runnable);
3196788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  return true;
3206788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin}
3216788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin
3226788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinvoid RDebug::AddEntryImpl(link_map_t* entry) {
3236788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  LOG("%s: Adding: %s\n", __FUNCTION__, entry->l_name);
32448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!init_)
32548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    Init();
32648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
32748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!r_debug_) {
32848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG("%s: Nothing to do\n", __FUNCTION__);
32948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return;
33048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
33148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
33248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Tell GDB the list is going to be modified.
33348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  r_debug_->r_state = RT_ADD;
33448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  r_debug_->r_brk();
33548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
33648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // IMPORTANT: GDB expects the first entry in the list to correspond
33748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // to the executable. So add our new entry just after it. This is ok
33848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // because by default, the linker is always the second entry, as in:
33948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
34048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //   [<executable>, /system/bin/linker, libc.so, libm.so, ...]
34148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
34248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // By design, the first two entries should never be removed since they
34348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // can't be unloaded from the process (they are loaded by the kernel
34448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // when invoking the program).
34548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
34648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // TODO(digit): Does GDB expect the linker to be the second entry?
34748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // It doesn't seem so, but have a look at the GDB sources to confirm
34848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // this. No problem appear experimentally.
34948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
35048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // What happens for static binaries? They don't have an .interp section,
35148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // and don't have a r_debug variable on Android, so GDB should not be
35248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // able to debug shared libraries at all for them (assuming one
35348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // statically links a linker into the executable).
35448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!r_debug_->r_map || !r_debug_->r_map->l_next ||
35548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      !r_debug_->r_map->l_next->l_next) {
35648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    // Sanity check: Must have at least two items in the list.
35748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    LOG("%s: Malformed r_debug.r_map list\n", __FUNCTION__);
35848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    r_debug_ = NULL;
35948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return;
36048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
36148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
36248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  link_map_t* before = r_debug_->r_map->l_next;
36348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  link_map_t* after = before->l_next;
36448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
36548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Prepare the new entry.
36648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  entry->l_prev = before;
36748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  entry->l_next = after;
36848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
36948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // IMPORTANT: Before modifying the previous and next entries in the
37048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // list, ensure that they are writable. This avoids crashing when
37148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // updating the 'l_prev' or 'l_next' fields of a system linker entry,
37248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // which are mapped read-only.
37348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  {
37448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ScopedPageMapper mapper;
37548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (readonly_entries_)
37648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      mapper.MapReadWrite(before);
37748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    before->l_next = entry;
37848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
37948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
38048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  {
38148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ScopedPageMapper mapper;
38248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (readonly_entries_)
38348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      mapper.MapReadWrite(after);
38448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    after->l_prev = entry;
38548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
38648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
38748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Tell GDB that the list modification has completed.
38848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  r_debug_->r_state = RT_CONSISTENT;
38948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  r_debug_->r_brk();
39048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
39148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
3926788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwinvoid RDebug::DelEntryImpl(link_map_t* entry) {
3936788f450cf7ef93fe2fe0c20ec4b44a38e049bc7Simon Baldwin  LOG("%s: Deleting: %s\n", __FUNCTION__, entry->l_name);
39448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (!r_debug_)
39548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    return;
39648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
39748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Tell GDB the list is going to be modified.
39848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  r_debug_->r_state = RT_DELETE;
39948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  r_debug_->r_brk();
40048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
40148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // IMPORTANT: Before modifying the previous and next entries in the
40248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // list, ensure that they are writable. See comment above for more
40348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // details.
40448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (entry->l_prev) {
40548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ScopedPageMapper mapper;
40648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (readonly_entries_)
40748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      mapper.MapReadWrite(entry->l_prev);
40848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    entry->l_prev->l_next = entry->l_next;
40948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
41048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
41148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (entry->l_next) {
41248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    ScopedPageMapper mapper;
41348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    if (readonly_entries_)
41448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner      mapper.MapReadWrite(entry->l_next);
41548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    entry->l_next->l_prev = entry->l_prev;
41648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  }
41748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
41848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  if (r_debug_->r_map == entry)
41948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner    r_debug_->r_map = entry->l_next;
42048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
42148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  entry->l_prev = NULL;
42248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  entry->l_next = NULL;
42348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
42448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Tell GDB the list modification has completed.
42548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  r_debug_->r_state = RT_CONSISTENT;
42648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  r_debug_->r_brk();
42748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}
42848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
42948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}  // namespace crazy
430