blob: 57075962ac6e3c568b885cb65bd850dd51ee1cd1 [file] [log] [blame]
Christopher Ferris61d40972017-06-12 19:14:20 -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#include <stdlib.h>
19
20#include <algorithm>
21
Christopher Ferrisd226a512017-07-14 10:37:19 -070022#include <unwindstack/DwarfStructs.h>
23#include <unwindstack/Memory.h>
24
Christopher Ferris61d40972017-06-12 19:14:20 -070025#include "DwarfDebugFrame.h"
Christopher Ferrisd226a512017-07-14 10:37:19 -070026#include "DwarfEncoding.h"
27#include "DwarfError.h"
28
29namespace unwindstack {
Christopher Ferris61d40972017-06-12 19:14:20 -070030
31template <typename AddressType>
32bool DwarfDebugFrame<AddressType>::Init(uint64_t offset, uint64_t size) {
33 offset_ = offset;
34 end_offset_ = offset + size;
35
36 memory_.clear_func_offset();
37 memory_.clear_text_offset();
38 memory_.set_data_offset(offset);
39 memory_.set_cur_offset(offset);
40
41 return CreateSortedFdeList();
42}
43
44template <typename AddressType>
45bool DwarfDebugFrame<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) {
46 uint8_t version;
47 if (!memory_.ReadBytes(&version, 1)) {
48 last_error_ = DWARF_ERROR_MEMORY_INVALID;
49 return false;
50 }
51 // Read the augmentation string.
52 std::vector<char> aug_string;
53 char aug_value;
54 bool get_encoding = false;
55 do {
56 if (!memory_.ReadBytes(&aug_value, 1)) {
57 last_error_ = DWARF_ERROR_MEMORY_INVALID;
58 return false;
59 }
60 if (aug_value == 'R') {
61 get_encoding = true;
62 }
63 aug_string.push_back(aug_value);
64 } while (aug_value != '\0');
65
66 if (version == 4) {
67 // Skip the Address Size field.
68 memory_.set_cur_offset(memory_.cur_offset() + 1);
69
70 // Read the segment size.
71 if (!memory_.ReadBytes(segment_size, 1)) {
72 last_error_ = DWARF_ERROR_MEMORY_INVALID;
73 return false;
74 }
75 } else {
76 *segment_size = 0;
77 }
78
79 if (aug_string[0] != 'z' || !get_encoding) {
80 // No encoding
81 return true;
82 }
83
84 // Skip code alignment factor
85 uint8_t value;
86 do {
87 if (!memory_.ReadBytes(&value, 1)) {
88 last_error_ = DWARF_ERROR_MEMORY_INVALID;
89 return false;
90 }
91 } while (value & 0x80);
92
93 // Skip data alignment factor
94 do {
95 if (!memory_.ReadBytes(&value, 1)) {
96 last_error_ = DWARF_ERROR_MEMORY_INVALID;
97 return false;
98 }
99 } while (value & 0x80);
100
101 if (version == 1) {
102 // Skip return address register.
103 memory_.set_cur_offset(memory_.cur_offset() + 1);
104 } else {
105 // Skip return address register.
106 do {
107 if (!memory_.ReadBytes(&value, 1)) {
108 last_error_ = DWARF_ERROR_MEMORY_INVALID;
109 return false;
110 }
111 } while (value & 0x80);
112 }
113
114 // Skip the augmentation length.
115 do {
116 if (!memory_.ReadBytes(&value, 1)) {
117 last_error_ = DWARF_ERROR_MEMORY_INVALID;
118 return false;
119 }
120 } while (value & 0x80);
121
122 for (size_t i = 1; i < aug_string.size(); i++) {
123 if (aug_string[i] == 'R') {
124 if (!memory_.ReadBytes(encoding, 1)) {
125 last_error_ = DWARF_ERROR_MEMORY_INVALID;
126 return false;
127 }
128 // Got the encoding, that's all we are looking for.
129 return true;
130 } else if (aug_string[i] == 'L') {
131 memory_.set_cur_offset(memory_.cur_offset() + 1);
132 } else if (aug_string[i] == 'P') {
133 uint8_t encoding;
134 if (!memory_.ReadBytes(&encoding, 1)) {
135 last_error_ = DWARF_ERROR_MEMORY_INVALID;
136 return false;
137 }
138 uint64_t value;
139 if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
140 last_error_ = DWARF_ERROR_MEMORY_INVALID;
141 return false;
142 }
143 }
144 }
145
146 // It should be impossible to get here.
147 abort();
148}
149
150template <typename AddressType>
151bool DwarfDebugFrame<AddressType>::AddFdeInfo(uint64_t entry_offset, uint8_t segment_size,
152 uint8_t encoding) {
153 if (segment_size != 0) {
154 memory_.set_cur_offset(memory_.cur_offset() + 1);
155 }
156
157 uint64_t start;
158 if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &start)) {
159 last_error_ = DWARF_ERROR_MEMORY_INVALID;
160 return false;
161 }
162
163 uint64_t length;
164 if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &length)) {
165 last_error_ = DWARF_ERROR_MEMORY_INVALID;
166 return false;
167 }
168 if (length != 0) {
169 fdes_.emplace_back(entry_offset, start, length);
170 }
171
172 return true;
173}
174
175template <typename AddressType>
176bool DwarfDebugFrame<AddressType>::CreateSortedFdeList() {
177 memory_.set_cur_offset(offset_);
178
179 // Loop through all of the entries and read just enough to create
180 // a sorted list of pcs.
181 // This code assumes that first comes the cie, then the fdes that
182 // it applies to.
183 uint64_t cie_offset = 0;
184 uint8_t address_encoding;
185 uint8_t segment_size;
186 while (memory_.cur_offset() < end_offset_) {
187 uint64_t cur_entry_offset = memory_.cur_offset();
188
189 // Figure out the entry length and type.
190 uint32_t value32;
191 if (!memory_.ReadBytes(&value32, sizeof(value32))) {
192 last_error_ = DWARF_ERROR_MEMORY_INVALID;
193 return false;
194 }
195
196 uint64_t next_entry_offset;
197 if (value32 == static_cast<uint32_t>(-1)) {
198 uint64_t value64;
199 if (!memory_.ReadBytes(&value64, sizeof(value64))) {
200 last_error_ = DWARF_ERROR_MEMORY_INVALID;
201 return false;
202 }
203 next_entry_offset = memory_.cur_offset() + value64;
204
205 // Read the Cie Id of a Cie or the pointer of the Fde.
206 if (!memory_.ReadBytes(&value64, sizeof(value64))) {
207 last_error_ = DWARF_ERROR_MEMORY_INVALID;
208 return false;
209 }
210
211 if (value64 == static_cast<uint64_t>(-1)) {
212 // Cie 64 bit
213 address_encoding = DW_EH_PE_sdata8;
214 if (!GetCieInfo(&segment_size, &address_encoding)) {
215 return false;
216 }
217 cie_offset = cur_entry_offset;
218 } else {
219 if (offset_ + value64 != cie_offset) {
220 // This means that this Fde is not following the Cie.
221 last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
222 return false;
223 }
224
225 // Fde 64 bit
226 if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
227 return false;
228 }
229 }
230 } else {
231 next_entry_offset = memory_.cur_offset() + value32;
232
233 // Read the Cie Id of a Cie or the pointer of the Fde.
234 if (!memory_.ReadBytes(&value32, sizeof(value32))) {
235 last_error_ = DWARF_ERROR_MEMORY_INVALID;
236 return false;
237 }
238
239 if (value32 == static_cast<uint32_t>(-1)) {
240 // Cie 32 bit
241 address_encoding = DW_EH_PE_sdata4;
242 if (!GetCieInfo(&segment_size, &address_encoding)) {
243 return false;
244 }
245 cie_offset = cur_entry_offset;
246 } else {
247 if (offset_ + value32 != cie_offset) {
248 // This means that this Fde is not following the Cie.
249 last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
250 return false;
251 }
252
253 // Fde 32 bit
254 if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
255 return false;
256 }
257 }
258 }
259
260 if (next_entry_offset < memory_.cur_offset()) {
261 // This indicates some kind of corruption, or malformed section data.
262 last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
263 return false;
264 }
265 memory_.set_cur_offset(next_entry_offset);
266 }
267
268 // Sort the entries.
269 std::sort(fdes_.begin(), fdes_.end(), [](const FdeInfo& a, const FdeInfo& b) {
270 if (a.start == b.start) return a.end < b.end;
271 return a.start < b.start;
272 });
273
274 fde_count_ = fdes_.size();
275
276 return true;
277}
278
279template <typename AddressType>
280bool DwarfDebugFrame<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
281 if (fde_count_ == 0) {
282 return false;
283 }
284
285 size_t first = 0;
286 size_t last = fde_count_;
287 while (first < last) {
288 size_t current = (first + last) / 2;
289 const FdeInfo* info = &fdes_[current];
290 if (pc >= info->start && pc <= info->end) {
291 *fde_offset = info->offset;
292 return true;
293 }
294
295 if (pc < info->start) {
296 last = current;
297 } else {
298 first = current + 1;
299 }
300 }
301 return false;
302}
303
304template <typename AddressType>
305const DwarfFde* DwarfDebugFrame<AddressType>::GetFdeFromIndex(size_t index) {
306 if (index >= fdes_.size()) {
307 return nullptr;
308 }
309 return this->GetFdeFromOffset(fdes_[index].offset);
310}
311
312// Explicitly instantiate DwarfDebugFrame.
313template class DwarfDebugFrame<uint32_t>;
314template class DwarfDebugFrame<uint64_t>;
Christopher Ferrisd226a512017-07-14 10:37:19 -0700315
316} // namespace unwindstack