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