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
parse_line(char * line)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>
get_val(MapEntry * entry,uintptr_t addr,T * store)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
valid_elf(MapEntry * entry)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
read_loadbias(MapEntry * entry)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
init(MapEntry * entry)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
ReadMaps()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
~MapData()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.
find(uintptr_t pc,uintptr_t * rel_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