| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2016 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 <inttypes.h> | 
 | 18 | #include <stdint.h> | 
 | 19 |  | 
 | 20 | #include <string> | 
 | 21 | #include <type_traits> | 
 | 22 | #include <vector> | 
 | 23 |  | 
 | 24 | #include <android-base/stringprintf.h> | 
 | 25 |  | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 26 | #include <unwindstack/DwarfError.h> | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 27 | #include <unwindstack/DwarfLocation.h> | 
 | 28 | #include <unwindstack/Log.h> | 
 | 29 |  | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 30 | #include "DwarfCfa.h" | 
 | 31 | #include "DwarfEncoding.h" | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 32 | #include "DwarfOp.h" | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 33 |  | 
 | 34 | namespace unwindstack { | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 35 |  | 
 | 36 | template <typename AddressType> | 
 | 37 | constexpr typename DwarfCfa<AddressType>::process_func DwarfCfa<AddressType>::kCallbackTable[64]; | 
 | 38 |  | 
 | 39 | template <typename AddressType> | 
 | 40 | bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset, | 
 | 41 |                                             dwarf_loc_regs_t* loc_regs) { | 
 | 42 |   if (cie_loc_regs_ != nullptr) { | 
 | 43 |     for (const auto& entry : *cie_loc_regs_) { | 
 | 44 |       (*loc_regs)[entry.first] = entry.second; | 
 | 45 |     } | 
 | 46 |   } | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 47 |   last_error_.code = DWARF_ERROR_NONE; | 
 | 48 |   last_error_.address = 0; | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 49 |  | 
 | 50 |   memory_->set_cur_offset(start_offset); | 
 | 51 |   uint64_t cfa_offset; | 
 | 52 |   cur_pc_ = fde_->pc_start; | 
 | 53 |   while ((cfa_offset = memory_->cur_offset()) < end_offset && cur_pc_ <= pc) { | 
 | 54 |     operands_.clear(); | 
 | 55 |     // Read the cfa information. | 
 | 56 |     uint8_t cfa_value; | 
 | 57 |     if (!memory_->ReadBytes(&cfa_value, 1)) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 58 |       last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 59 |       last_error_.address = memory_->cur_offset(); | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 60 |       return false; | 
 | 61 |     } | 
 | 62 |     uint8_t cfa_low = cfa_value & 0x3f; | 
 | 63 |     // Check the 2 high bits. | 
 | 64 |     switch (cfa_value >> 6) { | 
 | 65 |       case 1: | 
 | 66 |         cur_pc_ += cfa_low * fde_->cie->code_alignment_factor; | 
 | 67 |         break; | 
 | 68 |       case 2: { | 
 | 69 |         uint64_t offset; | 
 | 70 |         if (!memory_->ReadULEB128(&offset)) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 71 |           last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 72 |           last_error_.address = memory_->cur_offset(); | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 73 |           return false; | 
 | 74 |         } | 
 | 75 |         SignedType signed_offset = | 
 | 76 |             static_cast<SignedType>(offset) * fde_->cie->data_alignment_factor; | 
 | 77 |         (*loc_regs)[cfa_low] = {.type = DWARF_LOCATION_OFFSET, | 
 | 78 |                                 .values = {static_cast<uint64_t>(signed_offset)}}; | 
 | 79 |         break; | 
 | 80 |       } | 
 | 81 |       case 3: { | 
 | 82 |         if (cie_loc_regs_ == nullptr) { | 
 | 83 |           log(0, "restore while processing cie"); | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 84 |           last_error_.code = DWARF_ERROR_ILLEGAL_STATE; | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 85 |           return false; | 
 | 86 |         } | 
 | 87 |  | 
 | 88 |         auto reg_entry = cie_loc_regs_->find(cfa_low); | 
 | 89 |         if (reg_entry == cie_loc_regs_->end()) { | 
 | 90 |           loc_regs->erase(cfa_low); | 
 | 91 |         } else { | 
 | 92 |           (*loc_regs)[cfa_low] = reg_entry->second; | 
 | 93 |         } | 
 | 94 |         break; | 
 | 95 |       } | 
 | 96 |       case 0: { | 
 | 97 |         const auto handle_func = DwarfCfa<AddressType>::kCallbackTable[cfa_low]; | 
 | 98 |         if (handle_func == nullptr) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 99 |           last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 100 |           return false; | 
 | 101 |         } | 
 | 102 |  | 
 | 103 |         const auto cfa = &DwarfCfaInfo::kTable[cfa_low]; | 
 | 104 |         for (size_t i = 0; i < cfa->num_operands; i++) { | 
 | 105 |           if (cfa->operands[i] == DW_EH_PE_block) { | 
 | 106 |             uint64_t block_length; | 
 | 107 |             if (!memory_->ReadULEB128(&block_length)) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 108 |               last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 109 |               last_error_.address = memory_->cur_offset(); | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 110 |               return false; | 
 | 111 |             } | 
 | 112 |             operands_.push_back(block_length); | 
 | 113 |             memory_->set_cur_offset(memory_->cur_offset() + block_length); | 
 | 114 |             continue; | 
 | 115 |           } | 
 | 116 |           uint64_t value; | 
 | 117 |           if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) { | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 118 |             last_error_.code = DWARF_ERROR_MEMORY_INVALID; | 
 | 119 |             last_error_.address = memory_->cur_offset(); | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 120 |             return false; | 
 | 121 |           } | 
 | 122 |           operands_.push_back(value); | 
 | 123 |         } | 
 | 124 |  | 
 | 125 |         if (!(this->*handle_func)(loc_regs)) { | 
 | 126 |           return false; | 
 | 127 |         } | 
 | 128 |         break; | 
 | 129 |       } | 
 | 130 |     } | 
 | 131 |   } | 
 | 132 |   return true; | 
 | 133 | } | 
 | 134 |  | 
 | 135 | template <typename AddressType> | 
 | 136 | std::string DwarfCfa<AddressType>::GetOperandString(uint8_t operand, uint64_t value, | 
 | 137 |                                                     uint64_t* cur_pc) { | 
 | 138 |   std::string string; | 
 | 139 |   switch (operand) { | 
 | 140 |     case DwarfCfaInfo::DWARF_DISPLAY_REGISTER: | 
 | 141 |       string = " register(" + std::to_string(value) + ")"; | 
 | 142 |       break; | 
 | 143 |     case DwarfCfaInfo::DWARF_DISPLAY_SIGNED_NUMBER: | 
 | 144 |       string += " " + std::to_string(static_cast<SignedType>(value)); | 
 | 145 |       break; | 
 | 146 |     case DwarfCfaInfo::DWARF_DISPLAY_ADVANCE_LOC: | 
 | 147 |       *cur_pc += value; | 
 | 148 |     // Fall through to log the value. | 
 | 149 |     case DwarfCfaInfo::DWARF_DISPLAY_NUMBER: | 
 | 150 |       string += " " + std::to_string(value); | 
 | 151 |       break; | 
 | 152 |     case DwarfCfaInfo::DWARF_DISPLAY_SET_LOC: | 
 | 153 |       *cur_pc = value; | 
 | 154 |     // Fall through to log the value. | 
 | 155 |     case DwarfCfaInfo::DWARF_DISPLAY_ADDRESS: | 
 | 156 |       if (std::is_same<AddressType, uint32_t>::value) { | 
 | 157 |         string += android::base::StringPrintf(" 0x%" PRIx32, static_cast<uint32_t>(value)); | 
 | 158 |       } else { | 
 | 159 |         string += android::base::StringPrintf(" 0x%" PRIx64, static_cast<uint64_t>(value)); | 
 | 160 |       } | 
 | 161 |       break; | 
 | 162 |     default: | 
 | 163 |       string = " unknown"; | 
 | 164 |   } | 
 | 165 |   return string; | 
 | 166 | } | 
 | 167 |  | 
 | 168 | template <typename AddressType> | 
 | 169 | bool DwarfCfa<AddressType>::LogOffsetRegisterString(uint32_t indent, uint64_t cfa_offset, | 
 | 170 |                                                     uint8_t reg) { | 
 | 171 |   uint64_t offset; | 
 | 172 |   if (!memory_->ReadULEB128(&offset)) { | 
 | 173 |     return false; | 
 | 174 |   } | 
 | 175 |   uint64_t end_offset = memory_->cur_offset(); | 
 | 176 |   memory_->set_cur_offset(cfa_offset); | 
 | 177 |  | 
 | 178 |   std::string raw_data = "Raw Data:"; | 
 | 179 |   for (uint64_t i = cfa_offset; i < end_offset; i++) { | 
 | 180 |     uint8_t value; | 
 | 181 |     if (!memory_->ReadBytes(&value, 1)) { | 
 | 182 |       return false; | 
 | 183 |     } | 
 | 184 |     raw_data += android::base::StringPrintf(" 0x%02x", value); | 
 | 185 |   } | 
 | 186 |   log(indent, "DW_CFA_offset register(%d) %" PRId64, reg, offset); | 
 | 187 |   log(indent, "%s", raw_data.c_str()); | 
 | 188 |   return true; | 
 | 189 | } | 
 | 190 |  | 
 | 191 | template <typename AddressType> | 
 | 192 | bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, | 
 | 193 |                                            uint64_t* cur_pc) { | 
 | 194 |   const auto* cfa = &DwarfCfaInfo::kTable[op]; | 
 | 195 |   if (cfa->name == nullptr) { | 
 | 196 |     log(indent, "Illegal"); | 
 | 197 |     log(indent, "Raw Data: 0x%02x", op); | 
 | 198 |     return true; | 
 | 199 |   } | 
 | 200 |  | 
 | 201 |   std::string log_string(cfa->name); | 
 | 202 |   std::vector<std::string> expression_lines; | 
 | 203 |   for (size_t i = 0; i < cfa->num_operands; i++) { | 
 | 204 |     if (cfa->operands[i] == DW_EH_PE_block) { | 
 | 205 |       // This is a Dwarf Expression. | 
 | 206 |       uint64_t end_offset; | 
 | 207 |       if (!memory_->ReadULEB128(&end_offset)) { | 
 | 208 |         return false; | 
 | 209 |       } | 
 | 210 |       log_string += " " + std::to_string(end_offset); | 
 | 211 |       end_offset += memory_->cur_offset(); | 
 | 212 |  | 
 | 213 |       DwarfOp<AddressType> op(memory_, nullptr); | 
 | 214 |       op.GetLogInfo(memory_->cur_offset(), end_offset, &expression_lines); | 
 | 215 |       memory_->set_cur_offset(end_offset); | 
 | 216 |     } else { | 
 | 217 |       uint64_t value; | 
 | 218 |       if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) { | 
 | 219 |         return false; | 
 | 220 |       } | 
 | 221 |       log_string += GetOperandString(cfa->display_operands[i], value, cur_pc); | 
 | 222 |     } | 
 | 223 |   } | 
 | 224 |   log(indent, "%s", log_string.c_str()); | 
 | 225 |  | 
 | 226 |   // Get the raw bytes of the data. | 
 | 227 |   uint64_t end_offset = memory_->cur_offset(); | 
 | 228 |   memory_->set_cur_offset(cfa_offset); | 
 | 229 |   std::string raw_data("Raw Data:"); | 
 | 230 |   for (uint64_t i = 0; i < end_offset - cfa_offset; i++) { | 
 | 231 |     uint8_t value; | 
 | 232 |     if (!memory_->ReadBytes(&value, 1)) { | 
 | 233 |       return false; | 
 | 234 |     } | 
 | 235 |  | 
 | 236 |     // Only show 10 raw bytes per line. | 
 | 237 |     if ((i % 10) == 0 && i != 0) { | 
 | 238 |       log(indent, "%s", raw_data.c_str()); | 
 | 239 |       raw_data.clear(); | 
 | 240 |     } | 
 | 241 |     if (raw_data.empty()) { | 
 | 242 |       raw_data = "Raw Data:"; | 
 | 243 |     } | 
 | 244 |     raw_data += android::base::StringPrintf(" 0x%02x", value); | 
 | 245 |   } | 
 | 246 |   if (!raw_data.empty()) { | 
 | 247 |     log(indent, "%s", raw_data.c_str()); | 
 | 248 |   } | 
 | 249 |  | 
 | 250 |   // Log any of the expression data. | 
 | 251 |   for (const auto line : expression_lines) { | 
 | 252 |     log(indent + 1, "%s", line.c_str()); | 
 | 253 |   } | 
 | 254 |   return true; | 
 | 255 | } | 
 | 256 |  | 
 | 257 | template <typename AddressType> | 
 | 258 | bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t load_bias, | 
 | 259 |                                 uint64_t start_offset, uint64_t end_offset) { | 
 | 260 |   memory_->set_cur_offset(start_offset); | 
 | 261 |   uint64_t cfa_offset; | 
 | 262 |   uint64_t cur_pc = fde_->pc_start; | 
 | 263 |   uint64_t old_pc = cur_pc; | 
 | 264 |   while ((cfa_offset = memory_->cur_offset()) < end_offset && cur_pc <= pc) { | 
 | 265 |     // Read the cfa information. | 
 | 266 |     uint8_t cfa_value; | 
 | 267 |     if (!memory_->ReadBytes(&cfa_value, 1)) { | 
 | 268 |       return false; | 
 | 269 |     } | 
 | 270 |  | 
 | 271 |     // Check the 2 high bits. | 
 | 272 |     uint8_t cfa_low = cfa_value & 0x3f; | 
 | 273 |     switch (cfa_value >> 6) { | 
 | 274 |       case 0: | 
 | 275 |         if (!LogInstruction(indent, cfa_offset, cfa_low, &cur_pc)) { | 
 | 276 |           return false; | 
 | 277 |         } | 
 | 278 |         break; | 
 | 279 |       case 1: | 
 | 280 |         log(indent, "DW_CFA_advance_loc %d", cfa_low); | 
 | 281 |         log(indent, "Raw Data: 0x%02x", cfa_value); | 
 | 282 |         cur_pc += cfa_low * fde_->cie->code_alignment_factor; | 
 | 283 |         break; | 
 | 284 |       case 2: | 
 | 285 |         if (!LogOffsetRegisterString(indent, cfa_offset, cfa_low)) { | 
 | 286 |           return false; | 
 | 287 |         } | 
 | 288 |         break; | 
 | 289 |       case 3: | 
 | 290 |         log(indent, "DW_CFA_restore register(%d)", cfa_low); | 
 | 291 |         log(indent, "Raw Data: 0x%02x", cfa_value); | 
 | 292 |         break; | 
 | 293 |     } | 
 | 294 |     if (cur_pc != old_pc) { | 
 | 295 |       log(indent, ""); | 
 | 296 |       log(indent, "PC 0x%" PRIx64, cur_pc + load_bias); | 
 | 297 |     } | 
 | 298 |     old_pc = cur_pc; | 
 | 299 |   } | 
 | 300 |   return true; | 
 | 301 | } | 
 | 302 |  | 
 | 303 | // Static data. | 
 | 304 | template <typename AddressType> | 
 | 305 | bool DwarfCfa<AddressType>::cfa_nop(dwarf_loc_regs_t*) { | 
 | 306 |   return true; | 
 | 307 | } | 
 | 308 |  | 
 | 309 | template <typename AddressType> | 
 | 310 | bool DwarfCfa<AddressType>::cfa_set_loc(dwarf_loc_regs_t*) { | 
 | 311 |   AddressType cur_pc = cur_pc_; | 
 | 312 |   AddressType new_pc = operands_[0]; | 
 | 313 |   if (new_pc < cur_pc) { | 
 | 314 |     if (std::is_same<AddressType, uint32_t>::value) { | 
 | 315 |       log(0, "Warning: PC is moving backwards: old 0x%" PRIx32 " new 0x%" PRIx32, cur_pc, new_pc); | 
 | 316 |     } else { | 
 | 317 |       log(0, "Warning: PC is moving backwards: old 0x%" PRIx64 " new 0x%" PRIx64, cur_pc, new_pc); | 
 | 318 |     } | 
 | 319 |   } | 
 | 320 |   cur_pc_ = new_pc; | 
 | 321 |   return true; | 
 | 322 | } | 
 | 323 |  | 
 | 324 | template <typename AddressType> | 
 | 325 | bool DwarfCfa<AddressType>::cfa_advance_loc(dwarf_loc_regs_t*) { | 
 | 326 |   cur_pc_ += operands_[0] * fde_->cie->code_alignment_factor; | 
 | 327 |   return true; | 
 | 328 | } | 
 | 329 |  | 
 | 330 | template <typename AddressType> | 
 | 331 | bool DwarfCfa<AddressType>::cfa_offset(dwarf_loc_regs_t* loc_regs) { | 
 | 332 |   AddressType reg = operands_[0]; | 
 | 333 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {operands_[1]}}; | 
 | 334 |   return true; | 
 | 335 | } | 
 | 336 |  | 
 | 337 | template <typename AddressType> | 
 | 338 | bool DwarfCfa<AddressType>::cfa_restore(dwarf_loc_regs_t* loc_regs) { | 
 | 339 |   AddressType reg = operands_[0]; | 
 | 340 |   if (cie_loc_regs_ == nullptr) { | 
 | 341 |     log(0, "restore while processing cie"); | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 342 |     last_error_.code = DWARF_ERROR_ILLEGAL_STATE; | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 343 |     return false; | 
 | 344 |   } | 
 | 345 |   auto reg_entry = cie_loc_regs_->find(reg); | 
 | 346 |   if (reg_entry == cie_loc_regs_->end()) { | 
 | 347 |     loc_regs->erase(reg); | 
 | 348 |   } else { | 
 | 349 |     (*loc_regs)[reg] = reg_entry->second; | 
 | 350 |   } | 
 | 351 |   return true; | 
 | 352 | } | 
 | 353 |  | 
 | 354 | template <typename AddressType> | 
 | 355 | bool DwarfCfa<AddressType>::cfa_undefined(dwarf_loc_regs_t* loc_regs) { | 
 | 356 |   AddressType reg = operands_[0]; | 
 | 357 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_UNDEFINED}; | 
 | 358 |   return true; | 
 | 359 | } | 
 | 360 |  | 
 | 361 | template <typename AddressType> | 
 | 362 | bool DwarfCfa<AddressType>::cfa_same_value(dwarf_loc_regs_t* loc_regs) { | 
 | 363 |   AddressType reg = operands_[0]; | 
 | 364 |   loc_regs->erase(reg); | 
 | 365 |   return true; | 
 | 366 | } | 
 | 367 |  | 
 | 368 | template <typename AddressType> | 
 | 369 | bool DwarfCfa<AddressType>::cfa_register(dwarf_loc_regs_t* loc_regs) { | 
 | 370 |   AddressType reg = operands_[0]; | 
 | 371 |   AddressType reg_dst = operands_[1]; | 
 | 372 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_REGISTER, .values = {reg_dst}}; | 
 | 373 |   return true; | 
 | 374 | } | 
 | 375 |  | 
 | 376 | template <typename AddressType> | 
 | 377 | bool DwarfCfa<AddressType>::cfa_remember_state(dwarf_loc_regs_t* loc_regs) { | 
 | 378 |   loc_reg_state_.push(*loc_regs); | 
 | 379 |   return true; | 
 | 380 | } | 
 | 381 |  | 
 | 382 | template <typename AddressType> | 
 | 383 | bool DwarfCfa<AddressType>::cfa_restore_state(dwarf_loc_regs_t* loc_regs) { | 
 | 384 |   if (loc_reg_state_.size() == 0) { | 
 | 385 |     log(0, "Warning: Attempt to restore without remember."); | 
 | 386 |     return true; | 
 | 387 |   } | 
 | 388 |   *loc_regs = loc_reg_state_.top(); | 
 | 389 |   loc_reg_state_.pop(); | 
 | 390 |   return true; | 
 | 391 | } | 
 | 392 |  | 
 | 393 | template <typename AddressType> | 
 | 394 | bool DwarfCfa<AddressType>::cfa_def_cfa(dwarf_loc_regs_t* loc_regs) { | 
 | 395 |   (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {operands_[0], operands_[1]}}; | 
 | 396 |   return true; | 
 | 397 | } | 
 | 398 |  | 
 | 399 | template <typename AddressType> | 
 | 400 | bool DwarfCfa<AddressType>::cfa_def_cfa_register(dwarf_loc_regs_t* loc_regs) { | 
 | 401 |   auto cfa_location = loc_regs->find(CFA_REG); | 
 | 402 |   if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) { | 
 | 403 |     log(0, "Attempt to set new register, but cfa is not already set to a register."); | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 404 |     last_error_.code = DWARF_ERROR_ILLEGAL_STATE; | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 405 |     return false; | 
 | 406 |   } | 
 | 407 |  | 
 | 408 |   cfa_location->second.values[0] = operands_[0]; | 
 | 409 |   return true; | 
 | 410 | } | 
 | 411 |  | 
 | 412 | template <typename AddressType> | 
 | 413 | bool DwarfCfa<AddressType>::cfa_def_cfa_offset(dwarf_loc_regs_t* loc_regs) { | 
 | 414 |   // Changing the offset if this is not a register is illegal. | 
 | 415 |   auto cfa_location = loc_regs->find(CFA_REG); | 
 | 416 |   if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) { | 
 | 417 |     log(0, "Attempt to set offset, but cfa is not set to a register."); | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 418 |     last_error_.code = DWARF_ERROR_ILLEGAL_STATE; | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 419 |     return false; | 
 | 420 |   } | 
 | 421 |   cfa_location->second.values[1] = operands_[0]; | 
 | 422 |   return true; | 
 | 423 | } | 
 | 424 |  | 
 | 425 | template <typename AddressType> | 
 | 426 | bool DwarfCfa<AddressType>::cfa_def_cfa_expression(dwarf_loc_regs_t* loc_regs) { | 
 | 427 |   (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_EXPRESSION, | 
 | 428 |                           .values = {operands_[0], memory_->cur_offset()}}; | 
 | 429 |   return true; | 
 | 430 | } | 
 | 431 |  | 
 | 432 | template <typename AddressType> | 
 | 433 | bool DwarfCfa<AddressType>::cfa_expression(dwarf_loc_regs_t* loc_regs) { | 
 | 434 |   AddressType reg = operands_[0]; | 
 | 435 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_EXPRESSION, | 
 | 436 |                       .values = {operands_[1], memory_->cur_offset()}}; | 
 | 437 |   return true; | 
 | 438 | } | 
 | 439 |  | 
 | 440 | template <typename AddressType> | 
 | 441 | bool DwarfCfa<AddressType>::cfa_offset_extended_sf(dwarf_loc_regs_t* loc_regs) { | 
 | 442 |   AddressType reg = operands_[0]; | 
 | 443 |   SignedType value = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor; | 
 | 444 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {static_cast<uint64_t>(value)}}; | 
 | 445 |   return true; | 
 | 446 | } | 
 | 447 |  | 
 | 448 | template <typename AddressType> | 
 | 449 | bool DwarfCfa<AddressType>::cfa_def_cfa_sf(dwarf_loc_regs_t* loc_regs) { | 
 | 450 |   SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor; | 
 | 451 |   (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, | 
 | 452 |                           .values = {operands_[0], static_cast<uint64_t>(offset)}}; | 
 | 453 |   return true; | 
 | 454 | } | 
 | 455 |  | 
 | 456 | template <typename AddressType> | 
 | 457 | bool DwarfCfa<AddressType>::cfa_def_cfa_offset_sf(dwarf_loc_regs_t* loc_regs) { | 
 | 458 |   // Changing the offset if this is not a register is illegal. | 
 | 459 |   auto cfa_location = loc_regs->find(CFA_REG); | 
 | 460 |   if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) { | 
 | 461 |     log(0, "Attempt to set offset, but cfa is not set to a register."); | 
| Christopher Ferris | 2fcf4cf | 2018-01-23 17:52:23 -0800 | [diff] [blame] | 462 |     last_error_.code = DWARF_ERROR_ILLEGAL_STATE; | 
| Christopher Ferris | 8642fcb | 2017-04-24 11:14:39 -0700 | [diff] [blame] | 463 |     return false; | 
 | 464 |   } | 
 | 465 |   SignedType offset = static_cast<SignedType>(operands_[0]) * fde_->cie->data_alignment_factor; | 
 | 466 |   cfa_location->second.values[1] = static_cast<uint64_t>(offset); | 
 | 467 |   return true; | 
 | 468 | } | 
 | 469 |  | 
 | 470 | template <typename AddressType> | 
 | 471 | bool DwarfCfa<AddressType>::cfa_val_offset(dwarf_loc_regs_t* loc_regs) { | 
 | 472 |   AddressType reg = operands_[0]; | 
 | 473 |   SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor; | 
 | 474 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_OFFSET, .values = {static_cast<uint64_t>(offset)}}; | 
 | 475 |   return true; | 
 | 476 | } | 
 | 477 |  | 
 | 478 | template <typename AddressType> | 
 | 479 | bool DwarfCfa<AddressType>::cfa_val_offset_sf(dwarf_loc_regs_t* loc_regs) { | 
 | 480 |   AddressType reg = operands_[0]; | 
 | 481 |   SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor; | 
 | 482 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_OFFSET, .values = {static_cast<uint64_t>(offset)}}; | 
 | 483 |   return true; | 
 | 484 | } | 
 | 485 |  | 
 | 486 | template <typename AddressType> | 
 | 487 | bool DwarfCfa<AddressType>::cfa_val_expression(dwarf_loc_regs_t* loc_regs) { | 
 | 488 |   AddressType reg = operands_[0]; | 
 | 489 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_EXPRESSION, | 
 | 490 |                       .values = {operands_[1], memory_->cur_offset()}}; | 
 | 491 |   return true; | 
 | 492 | } | 
 | 493 |  | 
 | 494 | template <typename AddressType> | 
 | 495 | bool DwarfCfa<AddressType>::cfa_gnu_negative_offset_extended(dwarf_loc_regs_t* loc_regs) { | 
 | 496 |   AddressType reg = operands_[0]; | 
 | 497 |   SignedType offset = -static_cast<SignedType>(operands_[1]); | 
 | 498 |   (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {static_cast<uint64_t>(offset)}}; | 
 | 499 |   return true; | 
 | 500 | } | 
 | 501 |  | 
 | 502 | const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { | 
 | 503 |     { | 
 | 504 |         // 0x00 DW_CFA_nop | 
 | 505 |         "DW_CFA_nop", | 
 | 506 |         2, | 
 | 507 |         0, | 
 | 508 |         {}, | 
 | 509 |         {}, | 
 | 510 |     }, | 
 | 511 |     { | 
 | 512 |         "DW_CFA_set_loc",  // 0x01 DW_CFA_set_loc | 
 | 513 |         2, | 
 | 514 |         1, | 
 | 515 |         {DW_EH_PE_absptr}, | 
 | 516 |         {DWARF_DISPLAY_SET_LOC}, | 
 | 517 |     }, | 
 | 518 |     { | 
 | 519 |         "DW_CFA_advance_loc1",  // 0x02 DW_CFA_advance_loc1 | 
 | 520 |         2, | 
 | 521 |         1, | 
 | 522 |         {DW_EH_PE_udata1}, | 
 | 523 |         {DWARF_DISPLAY_ADVANCE_LOC}, | 
 | 524 |     }, | 
 | 525 |     { | 
 | 526 |         "DW_CFA_advance_loc2",  // 0x03 DW_CFA_advance_loc2 | 
 | 527 |         2, | 
 | 528 |         1, | 
 | 529 |         {DW_EH_PE_udata2}, | 
 | 530 |         {DWARF_DISPLAY_ADVANCE_LOC}, | 
 | 531 |     }, | 
 | 532 |     { | 
 | 533 |         "DW_CFA_advance_loc4",  // 0x04 DW_CFA_advance_loc4 | 
 | 534 |         2, | 
 | 535 |         1, | 
 | 536 |         {DW_EH_PE_udata4}, | 
 | 537 |         {DWARF_DISPLAY_ADVANCE_LOC}, | 
 | 538 |     }, | 
 | 539 |     { | 
 | 540 |         "DW_CFA_offset_extended",  // 0x05 DW_CFA_offset_extended | 
 | 541 |         2, | 
 | 542 |         2, | 
 | 543 |         {DW_EH_PE_uleb128, DW_EH_PE_uleb128}, | 
 | 544 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER}, | 
 | 545 |     }, | 
 | 546 |     { | 
 | 547 |         "DW_CFA_restore_extended",  // 0x06 DW_CFA_restore_extended | 
 | 548 |         2, | 
 | 549 |         1, | 
 | 550 |         {DW_EH_PE_uleb128}, | 
 | 551 |         {DWARF_DISPLAY_REGISTER}, | 
 | 552 |     }, | 
 | 553 |     { | 
 | 554 |         "DW_CFA_undefined",  // 0x07 DW_CFA_undefined | 
 | 555 |         2, | 
 | 556 |         1, | 
 | 557 |         {DW_EH_PE_uleb128}, | 
 | 558 |         {DWARF_DISPLAY_REGISTER}, | 
 | 559 |     }, | 
 | 560 |     { | 
 | 561 |         "DW_CFA_same_value",  // 0x08 DW_CFA_same_value | 
 | 562 |         2, | 
 | 563 |         1, | 
 | 564 |         {DW_EH_PE_uleb128}, | 
 | 565 |         {DWARF_DISPLAY_REGISTER}, | 
 | 566 |     }, | 
 | 567 |     { | 
 | 568 |         "DW_CFA_register",  // 0x09 DW_CFA_register | 
 | 569 |         2, | 
 | 570 |         2, | 
 | 571 |         {DW_EH_PE_uleb128, DW_EH_PE_uleb128}, | 
 | 572 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_REGISTER}, | 
 | 573 |     }, | 
 | 574 |     { | 
 | 575 |         "DW_CFA_remember_state",  // 0x0a DW_CFA_remember_state | 
 | 576 |         2, | 
 | 577 |         0, | 
 | 578 |         {}, | 
 | 579 |         {}, | 
 | 580 |     }, | 
 | 581 |     { | 
 | 582 |         "DW_CFA_restore_state",  // 0x0b DW_CFA_restore_state | 
 | 583 |         2, | 
 | 584 |         0, | 
 | 585 |         {}, | 
 | 586 |         {}, | 
 | 587 |     }, | 
 | 588 |     { | 
 | 589 |         "DW_CFA_def_cfa",  // 0x0c DW_CFA_def_cfa | 
 | 590 |         2, | 
 | 591 |         2, | 
 | 592 |         {DW_EH_PE_uleb128, DW_EH_PE_uleb128}, | 
 | 593 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER}, | 
 | 594 |     }, | 
 | 595 |     { | 
 | 596 |         "DW_CFA_def_cfa_register",  // 0x0d DW_CFA_def_cfa_register | 
 | 597 |         2, | 
 | 598 |         1, | 
 | 599 |         {DW_EH_PE_uleb128}, | 
 | 600 |         {DWARF_DISPLAY_REGISTER}, | 
 | 601 |     }, | 
 | 602 |     { | 
 | 603 |         "DW_CFA_def_cfa_offset",  // 0x0e DW_CFA_def_cfa_offset | 
 | 604 |         2, | 
 | 605 |         1, | 
 | 606 |         {DW_EH_PE_uleb128}, | 
 | 607 |         {DWARF_DISPLAY_NUMBER}, | 
 | 608 |     }, | 
 | 609 |     { | 
 | 610 |         "DW_CFA_def_cfa_expression",  // 0x0f DW_CFA_def_cfa_expression | 
 | 611 |         2, | 
 | 612 |         1, | 
 | 613 |         {DW_EH_PE_block}, | 
 | 614 |         {DWARF_DISPLAY_EVAL_BLOCK}, | 
 | 615 |     }, | 
 | 616 |     { | 
 | 617 |         "DW_CFA_expression",  // 0x10 DW_CFA_expression | 
 | 618 |         2, | 
 | 619 |         2, | 
 | 620 |         {DW_EH_PE_uleb128, DW_EH_PE_block}, | 
 | 621 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_EVAL_BLOCK}, | 
 | 622 |     }, | 
 | 623 |     { | 
 | 624 |         "DW_CFA_offset_extended_sf",  // 0x11 DW_CFA_offset_extend_sf | 
 | 625 |         2, | 
 | 626 |         2, | 
 | 627 |         {DW_EH_PE_uleb128, DW_EH_PE_sleb128}, | 
 | 628 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER}, | 
 | 629 |     }, | 
 | 630 |     { | 
 | 631 |         "DW_CFA_def_cfa_sf",  // 0x12 DW_CFA_def_cfa_sf | 
 | 632 |         2, | 
 | 633 |         2, | 
 | 634 |         {DW_EH_PE_uleb128, DW_EH_PE_sleb128}, | 
 | 635 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER}, | 
 | 636 |     }, | 
 | 637 |     { | 
 | 638 |         "DW_CFA_def_cfa_offset_sf",  // 0x13 DW_CFA_def_cfa_offset_sf | 
 | 639 |         2, | 
 | 640 |         1, | 
 | 641 |         {DW_EH_PE_sleb128}, | 
 | 642 |         {DWARF_DISPLAY_SIGNED_NUMBER}, | 
 | 643 |     }, | 
 | 644 |     { | 
 | 645 |         "DW_CFA_val_offset",  // 0x14 DW_CFA_val_offset | 
 | 646 |         2, | 
 | 647 |         2, | 
 | 648 |         {DW_EH_PE_uleb128, DW_EH_PE_uleb128}, | 
 | 649 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER}, | 
 | 650 |     }, | 
 | 651 |     { | 
 | 652 |         "DW_CFA_val_offset_sf",  // 0x15 DW_CFA_val_offset_sf | 
 | 653 |         2, | 
 | 654 |         2, | 
 | 655 |         {DW_EH_PE_uleb128, DW_EH_PE_sleb128}, | 
 | 656 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER}, | 
 | 657 |     }, | 
 | 658 |     { | 
 | 659 |         "DW_CFA_val_expression",  // 0x16 DW_CFA_val_expression | 
 | 660 |         2, | 
 | 661 |         2, | 
 | 662 |         {DW_EH_PE_uleb128, DW_EH_PE_block}, | 
 | 663 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_EVAL_BLOCK}, | 
 | 664 |     }, | 
 | 665 |     {nullptr, 0, 0, {}, {}},  // 0x17 illegal cfa | 
 | 666 |     {nullptr, 0, 0, {}, {}},  // 0x18 illegal cfa | 
 | 667 |     {nullptr, 0, 0, {}, {}},  // 0x19 illegal cfa | 
 | 668 |     {nullptr, 0, 0, {}, {}},  // 0x1a illegal cfa | 
 | 669 |     {nullptr, 0, 0, {}, {}},  // 0x1b illegal cfa | 
 | 670 |     {nullptr, 0, 0, {}, {}},  // 0x1c DW_CFA_lo_user (Treat as illegal) | 
 | 671 |     {nullptr, 0, 0, {}, {}},  // 0x1d illegal cfa | 
 | 672 |     {nullptr, 0, 0, {}, {}},  // 0x1e illegal cfa | 
 | 673 |     {nullptr, 0, 0, {}, {}},  // 0x1f illegal cfa | 
 | 674 |     {nullptr, 0, 0, {}, {}},  // 0x20 illegal cfa | 
 | 675 |     {nullptr, 0, 0, {}, {}},  // 0x21 illegal cfa | 
 | 676 |     {nullptr, 0, 0, {}, {}},  // 0x22 illegal cfa | 
 | 677 |     {nullptr, 0, 0, {}, {}},  // 0x23 illegal cfa | 
 | 678 |     {nullptr, 0, 0, {}, {}},  // 0x24 illegal cfa | 
 | 679 |     {nullptr, 0, 0, {}, {}},  // 0x25 illegal cfa | 
 | 680 |     {nullptr, 0, 0, {}, {}},  // 0x26 illegal cfa | 
 | 681 |     {nullptr, 0, 0, {}, {}},  // 0x27 illegal cfa | 
 | 682 |     {nullptr, 0, 0, {}, {}},  // 0x28 illegal cfa | 
 | 683 |     {nullptr, 0, 0, {}, {}},  // 0x29 illegal cfa | 
 | 684 |     {nullptr, 0, 0, {}, {}},  // 0x2a illegal cfa | 
 | 685 |     {nullptr, 0, 0, {}, {}},  // 0x2b illegal cfa | 
 | 686 |     {nullptr, 0, 0, {}, {}},  // 0x2c illegal cfa | 
 | 687 |     {nullptr, 0, 0, {}, {}},  // 0x2d DW_CFA_GNU_window_save (Treat as illegal) | 
 | 688 |     { | 
 | 689 |         "DW_CFA_GNU_args_size",  // 0x2e DW_CFA_GNU_args_size | 
 | 690 |         2, | 
 | 691 |         1, | 
 | 692 |         {DW_EH_PE_uleb128}, | 
 | 693 |         {DWARF_DISPLAY_NUMBER}, | 
 | 694 |     }, | 
 | 695 |     { | 
 | 696 |         "DW_CFA_GNU_negative_offset_extended",  // 0x2f DW_CFA_GNU_negative_offset_extended | 
 | 697 |         2, | 
 | 698 |         2, | 
 | 699 |         {DW_EH_PE_uleb128, DW_EH_PE_uleb128}, | 
 | 700 |         {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER}, | 
 | 701 |     }, | 
 | 702 |     {nullptr, 0, 0, {}, {}},  // 0x31 illegal cfa | 
 | 703 |     {nullptr, 0, 0, {}, {}},  // 0x32 illegal cfa | 
 | 704 |     {nullptr, 0, 0, {}, {}},  // 0x33 illegal cfa | 
 | 705 |     {nullptr, 0, 0, {}, {}},  // 0x34 illegal cfa | 
 | 706 |     {nullptr, 0, 0, {}, {}},  // 0x35 illegal cfa | 
 | 707 |     {nullptr, 0, 0, {}, {}},  // 0x36 illegal cfa | 
 | 708 |     {nullptr, 0, 0, {}, {}},  // 0x37 illegal cfa | 
 | 709 |     {nullptr, 0, 0, {}, {}},  // 0x38 illegal cfa | 
 | 710 |     {nullptr, 0, 0, {}, {}},  // 0x39 illegal cfa | 
 | 711 |     {nullptr, 0, 0, {}, {}},  // 0x3a illegal cfa | 
 | 712 |     {nullptr, 0, 0, {}, {}},  // 0x3b illegal cfa | 
 | 713 |     {nullptr, 0, 0, {}, {}},  // 0x3c illegal cfa | 
 | 714 |     {nullptr, 0, 0, {}, {}},  // 0x3d illegal cfa | 
 | 715 |     {nullptr, 0, 0, {}, {}},  // 0x3e illegal cfa | 
 | 716 |     {nullptr, 0, 0, {}, {}},  // 0x3f DW_CFA_hi_user (Treat as illegal) | 
 | 717 | }; | 
 | 718 |  | 
 | 719 | // Explicitly instantiate DwarfCfa. | 
 | 720 | template class DwarfCfa<uint32_t>; | 
 | 721 | template class DwarfCfa<uint64_t>; | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 722 |  | 
 | 723 | }  // namespace unwindstack |