1 /*
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
19 #include <string>
20
21 #include <unwindstack/DwarfMemory.h>
22 #include <unwindstack/Memory.h>
23
24 #include "Check.h"
25 #include "DwarfEncoding.h"
26
27 namespace unwindstack {
28
ReadBytes(void * dst,size_t num_bytes)29 bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
30 if (!memory_->ReadFully(cur_offset_, dst, num_bytes)) {
31 return false;
32 }
33 cur_offset_ += num_bytes;
34 return true;
35 }
36
37 template <typename SignedType>
ReadSigned(uint64_t * value)38 bool 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
ReadULEB128(uint64_t * value)47 bool 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
ReadSLEB128(int64_t * value)62 bool 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
81 template <typename AddressType>
GetEncodedSize(uint8_t encoding)82 size_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
AdjustEncodedValue(uint8_t encoding,uint64_t * value)105 bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
106 CHECK((encoding & 0x0f) == 0);
107
108 // Handle the encoding.
109 switch (encoding) {
110 case DW_EH_PE_absptr:
111 // Nothing to do.
112 break;
113 case DW_EH_PE_pcrel:
114 if (pc_offset_ == static_cast<uint64_t>(-1)) {
115 // Unsupported encoding.
116 return false;
117 }
118 *value += pc_offset_;
119 break;
120 case DW_EH_PE_textrel:
121 if (text_offset_ == static_cast<uint64_t>(-1)) {
122 // Unsupported encoding.
123 return false;
124 }
125 *value += text_offset_;
126 break;
127 case DW_EH_PE_datarel:
128 if (data_offset_ == static_cast<uint64_t>(-1)) {
129 // Unsupported encoding.
130 return false;
131 }
132 *value += data_offset_;
133 break;
134 case DW_EH_PE_funcrel:
135 if (func_offset_ == static_cast<uint64_t>(-1)) {
136 // Unsupported encoding.
137 return false;
138 }
139 *value += func_offset_;
140 break;
141 default:
142 return false;
143 }
144
145 return true;
146 }
147
148 template <typename AddressType>
ReadEncodedValue(uint8_t encoding,uint64_t * value)149 bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) {
150 if (encoding == DW_EH_PE_omit) {
151 *value = 0;
152 return true;
153 } else if (encoding == DW_EH_PE_aligned) {
154 if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) {
155 return false;
156 }
157 cur_offset_ &= -sizeof(AddressType);
158
159 if (sizeof(AddressType) != sizeof(uint64_t)) {
160 *value = 0;
161 }
162 return ReadBytes(value, sizeof(AddressType));
163 }
164
165 // Get the data.
166 switch (encoding & 0x0f) {
167 case DW_EH_PE_absptr:
168 if (sizeof(AddressType) != sizeof(uint64_t)) {
169 *value = 0;
170 }
171 if (!ReadBytes(value, sizeof(AddressType))) {
172 return false;
173 }
174 break;
175 case DW_EH_PE_uleb128:
176 if (!ReadULEB128(value)) {
177 return false;
178 }
179 break;
180 case DW_EH_PE_sleb128:
181 int64_t signed_value;
182 if (!ReadSLEB128(&signed_value)) {
183 return false;
184 }
185 *value = static_cast<uint64_t>(signed_value);
186 break;
187 case DW_EH_PE_udata1: {
188 uint8_t value8;
189 if (!ReadBytes(&value8, 1)) {
190 return false;
191 }
192 *value = value8;
193 } break;
194 case DW_EH_PE_sdata1:
195 if (!ReadSigned<int8_t>(value)) {
196 return false;
197 }
198 break;
199 case DW_EH_PE_udata2: {
200 uint16_t value16;
201 if (!ReadBytes(&value16, 2)) {
202 return false;
203 }
204 *value = value16;
205 } break;
206 case DW_EH_PE_sdata2:
207 if (!ReadSigned<int16_t>(value)) {
208 return false;
209 }
210 break;
211 case DW_EH_PE_udata4: {
212 uint32_t value32;
213 if (!ReadBytes(&value32, 4)) {
214 return false;
215 }
216 *value = value32;
217 } break;
218 case DW_EH_PE_sdata4:
219 if (!ReadSigned<int32_t>(value)) {
220 return false;
221 }
222 break;
223 case DW_EH_PE_udata8:
224 if (!ReadBytes(value, sizeof(uint64_t))) {
225 return false;
226 }
227 break;
228 case DW_EH_PE_sdata8:
229 if (!ReadSigned<int64_t>(value)) {
230 return false;
231 }
232 break;
233 default:
234 return false;
235 }
236
237 return AdjustEncodedValue(encoding & 0x70, value);
238 }
239
240 // Instantiate all of the needed template functions.
241 template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
242 template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
243 template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
244 template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);
245
246 template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
247 template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);
248
249 template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
250 template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
251
252 } // namespace unwindstack
253