| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 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 |  | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 19 | #include <unwindstack/DwarfError.h> | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 20 | #include <unwindstack/DwarfLocation.h> | 
 | 21 | #include <unwindstack/DwarfMemory.h> | 
 | 22 | #include <unwindstack/DwarfSection.h> | 
 | 23 | #include <unwindstack/DwarfStructs.h> | 
 | 24 | #include <unwindstack/Log.h> | 
 | 25 | #include <unwindstack/Memory.h> | 
 | 26 | #include <unwindstack/Regs.h> | 
 | 27 |  | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 28 | #include "DwarfCfa.h" | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 29 | #include "DwarfDebugFrame.h" | 
 | 30 | #include "DwarfEhFrame.h" | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 31 | #include "DwarfEncoding.h" | 
 | 32 | #include "DwarfOp.h" | 
 | 33 | #include "RegsInfo.h" | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 34 |  | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 35 | namespace unwindstack { | 
 | 36 |  | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 37 | DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {} | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 38 |  | 
| Christopher Ferris | b9de87f | 2017-09-20 13:37:24 -0700 | [diff] [blame] | 39 | bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) { | 
| David Srbecky | 3386eba | 2018-03-14 21:30:25 +0000 | [diff] [blame] | 40 |   // Lookup the pc in the cache. | 
 | 41 |   auto it = loc_regs_.upper_bound(pc); | 
 | 42 |   if (it == loc_regs_.end() || pc < it->second.pc_start) { | 
 | 43 |     last_error_.code = DWARF_ERROR_NONE; | 
 | 44 |     const DwarfFde* fde = GetFdeFromPc(pc); | 
 | 45 |     if (fde == nullptr || fde->cie == nullptr) { | 
 | 46 |       last_error_.code = DWARF_ERROR_ILLEGAL_STATE; | 
 | 47 |       return false; | 
 | 48 |     } | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 49 |  | 
| David Srbecky | 3386eba | 2018-03-14 21:30:25 +0000 | [diff] [blame] | 50 |     // Now get the location information for this pc. | 
 | 51 |     dwarf_loc_regs_t loc_regs; | 
 | 52 |     if (!GetCfaLocationInfo(pc, fde, &loc_regs)) { | 
 | 53 |       return false; | 
 | 54 |     } | 
 | 55 |     loc_regs.cie = fde->cie; | 
 | 56 |  | 
 | 57 |     // Store it in the cache. | 
 | 58 |     it = loc_regs_.emplace(loc_regs.pc_end, std::move(loc_regs)).first; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 59 |   } | 
 | 60 |  | 
 | 61 |   // Now eval the actual registers. | 
| David Srbecky | 3386eba | 2018-03-14 21:30:25 +0000 | [diff] [blame] | 62 |   return Eval(it->second.cie, process_memory, it->second, regs, finished); | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 63 | } | 
 | 64 |  | 
 | 65 | template <typename AddressType> | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 66 | const DwarfCie* DwarfSectionImpl<AddressType>::GetCieFromOffset(uint64_t offset) { | 
 | 67 |   auto cie_entry = cie_entries_.find(offset); | 
 | 68 |   if (cie_entry != cie_entries_.end()) { | 
 | 69 |     return &cie_entry->second; | 
 | 70 |   } | 
 | 71 |   DwarfCie* cie = &cie_entries_[offset]; | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 72 |   memory_.set_data_offset(entries_offset_); | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 73 |   memory_.set_cur_offset(offset); | 
 | 74 |   if (!FillInCieHeader(cie) || !FillInCie(cie)) { | 
 | 75 |     // Erase the cached entry. | 
 | 76 |     cie_entries_.erase(offset); | 
 | 77 |     return nullptr; | 
 | 78 |   } | 
 | 79 |   return cie; | 
 | 80 | } | 
 | 81 |  | 
 | 82 | template <typename AddressType> | 
 | 83 | bool DwarfSectionImpl<AddressType>::FillInCieHeader(DwarfCie* cie) { | 
 | 84 |   cie->lsda_encoding = DW_EH_PE_omit; | 
 | 85 |   uint32_t length32; | 
 | 86 |   if (!memory_.ReadBytes(&length32, sizeof(length32))) { | 
 | 87 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 88 |     last_error_.address = memory_.cur_offset(); | 
 | 89 |     return false; | 
 | 90 |   } | 
 | 91 |   if (length32 == static_cast<uint32_t>(-1)) { | 
 | 92 |     // 64 bit Cie | 
 | 93 |     uint64_t length64; | 
 | 94 |     if (!memory_.ReadBytes(&length64, sizeof(length64))) { | 
 | 95 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 96 |       last_error_.address = memory_.cur_offset(); | 
 | 97 |       return false; | 
 | 98 |     } | 
 | 99 |  | 
 | 100 |     cie->cfa_instructions_end = memory_.cur_offset() + length64; | 
 | 101 |     cie->fde_address_encoding = DW_EH_PE_sdata8; | 
 | 102 |  | 
 | 103 |     uint64_t cie_id; | 
 | 104 |     if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) { | 
 | 105 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 106 |       last_error_.address = memory_.cur_offset(); | 
 | 107 |       return false; | 
 | 108 |     } | 
 | 109 |     if (cie_id != cie64_value_) { | 
 | 110 |       // This is not a Cie, something has gone horribly wrong. | 
 | 111 |       last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
 | 112 |       return false; | 
 | 113 |     } | 
 | 114 |   } else { | 
 | 115 |     // 32 bit Cie | 
 | 116 |     cie->cfa_instructions_end = memory_.cur_offset() + length32; | 
 | 117 |     cie->fde_address_encoding = DW_EH_PE_sdata4; | 
 | 118 |  | 
 | 119 |     uint32_t cie_id; | 
 | 120 |     if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) { | 
 | 121 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 122 |       last_error_.address = memory_.cur_offset(); | 
 | 123 |       return false; | 
 | 124 |     } | 
 | 125 |     if (cie_id != cie32_value_) { | 
 | 126 |       // This is not a Cie, something has gone horribly wrong. | 
 | 127 |       last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
 | 128 |       return false; | 
 | 129 |     } | 
 | 130 |   } | 
 | 131 |   return true; | 
 | 132 | } | 
 | 133 |  | 
 | 134 | template <typename AddressType> | 
 | 135 | bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) { | 
 | 136 |   if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) { | 
 | 137 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 138 |     last_error_.address = memory_.cur_offset(); | 
 | 139 |     return false; | 
 | 140 |   } | 
 | 141 |  | 
