blob: eb8394989badd2135516f24fe28369c2520bc327 [file] [log] [blame]
Christopher Ferris53a3c9b2017-05-10 18:34:15 -07001/*
2 * Copyright (C) 2017 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 <stdint.h>
18
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080019#include <unwindstack/DwarfError.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070020#include <unwindstack/DwarfLocation.h>
21#include <unwindstack/DwarfMemory.h>
22#include <unwindstack/DwarfSection.h>
23#include <unwindstack/DwarfStructs.h>
24#include <unwindstack/Log.h>
25#include <unwindstack/Memory.h>
26#include <unwindstack/Regs.h>
27
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070028#include "DwarfCfa.h"
Christopher Ferrisc9dee842017-11-03 14:50:27 -070029#include "DwarfDebugFrame.h"
30#include "DwarfEhFrame.h"
Christopher Ferris559c7f22018-02-12 20:18:03 -080031#include "DwarfEncoding.h"
32#include "DwarfOp.h"
33#include "RegsInfo.h"
Christopher Ferrisc9dee842017-11-03 14:50:27 -070034
Christopher Ferrisd226a512017-07-14 10:37:19 -070035namespace unwindstack {
36
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080037DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070038
39const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
40 uint64_t fde_offset;
41 if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
42 return nullptr;
43 }
44 const DwarfFde* fde = GetFdeFromOffset(fde_offset);
Christopher Ferris13b86652017-11-05 14:01:43 -080045 if (fde == nullptr) {
46 return nullptr;
47 }
48
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070049 // Guaranteed pc >= pc_start, need to check pc in the fde range.
50 if (pc < fde->pc_end) {
51 return fde;
52 }
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080053 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070054 return nullptr;
55}
56
Christopher Ferrisb9de87f2017-09-20 13:37:24 -070057bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
David Srbecky3386eba2018-03-14 21:30:25 +000058 // Lookup the pc in the cache.
59 auto it = loc_regs_.upper_bound(pc);
60 if (it == loc_regs_.end() || pc < it->second.pc_start) {
61 last_error_.code = DWARF_ERROR_NONE;
62 const DwarfFde* fde = GetFdeFromPc(pc);
63 if (fde == nullptr || fde->cie == nullptr) {
64 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
65 return false;
66 }
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070067
David Srbecky3386eba2018-03-14 21:30:25 +000068 // Now get the location information for this pc.
69 dwarf_loc_regs_t loc_regs;
70 if (!GetCfaLocationInfo(pc, fde, &loc_regs)) {
71 return false;
72 }
73 loc_regs.cie = fde->cie;
74
75 // Store it in the cache.
76 it = loc_regs_.emplace(loc_regs.pc_end, std::move(loc_regs)).first;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070077 }
78
79 // Now eval the actual registers.
David Srbecky3386eba2018-03-14 21:30:25 +000080 return Eval(it->second.cie, process_memory, it->second, regs, finished);
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070081}
82
83template <typename AddressType>
Christopher Ferris559c7f22018-02-12 20:18:03 -080084bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, Memory* regular_memory,
85 AddressType* value,
86 RegsInfo<AddressType>* regs_info,
87 bool* is_dex_pc) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070088 DwarfOp<AddressType> op(&memory_, regular_memory);
Christopher Ferris559c7f22018-02-12 20:18:03 -080089 op.set_regs_info(regs_info);
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070090
91 // Need to evaluate the op data.
Christopher Ferris559c7f22018-02-12 20:18:03 -080092 uint64_t end = loc.values[1];
93 uint64_t start = end - loc.values[0];
94 if (!op.Eval(start, end)) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -070095 last_error_ = op.last_error();
96 return false;
97 }
98 if (op.StackSize() == 0) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080099 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700100 return false;
101 }
102 // We don't support an expression that evaluates to a register number.
103 if (op.is_register()) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800104 last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700105 return false;
106 }
107 *value = op.StackAt(0);
Christopher Ferris559c7f22018-02-12 20:18:03 -0800108 if (is_dex_pc != nullptr && op.dex_pc_set()) {
109 *is_dex_pc = true;
110 }
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700111 return true;
112}
113
114template <typename AddressType>
Christopher Ferris98984b42018-01-17 12:59:45 -0800115struct EvalInfo {
116 const dwarf_loc_regs_t* loc_regs;
117 const DwarfCie* cie;
Christopher Ferris98984b42018-01-17 12:59:45 -0800118 Memory* regular_memory;
119 AddressType cfa;
120 bool return_address_undefined = false;
Christopher Ferris559c7f22018-02-12 20:18:03 -0800121 RegsInfo<AddressType> regs_info;
Christopher Ferris98984b42018-01-17 12:59:45 -0800122};
123
124template <typename AddressType>
125bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint32_t reg,
126 AddressType* reg_ptr, void* info) {
127 EvalInfo<AddressType>* eval_info = reinterpret_cast<EvalInfo<AddressType>*>(info);
128 Memory* regular_memory = eval_info->regular_memory;
129 switch (loc->type) {
130 case DWARF_LOCATION_OFFSET:
131 if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800132 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
133 last_error_.address = eval_info->cfa + loc->values[0];
Christopher Ferris98984b42018-01-17 12:59:45 -0800134 return false;
135 }
136 break;
137 case DWARF_LOCATION_VAL_OFFSET:
138 *reg_ptr = eval_info->cfa + loc->values[0];
139 break;
140 case DWARF_LOCATION_REGISTER: {
141 uint32_t cur_reg = loc->values[0];
Christopher Ferris559c7f22018-02-12 20:18:03 -0800142 if (cur_reg >= eval_info->regs_info.Total()) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800143 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris98984b42018-01-17 12:59:45 -0800144 return false;
145 }
Christopher Ferris559c7f22018-02-12 20:18:03 -0800146 *reg_ptr = eval_info->regs_info.Get(cur_reg) + loc->values[1];
Christopher Ferris98984b42018-01-17 12:59:45 -0800147 break;
148 }
149 case DWARF_LOCATION_EXPRESSION:
150 case DWARF_LOCATION_VAL_EXPRESSION: {
151 AddressType value;
Christopher Ferris559c7f22018-02-12 20:18:03 -0800152 bool is_dex_pc = false;
153 if (!EvalExpression(*loc, regular_memory, &value, &eval_info->regs_info, &is_dex_pc)) {
Christopher Ferris98984b42018-01-17 12:59:45 -0800154 return false;
155 }
156 if (loc->type == DWARF_LOCATION_EXPRESSION) {
157 if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800158 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
159 last_error_.address = value;
Christopher Ferris98984b42018-01-17 12:59:45 -0800160 return false;
161 }
162 } else {
163 *reg_ptr = value;
Christopher Ferris559c7f22018-02-12 20:18:03 -0800164 if (is_dex_pc) {
165 eval_info->regs_info.regs->set_dex_pc(value);
166 }
Christopher Ferris98984b42018-01-17 12:59:45 -0800167 }
168 break;
169 }
170 case DWARF_LOCATION_UNDEFINED:
171 if (reg == eval_info->cie->return_address_register) {
172 eval_info->return_address_undefined = true;
173 }
174 default:
175 break;
176 }
177
178 return true;
179}
180
181template <typename AddressType>
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700182bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory,
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700183 const dwarf_loc_regs_t& loc_regs, Regs* regs,
184 bool* finished) {
Christopher Ferris7b8e4672017-06-01 17:55:25 -0700185 RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(regs);
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700186 if (cie->return_address_register >= cur_regs->total_regs()) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800187 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700188 return false;
189 }
190
191 // Get the cfa value;
192 auto cfa_entry = loc_regs.find(CFA_REG);
193 if (cfa_entry == loc_regs.end()) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800194 last_error_.code = DWARF_ERROR_CFA_NOT_DEFINED;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700195 return false;
196 }
197
Christopher Ferris98984b42018-01-17 12:59:45 -0800198 // Always set the dex pc to zero when evaluating.
199 cur_regs->set_dex_pc(0);
200
Christopher Ferris559c7f22018-02-12 20:18:03 -0800201 EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs,
202 .cie = cie,
203 .regular_memory = regular_memory,
204 .regs_info = RegsInfo<AddressType>(cur_regs)};
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700205 const DwarfLocation* loc = &cfa_entry->second;
206 // Only a few location types are valid for the cfa.
207 switch (loc->type) {
208 case DWARF_LOCATION_REGISTER:
209 if (loc->values[0] >= cur_regs->total_regs()) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800210 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700211 return false;
212 }
Yabin Cui11e96fe2018-03-14 18:16:22 -0700213 eval_info.cfa = (*cur_regs)[loc->values[0]];
Christopher Ferris98984b42018-01-17 12:59:45 -0800214 eval_info.cfa += loc->values[1];
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700215 break;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700216 case DWARF_LOCATION_VAL_EXPRESSION: {
217 AddressType value;
Christopher Ferris559c7f22018-02-12 20:18:03 -0800218 if (!EvalExpression(*loc, regular_memory, &value, &eval_info.regs_info, nullptr)) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700219 return false;
220 }
David Srbecky3692f252018-03-08 16:57:19 +0000221 // There is only one type of valid expression for CFA evaluation.
222 eval_info.cfa = value;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700223 break;
224 }
225 default:
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800226 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700227 return false;
228 }
229
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700230 for (const auto& entry : loc_regs) {
Christopher Ferris98984b42018-01-17 12:59:45 -0800231 uint32_t reg = entry.first;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700232 // Already handled the CFA register.
233 if (reg == CFA_REG) continue;
234
Christopher Ferris98984b42018-01-17 12:59:45 -0800235 AddressType* reg_ptr;
Christopher Ferris559c7f22018-02-12 20:18:03 -0800236 if (reg >= cur_regs->total_regs()) {
237 // Skip this unknown register.
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700238 continue;
239 }
240
Christopher Ferris559c7f22018-02-12 20:18:03 -0800241 reg_ptr = eval_info.regs_info.Save(reg);
Christopher Ferris98984b42018-01-17 12:59:45 -0800242 if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
243 return false;
244 }
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700245 }
246
247 // Find the return address location.
Christopher Ferris98984b42018-01-17 12:59:45 -0800248 if (eval_info.return_address_undefined) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700249 cur_regs->set_pc(0);
250 } else {
251 cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
252 }
Christopher Ferris2502a602017-10-23 13:51:54 -0700253
254 // If the pc was set to zero, consider this the final frame.
255 *finished = (cur_regs->pc() == 0) ? true : false;
256
Christopher Ferris98984b42018-01-17 12:59:45 -0800257 cur_regs->set_sp(eval_info.cfa);
Christopher Ferrisfda7edd2017-10-31 16:10:42 -0700258
259 return true;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700260}
261
262template <typename AddressType>
263const DwarfCie* DwarfSectionImpl<AddressType>::GetCie(uint64_t offset) {
264 auto cie_entry = cie_entries_.find(offset);
265 if (cie_entry != cie_entries_.end()) {
266 return &cie_entry->second;
267 }
268 DwarfCie* cie = &cie_entries_[offset];
269 memory_.set_cur_offset(offset);
270 if (!FillInCie(cie)) {
271 // Erase the cached entry.
272 cie_entries_.erase(offset);
273 return nullptr;
274 }
275 return cie;
276}
277
278template <typename AddressType>
279bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
280 uint32_t length32;
281 if (!memory_.ReadBytes(&length32, sizeof(length32))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800282 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
283 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700284 return false;
285 }
Christopher Ferrisd226a512017-07-14 10:37:19 -0700286 // Set the default for the lsda encoding.
287 cie->lsda_encoding = DW_EH_PE_omit;
288
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700289 if (length32 == static_cast<uint32_t>(-1)) {
290 // 64 bit Cie
291 uint64_t length64;
292 if (!memory_.ReadBytes(&length64, sizeof(length64))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800293 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
294 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700295 return false;
296 }
297
298 cie->cfa_instructions_end = memory_.cur_offset() + length64;
299 cie->fde_address_encoding = DW_EH_PE_sdata8;
300
301 uint64_t cie_id;
302 if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800303 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
304 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700305 return false;
306 }
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700307 if (cie_id != cie64_value_) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700308 // This is not a Cie, something has gone horribly wrong.
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800309 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700310 return false;
311 }
312 } else {
313 // 32 bit Cie
314 cie->cfa_instructions_end = memory_.cur_offset() + length32;
315 cie->fde_address_encoding = DW_EH_PE_sdata4;
316
317 uint32_t cie_id;
318 if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800319 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
320 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700321 return false;
322 }
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700323 if (cie_id != cie32_value_) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700324 // This is not a Cie, something has gone horribly wrong.
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800325 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700326 return false;
327 }
328 }
329
330 if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800331 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
332 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700333 return false;
334 }
335
336 if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
337 // Unrecognized version.
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800338 last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700339 return false;
340 }
341
342 // Read the augmentation string.
343 char aug_value;
344 do {
345 if (!memory_.ReadBytes(&aug_value, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800346 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
347 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700348 return false;
349 }
350 cie->augmentation_string.push_back(aug_value);
351 } while (aug_value != '\0');
352
353 if (cie->version == 4) {
354 // Skip the Address Size field since we only use it for validation.
355 memory_.set_cur_offset(memory_.cur_offset() + 1);
356
357 // Segment Size
358 if (!memory_.ReadBytes(&cie->segment_size, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800359 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
360 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700361 return false;
362 }
363 }
364
365 // Code Alignment Factor
366 if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800367 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
368 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700369 return false;
370 }
371
372 // Data Alignment Factor
373 if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800374 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
375 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700376 return false;
377 }
378
379 if (cie->version == 1) {
380 // Return Address is a single byte.
381 uint8_t return_address_register;
382 if (!memory_.ReadBytes(&return_address_register, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800383 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
384 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700385 return false;
386 }
387 cie->return_address_register = return_address_register;
388 } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800389 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
390 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700391 return false;
392 }
393
394 if (cie->augmentation_string[0] != 'z') {
395 cie->cfa_instructions_offset = memory_.cur_offset();
396 return true;
397 }
398
399 uint64_t aug_length;
400 if (!memory_.ReadULEB128(&aug_length)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800401 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
402 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700403 return false;
404 }
405 cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
406
407 for (size_t i = 1; i < cie->augmentation_string.size(); i++) {
408 switch (cie->augmentation_string[i]) {
409 case 'L':
410 if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800411 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
412 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700413 return false;
414 }
415 break;
416 case 'P': {
417 uint8_t encoding;
418 if (!memory_.ReadBytes(&encoding, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800419 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
420 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700421 return false;
422 }
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700423 memory_.set_pc_offset(pc_offset_);
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700424 if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800425 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
426 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700427 return false;
428 }
429 } break;
430 case 'R':
431 if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800432 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
433 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700434 return false;
435 }
436 break;
437 }
438 }
439 return true;
440}
441
442template <typename AddressType>
443const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) {
444 auto fde_entry = fde_entries_.find(offset);
445 if (fde_entry != fde_entries_.end()) {
446 return &fde_entry->second;
447 }
448 DwarfFde* fde = &fde_entries_[offset];
449 memory_.set_cur_offset(offset);
450 if (!FillInFde(fde)) {
451 fde_entries_.erase(offset);
452 return nullptr;
453 }
454 return fde;
455}
456
457template <typename AddressType>
458bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
459 uint32_t length32;
460 if (!memory_.ReadBytes(&length32, sizeof(length32))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800461 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
462 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700463 return false;
464 }
465
466 if (length32 == static_cast<uint32_t>(-1)) {
467 // 64 bit Fde.
468 uint64_t length64;
469 if (!memory_.ReadBytes(&length64, sizeof(length64))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800470 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
471 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700472 return false;
473 }
474 fde->cfa_instructions_end = memory_.cur_offset() + length64;
475
476 uint64_t value64;
477 if (!memory_.ReadBytes(&value64, sizeof(value64))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800478 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
479 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700480 return false;
481 }
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700482 if (value64 == cie64_value_) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700483 // This is a Cie, this means something has gone wrong.
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800484 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700485 return false;
486 }
487
488 // Get the Cie pointer, which is necessary to properly read the rest of
489 // of the Fde information.
490 fde->cie_offset = GetCieOffsetFromFde64(value64);
491 } else {
492 // 32 bit Fde.
493 fde->cfa_instructions_end = memory_.cur_offset() + length32;
494
495 uint32_t value32;
496 if (!memory_.ReadBytes(&value32, sizeof(value32))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800497 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
498 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700499 return false;
500 }
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700501 if (value32 == cie32_value_) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700502 // This is a Cie, this means something has gone wrong.
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800503 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700504 return false;
505 }
506
507 // Get the Cie pointer, which is necessary to properly read the rest of
508 // of the Fde information.
509 fde->cie_offset = GetCieOffsetFromFde32(value32);
510 }
511 uint64_t cur_offset = memory_.cur_offset();
512
513 const DwarfCie* cie = GetCie(fde->cie_offset);
514 if (cie == nullptr) {
515 return false;
516 }
517 fde->cie = cie;
518
519 if (cie->segment_size != 0) {
520 // Skip over the segment selector for now.
521 cur_offset += cie->segment_size;
522 }
523 memory_.set_cur_offset(cur_offset);
524
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700525 // The load bias only applies to the start.
526 memory_.set_pc_offset(load_bias_);
527 bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700528 fde->pc_start = AdjustPcFromFde(fde->pc_start);
529
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700530 memory_.set_pc_offset(0);
531 if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800532 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
533 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700534 return false;
535 }
536 fde->pc_end += fde->pc_start;
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700537
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700538 if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
539 // Augmentation Size
540 uint64_t aug_length;
541 if (!memory_.ReadULEB128(&aug_length)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800542 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
543 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700544 return false;
545 }
546 uint64_t cur_offset = memory_.cur_offset();
547
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700548 memory_.set_pc_offset(pc_offset_);
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700549 if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800550 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
551 last_error_.address = memory_.cur_offset();
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700552 return false;
553 }
554
555 // Set our position to after all of the augmentation data.
556 memory_.set_cur_offset(cur_offset + aug_length);
557 }
558 fde->cfa_instructions_offset = memory_.cur_offset();
559
560 return true;
561}
562
563template <typename AddressType>
564bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde,
565 dwarf_loc_regs_t* loc_regs) {
566 DwarfCfa<AddressType> cfa(&memory_, fde);
567
568 // Look for the cached copy of the cie data.
569 auto reg_entry = cie_loc_regs_.find(fde->cie_offset);
570 if (reg_entry == cie_loc_regs_.end()) {
571 if (!cfa.GetLocationInfo(pc, fde->cie->cfa_instructions_offset, fde->cie->cfa_instructions_end,
572 loc_regs)) {
573 last_error_ = cfa.last_error();
574 return false;
575 }
576 cie_loc_regs_[fde->cie_offset] = *loc_regs;
577 }
578 cfa.set_cie_loc_regs(&cie_loc_regs_[fde->cie_offset]);
579 if (!cfa.GetLocationInfo(pc, fde->cfa_instructions_offset, fde->cfa_instructions_end, loc_regs)) {
580 last_error_ = cfa.last_error();
581 return false;
582 }
583 return true;
584}
585
586template <typename AddressType>
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700587bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700588 DwarfCfa<AddressType> cfa(&memory_, fde);
589
590 // Always print the cie information.
591 const DwarfCie* cie = fde->cie;
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700592 if (!cfa.Log(indent, pc, cie->cfa_instructions_offset, cie->cfa_instructions_end)) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700593 last_error_ = cfa.last_error();
594 return false;
595 }
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700596 if (!cfa.Log(indent, pc, fde->cfa_instructions_offset, fde->cfa_instructions_end)) {
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700597 last_error_ = cfa.last_error();
598 return false;
599 }
600 return true;
601}
602
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700603template <typename AddressType>
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700604bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
605 load_bias_ = load_bias;
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700606 entries_offset_ = offset;
607 entries_end_ = offset + size;
608
609 memory_.clear_func_offset();
610 memory_.clear_text_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700611 memory_.set_cur_offset(offset);
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700612 memory_.set_data_offset(offset);
613 pc_offset_ = offset;
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700614
615 return CreateSortedFdeList();
616}
617
618template <typename AddressType>
619bool DwarfSectionImpl<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) {
620 uint8_t version;
621 if (!memory_.ReadBytes(&version, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800622 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
623 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700624 return false;
625 }
626 // Read the augmentation string.
627 std::vector<char> aug_string;
628 char aug_value;
629 bool get_encoding = false;
630 do {
631 if (!memory_.ReadBytes(&aug_value, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800632 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
633 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700634 return false;
635 }
636 if (aug_value == 'R') {
637 get_encoding = true;
638 }
639 aug_string.push_back(aug_value);
640 } while (aug_value != '\0');
641
642 if (version == 4) {
643 // Skip the Address Size field.
644 memory_.set_cur_offset(memory_.cur_offset() + 1);
645
646 // Read the segment size.
647 if (!memory_.ReadBytes(segment_size, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800648 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
649 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700650 return false;
651 }
652 } else {
653 *segment_size = 0;
654 }
655
656 if (aug_string[0] != 'z' || !get_encoding) {
657 // No encoding
658 return true;
659 }
660
661 // Skip code alignment factor
662 uint8_t value;
663 do {
664 if (!memory_.ReadBytes(&value, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800665 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
666 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700667 return false;
668 }
669 } while (value & 0x80);
670
671 // Skip data alignment factor
672 do {
673 if (!memory_.ReadBytes(&value, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800674 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
675 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700676 return false;
677 }
678 } while (value & 0x80);
679
680 if (version == 1) {
681 // Skip return address register.
682 memory_.set_cur_offset(memory_.cur_offset() + 1);
683 } else {
684 // Skip return address register.
685 do {
686 if (!memory_.ReadBytes(&value, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800687 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
688 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700689 return false;
690 }
691 } while (value & 0x80);
692 }
693
694 // Skip the augmentation length.
695 do {
696 if (!memory_.ReadBytes(&value, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800697 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
698 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700699 return false;
700 }
701 } while (value & 0x80);
702
703 for (size_t i = 1; i < aug_string.size(); i++) {
704 if (aug_string[i] == 'R') {
705 if (!memory_.ReadBytes(encoding, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800706 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
707 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700708 return false;
709 }
710 // Got the encoding, that's all we are looking for.
711 return true;
712 } else if (aug_string[i] == 'L') {
713 memory_.set_cur_offset(memory_.cur_offset() + 1);
714 } else if (aug_string[i] == 'P') {
715 uint8_t encoding;
716 if (!memory_.ReadBytes(&encoding, 1)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800717 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
718 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700719 return false;
720 }
721 uint64_t value;
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700722 memory_.set_pc_offset(pc_offset_);
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700723 if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800724 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
725 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700726 return false;
727 }
728 }
729 }
730
731 // It should be impossible to get here.
732 abort();
733}
734
735template <typename AddressType>
736bool DwarfSectionImpl<AddressType>::AddFdeInfo(uint64_t entry_offset, uint8_t segment_size,
737 uint8_t encoding) {
738 if (segment_size != 0) {
739 memory_.set_cur_offset(memory_.cur_offset() + 1);
740 }
741
742 uint64_t start;
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700743 memory_.set_pc_offset(load_bias_);
744 bool valid = memory_.template ReadEncodedValue<AddressType>(encoding, &start);
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700745 start = AdjustPcFromFde(start);
746
747 uint64_t length;
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700748 memory_.set_pc_offset(0);
749 if (!valid || !memory_.template ReadEncodedValue<AddressType>(encoding, &length)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800750 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
751 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700752 return false;
753 }
754 if (length != 0) {
755 fdes_.emplace_back(entry_offset, start, length);
756 }
757
758 return true;
759}
760
761template <typename AddressType>
762bool DwarfSectionImpl<AddressType>::CreateSortedFdeList() {
763 memory_.set_cur_offset(entries_offset_);
764
765 // Loop through all of the entries and read just enough to create
766 // a sorted list of pcs.
767 // This code assumes that first comes the cie, then the fdes that
768 // it applies to.
769 uint64_t cie_offset = 0;
770 uint8_t address_encoding;
771 uint8_t segment_size;
772 while (memory_.cur_offset() < entries_end_) {
773 uint64_t cur_entry_offset = memory_.cur_offset();
774
775 // Figure out the entry length and type.
776 uint32_t value32;
777 if (!memory_.ReadBytes(&value32, sizeof(value32))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800778 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
779 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700780 return false;
781 }
782
783 uint64_t next_entry_offset;
784 if (value32 == static_cast<uint32_t>(-1)) {
785 uint64_t value64;
786 if (!memory_.ReadBytes(&value64, sizeof(value64))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800787 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
788 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700789 return false;
790 }
791 next_entry_offset = memory_.cur_offset() + value64;
792
793 // Read the Cie Id of a Cie or the pointer of the Fde.
794 if (!memory_.ReadBytes(&value64, sizeof(value64))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800795 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
796 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700797 return false;
798 }
799
800 if (value64 == cie64_value_) {
801 // Cie 64 bit
802 address_encoding = DW_EH_PE_sdata8;
803 if (!GetCieInfo(&segment_size, &address_encoding)) {
804 return false;
805 }
806 cie_offset = cur_entry_offset;
807 } else {
808 uint64_t last_cie_offset = GetCieOffsetFromFde64(value64);
809 if (last_cie_offset != cie_offset) {
810 // This means that this Fde is not following the Cie.
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800811 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700812 return false;
813 }
814
815 // Fde 64 bit
816 if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
817 return false;
818 }
819 }
820 } else {
821 next_entry_offset = memory_.cur_offset() + value32;
822
823 // Read the Cie Id of a Cie or the pointer of the Fde.
824 if (!memory_.ReadBytes(&value32, sizeof(value32))) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800825 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
826 last_error_.address = memory_.cur_offset();
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700827 return false;
828 }
829
830 if (value32 == cie32_value_) {
831 // Cie 32 bit
832 address_encoding = DW_EH_PE_sdata4;
833 if (!GetCieInfo(&segment_size, &address_encoding)) {
834 return false;
835 }
836 cie_offset = cur_entry_offset;
837 } else {
838 uint64_t last_cie_offset = GetCieOffsetFromFde32(value32);
839 if (last_cie_offset != cie_offset) {
840 // This means that this Fde is not following the Cie.
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800841 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700842 return false;
843 }
844
845 // Fde 32 bit
846 if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
847 return false;
848 }
849 }
850 }
851
852 if (next_entry_offset < memory_.cur_offset()) {
Christopher Ferris1a141a02018-01-24 08:52:47 -0800853 // Simply consider the processing done in this case.
854 break;
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700855 }
856 memory_.set_cur_offset(next_entry_offset);
857 }
858
859 // Sort the entries.
860 std::sort(fdes_.begin(), fdes_.end(), [](const FdeInfo& a, const FdeInfo& b) {
861 if (a.start == b.start) return a.end < b.end;
862 return a.start < b.start;
863 });
864
865 fde_count_ = fdes_.size();
866
867 return true;
868}
869
870template <typename AddressType>
871bool DwarfSectionImpl<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
872 if (fde_count_ == 0) {
873 return false;
874 }
875
876 size_t first = 0;
877 size_t last = fde_count_;
878 while (first < last) {
879 size_t current = (first + last) / 2;
880 const FdeInfo* info = &fdes_[current];
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700881 if (pc >= info->start && pc < info->end) {
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700882 *fde_offset = info->offset;
883 return true;
884 }
885
886 if (pc < info->start) {
887 last = current;
888 } else {
889 first = current + 1;
890 }
891 }
892 return false;
893}
894
895template <typename AddressType>
896const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromIndex(size_t index) {
897 if (index >= fdes_.size()) {
898 return nullptr;
899 }
900 return this->GetFdeFromOffset(fdes_[index].offset);
901}
902
Christopher Ferris53a3c9b2017-05-10 18:34:15 -0700903// Explicitly instantiate DwarfSectionImpl
904template class DwarfSectionImpl<uint32_t>;
905template class DwarfSectionImpl<uint64_t>;
Christopher Ferrisd226a512017-07-14 10:37:19 -0700906
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700907// Explicitly instantiate DwarfDebugFrame
908template class DwarfDebugFrame<uint32_t>;
909template class DwarfDebugFrame<uint64_t>;
910
911// Explicitly instantiate DwarfEhFrame
912template class DwarfEhFrame<uint32_t>;
913template class DwarfEhFrame<uint64_t>;
914
Christopher Ferrisd226a512017-07-14 10:37:19 -0700915} // namespace unwindstack