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_ == INT64_MAX) {
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