| Christopher Ferris | c312c9a | 2019-04-01 16:53:56 -0700 | [diff] [blame] | 142 |   if (cie->version != 1 && cie->version != 3 && cie->version != 4 && cie->version != 5) { | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 143 |     // Unrecognized version. | 
 | 144 |     last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION; | 
 | 145 |     return false; | 
 | 146 |   } | 
 | 147 |  | 
 | 148 |   // Read the augmentation string. | 
 | 149 |   char aug_value; | 
 | 150 |   do { | 
 | 151 |     if (!memory_.ReadBytes(&aug_value, 1)) { | 
 | 152 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 153 |       last_error_.address = memory_.cur_offset(); | 
 | 154 |       return false; | 
 | 155 |     } | 
 | 156 |     cie->augmentation_string.push_back(aug_value); | 
 | 157 |   } while (aug_value != '\0'); | 
 | 158 |  | 
| Christopher Ferris | c312c9a | 2019-04-01 16:53:56 -0700 | [diff] [blame] | 159 |   if (cie->version == 4 || cie->version == 5) { | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 160 |     // Skip the Address Size field since we only use it for validation. | 
 | 161 |     memory_.set_cur_offset(memory_.cur_offset() + 1); | 
 | 162 |  | 
 | 163 |     // Segment Size | 
 | 164 |     if (!memory_.ReadBytes(&cie->segment_size, 1)) { | 
 | 165 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 166 |       last_error_.address = memory_.cur_offset(); | 
 | 167 |       return false; | 
 | 168 |     } | 
 | 169 |   } | 
 | 170 |  | 
 | 171 |   // Code Alignment Factor | 
 | 172 |   if (!memory_.ReadULEB128(&cie->code_alignment_factor)) { | 
 | 173 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 174 |     last_error_.address = memory_.cur_offset(); | 
 | 175 |     return false; | 
 | 176 |   } | 
 | 177 |  | 
 | 178 |   // Data Alignment Factor | 
 | 179 |   if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) { | 
 | 180 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 181 |     last_error_.address = memory_.cur_offset(); | 
 | 182 |     return false; | 
 | 183 |   } | 
 | 184 |  | 
 | 185 |   if (cie->version == 1) { | 
 | 186 |     // Return Address is a single byte. | 
 | 187 |     uint8_t return_address_register; | 
 | 188 |     if (!memory_.ReadBytes(&return_address_register, 1)) { | 
 | 189 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 190 |       last_error_.address = memory_.cur_offset(); | 
 | 191 |       return false; | 
 | 192 |     } | 
 | 193 |     cie->return_address_register = return_address_register; | 
 | 194 |   } else if (!memory_.ReadULEB128(&cie->return_address_register)) { | 
 | 195 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 196 |     last_error_.address = memory_.cur_offset(); | 
 | 197 |     return false; | 
 | 198 |   } | 
 | 199 |  | 
 | 200 |   if (cie->augmentation_string[0] != 'z') { | 
 | 201 |     cie->cfa_instructions_offset = memory_.cur_offset(); | 
 | 202 |     return true; | 
 | 203 |   } | 
 | 204 |  | 
 | 205 |   uint64_t aug_length; | 
 | 206 |   if (!memory_.ReadULEB128(&aug_length)) { | 
 | 207 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 208 |     last_error_.address = memory_.cur_offset(); | 
 | 209 |     return false; | 
 | 210 |   } | 
 | 211 |   cie->cfa_instructions_offset = memory_.cur_offset() + aug_length; | 
 | 212 |  | 
 | 213 |   for (size_t i = 1; i < cie->augmentation_string.size(); i++) { | 
 | 214 |     switch (cie->augmentation_string[i]) { | 
 | 215 |       case 'L': | 
 | 216 |         if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) { | 
 | 217 |           last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 218 |           last_error_.address = memory_.cur_offset(); | 
 | 219 |           return false; | 
 | 220 |         } | 
 | 221 |         break; | 
 | 222 |       case 'P': { | 
 | 223 |         uint8_t encoding; | 
 | 224 |         if (!memory_.ReadBytes(&encoding, 1)) { | 
 | 225 |           last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 226 |           last_error_.address = memory_.cur_offset(); | 
 | 227 |           return false; | 
 | 228 |         } | 
 | 229 |         memory_.set_pc_offset(pc_offset_); | 
 | 230 |         if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) { | 
 | 231 |           last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 232 |           last_error_.address = memory_.cur_offset(); | 
 | 233 |           return false; | 
 | 234 |         } | 
 | 235 |       } break; | 
 | 236 |       case 'R': | 
 | 237 |         if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) { | 
 | 238 |           last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 239 |           last_error_.address = memory_.cur_offset(); | 
 | 240 |           return false; | 
 | 241 |         } | 
 | 242 |         break; | 
 | 243 |     } | 
 | 244 |   } | 
 | 245 |   return true; | 
 | 246 | } | 
 | 247 |  | 
 | 248 | template <typename AddressType> | 
 | 249 | const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) { | 
 | 250 |   auto fde_entry = fde_entries_.find(offset); | 
 | 251 |   if (fde_entry != fde_entries_.end()) { | 
 | 252 |     return &fde_entry->second; | 
 | 253 |   } | 
 | 254 |   DwarfFde* fde = &fde_entries_[offset]; | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 255 |   memory_.set_data_offset(entries_offset_); | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 256 |   memory_.set_cur_offset(offset); | 
 | 257 |   if (!FillInFdeHeader(fde) || !FillInFde(fde)) { | 
 | 258 |     fde_entries_.erase(offset); | 
 | 259 |     return nullptr; | 
 | 260 |   } | 
 | 261 |   return fde; | 
 | 262 | } | 
 | 263 |  | 
 | 264 | template <typename AddressType> | 
 | 265 | bool DwarfSectionImpl<AddressType>::FillInFdeHeader(DwarfFde* fde) { | 
 | 266 |   uint32_t length32; | 
 | 267 |   if (!memory_.ReadBytes(&length32, sizeof(length32))) { | 
 | 268 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 269 |     last_error_.address = memory_.cur_offset(); | 
 | 270 |     return false; | 
 | 271 |   } | 
 | 272 |  | 
 | 273 |   if (length32 == static_cast<uint32_t>(-1)) { | 
 | 274 |     // 64 bit Fde. | 
 | 275 |     uint64_t length64; | 
 | 276 |     if (!memory_.ReadBytes(&length64, sizeof(length64))) { | 
 | 277 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 278 |       last_error_.address = memory_.cur_offset(); | 
 | 279 |       return false; | 
 | 280 |     } | 
 | 281 |     fde->cfa_instructions_end = memory_.cur_offset() + length64; | 
 | 282 |  | 
 | 283 |     uint64_t value64; | 
 | 284 |     if (!memory_.ReadBytes(&value64, sizeof(value64))) { | 
 | 285 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 286 |       last_error_.address = memory_.cur_offset(); | 
 | 287 |       return false; | 
 | 288 |     } | 
 | 289 |     if (value64 == cie64_value_) { | 
 | 290 |       // This is a Cie, this means something has gone wrong. | 
 | 291 |       last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
 | 292 |       return false; | 
 | 293 |     } | 
 | 294 |  | 
 | 295 |     // Get the Cie pointer, which is necessary to properly read the rest of | 
 | 296 |     // of the Fde information. | 
 | 297 |     fde->cie_offset = GetCieOffsetFromFde64(value64); | 
 | 298 |   } else { | 
 | 299 |     // 32 bit Fde. | 
 | 300 |     fde->cfa_instructions_end = memory_.cur_offset() + length32; | 
 | 301 |  | 
 | 302 |     uint32_t value32; | 
 | 303 |     if (!memory_.ReadBytes(&value32, sizeof(value32))) { | 
 | 304 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 305 |       last_error_.address = memory_.cur_offset(); | 
 | 306 |       return false; | 
 | 307 |     } | 
 | 308 |     if (value32 == cie32_value_) { | 
 | 309 |       // This is a Cie, this means something has gone wrong. | 
 | 310 |       last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
 | 311 |       return false; | 
 | 312 |     } | 
 | 313 |  | 
 | 314 |     // Get the Cie pointer, which is necessary to properly read the rest of | 
 | 315 |     // of the Fde information. | 
 | 316 |     fde->cie_offset = GetCieOffsetFromFde32(value32); | 
 | 317 |   } | 
 | 318 |   return true; | 
 | 319 | } | 
 | 320 |  | 
 | 321 | template <typename AddressType> | 
 | 322 | bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) { | 
 | 323 |   uint64_t cur_offset = memory_.cur_offset(); | 
 | 324 |  | 
 | 325 |   const DwarfCie* cie = GetCieFromOffset(fde->cie_offset); | 
 | 326 |   if (cie == nullptr) { | 
 | 327 |     return false; | 
 | 328 |   } | 
 | 329 |   fde->cie = cie; | 
 | 330 |  | 
 | 331 |   if (cie->segment_size != 0) { | 
 | 332 |     // Skip over the segment selector for now. | 
 | 333 |     cur_offset += cie->segment_size; | 
 | 334 |   } | 
 | 335 |   memory_.set_cur_offset(cur_offset); | 
 | 336 |  | 
 | 337 |   // The load bias only applies to the start. | 
| Christopher Ferris | 819f131 | 2019-10-03 13:35:48 -0700 | [diff] [blame] | 338 |   memory_.set_pc_offset(section_bias_); | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 339 |   bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start); | 
 | 340 |   fde->pc_start = AdjustPcFromFde(fde->pc_start); | 
 | 341 |  | 
 | 342 |   memory_.set_pc_offset(0); | 
 | 343 |   if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) { | 
 | 344 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 345 |     last_error_.address = memory_.cur_offset(); | 
 | 346 |     return false; | 
 | 347 |   } | 
 | 348 |   fde->pc_end += fde->pc_start; | 
 | 349 |  | 
 | 350 |   if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') { | 
 | 351 |     // Augmentation Size | 
 | 352 |     uint64_t aug_length; | 
 | 353 |     if (!memory_.ReadULEB128(&aug_length)) { | 
 | 354 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 355 |       last_error_.address = memory_.cur_offset(); | 
 | 356 |       return false; | 
 | 357 |     } | 
 | 358 |     uint64_t cur_offset = memory_.cur_offset(); | 
 | 359 |  | 
 | 360 |     memory_.set_pc_offset(pc_offset_); | 
 | 361 |     if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) { | 
 | 362 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 363 |       last_error_.address = memory_.cur_offset(); | 
 | 364 |       return false; | 
 | 365 |     } | 
 | 366 |  | 
 | 367 |     // Set our position to after all of the augmentation data. | 
 | 368 |     memory_.set_cur_offset(cur_offset + aug_length); | 
 | 369 |   } | 
 | 370 |   fde->cfa_instructions_offset = memory_.cur_offset(); | 
 | 371 |  | 
 | 372 |   return true; | 
 | 373 | } | 
 | 374 |  | 
 | 375 | template <typename AddressType> | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 376 | bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, Memory* regular_memory, | 
 | 377 |                                                    AddressType* value, | 
 | 378 |                                                    RegsInfo<AddressType>* regs_info, | 
 | 379 |                                                    bool* is_dex_pc) { | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 380 |   DwarfOp<AddressType> op(&memory_, regular_memory); | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 381 |   op.set_regs_info(regs_info); | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 382 |  | 
 | 383 |   // Need to evaluate the op data. | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 384 |   uint64_t end = loc.values[1]; | 
 | 385 |   uint64_t start = end - loc.values[0]; | 
 | 386 |   if (!op.Eval(start, end)) { | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 387 |     last_error_ = op.last_error(); | 
 | 388 |     return false; | 
 | 389 |   } | 
 | 390 |   if (op.StackSize() == 0) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 391 |     last_error_.code = DWARF_ERROR_ILLEGAL_STATE; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 392 |     return false; | 
 | 393 |   } | 
 | 394 |   // We don't support an expression that evaluates to a register number. | 
 | 395 |   if (op.is_register()) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 396 |     last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 397 |     return false; | 
 | 398 |   } | 
 | 399 |   *value = op.StackAt(0); | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 400 |   if (is_dex_pc != nullptr && op.dex_pc_set()) { | 
 | 401 |     *is_dex_pc = true; | 
 | 402 |   } | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 403 |   return true; | 
 | 404 | } | 
 | 405 |  | 
 | 406 | template <typename AddressType> | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 407 | struct EvalInfo { | 
 | 408 |   const dwarf_loc_regs_t* loc_regs; | 
 | 409 |   const DwarfCie* cie; | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 410 |   Memory* regular_memory; | 
 | 411 |   AddressType cfa; | 
 | 412 |   bool return_address_undefined = false; | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 413 |   RegsInfo<AddressType> regs_info; | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 414 | }; | 
 | 415 |  | 
 | 416 | template <typename AddressType> | 
 | 417 | bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint32_t reg, | 
 | 418 |                                                  AddressType* reg_ptr, void* info) { | 
 | 419 |   EvalInfo<AddressType>* eval_info = reinterpret_cast<EvalInfo<AddressType>*>(info); | 
 | 420 |   Memory* regular_memory = eval_info->regular_memory; | 
 | 421 |   switch (loc->type) { | 
 | 422 |     case DWARF_LOCATION_OFFSET: | 
 | 423 |       if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 424 |         last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 425 |         last_error_.address = eval_info->cfa + loc->values[0]; | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 426 |         return false; | 
 | 427 |       } | 
 | 428 |       break; | 
 | 429 |     case DWARF_LOCATION_VAL_OFFSET: | 
 | 430 |       *reg_ptr = eval_info->cfa + loc->values[0]; | 
 | 431 |       break; | 
 | 432 |     case DWARF_LOCATION_REGISTER: { | 
 | 433 |       uint32_t cur_reg = loc->values[0]; | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 434 |       if (cur_reg >= eval_info->regs_info.Total()) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 435 |         last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 436 |         return false; | 
 | 437 |       } | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 438 |       *reg_ptr = eval_info->regs_info.Get(cur_reg) + loc->values[1]; | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 439 |       break; | 
 | 440 |     } | 
 | 441 |     case DWARF_LOCATION_EXPRESSION: | 
 | 442 |     case DWARF_LOCATION_VAL_EXPRESSION: { | 
 | 443 |       AddressType value; | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 444 |       bool is_dex_pc = false; | 
 | 445 |       if (!EvalExpression(*loc, regular_memory, &value, &eval_info->regs_info, &is_dex_pc)) { | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 446 |         return false; | 
 | 447 |       } | 
 | 448 |       if (loc->type == DWARF_LOCATION_EXPRESSION) { | 
 | 449 |         if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 450 |           last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 451 |           last_error_.address = value; | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 452 |           return false; | 
 | 453 |         } | 
 | 454 |       } else { | 
 | 455 |         *reg_ptr = value; | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 456 |         if (is_dex_pc) { | 
 | 457 |           eval_info->regs_info.regs->set_dex_pc(value); | 
 | 458 |         } | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 459 |       } | 
 | 460 |       break; | 
 | 461 |     } | 
 | 462 |     case DWARF_LOCATION_UNDEFINED: | 
 | 463 |       if (reg == eval_info->cie->return_address_register) { | 
 | 464 |         eval_info->return_address_undefined = true; | 
 | 465 |       } | 
