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