1 /* 2 * Copyright (C) 2017 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 19 #include <unwindstack/DwarfError.h> 20 #include <unwindstack/DwarfStructs.h> 21 #include <unwindstack/Memory.h> 22 23 #include "Check.h" 24 #include "DwarfEhFrameWithHdr.h" 25 26 namespace unwindstack { 27 28 template <typename AddressType> 29 bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size) { 30 uint8_t data[4]; 31 32 memory_.clear_func_offset(); 33 memory_.clear_text_offset(); 34 memory_.set_data_offset(offset); 35 memory_.set_cur_offset(offset); 36 37 // Read the first four bytes all at once. 38 if (!memory_.ReadBytes(data, 4)) { 39 last_error_.code = DWARF_ERROR_MEMORY_INVALID; 40 last_error_.address = memory_.cur_offset(); 41 return false; 42 } 43 44 version_ = data[0]; 45 if (version_ != 1) { 46 // Unknown version. 47 last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION; 48 return false; 49 } 50 51 ptr_encoding_ = data[1]; 52 uint8_t fde_count_encoding = data[2]; 53 table_encoding_ = data[3]; 54 table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_); 55 56 memory_.set_pc_offset(memory_.cur_offset()); 57 if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) { 58 last_error_.code = DWARF_ERROR_MEMORY_INVALID; 59 last_error_.address = memory_.cur_offset(); 60 return false; 61 } 62 63 memory_.set_pc_offset(memory_.cur_offset()); 64 if (!memory_.template ReadEncodedValue<AddressType>(fde_count_encoding, &fde_count_)) { 65 last_error_.code = DWARF_ERROR_MEMORY_INVALID; 66 last_error_.address = memory_.cur_offset(); 67 return false; 68 } 69 70 if (fde_count_ == 0) { 71 last_error_.code = DWARF_ERROR_NO_FDES; 72 return false; 73 } 74 75 entries_offset_ = memory_.cur_offset(); 76 entries_end_ = offset + size; 77 entries_data_offset_ = offset; 78 cur_entries_offset_ = entries_offset_; 79 80 return true; 81 } 82 83 template <typename AddressType> 84 const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromIndex(size_t index) { 85 const FdeInfo* info = GetFdeInfoFromIndex(index); 86 if (info == nullptr) { 87 return nullptr; 88 } 89 return this->GetFdeFromOffset(info->offset); 90 } 91 92 template <typename AddressType> 93 const typename DwarfEhFrameWithHdr<AddressType>::FdeInfo* 94 DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) { 95 auto entry = fde_info_.find(index); 96 if (entry != fde_info_.end()) { 97 return &fde_info_[index]; 98 } 99 FdeInfo* info = &fde_info_[index]; 100 101 memory_.set_data_offset(entries_data_offset_); 102 memory_.set_cur_offset(entries_offset_ + 2 * index * table_entry_size_); 103 memory_.set_pc_offset(memory_.cur_offset()); 104 uint64_t value; 105 if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) || 106 !memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) { 107 last_error_.code = DWARF_ERROR_MEMORY_INVALID; 108 last_error_.address = memory_.cur_offset(); 109 fde_info_.erase(index); 110 return nullptr; 111 } 112 info->pc = value; 113 return info; 114 } 115 116 template <typename AddressType> 117 bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, 118 uint64_t total_entries) { 119 CHECK(fde_count_ > 0); 120 CHECK(total_entries <= fde_count_); 121 122 size_t first = 0; 123 size_t last = total_entries; 124 while (first < last) { 125 size_t current = (first + last) / 2; 126 const FdeInfo* info = GetFdeInfoFromIndex(current); 127 if (info == nullptr) { 128 return false; 129 } 130 if (pc == info->pc) { 131 *fde_offset = info->offset; 132 return true; 133 } 134 if (pc < info->pc) { 135 last = current; 136 } else { 137 first = current + 1; 138 } 139 } 140 if (last != 0) { 141 const FdeInfo* info = GetFdeInfoFromIndex(last - 1); 142 if (info == nullptr) { 143 return false; 144 } 145 *fde_offset = info->offset; 146 return true; 147 } 148 return false; 149 } 150 151 template <typename AddressType> 152 bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) { 153 CHECK(fde_count_ != 0); 154 last_error_.code = DWARF_ERROR_NONE; 155 last_error_.address = 0; 156 157 // We can do a binary search if the pc is in the range of the elements 158 // that have already been cached. 159 if (!fde_info_.empty()) { 160 const FdeInfo* info = &fde_info_[fde_info_.size() - 1]; 161 if (pc >= info->pc) { 162 *fde_offset = info->offset; 163 return true; 164 } 165 if (pc < info->pc) { 166 return GetFdeOffsetBinary(pc, fde_offset, fde_info_.size()); 167 } 168 } 169 170 if (cur_entries_offset_ == 0) { 171 // All entries read, or error encountered. 172 return false; 173 } 174 175 memory_.set_data_offset(entries_data_offset_); 176 memory_.set_cur_offset(cur_entries_offset_); 177 cur_entries_offset_ = 0; 178 179 FdeInfo* prev_info = nullptr; 180 for (size_t current = fde_info_.size(); 181 current < fde_count_ && memory_.cur_offset() < entries_end_; current++) { 182 memory_.set_pc_offset(memory_.cur_offset()); 183 uint64_t value; 184 if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value)) { 185 last_error_.code = DWARF_ERROR_MEMORY_INVALID; 186 last_error_.address = memory_.cur_offset(); 187 return false; 188 } 189 190 FdeInfo* info = &fde_info_[current]; 191 if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) { 192 fde_info_.erase(current); 193 last_error_.code = DWARF_ERROR_MEMORY_INVALID; 194 last_error_.address = memory_.cur_offset(); 195 return false; 196 } 197 info->pc = value + 4; 198 199 if (pc < info->pc) { 200 if (prev_info == nullptr) { 201 return false; 202 } 203 cur_entries_offset_ = memory_.cur_offset(); 204 *fde_offset = prev_info->offset; 205 return true; 206 } 207 prev_info = info; 208 } 209 210 if (fde_count_ == fde_info_.size() && pc >= prev_info->pc) { 211 *fde_offset = prev_info->offset; 212 return true; 213 } 214 return false; 215 } 216 217 template <typename AddressType> 218 bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) { 219 if (fde_count_ == 0) { 220 return false; 221 } 222 223 if (table_entry_size_ > 0) { 224 // Do a binary search since the size of each table entry is fixed. 225 return GetFdeOffsetBinary(pc, fde_offset, fde_count_); 226 } else { 227 // Do a sequential search since each table entry size is variable. 228 return GetFdeOffsetSequential(pc, fde_offset); 229 } 230 } 231 232 // Explicitly instantiate DwarfEhFrameWithHdr 233 template class DwarfEhFrameWithHdr<uint32_t>; 234 template class DwarfEhFrameWithHdr<uint64_t>; 235 236 } // namespace unwindstack 237