| Christopher Ferris | 3f9582f | 2018-09-19 14:12:59 -0700 | [diff] [blame] | 466 |       break; | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 467 |     default: | 
 | 468 |       break; | 
 | 469 |   } | 
 | 470 |  | 
 | 471 |   return true; | 
 | 472 | } | 
 | 473 |  | 
 | 474 | template <typename AddressType> | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 475 | bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory, | 
| Christopher Ferris | b9de87f | 2017-09-20 13:37:24 -0700 | [diff] [blame] | 476 |                                          const dwarf_loc_regs_t& loc_regs, Regs* regs, | 
 | 477 |                                          bool* finished) { | 
| Christopher Ferris | 7b8e467 | 2017-06-01 17:55:25 -0700 | [diff] [blame] | 478 |   RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(regs); | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 479 |   if (cie->return_address_register >= cur_regs->total_regs()) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 480 |     last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 481 |     return false; | 
 | 482 |   } | 
 | 483 |  | 
 | 484 |   // Get the cfa value; | 
 | 485 |   auto cfa_entry = loc_regs.find(CFA_REG); | 
 | 486 |   if (cfa_entry == loc_regs.end()) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 487 |     last_error_.code = DWARF_ERROR_CFA_NOT_DEFINED; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 488 |     return false; | 
 | 489 |   } | 
 | 490 |  | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 491 |   // Always set the dex pc to zero when evaluating. | 
 | 492 |   cur_regs->set_dex_pc(0); | 
 | 493 |  | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 494 |   EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs, | 
 | 495 |                                   .cie = cie, | 
 | 496 |                                   .regular_memory = regular_memory, | 
 | 497 |                                   .regs_info = RegsInfo<AddressType>(cur_regs)}; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 498 |   const DwarfLocation* loc = &cfa_entry->second; | 
 | 499 |   // Only a few location types are valid for the cfa. | 
 | 500 |   switch (loc->type) { | 
 | 501 |     case DWARF_LOCATION_REGISTER: | 
 | 502 |       if (loc->values[0] >= cur_regs->total_regs()) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 503 |         last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 504 |         return false; | 
 | 505 |       } | 
