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