Home | History | Annotate | Download | only in malloc_debug
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <ctype.h>
     30 #include <elf.h>
     31 #include <inttypes.h>
     32 #include <link.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <sys/mman.h>
     37 
     38 #include <vector>
     39 
     40 #include "MapData.h"
     41 
     42 // Format of /proc/<PID>/maps:
     43 //   6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
     44 static MapEntry* parse_line(char* line) {
     45   uintptr_t start;
     46   uintptr_t end;
     47   uintptr_t offset;
     48   int flags;
     49   char permissions[5];
     50   int name_pos;
     51   if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start, &end,
     52              permissions, &offset, &name_pos) < 2) {
     53     return nullptr;
     54   }
     55 
     56   const char* name = line + name_pos;
     57   size_t name_len = strlen(name);
     58   if (name_len && name[name_len - 1] == '\n') {
     59     name_len -= 1;
     60   }
     61 
     62   flags = 0;
     63   if (permissions[0] == 'r') {
     64     flags |= PROT_READ;
     65   }
     66   if (permissions[2] == 'x') {
     67     flags |= PROT_EXEC;
     68   }
     69 
     70   MapEntry* entry = new MapEntry(start, end, offset, name, name_len, flags);
     71   if (!(flags & PROT_READ)) {
     72     // Any unreadable map will just get a zero load bias.
     73     entry->load_bias = 0;
     74     entry->init = true;
     75     entry->valid = false;
     76   }
     77   return entry;
     78 }
     79 
     80 template <typename T>
     81 static inline bool get_val(MapEntry* entry, uintptr_t addr, T* store) {
     82   if (!(entry->flags & PROT_READ) || addr < entry->start || addr + sizeof(T) > entry->end) {
     83     return false;
     84   }
     85   // Make sure the address is aligned properly.
     86   if (addr & (sizeof(T) - 1)) {
     87     return false;
     88   }
     89   *store = *reinterpret_cast<T*>(addr);
     90   return true;
     91 }
     92 
     93 static bool valid_elf(MapEntry* entry) {
     94   uintptr_t addr = entry->start;
     95   uintptr_t end;
     96   if (__builtin_add_overflow(addr, SELFMAG, &end) || end >= entry->end) {
     97     return false;
     98   }
     99 
    100   return memcmp(reinterpret_cast<void*>(addr), ELFMAG, SELFMAG) == 0;
    101 }
    102 
    103 static void read_loadbias(MapEntry* entry) {
    104   entry->load_bias = 0;
    105   uintptr_t addr = entry->start;
    106   ElfW(Ehdr) ehdr;
    107   if (!get_val<ElfW(Half)>(entry, addr + offsetof(ElfW(Ehdr), e_phnum), &ehdr.e_phnum)) {
    108     return;
    109   }
    110   if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Ehdr), e_phoff), &ehdr.e_phoff)) {
    111     return;
    112   }
    113   addr += ehdr.e_phoff;
    114   for (size_t i = 0; i < ehdr.e_phnum; i++) {
    115     ElfW(Phdr) phdr;
    116     if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_type), &phdr.p_type)) {
    117       return;
    118     }
    119     if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Phdr), p_offset), &phdr.p_offset)) {
    120       return;
    121     }
    122     if (phdr.p_type == PT_LOAD && phdr.p_offset == entry->offset) {
    123       if (!get_val<ElfW(Addr)>(entry, addr + offsetof(ElfW(Phdr), p_vaddr), &phdr.p_vaddr)) {
    124         return;
    125       }
    126       entry->load_bias = phdr.p_vaddr;
    127       return;
    128     }
    129     addr += sizeof(phdr);
    130   }
    131 }
    132 
    133 static void inline init(MapEntry* entry) {
    134   if (entry->init) {
    135     return;
    136   }
    137   entry->init = true;
    138   if (valid_elf(entry)) {
    139     entry->valid = true;
    140     read_loadbias(entry);
    141   }
    142 }
    143 
    144 bool MapData::ReadMaps() {
    145   FILE* fp = fopen("/proc/self/maps", "re");
    146   if (fp == nullptr) {
    147     return false;
    148   }
    149 
    150   std::vector<char> buffer(1024);
    151   while (fgets(buffer.data(), buffer.size(), fp) != nullptr) {
    152     MapEntry* entry = parse_line(buffer.data());
    153     if (entry == nullptr) {
    154       fclose(fp);
    155       return false;
    156     }
    157 
    158     auto it = entries_.find(entry);
    159     if (it == entries_.end()) {
    160       entries_.insert(entry);
    161     } else {
    162       delete entry;
    163     }
    164   }
    165   fclose(fp);
    166   return true;
    167 }
    168 
    169 MapData::~MapData() {
    170   for (auto* entry : entries_) {
    171     delete entry;
    172   }
    173   entries_.clear();
    174 }
    175 
    176 // Find the containing map info for the PC.
    177 const MapEntry* MapData::find(uintptr_t pc, uintptr_t* rel_pc) {
    178   MapEntry pc_entry(pc);
    179 
    180   std::lock_guard<std::mutex> lock(m_);
    181 
    182   auto it = entries_.find(&pc_entry);
    183   if (it == entries_.end()) {
    184     ReadMaps();
    185   }
    186   it = entries_.find(&pc_entry);
    187   if (it == entries_.end()) {
    188     return nullptr;
    189   }
    190 
    191   MapEntry* entry = *it;
    192   init(entry);
    193 
    194   if (rel_pc != nullptr) {
    195     // Need to check to see if this is a read-execute map and the read-only
    196     // map is the previous one.
    197     if (!entry->valid && it != entries_.begin()) {
    198       MapEntry* prev_entry = *--it;
    199       if (prev_entry->flags == PROT_READ && prev_entry->offset < entry->offset &&
    200           prev_entry->name == entry->name) {
    201         init(prev_entry);
    202 
    203         if (prev_entry->valid) {
    204           entry->elf_start_offset = prev_entry->offset;
    205           *rel_pc = pc - entry->start + entry->offset + prev_entry->load_bias;
    206           return entry;
    207         }
    208       }
    209     }
    210     *rel_pc = pc - entry->start + entry->load_bias;
    211   }
    212   return entry;
    213 }
    214