| Yabin Cui | 11e96fe | 2018-03-14 18:16:22 -0700 | [diff] [blame] | 506 |       eval_info.cfa = (*cur_regs)[loc->values[0]]; | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 507 |       eval_info.cfa += loc->values[1]; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 508 |       break; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 509 |     case DWARF_LOCATION_VAL_EXPRESSION: { | 
 | 510 |       AddressType value; | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 511 |       if (!EvalExpression(*loc, regular_memory, &value, &eval_info.regs_info, nullptr)) { | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 512 |         return false; | 
 | 513 |       } | 
| David Srbecky | 3692f25 | 2018-03-08 16:57:19 +0000 | [diff] [blame] | 514 |       // There is only one type of valid expression for CFA evaluation. | 
 | 515 |       eval_info.cfa = value; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 516 |       break; | 
 | 517 |     } | 
 | 518 |     default: | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 519 |       last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 520 |       return false; | 
 | 521 |   } | 
 | 522 |  | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 523 |   for (const auto& entry : loc_regs) { | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 524 |     uint32_t reg = entry.first; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 525 |     // Already handled the CFA register. | 
 | 526 |     if (reg == CFA_REG) continue; | 
 | 527 |  | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 528 |     AddressType* reg_ptr; | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 529 |     if (reg >= cur_regs->total_regs()) { | 
 | 530 |       // Skip this unknown register. | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 531 |       continue; | 
 | 532 |     } | 
 | 533 |  | 
| Christopher Ferris | 559c7f2 | 2018-02-12 20:18:03 -0800 | [diff] [blame] | 534 |     reg_ptr = eval_info.regs_info.Save(reg); | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 535 |     if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) { | 
 | 536 |       return false; | 
 | 537 |     } | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 538 |   } | 
 | 539 |  | 
 | 540 |   // Find the return address location. | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 541 |   if (eval_info.return_address_undefined) { | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 542 |     cur_regs->set_pc(0); | 
 | 543 |   } else { | 
 | 544 |     cur_regs->set_pc((*cur_regs)[cie->return_address_register]); | 
 | 545 |   } | 
