blob: e8fbc5401a3a657a34057ed0030ce4c0c544f3f8 [file] [log] [blame]
Christopher Ferris63860cb2015-11-16 17:30:32 -08001/*
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>
Christopher Ferris63860cb2015-11-16 17:30:32 -080034#include <stdlib.h>
Christopher Ferris4da25032018-03-07 13:38:48 -080035#include <string.h>
Christopher Ferrisb233fab2018-12-18 16:44:42 -080036#include <sys/mman.h>
Christopher Ferris63860cb2015-11-16 17:30:32 -080037
38#include <vector>
39
Christopher Ferris63860cb2015-11-16 17:30:32 -080040#include "MapData.h"
41
42// Format of /proc/<PID>/maps:
43// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
44static MapEntry* parse_line(char* line) {
45 uintptr_t start;
46 uintptr_t end;
47 uintptr_t offset;
Christopher Ferrisb233fab2018-12-18 16:44:42 -080048 int flags;
Christopher Ferrisf499dc92016-02-19 18:13:29 -080049 char permissions[5];
Christopher Ferris63860cb2015-11-16 17:30:32 -080050 int name_pos;
Christopher Ferris4da25032018-03-07 13:38:48 -080051 if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start, &end,
52 permissions, &offset, &name_pos) < 2) {
Christopher Ferris63860cb2015-11-16 17:30:32 -080053 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
Christopher Ferrisb233fab2018-12-18 16:44:42 -080062 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;
Christopher Ferris63860cb2015-11-16 17:30:32 -080076 }
77 return entry;
78}
79
Christopher Ferris4da25032018-03-07 13:38:48 -080080template <typename T>
Christopher Ferris63860cb2015-11-16 17:30:32 -080081static inline bool get_val(MapEntry* entry, uintptr_t addr, T* store) {
Christopher Ferrisb233fab2018-12-18 16:44:42 -080082 if (!(entry->flags & PROT_READ) || addr < entry->start || addr + sizeof(T) > entry->end) {
Christopher Ferris63860cb2015-11-16 17:30:32 -080083 return false;
84 }
85 // Make sure the address is aligned properly.
Christopher Ferris4da25032018-03-07 13:38:48 -080086 if (addr & (sizeof(T) - 1)) {
Christopher Ferris63860cb2015-11-16 17:30:32 -080087 return false;
88 }
89 *store = *reinterpret_cast<T*>(addr);
90 return true;
91}
92
Christopher Ferrisb233fab2018-12-18 16:44:42 -080093static 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
103static void read_loadbias(MapEntry* entry) {
104 entry->load_bias = 0;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800105 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 }
Christopher Ferrisb233fab2018-12-18 16:44:42 -0800126 entry->load_bias = phdr.p_vaddr;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800127 return;
128 }
129 addr += sizeof(phdr);
130 }
131}
132
Christopher Ferrisb233fab2018-12-18 16:44:42 -0800133static 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
Colin Crossd75d4be2016-02-08 14:29:03 -0800144bool MapData::ReadMaps() {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800145 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) {
Colin Crossd75d4be2016-02-08 14:29:03 -0800154 fclose(fp);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800155 return false;
156 }
Colin Crossd75d4be2016-02-08 14:29:03 -0800157
158 auto it = entries_.find(entry);
159 if (it == entries_.end()) {
160 entries_.insert(entry);
161 } else {
162 delete entry;
163 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800164 }
165 fclose(fp);
166 return true;
167}
168
Christopher Ferris63860cb2015-11-16 17:30:32 -0800169MapData::~MapData() {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800170 for (auto* entry : entries_) {
171 delete entry;
172 }
173 entries_.clear();
174}
175
176// Find the containing map info for the PC.
177const MapEntry* MapData::find(uintptr_t pc, uintptr_t* rel_pc) {
Colin Crossd75d4be2016-02-08 14:29:03 -0800178 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
Christopher Ferris4da25032018-03-07 13:38:48 -0800191 MapEntry* entry = *it;
Christopher Ferrisb233fab2018-12-18 16:44:42 -0800192 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;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800211 }
Colin Crossd75d4be2016-02-08 14:29:03 -0800212 return entry;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800213}