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