| David Srbecky | b9cc4fb | 2019-04-05 18:23:32 +0000 | [diff] [blame] | 1 | /* | 
 | 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> | 
 | 27 | #include <unwindstack/Maps.h> | 
 | 28 | #include <unwindstack/Memory.h> | 
 | 29 |  | 
| Christopher Ferris | 456df69 | 2019-11-20 14:46:10 -0800 | [diff] [blame] | 30 | #if defined(DEXFILE_SUPPORT) | 
| David Srbecky | b9cc4fb | 2019-04-05 18:23:32 +0000 | [diff] [blame] | 31 | #include "DexFile.h" | 
| Christopher Ferris | 456df69 | 2019-11-20 14:46:10 -0800 | [diff] [blame] | 32 | #endif | 
| David Srbecky | b9cc4fb | 2019-04-05 18:23:32 +0000 | [diff] [blame] | 33 |  | 
 | 34 | namespace unwindstack { | 
 | 35 |  | 
| Christopher Ferris | 456df69 | 2019-11-20 14:46:10 -0800 | [diff] [blame] | 36 | #if !defined(DEXFILE_SUPPORT) | 
 | 37 | // Empty class definition. | 
 | 38 | class DexFile { | 
 | 39 |  public: | 
 | 40 |   DexFile() = default; | 
 | 41 |   virtual ~DexFile() = default; | 
 | 42 | }; | 
 | 43 | #endif | 
 | 44 |  | 
| David Srbecky | b9cc4fb | 2019-04-05 18:23:32 +0000 | [diff] [blame] | 45 | struct DEXFileEntry32 { | 
 | 46 |   uint32_t next; | 
 | 47 |   uint32_t prev; | 
 | 48 |   uint32_t dex_file; | 
 | 49 | }; | 
 | 50 |  | 
 | 51 | struct DEXFileEntry64 { | 
 | 52 |   uint64_t next; | 
 | 53 |   uint64_t prev; | 
 | 54 |   uint64_t dex_file; | 
 | 55 | }; | 
 | 56 |  | 
 | 57 | DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {} | 
 | 58 |  | 
 | 59 | DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs) | 
 | 60 |     : Global(memory, search_libs) {} | 
 | 61 |  | 
 | 62 | DexFiles::~DexFiles() {} | 
 | 63 |  | 
 | 64 | void DexFiles::ProcessArch() { | 
 | 65 |   switch (arch()) { | 
 | 66 |     case ARCH_ARM: | 
 | 67 |     case ARCH_MIPS: | 
 | 68 |     case ARCH_X86: | 
 | 69 |       read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32; | 
 | 70 |       read_entry_func_ = &DexFiles::ReadEntry32; | 
 | 71 |       break; | 
 | 72 |  | 
 | 73 |     case ARCH_ARM64: | 
 | 74 |     case ARCH_MIPS64: | 
 | 75 |     case ARCH_X86_64: | 
 | 76 |       read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64; | 
 | 77 |       read_entry_func_ = &DexFiles::ReadEntry64; | 
 | 78 |       break; | 
 | 79 |  | 
 | 80 |     case ARCH_UNKNOWN: | 
 | 81 |       abort(); | 
 | 82 |   } | 
 | 83 | } | 
 | 84 |  | 
 | 85 | uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) { | 
 | 86 |   uint32_t entry; | 
 | 87 |   const uint32_t field_offset = 12;  // offset of first_entry_ in the descriptor struct. | 
 | 88 |   if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) { | 
 | 89 |     return 0; | 
 | 90 |   } | 
 | 91 |   return entry; | 
 | 92 | } | 
 | 93 |  | 
 | 94 | uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) { | 
 | 95 |   uint64_t entry; | 
 | 96 |   const uint32_t field_offset = 16;  // offset of first_entry_ in the descriptor struct. | 
 | 97 |   if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) { | 
 | 98 |     return 0; | 
 | 99 |   } | 
 | 100 |   return entry; | 
 | 101 | } | 
 | 102 |  | 
 | 103 | bool DexFiles::ReadEntry32() { | 
 | 104 |   DEXFileEntry32 entry; | 
 | 105 |   if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { | 
 | 106 |     entry_addr_ = 0; | 
 | 107 |     return false; | 
 | 108 |   } | 
 | 109 |  | 
 | 110 |   addrs_.push_back(entry.dex_file); | 
 | 111 |   entry_addr_ = entry.next; | 
 | 112 |   return true; | 
 | 113 | } | 
 | 114 |  | 
 | 115 | bool DexFiles::ReadEntry64() { | 
 | 116 |   DEXFileEntry64 entry; | 
 | 117 |   if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { | 
 | 118 |     entry_addr_ = 0; | 
 | 119 |     return false; | 
 | 120 |   } | 
 | 121 |  | 
 | 122 |   addrs_.push_back(entry.dex_file); | 
 | 123 |   entry_addr_ = entry.next; | 
 | 124 |   return true; | 
 | 125 | } | 
 | 126 |  | 
 | 127 | bool DexFiles::ReadVariableData(uint64_t ptr_offset) { | 
 | 128 |   entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset); | 
 | 129 |   return entry_addr_ != 0; | 
 | 130 | } | 
 | 131 |  | 
 | 132 | void DexFiles::Init(Maps* maps) { | 
 | 133 |   if (initialized_) { | 
 | 134 |     return; | 
 | 135 |   } | 
 | 136 |   initialized_ = true; | 
 | 137 |   entry_addr_ = 0; | 
 | 138 |  | 
 | 139 |   FindAndReadVariable(maps, "__dex_debug_descriptor"); | 
 | 140 | } | 
 | 141 |  | 
| Christopher Ferris | 456df69 | 2019-11-20 14:46:10 -0800 | [diff] [blame] | 142 | #if defined(DEXFILE_SUPPORT) | 
| David Srbecky | b9cc4fb | 2019-04-05 18:23:32 +0000 | [diff] [blame] | 143 | DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { | 
 | 144 |   // Lock while processing the data. | 
 | 145 |   DexFile* dex_file; | 
 | 146 |   auto entry = files_.find(dex_file_offset); | 
 | 147 |   if (entry == files_.end()) { | 
 | 148 |     std::unique_ptr<DexFile> new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); | 
 | 149 |     dex_file = new_dex_file.get(); | 
 | 150 |     files_[dex_file_offset] = std::move(new_dex_file); | 
 | 151 |   } else { | 
 | 152 |     dex_file = entry->second.get(); | 
 | 153 |   } | 
 | 154 |   return dex_file; | 
 | 155 | } | 
| Christopher Ferris | 456df69 | 2019-11-20 14:46:10 -0800 | [diff] [blame] | 156 | #else | 
 | 157 | DexFile* DexFiles::GetDexFile(uint64_t, MapInfo*) { | 
 | 158 |   return nullptr; | 
 | 159 | } | 
 | 160 | #endif | 
| David Srbecky | b9cc4fb | 2019-04-05 18:23:32 +0000 | [diff] [blame] | 161 |  | 
 | 162 | bool DexFiles::GetAddr(size_t index, uint64_t* addr) { | 
 | 163 |   if (index < addrs_.size()) { | 
 | 164 |     *addr = addrs_[index]; | 
 | 165 |     return true; | 
 | 166 |   } | 
 | 167 |   if (entry_addr_ != 0 && (this->*read_entry_func_)()) { | 
 | 168 |     *addr = addrs_.back(); | 
 | 169 |     return true; | 
 | 170 |   } | 
 | 171 |   return false; | 
 | 172 | } | 
 | 173 |  | 
| Christopher Ferris | 456df69 | 2019-11-20 14:46:10 -0800 | [diff] [blame] | 174 | #if defined(DEXFILE_SUPPORT) | 
| David Srbecky | b9cc4fb | 2019-04-05 18:23:32 +0000 | [diff] [blame] | 175 | void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, | 
 | 176 |                                     std::string* method_name, uint64_t* method_offset) { | 
 | 177 |   std::lock_guard<std::mutex> guard(lock_); | 
 | 178 |   if (!initialized_) { | 
 | 179 |     Init(maps); | 
 | 180 |   } | 
 | 181 |  | 
 | 182 |   size_t index = 0; | 
 | 183 |   uint64_t addr; | 
 | 184 |   while (GetAddr(index++, &addr)) { | 
 | 185 |     if (addr < info->start || addr >= info->end) { | 
 | 186 |       continue; | 
 | 187 |     } | 
 | 188 |  | 
 | 189 |     DexFile* dex_file = GetDexFile(addr, info); | 
 | 190 |     if (dex_file != nullptr && | 
 | 191 |         dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) { | 
 | 192 |       break; | 
 | 193 |     } | 
 | 194 |   } | 
 | 195 | } | 
| Christopher Ferris | 456df69 | 2019-11-20 14:46:10 -0800 | [diff] [blame] | 196 | #else | 
 | 197 | void DexFiles::GetMethodInformation(Maps*, MapInfo*, uint64_t, std::string*, uint64_t*) {} | 
 | 198 | #endif | 
| David Srbecky | b9cc4fb | 2019-04-05 18:23:32 +0000 | [diff] [blame] | 199 |  | 
 | 200 | }  // namespace unwindstack |