blob: 6ffdc0de1f56e1062b49beb49d07a5b8c8b689ad [file] [log] [blame]
Christopher Ferris72a6fa62017-03-21 12:41:17 -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
Christopher Ferris72a6fa62017-03-21 12:41:17 -070017#include <stdint.h>
18
19#include <string>
20
Christopher Ferrisd226a512017-07-14 10:37:19 -070021#include <unwindstack/DwarfMemory.h>
22#include <unwindstack/Memory.h>
23
Christopher Ferris94167032017-06-28 18:56:52 -070024#include "Check.h"
Christopher Ferris72a6fa62017-03-21 12:41:17 -070025#include "DwarfEncoding.h"
Christopher Ferrisd226a512017-07-14 10:37:19 -070026
27namespace unwindstack {
Christopher Ferris72a6fa62017-03-21 12:41:17 -070028
29bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
Josh Gaoef35aa52017-10-18 11:44:51 -070030 if (!memory_->ReadFully(cur_offset_, dst, num_bytes)) {
Christopher Ferris72a6fa62017-03-21 12:41:17 -070031 return false;
32 }
33 cur_offset_ += num_bytes;
34 return true;
35}
36
37template <typename SignedType>
38bool DwarfMemory::ReadSigned(uint64_t* value) {
39 SignedType signed_value;
40 if (!ReadBytes(&signed_value, sizeof(SignedType))) {
41 return false;
42 }
43 *value = static_cast<int64_t>(signed_value);
44 return true;
45}
46
47bool DwarfMemory::ReadULEB128(uint64_t* value) {
48 uint64_t cur_value = 0;
49 uint64_t shift = 0;
50 uint8_t byte;
51 do {
52 if (!ReadBytes(&byte, 1)) {
53 return false;
54 }
55 cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
56 shift += 7;
57 } while (byte & 0x80);
58 *value = cur_value;
59 return true;
60}
61
62bool DwarfMemory::ReadSLEB128(int64_t* value) {
63 uint64_t cur_value = 0;
64 uint64_t shift = 0;
65 uint8_t byte;
66 do {
67 if (!ReadBytes(&byte, 1)) {
68 return false;
69 }
70 cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
71 shift += 7;
72 } while (byte & 0x80);
73 if (byte & 0x40) {
74 // Negative value, need to sign extend.
75 cur_value |= static_cast<uint64_t>(-1) << shift;
76 }
77 *value = static_cast<int64_t>(cur_value);
78 return true;
79}
80
81template <typename AddressType>
82size_t DwarfMemory::GetEncodedSize(uint8_t encoding) {
83 switch (encoding & 0x0f) {
84 case DW_EH_PE_absptr:
85 return sizeof(AddressType);
86 case DW_EH_PE_udata1:
87 case DW_EH_PE_sdata1:
88 return 1;
89 case DW_EH_PE_udata2:
90 case DW_EH_PE_sdata2:
91 return 2;
92 case DW_EH_PE_udata4:
93 case DW_EH_PE_sdata4:
94 return 4;
95 case DW_EH_PE_udata8:
96 case DW_EH_PE_sdata8:
97 return 8;
98 case DW_EH_PE_uleb128:
99 case DW_EH_PE_sleb128:
100 default:
101 return 0;
102 }
103}
104
105bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
Christopher Ferris94167032017-06-28 18:56:52 -0700106 CHECK((encoding & 0x0f) == 0);
107 CHECK(encoding != DW_EH_PE_aligned);
Christopher Ferris72a6fa62017-03-21 12:41:17 -0700108
109 // Handle the encoding.
110 switch (encoding) {
111 case DW_EH_PE_absptr:
112 // Nothing to do.
113 break;
114 case DW_EH_PE_pcrel:
115 if (pc_offset_ == static_cast<uint64_t>(-1)) {
116 // Unsupported encoding.
117 return false;
118 }
119 *value += pc_offset_;
120 break;
121 case DW_EH_PE_textrel:
122 if (text_offset_ == static_cast<uint64_t>(-1)) {
123 // Unsupported encoding.
124 return false;
125 }
126 *value += text_offset_;
127 break;
128 case DW_EH_PE_datarel:
129 if (data_offset_ == static_cast<uint64_t>(-1)) {
130 // Unsupported encoding.
131 return false;
132 }
133 *value += data_offset_;
134 break;
135 case DW_EH_PE_funcrel:
136 if (func_offset_ == static_cast<uint64_t>(-1)) {
137 // Unsupported encoding.
138 return false;
139 }
140 *value += func_offset_;
141 break;
142 default:
143 return false;
144 }
145
146 return true;
147}
148
149template <typename AddressType>
150bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) {
151 if (encoding == DW_EH_PE_omit) {
152 *value = 0;
153 return true;
154 } else if (encoding == DW_EH_PE_aligned) {
155 if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) {
156 return false;
157 }
158 cur_offset_ &= -sizeof(AddressType);
159
160 if (sizeof(AddressType) != sizeof(uint64_t)) {
161 *value = 0;
162 }
163 return ReadBytes(value, sizeof(AddressType));
164 }
165
166 // Get the data.
167 switch (encoding & 0x0f) {
168 case DW_EH_PE_absptr:
169 if (sizeof(AddressType) != sizeof(uint64_t)) {
170 *value = 0;
171 }
172 if (!ReadBytes(value, sizeof(AddressType))) {
173 return false;
174 }
175 break;
176 case DW_EH_PE_uleb128:
177 if (!ReadULEB128(value)) {
178 return false;
179 }
180 break;
181 case DW_EH_PE_sleb128:
182 int64_t signed_value;
183 if (!ReadSLEB128(&signed_value)) {
184 return false;
185 }
186 *value = static_cast<uint64_t>(signed_value);
187 break;
188 case DW_EH_PE_udata1: {
189 uint8_t value8;
190 if (!ReadBytes(&value8, 1)) {
191 return false;
192 }
193 *value = value8;
194 } break;
195 case DW_EH_PE_sdata1:
196 if (!ReadSigned<int8_t>(value)) {
197 return false;
198 }
199 break;
200 case DW_EH_PE_udata2: {
201 uint16_t value16;
202 if (!ReadBytes(&value16, 2)) {
203 return false;
204 }
205 *value = value16;
206 } break;
207 case DW_EH_PE_sdata2:
208 if (!ReadSigned<int16_t>(value)) {
209 return false;
210 }
211 break;
212 case DW_EH_PE_udata4: {
213 uint32_t value32;
214 if (!ReadBytes(&value32, 4)) {
215 return false;
216 }
217 *value = value32;
218 } break;
219 case DW_EH_PE_sdata4:
220 if (!ReadSigned<int32_t>(value)) {
221 return false;
222 }
223 break;
224 case DW_EH_PE_udata8:
225 if (!ReadBytes(value, sizeof(uint64_t))) {
226 return false;
227 }
228 break;
229 case DW_EH_PE_sdata8:
230 if (!ReadSigned<int64_t>(value)) {
231 return false;
232 }
233 break;
234 default:
235 return false;
236 }
237
Christopher Ferris9e484bd2017-08-10 17:37:32 -0700238 return AdjustEncodedValue(encoding & 0x70, value);
Christopher Ferris72a6fa62017-03-21 12:41:17 -0700239}
240
241// Instantiate all of the needed template functions.
242template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
243template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
244template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
245template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);
246
247template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
248template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);
249
250template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
251template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
Christopher Ferrisd226a512017-07-14 10:37:19 -0700252
253} // namespace unwindstack