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