blob: 451a0b90d57149e2c8b6c16d65af437ad4a3002f [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 Ferris56d0e072018-10-17 10:57:53 -070046DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -080047
Christopher Ferris7747b602018-01-31 19:05:19 -080048DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
Christopher Ferris56d0e072018-10-17 10:57:53 -070049 : Global(memory, search_libs) {}
Christopher Ferris7747b602018-01-31 19:05:19 -080050
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -080051DexFiles::~DexFiles() {
52 for (auto& entry : files_) {
53 delete entry.second;
54 }
55}
56
Christopher Ferris4568f4b2018-10-23 17:42:41 -070057void DexFiles::ProcessArch() {
58 switch (arch()) {
Christopher Ferris7747b602018-01-31 19:05:19 -080059 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
Christopher Ferris56d0e072018-10-17 10:57:53 -0700120bool DexFiles::ReadVariableData(uint64_t ptr_offset) {
121 entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset);
122 return entry_addr_ != 0;
123}
124
Christopher Ferris7747b602018-01-31 19:05:19 -0800125void DexFiles::Init(Maps* maps) {
126 if (initialized_) {
127 return;
128 }
129 initialized_ = true;
130 entry_addr_ = 0;
131
Christopher Ferris56d0e072018-10-17 10:57:53 -0700132 FindAndReadVariable(maps, "__dex_debug_descriptor");
Christopher Ferris7747b602018-01-31 19:05:19 -0800133}
134
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800135DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
136 // Lock while processing the data.
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800137 DexFile* dex_file;
138 auto entry = files_.find(dex_file_offset);
139 if (entry == files_.end()) {
140 dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
141 files_[dex_file_offset] = dex_file;
142 } else {
143 dex_file = entry->second;
144 }
145 return dex_file;
146}
147
Christopher Ferris7747b602018-01-31 19:05:19 -0800148bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
149 if (index < addrs_.size()) {
150 *addr = addrs_[index];
151 return true;
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800152 }
Christopher Ferris7747b602018-01-31 19:05:19 -0800153 if (entry_addr_ != 0 && (this->*read_entry_func_)()) {
154 *addr = addrs_.back();
155 return true;
156 }
157 return false;
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800158}
159
Christopher Ferris7747b602018-01-31 19:05:19 -0800160void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
161 std::string* method_name, uint64_t* method_offset) {
162 std::lock_guard<std::mutex> guard(lock_);
163 if (!initialized_) {
164 Init(maps);
165 }
166
167 size_t index = 0;
168 uint64_t addr;
169 while (GetAddr(index++, &addr)) {
170 if (addr < info->start || addr >= info->end) {
171 continue;
172 }
173
174 DexFile* dex_file = GetDexFile(addr, info);
175 if (dex_file != nullptr &&
176 dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) {
177 break;
178 }
179 }
180}
Christopher Ferrisd70ea5e2018-01-30 19:47:24 -0800181
182} // namespace unwindstack