| Christopher Ferris | 2502a60 | 2017-10-23 13:51:54 -0700 | [diff] [blame] | 546 |  | 
 | 547 |   // If the pc was set to zero, consider this the final frame. | 
 | 548 |   *finished = (cur_regs->pc() == 0) ? true : false; | 
 | 549 |  | 
| Christopher Ferris | 98984b4 | 2018-01-17 12:59:45 -0800 | [diff] [blame] | 550 |   cur_regs->set_sp(eval_info.cfa); | 
| Christopher Ferris | fda7edd | 2017-10-31 16:10:42 -0700 | [diff] [blame] | 551 |  | 
 | 552 |   return true; | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 553 | } | 
 | 554 |  | 
 | 555 | template <typename AddressType> | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 556 | bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, | 
 | 557 |                                                        dwarf_loc_regs_t* loc_regs) { | 
 | 558 |   DwarfCfa<AddressType> cfa(&memory_, fde); | 
 | 559 |  | 
 | 560 |   // Look for the cached copy of the cie data. | 
 | 561 |   auto reg_entry = cie_loc_regs_.find(fde->cie_offset); | 
 | 562 |   if (reg_entry == cie_loc_regs_.end()) { | 
 | 563 |     if (!cfa.GetLocationInfo(pc, fde->cie->cfa_instructions_offset, fde->cie->cfa_instructions_end, | 
 | 564 |                              loc_regs)) { | 
 | 565 |       last_error_ = cfa.last_error(); | 
 | 566 |       return false; | 
 | 567 |     } | 
 | 568 |     cie_loc_regs_[fde->cie_offset] = *loc_regs; | 
 | 569 |   } | 
 | 570 |   cfa.set_cie_loc_regs(&cie_loc_regs_[fde->cie_offset]); | 
 | 571 |   if (!cfa.GetLocationInfo(pc, fde->cfa_instructions_offset, fde->cfa_instructions_end, loc_regs)) { | 
 | 572 |     last_error_ = cfa.last_error(); | 
 | 573 |     return false; | 
 | 574 |   } | 
 | 575 |   return true; | 
 | 576 | } | 
 | 577 |  | 
 | 578 | template <typename AddressType> | 
