blob: c6db209dbdd775975b45e9f9d51d687f9d0b2796 [file] [log] [blame]
Christopher Ferris8642fcb2017-04-24 11:14:39 -07001/*
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
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -070024#include <android-base/macros.h>
Christopher Ferris8642fcb2017-04-24 11:14:39 -070025#include <android-base/stringprintf.h>
26
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080027#include <unwindstack/DwarfError.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070028#include <unwindstack/DwarfLocation.h>
Tamas Petz6835d012020-01-22 14:22:41 +010029#include <unwindstack/Elf.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070030#include <unwindstack/Log.h>
Tamas Petz6835d012020-01-22 14:22:41 +010031#include <unwindstack/MachineArm64.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070032
Christopher Ferris8642fcb2017-04-24 11:14:39 -070033#include "DwarfCfa.h"
34#include "DwarfEncoding.h"
Christopher Ferris8642fcb2017-04-24 11:14:39 -070035#include "DwarfOp.h"
Christopher Ferrisd226a512017-07-14 10:37:19 -070036
37namespace unwindstack {
Christopher Ferris8642fcb2017-04-24 11:14:39 -070038
39template <typename AddressType>
40constexpr typename DwarfCfa<AddressType>::process_func DwarfCfa<AddressType>::kCallbackTable[64];
41
42template <typename AddressType>
43bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
44 dwarf_loc_regs_t* 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 }
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080050 last_error_.code = DWARF_ERROR_NONE;
51 last_error_.address = 0;
Christopher Ferris8642fcb2017-04-24 11:14:39 -070052
53 memory_->set_cur_offset(start_offset);
54 uint64_t cfa_offset;
55 cur_pc_ = fde_->pc_start;
David Srbecky3386eba2018-03-14 21:30:25 +000056 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_;
Christopher Ferris8642fcb2017-04-24 11:14:39 -070067 operands_.clear();
68 // Read the cfa information.
69 uint8_t cfa_value;
70 if (!memory_->ReadBytes(&cfa_value, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080071 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
72 last_error_.address = memory_->cur_offset();
Christopher Ferris8642fcb2017-04-24 11:14:39 -070073 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)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080084 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
85 last_error_.address = memory_->cur_offset();
Christopher Ferris8642fcb2017-04-24 11:14:39 -070086 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(0, "restore while processing cie");
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080097 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
Christopher Ferris8642fcb2017-04-24 11:14:39 -070098 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) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800112 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700113 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)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800121 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
122 last_error_.address = memory_->cur_offset();
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700123 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)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800131 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
132 last_error_.address = memory_->cur_offset();
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700133 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 }
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700145}
146
147template <typename AddressType>
148std::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;
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -0700160 FALLTHROUGH_INTENDED;
161 // Fall through to log the value.
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700162 case DwarfCfaInfo::DWARF_DISPLAY_NUMBER:
163 string += " " + std::to_string(value);
164 break;
165 case DwarfCfaInfo::DWARF_DISPLAY_SET_LOC:
166 *cur_pc = value;
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -0700167 FALLTHROUGH_INTENDED;
168 // Fall through to log the value.
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700169 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
182template <typename AddressType>
183bool 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(indent, "DW_CFA_offset register(%d) %" PRId64, reg, offset);
201 log(indent, "%s", raw_data.c_str());
202 return true;
203}
204
205template <typename AddressType>
206bool 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];
Tamas Petz6835d012020-01-22 14:22:41 +0100209 if (cfa->name[0] == '\0' || (arch_ != ARCH_ARM64 && op == 0x2d)) {
210 if (op == 0x2d) {
211 log(indent, "Illegal (Only valid on aarch64)");
212 } else {
213 log(indent, "Illegal");
214 }
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700215 log(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(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(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(indent, "%s", raw_data.c_str());
266 }
267
268 // Log any of the expression data.
Chih-Hung Hsieh1b7b7972018-12-11 10:34:33 -0800269 for (const auto& line : expression_lines) {
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700270 log(indent + 1, "%s", line.c_str());
271 }
272 return true;
273}
274
275template <typename AddressType>
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700276bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t start_offset,
277 uint64_t end_offset) {
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700278 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(indent, "DW_CFA_advance_loc %d", cfa_low);
299 log(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(indent, "DW_CFA_restore register(%d)", cfa_low);
309 log(indent, "Raw Data: 0x%02x", cfa_value);
310 break;
311 }
312 if (cur_pc != old_pc) {
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700313 log(0, "");
314 log(indent, "PC 0x%" PRIx64, cur_pc);
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700315 }
316 old_pc = cur_pc;
317 }
318 return true;
319}
320
321// Static data.
322template <typename AddressType>
323bool DwarfCfa<AddressType>::cfa_nop(dwarf_loc_regs_t*) {
324 return true;
325}
326
327template <typename AddressType>
328bool DwarfCfa<AddressType>::cfa_set_loc(dwarf_loc_regs_t*) {
329 AddressType cur_pc = cur_pc_;
330 AddressType new_pc = operands_[0];
331 if (new_pc < cur_pc) {
332 if (std::is_same<AddressType, uint32_t>::value) {
333 log(0, "Warning: PC is moving backwards: old 0x%" PRIx32 " new 0x%" PRIx32, cur_pc, new_pc);
334 } else {
335 log(0, "Warning: PC is moving backwards: old 0x%" PRIx64 " new 0x%" PRIx64, cur_pc, new_pc);
336 }
337 }
338 cur_pc_ = new_pc;
339 return true;
340}
341
342template <typename AddressType>
343bool DwarfCfa<AddressType>::cfa_advance_loc(dwarf_loc_regs_t*) {
344 cur_pc_ += operands_[0] * fde_->cie->code_alignment_factor;
345 return true;
346}
347
348template <typename AddressType>
349bool DwarfCfa<AddressType>::cfa_offset(dwarf_loc_regs_t* loc_regs) {
350 AddressType reg = operands_[0];
351 (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {operands_[1]}};
352 return true;
353}
354
355template <typename AddressType>
356bool DwarfCfa<AddressType>::cfa_restore(dwarf_loc_regs_t* loc_regs) {
357 AddressType reg = operands_[0];
358 if (cie_loc_regs_ == nullptr) {
359 log(0, "restore while processing cie");
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800360 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700361 return false;
362 }
363 auto reg_entry = cie_loc_regs_->find(reg);
364 if (reg_entry == cie_loc_regs_->end()) {
365 loc_regs->erase(reg);
366 } else {
367 (*loc_regs)[reg] = reg_entry->second;
368 }
369 return true;
370}
371
372template <typename AddressType>
373bool DwarfCfa<AddressType>::cfa_undefined(dwarf_loc_regs_t* loc_regs) {
374 AddressType reg = operands_[0];
375 (*loc_regs)[reg] = {.type = DWARF_LOCATION_UNDEFINED};
376 return true;
377}
378
379template <typename AddressType>
380bool DwarfCfa<AddressType>::cfa_same_value(dwarf_loc_regs_t* loc_regs) {
381 AddressType reg = operands_[0];
382 loc_regs->erase(reg);
383 return true;
384}
385
386template <typename AddressType>
387bool DwarfCfa<AddressType>::cfa_register(dwarf_loc_regs_t* loc_regs) {
388 AddressType reg = operands_[0];
389 AddressType reg_dst = operands_[1];
390 (*loc_regs)[reg] = {.type = DWARF_LOCATION_REGISTER, .values = {reg_dst}};
391 return true;
392}
393
394template <typename AddressType>
395bool DwarfCfa<AddressType>::cfa_remember_state(dwarf_loc_regs_t* loc_regs) {
396 loc_reg_state_.push(*loc_regs);
397 return true;
398}
399
400template <typename AddressType>
401bool DwarfCfa<AddressType>::cfa_restore_state(dwarf_loc_regs_t* loc_regs) {
402 if (loc_reg_state_.size() == 0) {
403 log(0, "Warning: Attempt to restore without remember.");
404 return true;
405 }
406 *loc_regs = loc_reg_state_.top();
407 loc_reg_state_.pop();
408 return true;
409}
410
411template <typename AddressType>
412bool DwarfCfa<AddressType>::cfa_def_cfa(dwarf_loc_regs_t* loc_regs) {
413 (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {operands_[0], operands_[1]}};
414 return true;
415}
416
417template <typename AddressType>
418bool DwarfCfa<AddressType>::cfa_def_cfa_register(dwarf_loc_regs_t* loc_regs) {
419 auto cfa_location = loc_regs->find(CFA_REG);
420 if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
421 log(0, "Attempt to set new register, but cfa is not already set to a register.");
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800422 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700423 return false;
424 }
425
426 cfa_location->second.values[0] = operands_[0];
427 return true;
428}
429
430template <typename AddressType>
431bool DwarfCfa<AddressType>::cfa_def_cfa_offset(dwarf_loc_regs_t* loc_regs) {
432 // Changing the offset if this is not a register is illegal.
433 auto cfa_location = loc_regs->find(CFA_REG);
434 if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
435 log(0, "Attempt to set offset, but cfa is not set to a register.");
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800436 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700437 return false;
438 }
439 cfa_location->second.values[1] = operands_[0];
440 return true;
441}
442
443template <typename AddressType>
444bool DwarfCfa<AddressType>::cfa_def_cfa_expression(dwarf_loc_regs_t* loc_regs) {
David Srbecky3692f252018-03-08 16:57:19 +0000445 // There is only one type of expression for CFA evaluation and the DWARF
446 // specification is unclear whether it returns the address or the
447 // dereferenced value. GDB expects the value, so will we.
448 (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_VAL_EXPRESSION,
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700449 .values = {operands_[0], memory_->cur_offset()}};
450 return true;
451}
452
453template <typename AddressType>
454bool DwarfCfa<AddressType>::cfa_expression(dwarf_loc_regs_t* loc_regs) {
455 AddressType reg = operands_[0];
456 (*loc_regs)[reg] = {.type = DWARF_LOCATION_EXPRESSION,
457 .values = {operands_[1], memory_->cur_offset()}};
458 return true;
459}
460
461template <typename AddressType>
462bool DwarfCfa<AddressType>::cfa_offset_extended_sf(dwarf_loc_regs_t* loc_regs) {
463 AddressType reg = operands_[0];
464 SignedType value = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
465 (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {static_cast<uint64_t>(value)}};
466 return true;
467}
468
469template <typename AddressType>
470bool DwarfCfa<AddressType>::cfa_def_cfa_sf(dwarf_loc_regs_t* loc_regs) {
471 SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
472 (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_REGISTER,
473 .values = {operands_[0], static_cast<uint64_t>(offset)}};
474 return true;
475}
476
477template <typename AddressType>
478bool DwarfCfa<AddressType>::cfa_def_cfa_offset_sf(dwarf_loc_regs_t* loc_regs) {
479 // Changing the offset if this is not a register is illegal.
480 auto cfa_location = loc_regs->find(CFA_REG);
481 if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
482 log(0, "Attempt to set offset, but cfa is not set to a register.");
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800483 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700484 return false;
485 }
486 SignedType offset = static_cast<SignedType>(operands_[0]) * fde_->cie->data_alignment_factor;
487 cfa_location->second.values[1] = static_cast<uint64_t>(offset);
488 return true;
489}
490
491template <typename AddressType>
492bool DwarfCfa<AddressType>::cfa_val_offset(dwarf_loc_regs_t* loc_regs) {
493 AddressType reg = operands_[0];
494 SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
495 (*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_OFFSET, .values = {static_cast<uint64_t>(offset)}};
496 return true;
497}
498
499template <typename AddressType>
500bool DwarfCfa<AddressType>::cfa_val_offset_sf(dwarf_loc_regs_t* 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
507template <typename AddressType>
508bool DwarfCfa<AddressType>::cfa_val_expression(dwarf_loc_regs_t* loc_regs) {
509 AddressType reg = operands_[0];
510 (*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_EXPRESSION,
511 .values = {operands_[1], memory_->cur_offset()}};
512 return true;
513}
514
515template <typename AddressType>
516bool DwarfCfa<AddressType>::cfa_gnu_negative_offset_extended(dwarf_loc_regs_t* loc_regs) {
517 AddressType reg = operands_[0];
518 SignedType offset = -static_cast<SignedType>(operands_[1]);
519 (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {static_cast<uint64_t>(offset)}};
520 return true;
521}
522
Tamas Petz6835d012020-01-22 14:22:41 +0100523template <typename AddressType>
524bool DwarfCfa<AddressType>::cfa_aarch64_negate_ra_state(dwarf_loc_regs_t* loc_regs) {
525 // Only supported on aarch64.
526 if (arch_ != ARCH_ARM64) {
527 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
528 return false;
529 }
530
531 auto cfa_location = loc_regs->find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
532 if (cfa_location == loc_regs->end()) {
533 (*loc_regs)[Arm64Reg::ARM64_PREG_RA_SIGN_STATE] = {.type = DWARF_LOCATION_PSEUDO_REGISTER,
534 .values = {1}};
535 } else {
536 cfa_location->second.values[0] ^= 1;
537 }
538 return true;
539}
540
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700541const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = {
542 {
543 // 0x00 DW_CFA_nop
544 "DW_CFA_nop",
545 2,
546 0,
547 {},
548 {},
549 },
550 {
551 "DW_CFA_set_loc", // 0x01 DW_CFA_set_loc
552 2,
553 1,
554 {DW_EH_PE_absptr},
555 {DWARF_DISPLAY_SET_LOC},
556 },
557 {
558 "DW_CFA_advance_loc1", // 0x02 DW_CFA_advance_loc1
559 2,
560 1,
561 {DW_EH_PE_udata1},
562 {DWARF_DISPLAY_ADVANCE_LOC},
563 },
564 {
565 "DW_CFA_advance_loc2", // 0x03 DW_CFA_advance_loc2
566 2,
567 1,
568 {DW_EH_PE_udata2},
569 {DWARF_DISPLAY_ADVANCE_LOC},
570 },
571 {
572 "DW_CFA_advance_loc4", // 0x04 DW_CFA_advance_loc4
573 2,
574 1,
575 {DW_EH_PE_udata4},
576 {DWARF_DISPLAY_ADVANCE_LOC},
577 },
578 {
579 "DW_CFA_offset_extended", // 0x05 DW_CFA_offset_extended
580 2,
581 2,
582 {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
583 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
584 },
585 {
586 "DW_CFA_restore_extended", // 0x06 DW_CFA_restore_extended
587 2,
588 1,
589 {DW_EH_PE_uleb128},
590 {DWARF_DISPLAY_REGISTER},
591 },
592 {
593 "DW_CFA_undefined", // 0x07 DW_CFA_undefined
594 2,
595 1,
596 {DW_EH_PE_uleb128},
597 {DWARF_DISPLAY_REGISTER},
598 },
599 {
600 "DW_CFA_same_value", // 0x08 DW_CFA_same_value
601 2,
602 1,
603 {DW_EH_PE_uleb128},
604 {DWARF_DISPLAY_REGISTER},
605 },
606 {
607 "DW_CFA_register", // 0x09 DW_CFA_register
608 2,
609 2,
610 {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
611 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_REGISTER},
612 },
613 {
614 "DW_CFA_remember_state", // 0x0a DW_CFA_remember_state
615 2,
616 0,
617 {},
618 {},
619 },
620 {
621 "DW_CFA_restore_state", // 0x0b DW_CFA_restore_state
622 2,
623 0,
624 {},
625 {},
626 },
627 {
628 "DW_CFA_def_cfa", // 0x0c DW_CFA_def_cfa
629 2,
630 2,
631 {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
632 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
633 },
634 {
635 "DW_CFA_def_cfa_register", // 0x0d DW_CFA_def_cfa_register
636 2,
637 1,
638 {DW_EH_PE_uleb128},
639 {DWARF_DISPLAY_REGISTER},
640 },
641 {
642 "DW_CFA_def_cfa_offset", // 0x0e DW_CFA_def_cfa_offset
643 2,
644 1,
645 {DW_EH_PE_uleb128},
646 {DWARF_DISPLAY_NUMBER},
647 },
648 {
649 "DW_CFA_def_cfa_expression", // 0x0f DW_CFA_def_cfa_expression
650 2,
651 1,
652 {DW_EH_PE_block},
653 {DWARF_DISPLAY_EVAL_BLOCK},
654 },
655 {
656 "DW_CFA_expression", // 0x10 DW_CFA_expression
657 2,
658 2,
659 {DW_EH_PE_uleb128, DW_EH_PE_block},
660 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_EVAL_BLOCK},
661 },
662 {
663 "DW_CFA_offset_extended_sf", // 0x11 DW_CFA_offset_extend_sf
664 2,
665 2,
666 {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
667 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
668 },
669 {
670 "DW_CFA_def_cfa_sf", // 0x12 DW_CFA_def_cfa_sf
671 2,
672 2,
673 {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
674 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
675 },
676 {
677 "DW_CFA_def_cfa_offset_sf", // 0x13 DW_CFA_def_cfa_offset_sf
678 2,
679 1,
680 {DW_EH_PE_sleb128},
681 {DWARF_DISPLAY_SIGNED_NUMBER},
682 },
683 {
684 "DW_CFA_val_offset", // 0x14 DW_CFA_val_offset
685 2,
686 2,
687 {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
688 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
689 },
690 {
691 "DW_CFA_val_offset_sf", // 0x15 DW_CFA_val_offset_sf
692 2,
693 2,
694 {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
695 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
696 },
697 {
698 "DW_CFA_val_expression", // 0x16 DW_CFA_val_expression
699 2,
700 2,
701 {DW_EH_PE_uleb128, DW_EH_PE_block},
702 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_EVAL_BLOCK},
703 },
Vic Yang80aba542018-12-14 05:58:32 -0800704 {"", 0, 0, {}, {}}, // 0x17 illegal cfa
705 {"", 0, 0, {}, {}}, // 0x18 illegal cfa
706 {"", 0, 0, {}, {}}, // 0x19 illegal cfa
707 {"", 0, 0, {}, {}}, // 0x1a illegal cfa
708 {"", 0, 0, {}, {}}, // 0x1b illegal cfa
709 {"", 0, 0, {}, {}}, // 0x1c DW_CFA_lo_user (Treat as illegal)
710 {"", 0, 0, {}, {}}, // 0x1d illegal cfa
711 {"", 0, 0, {}, {}}, // 0x1e illegal cfa
712 {"", 0, 0, {}, {}}, // 0x1f illegal cfa
713 {"", 0, 0, {}, {}}, // 0x20 illegal cfa
714 {"", 0, 0, {}, {}}, // 0x21 illegal cfa
715 {"", 0, 0, {}, {}}, // 0x22 illegal cfa
716 {"", 0, 0, {}, {}}, // 0x23 illegal cfa
717 {"", 0, 0, {}, {}}, // 0x24 illegal cfa
718 {"", 0, 0, {}, {}}, // 0x25 illegal cfa
719 {"", 0, 0, {}, {}}, // 0x26 illegal cfa
720 {"", 0, 0, {}, {}}, // 0x27 illegal cfa
721 {"", 0, 0, {}, {}}, // 0x28 illegal cfa
722 {"", 0, 0, {}, {}}, // 0x29 illegal cfa
723 {"", 0, 0, {}, {}}, // 0x2a illegal cfa
724 {"", 0, 0, {}, {}}, // 0x2b illegal cfa
725 {"", 0, 0, {}, {}}, // 0x2c illegal cfa
Tamas Petz6835d012020-01-22 14:22:41 +0100726 {
727 "DW_CFA_AARCH64_negate_ra_state", // 0x2d DW_CFA_AARCH64_negate_ra_state
728 3,
729 0,
730 {},
731 {},
732 },
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700733 {
734 "DW_CFA_GNU_args_size", // 0x2e DW_CFA_GNU_args_size
735 2,
736 1,
737 {DW_EH_PE_uleb128},
738 {DWARF_DISPLAY_NUMBER},
739 },
740 {
741 "DW_CFA_GNU_negative_offset_extended", // 0x2f DW_CFA_GNU_negative_offset_extended
742 2,
743 2,
744 {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
745 {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
746 },
Vic Yang80aba542018-12-14 05:58:32 -0800747 {"", 0, 0, {}, {}}, // 0x31 illegal cfa
748 {"", 0, 0, {}, {}}, // 0x32 illegal cfa
749 {"", 0, 0, {}, {}}, // 0x33 illegal cfa
750 {"", 0, 0, {}, {}}, // 0x34 illegal cfa
751 {"", 0, 0, {}, {}}, // 0x35 illegal cfa
752 {"", 0, 0, {}, {}}, // 0x36 illegal cfa
753 {"", 0, 0, {}, {}}, // 0x37 illegal cfa
754 {"", 0, 0, {}, {}}, // 0x38 illegal cfa
755 {"", 0, 0, {}, {}}, // 0x39 illegal cfa
756 {"", 0, 0, {}, {}}, // 0x3a illegal cfa
757 {"", 0, 0, {}, {}}, // 0x3b illegal cfa
758 {"", 0, 0, {}, {}}, // 0x3c illegal cfa
759 {"", 0, 0, {}, {}}, // 0x3d illegal cfa
760 {"", 0, 0, {}, {}}, // 0x3e illegal cfa
761 {"", 0, 0, {}, {}}, // 0x3f DW_CFA_hi_user (Treat as illegal)
Christopher Ferris8642fcb2017-04-24 11:14:39 -0700762};
763
764// Explicitly instantiate DwarfCfa.
765template class DwarfCfa<uint32_t>;
766template class DwarfCfa<uint64_t>;
Christopher Ferrisd226a512017-07-14 10:37:19 -0700767
768} // namespace unwindstack