blob: 430f6c58061859a9b51e9cdf43e3be85db5a2c98 [file] [log] [blame]
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdint.h>
18#include <sys/mman.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <unistd.h>
22
23#include <memory>
24
25#include <unwindstack/DexFiles.h>
26#include <unwindstack/MapInfo.h>
Christopher Ferris7747b602018-01-31 19:05:19 -080027#include <unwindstack/Maps.h>
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -080028#include <unwindstack/Memory.h>
29
30#include "DexFile.h"
31
32namespace unwindstack {
33
Christopher Ferris7747b602018-01-31 19:05:19 -080034struct DEXFileEntry32 {
35 uint32_t next;
36 uint32_t prev;
37 uint32_t dex_file;
38};
39
40struct DEXFileEntry64 {
41 uint64_t next;
42 uint64_t prev;
43 uint64_t dex_file;
44};
45
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -080046DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
47
Christopher Ferris7747b602018-01-31 19:05:19 -080048DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
49 : memory_(memory), search_libs_(search_libs) {}
50
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -080051DexFiles::~DexFiles() {
52 for (auto& entry : files_) {
53 delete entry.second;
54 }
55}
56
Christopher Ferris7747b602018-01-31 19:05:19 -080057void DexFiles::SetArch(ArchEnum arch) {
58 switch (arch) {
59 case ARCH_ARM:
60 case ARCH_MIPS:
61 case ARCH_X86:
62 read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32;
63 read_entry_func_ = &DexFiles::ReadEntry32;
64 break;
65
66 case ARCH_ARM64:
67 case ARCH_MIPS64:
68 case ARCH_X86_64:
69 read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64;
70 read_entry_func_ = &DexFiles::ReadEntry64;
71 break;
72
73 case ARCH_UNKNOWN:
74 abort();
75 }
76}
77
78uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) {
79 uint32_t entry;
David Srbecky4015ef42018-02-15 17:57:16 +000080 const uint32_t field_offset = 12; // offset of first_entry_ in the descriptor struct.
81 if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
Christopher Ferris7747b602018-01-31 19:05:19 -080082 return 0;
83 }
84 return entry;
85}
86
87uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
88 uint64_t entry;
David Srbecky4015ef42018-02-15 17:57:16 +000089 const uint32_t field_offset = 16; // offset of first_entry_ in the descriptor struct.
90 if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
Christopher Ferris7747b602018-01-31 19:05:19 -080091 return 0;
92 }
93 return entry;
94}
95
96bool DexFiles::ReadEntry32() {
97 DEXFileEntry32 entry;
98 if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
99 entry_addr_ = 0;
100 return false;
101 }
102
103 addrs_.push_back(entry.dex_file);
104 entry_addr_ = entry.next;
105 return true;
106}
107
108bool DexFiles::ReadEntry64() {
109 DEXFileEntry64 entry;
110 if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
111 entry_addr_ = 0;
112 return false;
113 }
114
115 addrs_.push_back(entry.dex_file);
116 entry_addr_ = entry.next;
117 return true;
118}
119
120void DexFiles::Init(Maps* maps) {
121 if (initialized_) {
122 return;
123 }
124 initialized_ = true;
125 entry_addr_ = 0;
126
David Srbecky4015ef42018-02-15 17:57:16 +0000127 const std::string dex_debug_name("__dex_debug_descriptor");
Christopher Ferris7747b602018-01-31 19:05:19 -0800128 for (MapInfo* info : *maps) {
129 if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
130 continue;
131 }
132
133 if (!search_libs_.empty()) {
134 bool found = false;
135 const char* lib = basename(info->name.c_str());
136 for (const std::string& name : search_libs_) {
137 if (name == lib) {
138 found = true;
139 break;
140 }
141 }
142 if (!found) {
143 continue;
144 }
145 }
146
147 Elf* elf = info->GetElf(memory_, true);
148 uint64_t ptr;
149 // Find first non-empty list (libart might be loaded multiple times).
150 if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) {
151 entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start);
152 if (entry_addr_ != 0) {
153 break;
154 }
155 }
156 }
157}
158
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800159DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
160 // Lock while processing the data.
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800161 DexFile* dex_file;
162 auto entry = files_.find(dex_file_offset);
163 if (entry == files_.end()) {
164 dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
165 files_[dex_file_offset] = dex_file;
166 } else {
167 dex_file = entry->second;
168 }
169 return dex_file;
170}
171
Christopher Ferris7747b602018-01-31 19:05:19 -0800172bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
173 if (index < addrs_.size()) {
174 *addr = addrs_[index];
175 return true;
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800176 }
Christopher Ferris7747b602018-01-31 19:05:19 -0800177 if (entry_addr_ != 0 && (this->*read_entry_func_)()) {
178 *addr = addrs_.back();
179 return true;
180 }
181 return false;
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800182}
183
Christopher Ferris7747b602018-01-31 19:05:19 -0800184void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
185 std::string* method_name, uint64_t* method_offset) {
186 std::lock_guard<std::mutex> guard(lock_);
187 if (!initialized_) {
188 Init(maps);
189 }
190
191 size_t index = 0;
192 uint64_t addr;
193 while (GetAddr(index++, &addr)) {
194 if (addr < info->start || addr >= info->end) {
195 continue;
196 }
197
198 DexFile* dex_file = GetDexFile(addr, info);
199 if (dex_file != nullptr &&
200 dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) {
201 break;
202 }
203 }
204}
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800205
206} // namespace unwindstack