11e980b6bc8315d00a07312b25486531247abd98cElliott Hughes/* 21e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * Copyright (C) 2012 The Android Open Source Project 31e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * All rights reserved. 41e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * 51e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * Redistribution and use in source and binary forms, with or without 61e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * modification, are permitted provided that the following conditions 71e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * are met: 81e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * * Redistributions of source code must retain the above copyright 91e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * notice, this list of conditions and the following disclaimer. 101e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * * Redistributions in binary form must reproduce the above copyright 111e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * notice, this list of conditions and the following disclaimer in 121e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * the documentation and/or other materials provided with the 131e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * distribution. 141e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * 151e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 161e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 171e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 181e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 191e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 201e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 221e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 251e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * SUCH DAMAGE. 271e980b6bc8315d00a07312b25486531247abd98cElliott Hughes */ 281e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 29861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris#include <ctype.h> 3070b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris#include <elf.h> 31861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris#include <inttypes.h> 3263860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris#include <link.h> 331e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include <stdio.h> 341e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include <stdlib.h> 358b70a0266d42297e9b38e6209588eb3621843e95Christopher Ferris#include <string.h> 361e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 3763860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris#include <vector> 381e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 3963860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris#include "MapData.h" 4070b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris 41861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris// Format of /proc/<PID>/maps: 42861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so 4363860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferrisstatic MapEntry* parse_line(char* line) { 44861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris uintptr_t start; 45861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris uintptr_t end; 4670b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris uintptr_t offset; 47f499dc91e774db4cb9d21f9a7c34704fa9b7ed39Christopher Ferris char permissions[5]; 48861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris int name_pos; 498b70a0266d42297e9b38e6209588eb3621843e95Christopher Ferris if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start, &end, 508b70a0266d42297e9b38e6209588eb3621843e95Christopher Ferris permissions, &offset, &name_pos) < 2) { 5163860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris return nullptr; 52861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris } 531e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 54861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris const char* name = line + name_pos; 55861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris size_t name_len = strlen(name); 56861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris if (name_len && name[name_len - 1] == '\n') { 57861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris name_len -= 1; 58861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris } 591e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 6063860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris MapEntry* entry = new MapEntry(start, end, offset, name, name_len); 6163860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (permissions[0] != 'r') { 6263860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris // Any unreadable map will just get a zero load base. 6363860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris entry->load_base = 0; 6463860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris entry->load_base_read = true; 651e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 6663860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris return entry; 671e980b6bc8315d00a07312b25486531247abd98cElliott Hughes} 681e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 698b70a0266d42297e9b38e6209588eb3621843e95Christopher Ferristemplate <typename T> 7063860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferrisstatic inline bool get_val(MapEntry* entry, uintptr_t addr, T* store) { 7163860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (addr < entry->start || addr + sizeof(T) > entry->end) { 7270b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return false; 7370b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 7470b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris // Make sure the address is aligned properly. 758b70a0266d42297e9b38e6209588eb3621843e95Christopher Ferris if (addr & (sizeof(T) - 1)) { 7670b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return false; 7770b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 7870b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris *store = *reinterpret_cast<T*>(addr); 7970b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return true; 8070b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris} 8170b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris 8263860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferrisstatic void read_loadbase(MapEntry* entry) { 8363860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris entry->load_base = 0; 8463860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris entry->load_base_read = true; 8563860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris uintptr_t addr = entry->start; 8663860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris ElfW(Ehdr) ehdr; 8763860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (!get_val<ElfW(Half)>(entry, addr + offsetof(ElfW(Ehdr), e_phnum), &ehdr.e_phnum)) { 8870b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return; 8970b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 9063860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Ehdr), e_phoff), &ehdr.e_phoff)) { 9170b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return; 9270b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 9370b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris addr += ehdr.e_phoff; 9470b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris for (size_t i = 0; i < ehdr.e_phnum; i++) { 9563860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris ElfW(Phdr) phdr; 9663860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_type), &phdr.p_type)) { 9770b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return; 9870b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 9963860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Phdr), p_offset), &phdr.p_offset)) { 10070b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return; 10170b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 10263860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (phdr.p_type == PT_LOAD && phdr.p_offset == entry->offset) { 10363860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (!get_val<ElfW(Addr)>(entry, addr + offsetof(ElfW(Phdr), p_vaddr), &phdr.p_vaddr)) { 10470b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return; 10570b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 10663860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris entry->load_base = phdr.p_vaddr; 10770b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris return; 10870b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 10970b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris addr += sizeof(phdr); 11070b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris } 11170b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris} 11270b6e1daffd58ebce006d4b504cd0fb9672b6d07Christopher Ferris 113d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Crossbool MapData::ReadMaps() { 11463860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris FILE* fp = fopen("/proc/self/maps", "re"); 11563860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (fp == nullptr) { 11663860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris return false; 11763860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris } 11863860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris 11963860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris std::vector<char> buffer(1024); 12063860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris while (fgets(buffer.data(), buffer.size(), fp) != nullptr) { 12163860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris MapEntry* entry = parse_line(buffer.data()); 12263860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (entry == nullptr) { 123d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross fclose(fp); 12463860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris return false; 12563860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris } 126d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross 127d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross auto it = entries_.find(entry); 128d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross if (it == entries_.end()) { 129d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross entries_.insert(entry); 130d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross } else { 131d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross delete entry; 132d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross } 13363860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris } 13463860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris fclose(fp); 13563860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris return true; 13663860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris} 13763860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris 13863860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher FerrisMapData::~MapData() { 13963860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris for (auto* entry : entries_) { 14063860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris delete entry; 14163860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris } 14263860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris entries_.clear(); 14363860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris} 14463860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris 1451e980b6bc8315d00a07312b25486531247abd98cElliott Hughes// Find the containing map info for the PC. 14663860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferrisconst MapEntry* MapData::find(uintptr_t pc, uintptr_t* rel_pc) { 147d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross MapEntry pc_entry(pc); 148d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross 149d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross std::lock_guard<std::mutex> lock(m_); 150d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross 151d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross auto it = entries_.find(&pc_entry); 152d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross if (it == entries_.end()) { 153d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross ReadMaps(); 154d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross } 155d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross it = entries_.find(&pc_entry); 156d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross if (it == entries_.end()) { 157d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross return nullptr; 158d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross } 159d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross 1608b70a0266d42297e9b38e6209588eb3621843e95Christopher Ferris MapEntry* entry = *it; 161d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross if (!entry->load_base_read) { 162d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross read_loadbase(entry); 1631e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 16463860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris if (rel_pc) { 165d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross *rel_pc = pc - entry->start + entry->load_base; 16663860cb8fd1adf3f679b9b4ad876323a8d65cd9dChristopher Ferris } 167d75d4bea54a788dada3f2538a33cc491e4c56ed4Colin Cross return entry; 1681e980b6bc8315d00a07312b25486531247abd98cElliott Hughes} 169