| Christopher Ferris | 4cc36d2 | 2018-06-06 14:47:31 -0700 | [diff] [blame] | 579 | bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) { | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 580 |   DwarfCfa<AddressType> cfa(&memory_, fde); | 
 | 581 |  | 
 | 582 |   // Always print the cie information. | 
 | 583 |   const DwarfCie* cie = fde->cie; | 
| Christopher Ferris | 4cc36d2 | 2018-06-06 14:47:31 -0700 | [diff] [blame] | 584 |   if (!cfa.Log(indent, pc, cie->cfa_instructions_offset, cie->cfa_instructions_end)) { | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 585 |     last_error_ = cfa.last_error(); | 
 | 586 |     return false; | 
 | 587 |   } | 
| Christopher Ferris | 4cc36d2 | 2018-06-06 14:47:31 -0700 | [diff] [blame] | 588 |   if (!cfa.Log(indent, pc, fde->cfa_instructions_offset, fde->cfa_instructions_end)) { | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 589 |     last_error_ = cfa.last_error(); | 
 | 590 |     return false; | 
 | 591 |   } | 
 | 592 |   return true; | 
 | 593 | } | 
 | 594 |  | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 595 | template <typename AddressType> | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 596 | bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) { | 
| Christopher Ferris | 819f131 | 2019-10-03 13:35:48 -0700 | [diff] [blame] | 597 |   section_bias_ = section_bias; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 598 |   entries_offset_ = offset; | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 599 |   next_entries_offset_ = offset; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 600 |   entries_end_ = offset + size; | 
 | 601 |  | 
 | 602 |   memory_.clear_func_offset(); | 
 | 603 |   memory_.clear_text_offset(); | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 604 |   memory_.set_cur_offset(offset); | 
| Christopher Ferris | 4cc36d2 | 2018-06-06 14:47:31 -0700 | [diff] [blame] | 605 |   pc_offset_ = offset; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 606 |  | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 607 |   return true; | 
 | 608 | } | 
 | 609 |  | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 610 | // Create a cached version of the fde information such that it is a std::map | 
 | 611 | // that is indexed by end pc and contains a pair that represents the start pc | 
 | 612 | // followed by the fde object. The fde pointers are owned by fde_entries_ | 
 | 613 | // and not by the map object. | 
 | 614 | // It is possible for an fde to be represented by multiple entries in | 
 | 615 | // the map. This can happen if the the start pc and end pc overlap already | 
 | 616 | // existing entries. For example, if there is already an entry of 0x400, 0x200, | 
 | 617 | // and an fde has a start pc of 0x100 and end pc of 0x500, two new entries | 
 | 618 | // will be added: 0x200, 0x100 and 0x500, 0x400. | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 619 | template <typename AddressType> | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 620 | void DwarfSectionImpl<AddressType>::InsertFde(const DwarfFde* fde) { | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 621 |   uint64_t start = fde->pc_start; | 
 | 622 |   uint64_t end = fde->pc_end; | 
 | 623 |   auto it = fdes_.upper_bound(start); | 
 | 624 |   bool add_element = false; | 
 | 625 |   while (it != fdes_.end() && start < end) { | 
 | 626 |     if (add_element) { | 
 | 627 |       add_element = false; | 
 | 628 |       if (end < it->second.first) { | 
 | 629 |         if (it->first == end) { | 
 | 630 |           return; | 
 | 631 |         } | 
 | 632 |         fdes_[end] = std::make_pair(start, fde); | 
 | 633 |         return; | 
 | 634 |       } | 
 | 635 |       if (start != it->second.first) { | 
 | 636 |         fdes_[it->second.first] = std::make_pair(start, fde); | 
 | 637 |       } | 
 | 638 |     } | 
 | 639 |     if (start < it->first) { | 
 | 640 |       if (end < it->second.first) { | 
 | 641 |         if (it->first != end) { | 
 | 642 |           fdes_[end] = std::make_pair(start, fde); | 
 | 643 |         } | 
 | 644 |         return; | 
 | 645 |       } | 
 | 646 |       add_element = true; | 
 | 647 |     } | 
 | 648 |     start = it->first; | 
 | 649 |     ++it; | 
 | 650 |   } | 
 | 651 |   if (start < end) { | 
 | 652 |     fdes_[end] = std::make_pair(start, fde); | 
 | 653 |   } | 
 | 654 | } | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 655 |  | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 656 | template <typename AddressType> | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 657 | bool DwarfSectionImpl<AddressType>::GetNextCieOrFde(const DwarfFde** fde_entry) { | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 658 |   uint64_t start_offset = next_entries_offset_; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 659 |  | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 660 |   memory_.set_data_offset(entries_offset_); | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 661 |   memory_.set_cur_offset(next_entries_offset_); | 
 | 662 |   uint32_t value32; | 
 | 663 |   if (!memory_.ReadBytes(&value32, sizeof(value32))) { | 
 | 664 |     last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 665 |     last_error_.address = memory_.cur_offset(); | 
 | 666 |     return false; | 
 | 667 |   } | 
 | 668 |  | 
 | 669 |   uint64_t cie_offset; | 
 | 670 |   uint8_t cie_fde_encoding; | 
 | 671 |   bool entry_is_cie = false; | 
 | 672 |   if (value32 == static_cast<uint32_t>(-1)) { | 
 | 673 |     // 64 bit entry. | 
 | 674 |     uint64_t value64; | 
 | 675 |     if (!memory_.ReadBytes(&value64, sizeof(value64))) { | 
 | 676 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 677 |       last_error_.address = memory_.cur_offset(); | 
 | 678 |       return false; | 
 | 679 |     } | 
 | 680 |  | 
 | 681 |     next_entries_offset_ = memory_.cur_offset() + value64; | 
 | 682 |     // Read the Cie Id of a Cie or the pointer of the Fde. | 
 | 683 |     if (!memory_.ReadBytes(&value64, sizeof(value64))) { | 
 | 684 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 685 |       last_error_.address = memory_.cur_offset(); | 
 | 686 |       return false; | 
 | 687 |     } | 
 | 688 |  | 
 | 689 |     if (value64 == cie64_value_) { | 
 | 690 |       entry_is_cie = true; | 
 | 691 |       cie_fde_encoding = DW_EH_PE_sdata8; | 
 | 692 |     } else { | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 693 |       cie_offset = GetCieOffsetFromFde64(value64); | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 694 |     } | 
 | 695 |   } else { | 
 | 696 |     next_entries_offset_ = memory_.cur_offset() + value32; | 
 | 697 |  | 
 | 698 |     // 32 bit Cie | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 699 |     if (!memory_.ReadBytes(&value32, sizeof(value32))) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 700 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 701 |       last_error_.address = memory_.cur_offset(); | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 702 |       return false; | 
 | 703 |     } | 
 | 704 |  | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 705 |     if (value32 == cie32_value_) { | 
 | 706 |       entry_is_cie = true; | 
 | 707 |       cie_fde_encoding = DW_EH_PE_sdata4; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 708 |     } else { | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 709 |       cie_offset = GetCieOffsetFromFde32(value32); | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 710 |     } | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 711 |   } | 
 | 712 |  | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 713 |   if (entry_is_cie) { | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 714 |     auto entry = cie_entries_.find(start_offset); | 
 | 715 |     if (entry == cie_entries_.end()) { | 
 | 716 |       DwarfCie* cie = &cie_entries_[start_offset]; | 
 | 717 |       cie->lsda_encoding = DW_EH_PE_omit; | 
 | 718 |       cie->cfa_instructions_end = next_entries_offset_; | 
 | 719 |       cie->fde_address_encoding = cie_fde_encoding; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 720 |  | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 721 |       if (!FillInCie(cie)) { | 
 | 722 |         cie_entries_.erase(start_offset); | 
 | 723 |         return false; | 
 | 724 |       } | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 725 |     } | 
 | 726 |     *fde_entry = nullptr; | 
 | 727 |   } else { | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 728 |     auto entry = fde_entries_.find(start_offset); | 
 | 729 |     if (entry != fde_entries_.end()) { | 
 | 730 |       *fde_entry = &entry->second; | 
 | 731 |     } else { | 
 | 732 |       DwarfFde* fde = &fde_entries_[start_offset]; | 
 | 733 |       fde->cfa_instructions_end = next_entries_offset_; | 
 | 734 |       fde->cie_offset = cie_offset; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 735 |  | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 736 |       if (!FillInFde(fde)) { | 
 | 737 |         fde_entries_.erase(start_offset); | 
 | 738 |         return false; | 
 | 739 |       } | 
 | 740 |       *fde_entry = fde; | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 741 |     } | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 742 |   } | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 743 |   return true; | 
 | 744 | } | 
 | 745 |  | 
 | 746 | template <typename AddressType> | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 747 | void DwarfSectionImpl<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) { | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 748 |   // Loop through the already cached entries. | 
 | 749 |   uint64_t entry_offset = entries_offset_; | 
 | 750 |   while (entry_offset < next_entries_offset_) { | 
 | 751 |     auto cie_it = cie_entries_.find(entry_offset); | 
 | 752 |     if (cie_it != cie_entries_.end()) { | 
 | 753 |       entry_offset = cie_it->second.cfa_instructions_end; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 754 |     } else { | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 755 |       auto fde_it = fde_entries_.find(entry_offset); | 
 | 756 |       if (fde_it == fde_entries_.end()) { | 
 | 757 |         // No fde or cie at this entry, should not be possible. | 
 | 758 |         return; | 
 | 759 |       } | 
 | 760 |       entry_offset = fde_it->second.cfa_instructions_end; | 
 | 761 |       fdes->push_back(&fde_it->second); | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 762 |     } | 
 | 763 |   } | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 764 |  | 
 | 765 |   while (next_entries_offset_ < entries_end_) { | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 766 |     const DwarfFde* fde; | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 767 |     if (!GetNextCieOrFde(&fde)) { | 
 | 768 |       break; | 
 | 769 |     } | 
 | 770 |     if (fde != nullptr) { | 
 | 771 |       InsertFde(fde); | 
 | 772 |       fdes->push_back(fde); | 
 | 773 |     } | 
 | 774 |  | 
 | 775 |     if (next_entries_offset_ < memory_.cur_offset()) { | 
 | 776 |       // Simply consider the processing done in this case. | 
 | 777 |       break; | 
 | 778 |     } | 
 | 779 |   } | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 780 | } | 
 | 781 |  | 
 | 782 | template <typename AddressType> | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 783 | const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromPc(uint64_t pc) { | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 784 |   // Search in the list of fdes we already have. | 
 | 785 |   auto it = fdes_.upper_bound(pc); | 
 | 786 |   if (it != fdes_.end()) { | 
 | 787 |     if (pc >= it->second.first) { | 
 | 788 |       return it->second.second; | 
 | 789 |     } | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 790 |   } | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 791 |  | 
 | 792 |   // The section might have overlapping pcs in fdes, so it is necessary | 
 | 793 |   // to do a linear search of the fdes by pc. As fdes are read, a cached | 
 | 794 |   // search map is created. | 
 | 795 |   while (next_entries_offset_ < entries_end_) { | 
| Christopher Ferris | 4ca98e1 | 2019-10-29 10:21:11 -0700 | [diff] [blame] | 796 |     const DwarfFde* fde; | 
| Christopher Ferris | 92acaac | 2018-06-21 10:44:02 -0700 | [diff] [blame] | 797 |     if (!GetNextCieOrFde(&fde)) { | 
 | 798 |       return nullptr; | 
 | 799 |     } | 
 | 800 |     if (fde != nullptr) { | 
 | 801 |       InsertFde(fde); | 
 | 802 |       if (pc >= fde->pc_start && pc < fde->pc_end) { | 
 | 803 |         return fde; | 
 | 804 |       } | 
 | 805 |     } | 
 | 806 |  | 
 | 807 |     if (next_entries_offset_ < memory_.cur_offset()) { | 
 | 808 |       // Simply consider the processing done in this case. | 
 | 809 |       break; | 
 | 810 |     } | 
 | 811 |   } | 
 | 812 |   return nullptr; | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 813 | } | 
 | 814 |  | 
| Christopher Ferris | 53a3c9b | 2017-05-10 18:34:15 -0700 | [diff] [blame] | 815 | // Explicitly instantiate DwarfSectionImpl | 
 | 816 | template class DwarfSectionImpl<uint32_t>; | 
 | 817 | template class DwarfSectionImpl<uint64_t>; | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 818 |  | 
| Christopher Ferris | c9dee84 | 2017-11-03 14:50:27 -0700 | [diff] [blame] | 819 | // Explicitly instantiate DwarfDebugFrame | 
 | 820 | template class DwarfDebugFrame<uint32_t>; | 
 | 821 | template class DwarfDebugFrame<uint64_t>; | 
 | 822 |  | 
 | 823 | // Explicitly instantiate DwarfEhFrame | 
 | 824 | template class DwarfEhFrame<uint32_t>; | 
 | 825 | template class DwarfEhFrame<uint64_t>; | 
 | 826 |  | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 827 | }  // namespace unwindstack |