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