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