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