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 
30 #if defined(DEXFILE_SUPPORT)
31 #include "DexFile.h"
32 #endif
33 
34 namespace unwindstack {
35 
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 
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 
DexFiles(std::shared_ptr<Memory> & memory)57 DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
58 
DexFiles(std::shared_ptr<Memory> & memory,std::vector<std::string> & search_libs)59 DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
60     : Global(memory, search_libs) {}
61 
~DexFiles()62 DexFiles::~DexFiles() {}
63 
ProcessArch()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 
ReadEntryPtr32(uint64_t addr)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 
ReadEntryPtr64(uint64_t addr)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 
ReadEntry32()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 
ReadEntry64()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 
ReadVariableData(uint64_t ptr_offset)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 
Init(Maps * maps)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 
142 #if defined(DEXFILE_SUPPORT)
GetDexFile(uint64_t dex_file_offset,MapInfo * info)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 }
156 #else
GetDexFile(uint64_t,MapInfo *)157 DexFile* DexFiles::GetDexFile(uint64_t, MapInfo*) {
158   return nullptr;
159 }
160 #endif
161 
GetAddr(size_t index,uint64_t * addr)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 
174 #if defined(DEXFILE_SUPPORT)
GetMethodInformation(Maps * maps,MapInfo * info,uint64_t dex_pc,std::string * method_name,uint64_t * method_offset)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 }
196 #else
GetMethodInformation(Maps *,MapInfo *,uint64_t,std::string *,uint64_t *)197 void DexFiles::GetMethodInformation(Maps*, MapInfo*, uint64_t, std::string*, uint64_t*) {}
198 #endif
199 
200 }  // namespace unwindstack
201