• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   CHECK(encoding != DW_EH_PE_aligned);
108 
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 
149 template <typename AddressType>
ReadEncodedValue(uint8_t encoding,uint64_t * value)150 bool 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 
238   return AdjustEncodedValue(encoding & 0x70, value);
239 }
240 
241 // Instantiate all of the needed template functions.
242 template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
243 template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
244 template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
245 template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);
246 
247 template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
248 template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);
249 
250 template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
251 template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
252 
253 }  // namespace unwindstack
254