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 <string.h>
     35 #include <stdlib.h>
     36 
     37 #include <vector>
     38 
     39 #include "MapData.h"
     40 
     41 // Format of /proc/<PID>/maps:
     42 //   6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
     43 static MapEntry* parse_line(char* line) {
     44   uintptr_t start;
     45   uintptr_t end;
     46   uintptr_t offset;
     47   char permissions[5];
     48   int name_pos;
     49   if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start,
     50              &end, permissions, &offset, &name_pos) < 2) {
     51     return nullptr;
     52   }
     53 
     54   const char* name = line + name_pos;
     55   size_t name_len = strlen(name);
     56   if (name_len && name[name_len - 1] == '\n') {
     57     name_len -= 1;
     58   }
     59 
     60   MapEntry* entry = new MapEntry(start, end, offset, name, name_len);
     61   if (permissions[0] != 'r') {
     62     // Any unreadable map will just get a zero load base.
     63     entry->load_base = 0;
     64     entry->load_base_read = true;
     65   }
     66   return entry;
     67 }
     68 
     69 template<typename T>
     70 static inline bool get_val(MapEntry* entry, uintptr_t addr, T* store) {
     71   if (addr < entry->start || addr + sizeof(T) > entry->end) {
     72     return false;
     73   }
     74   // Make sure the address is aligned properly.
     75   if (addr & (sizeof(T)-1)) {
     76     return false;
     77   }
     78   *store = *reinterpret_cast<T*>(addr);
     79   return true;
     80 }
     81 
     82 static void read_loadbase(MapEntry* entry) {
     83   entry->load_base = 0;
     84   entry->load_base_read = true;
     85   uintptr_t addr = entry->start;
     86   ElfW(Ehdr) ehdr;
     87   if (!get_val<ElfW(Half)>(entry, addr + offsetof(ElfW(Ehdr), e_phnum), &ehdr.e_phnum)) {
     88     return;
     89   }
     90   if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Ehdr), e_phoff), &ehdr.e_phoff)) {
     91     return;
     92   }
     93   addr += ehdr.e_phoff;
     94   for (size_t i = 0; i < ehdr.e_phnum; i++) {
     95     ElfW(Phdr) phdr;
     96     if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_type), &phdr.p_type)) {
     97       return;
     98     }
     99     if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Phdr), p_offset), &phdr.p_offset)) {
    100       return;
    101     }
    102     if (phdr.p_type == PT_LOAD && phdr.p_offset == entry->offset) {
    103       if (!get_val<ElfW(Addr)>(entry, addr + offsetof(ElfW(Phdr), p_vaddr), &phdr.p_vaddr)) {
    104         return;
    105       }
    106       entry->load_base = phdr.p_vaddr;
    107       return;
    108     }
    109     addr += sizeof(phdr);
    110   }
    111 }
    112 
    113 bool MapData::ReadMaps() {
    114   FILE* fp = fopen("/proc/self/maps", "re");
    115   if (fp == nullptr) {
    116     return false;
    117   }
    118 
    119   std::vector<char> buffer(1024);
    120   while (fgets(buffer.data(), buffer.size(), fp) != nullptr) {
    121     MapEntry* entry = parse_line(buffer.data());
    122     if (entry == nullptr) {
    123       fclose(fp);
    124       return false;
    125     }
    126 
    127     auto it = entries_.find(entry);
    128     if (it == entries_.end()) {
    129       entries_.insert(entry);
    130     } else {
    131       delete entry;
    132     }
    133   }
    134   fclose(fp);
    135   return true;
    136 }
    137 
    138 MapData::~MapData() {
    139   for (auto* entry : entries_) {
    140     delete entry;
    141   }
    142   entries_.clear();
    143 }
    144 
    145 // Find the containing map info for the PC.
    146 const MapEntry* MapData::find(uintptr_t pc, uintptr_t* rel_pc) {
    147   MapEntry pc_entry(pc);
    148 
    149   std::lock_guard<std::mutex> lock(m_);
    150 
    151   auto it = entries_.find(&pc_entry);
    152   if (it == entries_.end()) {
    153     ReadMaps();
    154   }
    155   it = entries_.find(&pc_entry);
    156   if (it == entries_.end()) {
    157     return nullptr;
    158   }
    159 
    160   MapEntry *entry = *it;
    161   if (!entry->load_base_read) {
    162     read_loadbase(entry);
    163   }
    164   if (rel_pc) {
    165     *rel_pc = pc - entry->start + entry->load_base;
    166   }
    167   return entry;
    168 }
    169