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
27namespace unwindstack {
28
29bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
30  if (!memory_->Read(cur_offset_, dst, num_bytes)) {
31    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) {
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
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
238  return AdjustEncodedValue(encoding & 0xf0, value);
239}
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*);
252
253}  // namespace unwindstack
254